1 |
twoaday |
2 |
/* rungpg.c |
2 |
|
|
* Copyright (C) 2000, 2001 Werner Koch (dd9jn), g10 Code GmbH |
3 |
|
|
* Copyright (C) 2002, 2003, 2004 Timo Schulz |
4 |
|
|
* |
5 |
|
|
* This file is part of MyGPGME. |
6 |
|
|
* |
7 |
|
|
* MyGPGME is free software; you can redistribute it and/or modify |
8 |
|
|
* it under the terms of the GNU General Public License as published by |
9 |
|
|
* the Free Software Foundation; either version 2 of the License, or |
10 |
|
|
* (at your option) any later version. |
11 |
|
|
* |
12 |
|
|
* MyGPGME is distributed in the hope that it will be useful, |
13 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
|
|
* GNU General Public License for more details. |
16 |
|
|
* |
17 |
|
|
* You should have received a copy of the GNU General Public License |
18 |
|
|
* along with this program; if not, write to the Free Software |
19 |
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
20 |
|
|
*/ |
21 |
|
|
|
22 |
|
|
#include <stdio.h> |
23 |
|
|
#include <stdlib.h> |
24 |
|
|
#include <string.h> |
25 |
|
|
#include <assert.h> |
26 |
|
|
#include <errno.h> |
27 |
|
|
#include <time.h> |
28 |
|
|
#include <sys/types.h> |
29 |
|
|
#include <signal.h> |
30 |
|
|
#include <fcntl.h> |
31 |
|
|
#include <windows.h> |
32 |
|
|
|
33 |
|
|
#include "gpgme.h" |
34 |
|
|
#include "util.h" |
35 |
|
|
#include "ops.h" |
36 |
|
|
#include "wait.h" |
37 |
|
|
#include "rungpg.h" |
38 |
|
|
#include "context.h" /*temp hack until we have gpgme_dat_t methods to do I/O */ |
39 |
|
|
#include "gpgme-io.h" |
40 |
|
|
#include "sema.h" |
41 |
|
|
|
42 |
|
|
#include "status-table.h" |
43 |
|
|
|
44 |
|
|
|
45 |
|
|
/* This type is used to build a list of gpg arguments and |
46 |
|
|
* data sources/sinks */ |
47 |
|
|
struct arg_and_data_s { |
48 |
|
|
struct arg_and_data_s * next; |
49 |
|
|
gpgme_data_t data;/* If this is not NULL .. */ |
50 |
|
|
int dup_to; |
51 |
|
|
int print_fd; /* print the fd number and not the special form of it */ |
52 |
|
|
char arg[1]; /* .. this is used */ |
53 |
|
|
}; |
54 |
|
|
|
55 |
|
|
struct fd_data_map_s { |
56 |
|
|
gpgme_data_t data; |
57 |
|
|
int inbound; /* true if this is used for reading from gpg */ |
58 |
|
|
int dup_to; |
59 |
|
|
int fd; /* the fd to use */ |
60 |
|
|
int peer_fd; /* the outher side of the pipe */ |
61 |
|
|
}; |
62 |
|
|
|
63 |
|
|
|
64 |
|
|
struct gpg_object_s { |
65 |
|
|
struct arg_and_data_s * arglist; |
66 |
|
|
struct arg_and_data_s ** argtail; |
67 |
|
|
int arg_error; |
68 |
|
|
|
69 |
|
|
struct { |
70 |
|
|
int fd[2]; |
71 |
|
|
int eof; |
72 |
|
|
size_t bufsize; |
73 |
|
|
char * buffer; |
74 |
|
|
size_t readpos; |
75 |
|
|
gpg_status_handler_t fnc; |
76 |
|
|
void * fnc_value; |
77 |
|
|
} status; |
78 |
|
|
|
79 |
|
|
struct { |
80 |
|
|
int fd[2]; |
81 |
|
|
int eof; |
82 |
|
|
int enabled; |
83 |
|
|
size_t bufsize; |
84 |
|
|
char * buffer; |
85 |
|
|
void * fnc_value; |
86 |
|
|
} logging; |
87 |
|
|
|
88 |
|
|
/* This is a kludge - see the comment at gpg_colon_line_handler */ |
89 |
|
|
struct { |
90 |
|
|
int fd[2]; |
91 |
|
|
int eof; |
92 |
|
|
size_t bufsize; |
93 |
|
|
char *buffer; |
94 |
|
|
size_t readpos; |
95 |
|
|
gpg_colon_line_handler_t fnc; /* this indicate use of this structrue */ |
96 |
|
|
void *fnc_value; |
97 |
|
|
int simple; |
98 |
|
|
} colon; |
99 |
|
|
|
100 |
|
|
char **argv; |
101 |
|
|
struct fd_data_map_s *fd_data_map; |
102 |
|
|
|
103 |
|
|
int pid; /* we can't use pid_t because we don't use it in Windows */ |
104 |
|
|
|
105 |
|
|
int running; |
106 |
|
|
|
107 |
|
|
/* stuff needed for interactive (command) mode */ |
108 |
|
|
struct { |
109 |
|
|
int used; |
110 |
|
|
int fd; |
111 |
|
|
gpgme_data_t cb_data; /* hack to get init the above fd later */ |
112 |
|
|
gpg_status_code_t code; /* last code */ |
113 |
|
|
char *keyword; /* what has been requested (malloced) */ |
114 |
|
|
gpg_command_handler_t fnc; |
115 |
|
|
void *fnc_value; |
116 |
|
|
} cmd; |
117 |
|
|
}; |
118 |
|
|
|
119 |
|
|
struct reap_s { |
120 |
|
|
struct reap_s *next; |
121 |
|
|
int pid; |
122 |
|
|
time_t entered; |
123 |
|
|
int term_send; |
124 |
|
|
}; |
125 |
|
|
|
126 |
|
|
static struct reap_s *reap_list; |
127 |
|
|
DEFINE_STATIC_LOCK (reap_list_lock); |
128 |
|
|
|
129 |
|
|
|
130 |
|
|
static void free_argv ( char **argv ); |
131 |
|
|
static void free_fd_data_map ( struct fd_data_map_s *fd_data_map ); |
132 |
|
|
|
133 |
|
|
static int gpg_inbound_handler ( void *opaque, int pid, int fd ); |
134 |
|
|
static int gpg_outbound_handler ( void *opaque, int pid, int fd ); |
135 |
|
|
|
136 |
|
|
static int gpg_logging_handler( void * opaque, int pid, int fd ); |
137 |
|
|
static gpgme_error_t read_logging( _gpg_object_t gpg ); |
138 |
|
|
|
139 |
|
|
static int gpg_status_handler( void *opaque, int pid, int fd ); |
140 |
|
|
static gpgme_error_t read_status( _gpg_object_t gpg ); |
141 |
|
|
|
142 |
|
|
static int gpg_colon_line_handler ( void *opaque, int pid, int fd ); |
143 |
|
|
static gpgme_error_t read_colon_line ( _gpg_object_t gpg ); |
144 |
|
|
|
145 |
|
|
static int command_cb ( void *opaque, |
146 |
|
|
char *buffer, size_t length, size_t *nread ); |
147 |
|
|
|
148 |
|
|
|
149 |
|
|
void |
150 |
|
|
rungpg_cleanup (void) |
151 |
|
|
{ |
152 |
|
|
DESTROY_LOCK (reap_list_lock); |
153 |
|
|
} |
154 |
|
|
|
155 |
|
|
|
156 |
|
|
static void |
157 |
|
|
close_notify_handler ( int fd, void *opaque ) |
158 |
|
|
{ |
159 |
|
|
_gpg_object_t gpg = opaque; |
160 |
|
|
|
161 |
|
|
assert( fd != -1 ); |
162 |
|
|
if( gpg->status.fd[0] == fd ) |
163 |
|
|
gpg->status.fd[0] = -1; |
164 |
|
|
else if (gpg->status.fd[1] == fd ) |
165 |
|
|
gpg->status.fd[1] = -1; |
166 |
|
|
else if( gpg->logging.fd[0] == fd ) |
167 |
|
|
gpg->logging.fd[0] = -1; |
168 |
|
|
else if( gpg->logging.fd[1] == fd ) |
169 |
|
|
gpg->logging.fd[1] = -1; |
170 |
|
|
else if (gpg->colon.fd[0] == fd ) |
171 |
|
|
gpg->colon.fd[0] = -1; |
172 |
|
|
else if (gpg->colon.fd[1] == fd ) |
173 |
|
|
gpg->colon.fd[1] = -1; |
174 |
|
|
else if (gpg->fd_data_map) { |
175 |
|
|
int i; |
176 |
|
|
|
177 |
|
|
for (i=0; gpg->fd_data_map[i].data; i++ ) { |
178 |
|
|
if ( gpg->fd_data_map[i].fd == fd ) { |
179 |
|
|
gpg->fd_data_map[i].fd = -1; |
180 |
|
|
break; |
181 |
|
|
} |
182 |
|
|
if ( gpg->fd_data_map[i].peer_fd == fd ) { |
183 |
|
|
gpg->fd_data_map[i].peer_fd = -1; |
184 |
|
|
break; |
185 |
|
|
} |
186 |
|
|
} |
187 |
|
|
} |
188 |
|
|
} |
189 |
|
|
|
190 |
|
|
|
191 |
|
|
gpgme_error_t |
192 |
|
|
_gpgme_gpg_new ( _gpg_object_t *r_gpg ) |
193 |
|
|
{ |
194 |
|
|
_gpg_object_t gpg; |
195 |
|
|
char * p; |
196 |
|
|
char buf[25]; |
197 |
|
|
int rc = 0; |
198 |
|
|
|
199 |
|
|
gpg = calloc ( 1, sizeof *gpg ); |
200 |
|
|
if ( !gpg ) { |
201 |
|
|
rc = mk_error (Out_Of_Core); |
202 |
|
|
goto leave; |
203 |
|
|
} |
204 |
|
|
gpg->argtail = &gpg->arglist; |
205 |
|
|
|
206 |
|
|
gpg->status.fd[0] = -1; |
207 |
|
|
gpg->status.fd[1] = -1; |
208 |
|
|
gpg->logging.fd[0] = -1; |
209 |
|
|
gpg->logging.fd[1] = -1; |
210 |
|
|
gpg->colon.fd[0] = -1; |
211 |
|
|
gpg->colon.fd[1] = -1; |
212 |
|
|
gpg->cmd.fd = -1; |
213 |
|
|
|
214 |
|
|
gpg->pid = -1; |
215 |
|
|
|
216 |
|
|
/* allocate the read buffer for the status pipe */ |
217 |
|
|
gpg->status.bufsize = 1024; |
218 |
|
|
gpg->status.readpos = 0; |
219 |
|
|
p = gpg->status.buffer = malloc( gpg->status.bufsize ); |
220 |
|
|
if( !p ) { |
221 |
|
|
rc = mk_error (Out_Of_Core); |
222 |
|
|
goto leave; |
223 |
|
|
} |
224 |
|
|
|
225 |
|
|
gpg->logging.bufsize = 512; |
226 |
|
|
p = gpg->logging.buffer = malloc( gpg->logging.bufsize+4 ); |
227 |
|
|
if( !p ) { |
228 |
|
|
rc = mk_error( Out_Of_Core ); |
229 |
|
|
goto leave; |
230 |
|
|
} |
231 |
|
|
|
232 |
|
|
/* In any case we need a status pipe - create it right here and |
233 |
|
|
* don't handle it with our generic gpgme_data_t mechanism */ |
234 |
|
|
if( _gpgme_io_pipe( gpg->status.fd, 1 ) == -1 |
235 |
|
|
|| _gpgme_io_pipe( gpg->logging.fd, 1 ) == -1 ) { |
236 |
|
|
rc = mk_error (Pipe_Error); |
237 |
|
|
goto leave; |
238 |
|
|
} |
239 |
|
|
if ( _gpgme_io_set_close_notify( gpg->status.fd[0], |
240 |
|
|
close_notify_handler, gpg ) |
241 |
|
|
|| _gpgme_io_set_close_notify( gpg->status.fd[1], |
242 |
|
|
close_notify_handler, gpg ) |
243 |
|
|
|| _gpgme_io_set_close_notify( gpg->logging.fd[0], |
244 |
|
|
close_notify_handler, gpg ) |
245 |
|
|
|| _gpgme_io_set_close_notify( gpg->logging.fd[1], |
246 |
|
|
close_notify_handler, gpg ) ) { |
247 |
|
|
rc = mk_error (General_Error); |
248 |
|
|
goto leave; |
249 |
|
|
} |
250 |
|
|
|
251 |
|
|
gpg->status.eof = 0; |
252 |
|
|
_gpgme_gpg_add_arg( gpg, "--status-fd" ); |
253 |
|
|
sprintf( buf, "%d", gpg->status.fd[1] ); |
254 |
|
|
_gpgme_gpg_add_arg ( gpg, buf ); |
255 |
|
|
|
256 |
|
|
gpg->logging.eof = 0; |
257 |
|
|
_gpgme_gpg_add_arg( gpg, "--logger-fd" ); |
258 |
|
|
sprintf( buf, "%d", gpg->logging.fd[1] ); |
259 |
|
|
_gpgme_gpg_add_arg( gpg, buf ); |
260 |
|
|
|
261 |
|
|
_gpgme_gpg_add_arg ( gpg, "--no-tty" ); |
262 |
|
|
|
263 |
|
|
|
264 |
|
|
leave: |
265 |
|
|
if( rc ) { |
266 |
|
|
_gpgme_gpg_release( &gpg ); |
267 |
|
|
*r_gpg = NULL; |
268 |
|
|
} |
269 |
|
|
else |
270 |
|
|
*r_gpg = gpg; |
271 |
|
|
return rc; |
272 |
|
|
} |
273 |
|
|
|
274 |
|
|
static void |
275 |
|
|
_pipe_close( int * fd ) |
276 |
|
|
{ |
277 |
|
|
if( fd[0] != -1 ) |
278 |
|
|
_gpgme_io_close( fd[0] ); |
279 |
|
|
if( fd[1] != -1 ) |
280 |
|
|
_gpgme_io_close( fd[1] ); |
281 |
|
|
} |
282 |
|
|
|
283 |
|
|
|
284 |
|
|
void |
285 |
|
|
_gpgme_gpg_release( _gpg_object_t *r_gpg ) |
286 |
|
|
{ |
287 |
|
|
struct arg_and_data_s * a; |
288 |
|
|
_gpg_object_t gpg = *r_gpg; |
289 |
|
|
|
290 |
|
|
if( !gpg ) |
291 |
|
|
return; |
292 |
|
|
safe_free( gpg->status.buffer ); |
293 |
|
|
safe_free( gpg->logging.buffer ); |
294 |
|
|
safe_free( gpg->colon.buffer ); |
295 |
|
|
safe_free( gpg->cmd.keyword ); |
296 |
|
|
if (gpg->argv) |
297 |
|
|
free_argv(gpg->argv); |
298 |
|
|
|
299 |
|
|
if (gpg->pid != -1) |
300 |
|
|
_gpgme_remove_proc_from_wait_queue ( gpg->pid ); |
301 |
|
|
_pipe_close( gpg->status.fd ); |
302 |
|
|
_pipe_close( gpg->colon.fd ); |
303 |
|
|
_pipe_close( gpg->logging.fd ); |
304 |
|
|
free_fd_data_map (gpg->fd_data_map); |
305 |
|
|
while (gpg->arglist) { |
306 |
|
|
a = gpg->arglist->next; |
307 |
|
|
safe_free (gpg->arglist); |
308 |
|
|
gpg->arglist = a; |
309 |
|
|
} |
310 |
|
|
if( gpg->running ) { |
311 |
|
|
int pid = gpg->pid; |
312 |
|
|
struct reap_s *r; |
313 |
|
|
|
314 |
|
|
/* resuse the memory, so that we don't need to allocate another |
315 |
|
|
* mem block and have to handle errors */ |
316 |
|
|
assert( sizeof *r < sizeof *gpg ); |
317 |
|
|
r = (void*)gpg; |
318 |
|
|
memset( r, 0, sizeof *r ); |
319 |
|
|
r->pid = pid; |
320 |
|
|
r->entered = time( NULL ); |
321 |
|
|
LOCK(reap_list_lock); |
322 |
|
|
r->next = reap_list; |
323 |
|
|
reap_list = r; |
324 |
|
|
UNLOCK(reap_list_lock); |
325 |
|
|
} |
326 |
|
|
else |
327 |
|
|
safe_free ( gpg ); |
328 |
|
|
*r_gpg = NULL; |
329 |
|
|
} |
330 |
|
|
|
331 |
|
|
|
332 |
|
|
static void |
333 |
|
|
do_reaping (void) |
334 |
|
|
{ |
335 |
|
|
struct reap_s *r, *rlast; |
336 |
|
|
static time_t last_check; |
337 |
|
|
time_t cur_time = time (NULL); |
338 |
|
|
|
339 |
|
|
/* a race does not matter here */ |
340 |
|
|
if (!last_check) |
341 |
|
|
last_check = time(NULL); |
342 |
|
|
|
343 |
|
|
if (last_check >= cur_time) |
344 |
|
|
return; /* we check only every second */ |
345 |
|
|
|
346 |
|
|
/* fixme: it would be nice if to have a TRYLOCK here */ |
347 |
|
|
LOCK (reap_list_lock); |
348 |
|
|
for (r=reap_list,rlast=NULL; r ; rlast=r, r=r?r->next:NULL) { |
349 |
|
|
int dummy1, dummy2; |
350 |
|
|
|
351 |
|
|
if ( _gpgme_io_waitpid (r->pid, 0, &dummy1, &dummy2) ) { |
352 |
|
|
/* process has terminated - remove it from the queue */ |
353 |
|
|
void *p = r; |
354 |
|
|
if (!rlast) { |
355 |
|
|
reap_list = r->next; |
356 |
|
|
r = reap_list; |
357 |
|
|
} |
358 |
|
|
else { |
359 |
|
|
rlast->next = r->next; |
360 |
|
|
r = rlast; |
361 |
|
|
} |
362 |
|
|
safe_free (p); |
363 |
|
|
} |
364 |
|
|
else if ( !r->term_send ) { |
365 |
|
|
if( r->entered+1 >= cur_time ) { |
366 |
|
|
_gpgme_io_kill ( r->pid, 0); |
367 |
|
|
r->term_send = 1; |
368 |
|
|
r->entered = cur_time; |
369 |
|
|
} |
370 |
|
|
} |
371 |
|
|
else { |
372 |
|
|
/* give it 5 second before we are going to send the killer */ |
373 |
|
|
if ( r->entered+5 >= cur_time ) { |
374 |
|
|
_gpgme_io_kill (r->pid, 1); |
375 |
|
|
r->entered = cur_time; /* just in case we have to repat it */ |
376 |
|
|
} |
377 |
|
|
} |
378 |
|
|
} |
379 |
|
|
UNLOCK (reap_list_lock); |
380 |
|
|
} |
381 |
|
|
|
382 |
|
|
void |
383 |
|
|
_gpgme_gpg_housecleaning () |
384 |
|
|
{ |
385 |
|
|
do_reaping (); |
386 |
|
|
} |
387 |
|
|
|
388 |
|
|
|
389 |
|
|
|
390 |
|
|
gpgme_error_t |
391 |
|
|
_gpgme_gpg_add_arg_concat (_gpg_object_t gpg, const char *arg1, const char *arg2) |
392 |
|
|
{ |
393 |
|
|
char * str; |
394 |
|
|
|
395 |
|
|
str = malloc (strlen (arg1) + strlen (arg2) + 2); |
396 |
|
|
if (!str) |
397 |
|
|
return GPGME_Out_Of_Core; |
398 |
|
|
sprintf (str, "%s%s", arg1, arg2); |
399 |
|
|
_gpgme_gpg_add_arg (gpg, str); |
400 |
|
|
free (str); |
401 |
|
|
return 0; |
402 |
|
|
} |
403 |
|
|
|
404 |
|
|
|
405 |
|
|
gpgme_error_t |
406 |
|
|
_gpgme_gpg_add_arg (_gpg_object_t gpg, const char *arg) |
407 |
|
|
{ |
408 |
|
|
struct arg_and_data_s *a; |
409 |
|
|
|
410 |
|
|
assert (gpg); |
411 |
|
|
assert (arg); |
412 |
|
|
|
413 |
|
|
a = malloc (sizeof *a + strlen (arg)); |
414 |
|
|
if (!a) |
415 |
|
|
{ |
416 |
|
|
gpg->arg_error = 1; |
417 |
|
|
return mk_error (Out_Of_Core); |
418 |
|
|
} |
419 |
|
|
a->next = NULL; |
420 |
|
|
a->data = NULL; |
421 |
|
|
a->dup_to = -1; |
422 |
|
|
strcpy (a->arg, arg); |
423 |
|
|
*gpg->argtail = a; |
424 |
|
|
gpg->argtail = &a->next; |
425 |
|
|
return 0; |
426 |
|
|
} |
427 |
|
|
|
428 |
|
|
gpgme_error_t |
429 |
|
|
_gpgme_gpg_add_data ( _gpg_object_t gpg, gpgme_data_t data, int dup_to ) |
430 |
|
|
{ |
431 |
|
|
struct arg_and_data_s *a; |
432 |
|
|
|
433 |
|
|
assert (gpg); |
434 |
|
|
assert (data); |
435 |
|
|
|
436 |
|
|
a = malloc ( sizeof *a - 1 ); |
437 |
|
|
if ( !a ) { |
438 |
|
|
gpg->arg_error = 1; |
439 |
|
|
return mk_error(Out_Of_Core); |
440 |
|
|
} |
441 |
|
|
a->next = NULL; |
442 |
|
|
a->data = data; |
443 |
|
|
if ( dup_to == -2 ) { |
444 |
|
|
a->print_fd = 1; |
445 |
|
|
a->dup_to = -1; |
446 |
|
|
} |
447 |
|
|
else { |
448 |
|
|
a->print_fd = 0; |
449 |
|
|
a->dup_to = dup_to; |
450 |
|
|
} |
451 |
|
|
*gpg->argtail = a; |
452 |
|
|
gpg->argtail = &a->next; |
453 |
|
|
return 0; |
454 |
|
|
} |
455 |
|
|
|
456 |
|
|
|
457 |
|
|
/* |
458 |
|
|
* Note, that the status_handler is allowed to modifiy the args value |
459 |
|
|
*/ |
460 |
|
|
void |
461 |
|
|
_gpgme_gpg_set_status_handler ( _gpg_object_t gpg, |
462 |
|
|
gpg_status_handler_t fnc, void *fnc_value ) |
463 |
|
|
{ |
464 |
|
|
assert (gpg); |
465 |
|
|
gpg->status.fnc = fnc; |
466 |
|
|
gpg->status.fnc_value = fnc_value; |
467 |
|
|
} |
468 |
|
|
|
469 |
|
|
/* Kludge to process --with-colon output */ |
470 |
|
|
gpgme_error_t |
471 |
|
|
_gpgme_gpg_set_colon_line_handler ( _gpg_object_t gpg, |
472 |
|
|
gpg_colon_line_handler_t fnc, void *fnc_value ) |
473 |
|
|
{ |
474 |
|
|
assert (gpg); |
475 |
|
|
|
476 |
|
|
gpg->colon.bufsize = 1024; |
477 |
|
|
gpg->colon.readpos = 0; |
478 |
|
|
gpg->colon.buffer = malloc (gpg->colon.bufsize); |
479 |
|
|
if (!gpg->colon.buffer) { |
480 |
|
|
return mk_error (Out_Of_Core); |
481 |
|
|
} |
482 |
|
|
if (_gpgme_io_pipe (gpg->colon.fd, 1) == -1) { |
483 |
|
|
safe_free (gpg->colon.buffer); gpg->colon.buffer = NULL; |
484 |
|
|
return mk_error (Pipe_Error); |
485 |
|
|
} |
486 |
|
|
if ( _gpgme_io_set_close_notify (gpg->colon.fd[0], |
487 |
|
|
close_notify_handler, gpg) |
488 |
|
|
|| _gpgme_io_set_close_notify (gpg->colon.fd[1], |
489 |
|
|
close_notify_handler, gpg) ) { |
490 |
|
|
return mk_error (General_Error); |
491 |
|
|
} |
492 |
|
|
gpg->colon.eof = 0; |
493 |
|
|
gpg->colon.fnc = fnc; |
494 |
|
|
gpg->colon.fnc_value = fnc_value; |
495 |
|
|
gpg->colon.simple = 0; |
496 |
|
|
return 0; |
497 |
|
|
} |
498 |
|
|
|
499 |
|
|
|
500 |
|
|
gpgme_error_t |
501 |
|
|
_gpgme_gpg_set_simple_line_handler ( _gpg_object_t gpg, |
502 |
|
|
gpg_colon_line_handler_t fnc, |
503 |
|
|
void *fnc_value ) |
504 |
|
|
{ |
505 |
|
|
gpgme_error_t err; |
506 |
|
|
|
507 |
|
|
err = _gpgme_gpg_set_colon_line_handler (gpg, fnc, fnc_value); |
508 |
|
|
if (!err) |
509 |
|
|
gpg->colon.simple = 1; |
510 |
|
|
return err; |
511 |
|
|
} |
512 |
|
|
|
513 |
|
|
|
514 |
|
|
gpgme_error_t |
515 |
|
|
_gpgme_gpg_set_list_options (_gpg_object_t gpg, int opts) |
516 |
|
|
{ |
517 |
|
|
assert (gpg); |
518 |
|
|
if (opts) { |
519 |
|
|
_gpgme_gpg_add_arg (gpg, "--list-options"); |
520 |
|
|
if (opts & GPGME_LISTOPT_SIGSUBPKT) |
521 |
|
|
_gpgme_gpg_add_arg (gpg, "show-sig-subpackets"); |
522 |
|
|
} |
523 |
|
|
return 0; |
524 |
|
|
} |
525 |
|
|
|
526 |
|
|
/* |
527 |
|
|
* The Fnc will be called to get a value for one of the commands with |
528 |
|
|
* a key KEY. If the Code pssed to FNC is 0, the function may release |
529 |
|
|
* resources associated with the returned value from another call. To |
530 |
|
|
* match such a second call to a first call, the returned value from |
531 |
|
|
* the first call is passed as keyword. |
532 |
|
|
*/ |
533 |
|
|
|
534 |
|
|
gpgme_error_t |
535 |
|
|
_gpgme_gpg_set_command_handler( _gpg_object_t gpg, |
536 |
|
|
gpg_command_handler_t fnc, void *fnc_value ) |
537 |
|
|
{ |
538 |
|
|
gpgme_data_t tmp; |
539 |
|
|
gpgme_error_t err; |
540 |
|
|
|
541 |
|
|
assert( gpg ); |
542 |
|
|
|
543 |
|
|
err = gpgme_data_new_with_read_cb( &tmp, command_cb, gpg ); |
544 |
|
|
if( err ) |
545 |
|
|
return err; |
546 |
|
|
|
547 |
|
|
_gpgme_gpg_add_arg ( gpg, "--command-fd" ); |
548 |
|
|
_gpgme_gpg_add_data( gpg, tmp, -2 ); |
549 |
|
|
gpg->cmd.cb_data = tmp; |
550 |
|
|
gpg->cmd.fnc = fnc; |
551 |
|
|
gpg->cmd.fnc_value = fnc_value; |
552 |
|
|
gpg->cmd.used = 1; |
553 |
|
|
return 0; |
554 |
|
|
} |
555 |
|
|
|
556 |
|
|
|
557 |
|
|
static void |
558 |
|
|
free_argv ( char **argv ) |
559 |
|
|
{ |
560 |
|
|
int i; |
561 |
|
|
|
562 |
|
|
for (i=0; argv[i]; i++ ) |
563 |
|
|
safe_free (argv[i]); |
564 |
|
|
safe_free (argv); |
565 |
|
|
} |
566 |
|
|
|
567 |
|
|
static void |
568 |
|
|
free_fd_data_map ( struct fd_data_map_s *fd_data_map ) |
569 |
|
|
{ |
570 |
|
|
int i; |
571 |
|
|
|
572 |
|
|
if ( !fd_data_map ) |
573 |
|
|
return; |
574 |
|
|
|
575 |
|
|
for (i=0; fd_data_map[i].data; i++ ) { |
576 |
|
|
if ( fd_data_map[i].fd != -1 ) |
577 |
|
|
_gpgme_io_close (fd_data_map[i].fd); |
578 |
|
|
if ( fd_data_map[i].peer_fd != -1 ) |
579 |
|
|
_gpgme_io_close (fd_data_map[i].peer_fd); |
580 |
|
|
/* don't release data because this is only a reference */ |
581 |
|
|
} |
582 |
|
|
safe_free (fd_data_map); |
583 |
|
|
} |
584 |
|
|
|
585 |
|
|
static gpgme_error_t |
586 |
|
|
build_argv (_gpg_object_t gpg) |
587 |
|
|
{ |
588 |
|
|
struct arg_and_data_s *a; |
589 |
|
|
struct fd_data_map_s *fd_data_map; |
590 |
|
|
size_t datac=0, argc=0; |
591 |
|
|
char **argv; |
592 |
|
|
int need_special = 0; |
593 |
|
|
int use_agent = !!getenv ("GPG_AGENT_INFO"); |
594 |
|
|
char *optfile = _gpgme_get_gpg_optfile (); |
595 |
|
|
|
596 |
|
|
if ( gpg->argv ) { |
597 |
|
|
free_argv ( gpg->argv ); |
598 |
|
|
gpg->argv = NULL; |
599 |
|
|
} |
600 |
|
|
if (gpg->fd_data_map) { |
601 |
|
|
free_fd_data_map (gpg->fd_data_map); |
602 |
|
|
gpg->fd_data_map = NULL; |
603 |
|
|
} |
604 |
|
|
|
605 |
|
|
argc++; /* for argv[0] */ |
606 |
|
|
for ( a=gpg->arglist; a; a = a->next ) { |
607 |
|
|
argc++; |
608 |
|
|
if (a->data) { |
609 |
|
|
/*fprintf (stderr, "build_argv: data\n" );*/ |
610 |
|
|
datac++; |
611 |
|
|
if ( a->dup_to == -1 && !a->print_fd ) |
612 |
|
|
need_special = 1; |
613 |
|
|
} |
614 |
|
|
else { |
615 |
|
|
/* fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/ |
616 |
|
|
} |
617 |
|
|
} |
618 |
|
|
if ( need_special ) |
619 |
|
|
argc++; |
620 |
|
|
if (use_agent) |
621 |
|
|
argc++; |
622 |
|
|
if (optfile) |
623 |
|
|
argc += 2; |
624 |
|
|
if (!gpg->cmd.used) |
625 |
|
|
argc++; |
626 |
|
|
|
627 |
|
|
argv = calloc ( argc+1, sizeof *argv ); |
628 |
|
|
if (!argv) |
629 |
|
|
return mk_error (Out_Of_Core); |
630 |
|
|
fd_data_map = calloc ( datac+1, sizeof *fd_data_map ); |
631 |
|
|
if (!fd_data_map) { |
632 |
|
|
free_argv (argv); |
633 |
|
|
return mk_error (Out_Of_Core); |
634 |
|
|
} |
635 |
|
|
|
636 |
|
|
argc = datac = 0; |
637 |
|
|
argv[argc] = strdup ( "gpg" ); /* argv[0] */ |
638 |
|
|
if (!argv[argc]) { |
639 |
|
|
safe_free (fd_data_map); |
640 |
|
|
free_argv (argv); |
641 |
|
|
return mk_error (Out_Of_Core); |
642 |
|
|
} |
643 |
|
|
argc++; |
644 |
|
|
if (need_special) { |
645 |
|
|
argv[argc] = strdup ( "--enable-special-filenames" ); |
646 |
|
|
if (!argv[argc]) { |
647 |
|
|
safe_free (fd_data_map); |
648 |
|
|
free_argv (argv); |
649 |
|
|
return mk_error (Out_Of_Core); |
650 |
|
|
} |
651 |
|
|
argc++; |
652 |
|
|
} |
653 |
|
|
if (use_agent) { |
654 |
|
|
argv[argc] = strdup ("--use-agent"); |
655 |
|
|
if( !argv[argc] ) { |
656 |
|
|
safe_free (fd_data_map); |
657 |
|
|
free_argv (argv); |
658 |
|
|
return mk_error (Out_Of_Core); |
659 |
|
|
} |
660 |
|
|
argc++; |
661 |
|
|
} |
662 |
|
|
if( optfile ) { |
663 |
|
|
char *p; |
664 |
|
|
|
665 |
|
|
argv[argc] = strdup ("--options"); |
666 |
|
|
if( !argv[argc] ) { |
667 |
|
|
safe_free(fd_data_map); |
668 |
|
|
free_argv(argv); |
669 |
|
|
return mk_error(Out_Of_Core); |
670 |
|
|
} |
671 |
|
|
argc++; |
672 |
|
|
p = malloc (strlen (optfile)+3); |
673 |
|
|
if (!p) |
674 |
|
|
{ |
675 |
|
|
safe_free (fd_data_map); |
676 |
|
|
free_argv (argv); |
677 |
|
|
return mk_error (Out_Of_Core); |
678 |
|
|
} |
679 |
|
|
strcpy (p+1, optfile); |
680 |
|
|
p[0] = '"'; |
681 |
|
|
p[strlen(optfile)+1] = '"'; |
682 |
|
|
p[strlen(optfile)+2] = '\0'; |
683 |
|
|
argv[argc] = p; |
684 |
|
|
if (!argv[argc]) { |
685 |
|
|
safe_free(fd_data_map); |
686 |
|
|
free_argv(argv); |
687 |
|
|
return mk_error(Out_Of_Core); |
688 |
|
|
} |
689 |
|
|
argc++; |
690 |
|
|
safe_free(optfile); |
691 |
|
|
} |
692 |
|
|
if (!gpg->cmd.used) { |
693 |
|
|
argv[argc] = strdup ( "--batch" ); |
694 |
|
|
if (!argv[argc]) { |
695 |
|
|
safe_free (fd_data_map); |
696 |
|
|
free_argv (argv); |
697 |
|
|
return mk_error (Out_Of_Core); |
698 |
|
|
} |
699 |
|
|
argc++; |
700 |
|
|
} |
701 |
|
|
for ( a=gpg->arglist; a; a = a->next ) { |
702 |
|
|
if ( a->data ) { |
703 |
|
|
switch ( _gpgme_data_get_mode (a->data) ) { |
704 |
|
|
case GPGME_DATA_MODE_NONE: |
705 |
|
|
case GPGME_DATA_MODE_INOUT: |
706 |
|
|
safe_free (fd_data_map); |
707 |
|
|
free_argv (argv); |
708 |
|
|
return mk_error (Invalid_Mode); |
709 |
|
|
case GPGME_DATA_MODE_IN: |
710 |
|
|
/* create a pipe to read from gpg */ |
711 |
|
|
fd_data_map[datac].inbound = 1; |
712 |
|
|
break; |
713 |
|
|
case GPGME_DATA_MODE_OUT: |
714 |
|
|
/* create a pipe to pass it down to gpg */ |
715 |
|
|
fd_data_map[datac].inbound = 0; |
716 |
|
|
break; |
717 |
|
|
} |
718 |
|
|
|
719 |
|
|
switch ( gpgme_data_get_type (a->data) ) { |
720 |
|
|
case GPGME_DATA_TYPE_NONE: |
721 |
|
|
if ( fd_data_map[datac].inbound ) |
722 |
|
|
break; /* allowed */ |
723 |
|
|
safe_free (fd_data_map); |
724 |
|
|
free_argv (argv); |
725 |
|
|
return mk_error (Invalid_Type); |
726 |
|
|
case GPGME_DATA_TYPE_MEM: |
727 |
|
|
case GPGME_DATA_TYPE_CB: |
728 |
|
|
break; |
729 |
|
|
case GPGME_DATA_TYPE_FD: |
730 |
|
|
case GPGME_DATA_TYPE_FILE: |
731 |
|
|
safe_free (fd_data_map); |
732 |
|
|
free_argv (argv); |
733 |
|
|
return mk_error (Not_Implemented); |
734 |
|
|
} |
735 |
|
|
|
736 |
|
|
/* create a pipe */ |
737 |
|
|
{ |
738 |
|
|
int fds[2]; |
739 |
|
|
|
740 |
|
|
if (_gpgme_io_pipe (fds, fd_data_map[datac].inbound?1:0 ) |
741 |
|
|
== -1) { |
742 |
|
|
safe_free (fd_data_map); |
743 |
|
|
free_argv (argv); |
744 |
|
|
return mk_error (Pipe_Error); |
745 |
|
|
} |
746 |
|
|
if ( _gpgme_io_set_close_notify (fds[0], |
747 |
|
|
close_notify_handler, gpg) |
748 |
|
|
|| _gpgme_io_set_close_notify (fds[1], |
749 |
|
|
close_notify_handler, |
750 |
|
|
gpg)) { |
751 |
|
|
return mk_error (General_Error); |
752 |
|
|
} |
753 |
|
|
/* if the data_type is FD, we have to do a dup2 here */ |
754 |
|
|
if (fd_data_map[datac].inbound) { |
755 |
|
|
fd_data_map[datac].fd = fds[0]; |
756 |
|
|
fd_data_map[datac].peer_fd = fds[1]; |
757 |
|
|
} |
758 |
|
|
else { |
759 |
|
|
fd_data_map[datac].fd = fds[1]; |
760 |
|
|
fd_data_map[datac].peer_fd = fds[0]; |
761 |
|
|
} |
762 |
|
|
} |
763 |
|
|
|
764 |
|
|
/* Hack to get hands on the fd later */ |
765 |
|
|
if ( gpg->cmd.used && gpg->cmd.cb_data == a->data ) { |
766 |
|
|
assert (gpg->cmd.fd == -1); |
767 |
|
|
gpg->cmd.fd = fd_data_map[datac].fd; |
768 |
|
|
} |
769 |
|
|
|
770 |
|
|
fd_data_map[datac].data = a->data; |
771 |
|
|
fd_data_map[datac].dup_to = a->dup_to; |
772 |
|
|
if ( a->dup_to == -1 ) { |
773 |
|
|
argv[argc] = malloc ( 25 ); |
774 |
|
|
if (!argv[argc]) { |
775 |
|
|
safe_free (fd_data_map); |
776 |
|
|
free_argv (argv); |
777 |
|
|
return mk_error (Out_Of_Core); |
778 |
|
|
} |
779 |
|
|
sprintf ( argv[argc], |
780 |
|
|
a->print_fd? "%d" : "-&%d", |
781 |
|
|
fd_data_map[datac].peer_fd ); |
782 |
|
|
argc++; |
783 |
|
|
} |
784 |
|
|
datac++; |
785 |
|
|
} |
786 |
|
|
else { |
787 |
|
|
argv[argc] = strdup ( a->arg ); |
788 |
|
|
if (!argv[argc]) { |
789 |
|
|
safe_free (fd_data_map); |
790 |
|
|
free_argv (argv); |
791 |
|
|
return mk_error (Out_Of_Core); |
792 |
|
|
} |
793 |
|
|
argc++; |
794 |
|
|
} |
795 |
|
|
} |
796 |
|
|
|
797 |
|
|
gpg->argv = argv; |
798 |
|
|
gpg->fd_data_map = fd_data_map; |
799 |
|
|
return 0; |
800 |
|
|
} |
801 |
|
|
|
802 |
|
|
|
803 |
|
|
ulong |
804 |
|
|
_gpgme_gpg_getpid( _gpg_object_t gpg ) |
805 |
|
|
{ |
806 |
|
|
assert( gpg ); |
807 |
|
|
return gpg->pid; |
808 |
|
|
} |
809 |
|
|
|
810 |
|
|
|
811 |
|
|
void |
812 |
|
|
_gpgme_gpg_set_logging_handler( _gpg_object_t gpg, void * cb_val ) |
813 |
|
|
{ |
814 |
|
|
assert( gpg ); |
815 |
|
|
gpg->logging.fnc_value = cb_val; |
816 |
|
|
gpg->logging.enabled = 1; |
817 |
|
|
} |
818 |
|
|
|
819 |
|
|
|
820 |
|
|
gpgme_error_t |
821 |
|
|
_gpgme_gpg_spawn( _gpg_object_t gpg, void *opaque ) |
822 |
|
|
{ |
823 |
|
|
int rc; |
824 |
|
|
int i, n; |
825 |
|
|
int pid; |
826 |
|
|
struct spawn_fd_item_s *fd_child_list, *fd_parent_list; |
827 |
|
|
|
828 |
|
|
if ( !gpg ) |
829 |
|
|
return mk_error (Invalid_Value); |
830 |
|
|
|
831 |
|
|
/* Kludge, so that we don't need to check the return code of |
832 |
|
|
* all the gpgme_gpg_add_arg(). we bail out here instead */ |
833 |
|
|
if ( gpg->arg_error ) |
834 |
|
|
return mk_error (Out_Of_Core); |
835 |
|
|
|
836 |
|
|
rc = build_argv ( gpg ); |
837 |
|
|
if ( rc ) |
838 |
|
|
return rc; |
839 |
|
|
|
840 |
|
|
n = 4; /* status fd, 2*colon_fd and end of list */ |
841 |
|
|
for (i=0; gpg->fd_data_map[i].data; i++ ) |
842 |
|
|
n += 2; |
843 |
|
|
fd_child_list = calloc ( n+n, sizeof *fd_child_list ); |
844 |
|
|
if (!fd_child_list) |
845 |
|
|
return mk_error (Out_Of_Core); |
846 |
|
|
fd_parent_list = fd_child_list + n; |
847 |
|
|
|
848 |
|
|
/* build the fd list for the child */ |
849 |
|
|
n=0; |
850 |
|
|
fd_child_list[n].fd = gpg->status.fd[0]; |
851 |
|
|
fd_child_list[n].dup_to = -1; |
852 |
|
|
n++; |
853 |
|
|
if( gpg->logging.enabled ) { |
854 |
|
|
fd_child_list[n].fd = gpg->logging.fd[0]; |
855 |
|
|
fd_child_list[n].dup_to = -1; |
856 |
|
|
n++; |
857 |
|
|
} |
858 |
|
|
if ( gpg->colon.fnc ) { |
859 |
|
|
fd_child_list[n].fd = gpg->colon.fd[0]; |
860 |
|
|
fd_child_list[n].dup_to = -1; |
861 |
|
|
n++; |
862 |
|
|
fd_child_list[n].fd = gpg->colon.fd[1]; |
863 |
|
|
fd_child_list[n].dup_to = 1; /* dup to stdout */ |
864 |
|
|
n++; |
865 |
|
|
} |
866 |
|
|
for (i=0; gpg->fd_data_map[i].data; i++ ) { |
867 |
|
|
fd_child_list[n].fd = gpg->fd_data_map[i].fd; |
868 |
|
|
fd_child_list[n].dup_to = -1; |
869 |
|
|
n++; |
870 |
|
|
if (gpg->fd_data_map[i].dup_to != -1) { |
871 |
|
|
fd_child_list[n].fd = gpg->fd_data_map[i].peer_fd; |
872 |
|
|
fd_child_list[n].dup_to = gpg->fd_data_map[i].dup_to; |
873 |
|
|
n++; |
874 |
|
|
} |
875 |
|
|
} |
876 |
|
|
fd_child_list[n].fd = -1; |
877 |
|
|
fd_child_list[n].dup_to = -1; |
878 |
|
|
|
879 |
|
|
/* build the fd list for the parent */ |
880 |
|
|
n=0; |
881 |
|
|
if ( gpg->status.fd[1] != -1 ) { |
882 |
|
|
fd_parent_list[n].fd = gpg->status.fd[1]; |
883 |
|
|
fd_parent_list[n].dup_to = -1; |
884 |
|
|
n++; |
885 |
|
|
gpg->status.fd[1] = -1; |
886 |
|
|
} |
887 |
|
|
if( gpg->logging.fd[1] != -1 ) { |
888 |
|
|
fd_parent_list[n].fd = gpg->logging.fd[1]; |
889 |
|
|
fd_parent_list[n].dup_to = -1; |
890 |
|
|
n++; |
891 |
|
|
gpg->logging.fd[1] = -1; |
892 |
|
|
} |
893 |
|
|
if ( gpg->colon.fd[1] != -1 ) { |
894 |
|
|
fd_parent_list[n].fd = gpg->colon.fd[1]; |
895 |
|
|
fd_parent_list[n].dup_to = -1; |
896 |
|
|
n++; |
897 |
|
|
gpg->colon.fd[1] = -1; |
898 |
|
|
} |
899 |
|
|
for (i=0; gpg->fd_data_map[i].data; i++ ) { |
900 |
|
|
fd_parent_list[n].fd = gpg->fd_data_map[i].peer_fd; |
901 |
|
|
fd_parent_list[n].dup_to = -1; |
902 |
|
|
n++; |
903 |
|
|
gpg->fd_data_map[i].peer_fd = -1; |
904 |
|
|
} |
905 |
|
|
fd_parent_list[n].fd = -1; |
906 |
|
|
fd_parent_list[n].dup_to = -1; |
907 |
|
|
|
908 |
|
|
|
909 |
|
|
pid = _gpgme_io_spawn (_gpgme_get_gpg_path (), |
910 |
|
|
gpg->argv, fd_child_list, fd_parent_list); |
911 |
|
|
safe_free (fd_child_list); |
912 |
|
|
if( pid == -1 ) |
913 |
|
|
return mk_error (Exec_Error); |
914 |
|
|
|
915 |
|
|
gpg->pid = pid; |
916 |
|
|
|
917 |
|
|
/*_gpgme_register_term_handler ( closure, closure_value, pid );*/ |
918 |
|
|
|
919 |
|
|
if( _gpgme_register_pipe_handler( opaque, gpg_status_handler, |
920 |
|
|
gpg, pid, gpg->status.fd[0], 1 ) ) { |
921 |
|
|
/* FIXME: kill the child */ |
922 |
|
|
return mk_error( General_Error ); |
923 |
|
|
} |
924 |
|
|
if( gpg->logging.enabled && |
925 |
|
|
_gpgme_register_pipe_handler( opaque, gpg_logging_handler, |
926 |
|
|
gpg, pid, gpg->logging.fd[0], 1 ) ) { |
927 |
|
|
/* FIXME: kill the child */ |
928 |
|
|
return mk_error( General_Error ); |
929 |
|
|
} |
930 |
|
|
|
931 |
|
|
if( gpg->colon.fnc ) { |
932 |
|
|
assert( gpg->colon.fd[0] != -1 ); |
933 |
|
|
if ( _gpgme_register_pipe_handler ( opaque, gpg_colon_line_handler, |
934 |
|
|
gpg, pid, gpg->colon.fd[0], 1 ) ) { |
935 |
|
|
/* FIXME: kill the child */ |
936 |
|
|
return mk_error (General_Error); |
937 |
|
|
|
938 |
|
|
} |
939 |
|
|
} |
940 |
|
|
|
941 |
|
|
for (i=0; gpg->fd_data_map[i].data; i++ ) { |
942 |
|
|
/* Due to problems with select and write we set outbound pipes |
943 |
|
|
* to non-blocking */ |
944 |
|
|
if (!gpg->fd_data_map[i].inbound) |
945 |
|
|
_gpgme_io_set_nonblocking (gpg->fd_data_map[i].fd); |
946 |
|
|
|
947 |
|
|
if ( _gpgme_register_pipe_handler ( |
948 |
|
|
opaque, |
949 |
|
|
gpg->fd_data_map[i].inbound? |
950 |
|
|
gpg_inbound_handler:gpg_outbound_handler, |
951 |
|
|
gpg->fd_data_map[i].data, |
952 |
|
|
pid, gpg->fd_data_map[i].fd, |
953 |
|
|
gpg->fd_data_map[i].inbound ) |
954 |
|
|
) { |
955 |
|
|
/* FIXME: kill the child */ |
956 |
|
|
return mk_error (General_Error); |
957 |
|
|
} |
958 |
|
|
} |
959 |
|
|
|
960 |
|
|
if( gpg->cmd.used ) |
961 |
|
|
_gpgme_freeze_fd( gpg->cmd.fd ); |
962 |
|
|
|
963 |
|
|
/* fixme: check what data we can release here */ |
964 |
|
|
|
965 |
|
|
gpg->running = 1; |
966 |
|
|
return 0; |
967 |
|
|
} |
968 |
|
|
|
969 |
|
|
|
970 |
|
|
static int |
971 |
|
|
gpg_inbound_handler ( void *opaque, int pid, int fd ) |
972 |
|
|
{ |
973 |
|
|
gpgme_data_t dh = opaque; |
974 |
|
|
gpgme_error_t err; |
975 |
|
|
int nread; |
976 |
|
|
char buf[200]; |
977 |
|
|
|
978 |
|
|
assert ( _gpgme_data_get_mode (dh) == GPGME_DATA_MODE_IN ); |
979 |
|
|
|
980 |
|
|
nread = _gpgme_io_read (fd, buf, 200 ); |
981 |
|
|
if ( nread < 0 ) { |
982 |
|
|
DEBUG3 ("read_mem_data: read failed on fd %d (n=%d): %s", |
983 |
|
|
fd, nread, strerror (errno) ); |
984 |
|
|
return 1; |
985 |
|
|
} |
986 |
|
|
else if (!nread) |
987 |
|
|
return 1; /* eof */ |
988 |
|
|
|
989 |
|
|
/* We could improve this with a gpgme_data_t function which takes |
990 |
|
|
* the read function or provides a memory area for writing to it. |
991 |
|
|
*/ |
992 |
|
|
|
993 |
|
|
err = _gpgme_data_append ( dh, buf, nread ); |
994 |
|
|
if ( err ) { |
995 |
|
|
DEBUG1 ("_gpgme_append_data failed: %s\n", |
996 |
|
|
gpgme_strerror(err)); |
997 |
|
|
/* Fixme: we should close the pipe or read it to /dev/null in |
998 |
|
|
* this case. Returnin EOF is not sufficient */ |
999 |
|
|
return 1; |
1000 |
|
|
} |
1001 |
|
|
|
1002 |
|
|
return 0; |
1003 |
|
|
} |
1004 |
|
|
|
1005 |
|
|
|
1006 |
|
|
static int |
1007 |
|
|
write_mem_data ( gpgme_data_t dh, int fd ) |
1008 |
|
|
{ |
1009 |
|
|
size_t nbytes; |
1010 |
|
|
int nwritten; |
1011 |
|
|
|
1012 |
|
|
nbytes = dh->len - dh->readpos; |
1013 |
|
|
if ( !nbytes ) { |
1014 |
|
|
_gpgme_io_close (fd); |
1015 |
|
|
return 1; |
1016 |
|
|
} |
1017 |
|
|
|
1018 |
|
|
/* FIXME: Arggg, the pipe blocks on large write request, although |
1019 |
|
|
* select told us that it is okay to write - need to figure out |
1020 |
|
|
* why this happens? Stevens says nothing about this problem (or |
1021 |
|
|
* is it my Linux kernel 2.4.0test1) |
1022 |
|
|
* To avoid that we have set the pipe to nonblocking. |
1023 |
|
|
*/ |
1024 |
|
|
|
1025 |
|
|
nwritten = _gpgme_io_write ( fd, dh->data+dh->readpos, nbytes ); |
1026 |
|
|
if (nwritten == -1 && errno == EAGAIN ) |
1027 |
|
|
return 0; |
1028 |
|
|
if ( nwritten < 1 ) { |
1029 |
|
|
DEBUG3 ("write_mem_data(%d): write failed (n=%d): %s", |
1030 |
|
|
fd, nwritten, strerror (errno) ); |
1031 |
|
|
_gpgme_io_close (fd); |
1032 |
|
|
return 1; |
1033 |
|
|
} |
1034 |
|
|
|
1035 |
|
|
dh->readpos += nwritten; |
1036 |
|
|
return 0; |
1037 |
|
|
} |
1038 |
|
|
|
1039 |
|
|
static int |
1040 |
|
|
write_cb_data( gpgme_data_t dh, int fd ) |
1041 |
|
|
{ |
1042 |
|
|
size_t nbytes; |
1043 |
|
|
int err, nwritten; |
1044 |
|
|
char buffer[512]; |
1045 |
|
|
|
1046 |
|
|
err = gpgme_data_read ( dh, buffer, DIM(buffer), &nbytes ); |
1047 |
|
|
if (err == GPGME_EOF) { |
1048 |
|
|
_gpgme_io_close (fd); |
1049 |
|
|
return 1; |
1050 |
|
|
} |
1051 |
|
|
|
1052 |
|
|
nwritten = _gpgme_io_write ( fd, buffer, nbytes ); |
1053 |
|
|
if (nwritten == -1 && errno == EAGAIN ) |
1054 |
|
|
return 0; |
1055 |
|
|
if ( nwritten < 1 ) { |
1056 |
|
|
DEBUG3 ("write_cb_data(%d): write failed (n=%d): %s", |
1057 |
|
|
fd, nwritten, strerror (errno) ); |
1058 |
|
|
_gpgme_io_close (fd); |
1059 |
|
|
return 1; |
1060 |
|
|
} |
1061 |
|
|
|
1062 |
|
|
if ( nwritten < nbytes ) { |
1063 |
|
|
/* ugly, ugly: It does currently only for for MEM type data */ |
1064 |
|
|
if ( _gpgme_data_unread (dh, buffer + nwritten, nbytes - nwritten ) ) |
1065 |
|
|
DEBUG1 ("wite_cb_data: unread of %d bytes failed\n", |
1066 |
|
|
nbytes - nwritten ); |
1067 |
|
|
_gpgme_io_close (fd); |
1068 |
|
|
return 1; |
1069 |
|
|
} |
1070 |
|
|
|
1071 |
|
|
return 0; |
1072 |
|
|
} |
1073 |
|
|
|
1074 |
|
|
|
1075 |
|
|
static int |
1076 |
|
|
gpg_outbound_handler ( void *opaque, int pid, int fd ) |
1077 |
|
|
{ |
1078 |
|
|
gpgme_data_t dh = opaque; |
1079 |
|
|
|
1080 |
|
|
assert ( _gpgme_data_get_mode (dh) == GPGME_DATA_MODE_OUT ); |
1081 |
|
|
switch ( gpgme_data_get_type (dh) ) { |
1082 |
|
|
case GPGME_DATA_TYPE_MEM: |
1083 |
|
|
if ( write_mem_data ( dh, fd ) ) |
1084 |
|
|
return 1; /* ready */ |
1085 |
|
|
break; |
1086 |
|
|
case GPGME_DATA_TYPE_CB: |
1087 |
|
|
if (write_cb_data (dh, fd)) |
1088 |
|
|
return 1; /* ready */ |
1089 |
|
|
break; |
1090 |
|
|
default: |
1091 |
|
|
assert (0); |
1092 |
|
|
} |
1093 |
|
|
|
1094 |
|
|
return 0; |
1095 |
|
|
} |
1096 |
|
|
|
1097 |
|
|
|
1098 |
|
|
|
1099 |
|
|
static int |
1100 |
|
|
gpg_logging_handler( void * opaque, int pid, int fd ) |
1101 |
|
|
{ |
1102 |
|
|
_gpg_object_t gpg = opaque; |
1103 |
|
|
int rc = 0; |
1104 |
|
|
|
1105 |
|
|
assert( fd == gpg->logging.fd[0] ); |
1106 |
|
|
rc = read_logging( gpg ); |
1107 |
|
|
if( rc ) { |
1108 |
|
|
DEBUG1( "gpg_handler: read_logging problem %d\n - stop", rc ); |
1109 |
|
|
return 1; |
1110 |
|
|
} |
1111 |
|
|
return gpg->logging.eof; |
1112 |
|
|
} |
1113 |
|
|
|
1114 |
|
|
|
1115 |
|
|
static int |
1116 |
|
|
gpg_status_handler ( void *opaque, int pid, int fd ) |
1117 |
|
|
{ |
1118 |
|
|
_gpg_object_t gpg = opaque; |
1119 |
|
|
int rc = 0; |
1120 |
|
|
|
1121 |
|
|
assert ( fd == gpg->status.fd[0] ); |
1122 |
|
|
rc = read_status ( gpg ); |
1123 |
|
|
if ( rc ) { |
1124 |
|
|
DEBUG1 ("gpg_handler: read_status problem %d\n - stop", rc); |
1125 |
|
|
return 1; |
1126 |
|
|
} |
1127 |
|
|
|
1128 |
|
|
return gpg->status.eof; |
1129 |
|
|
} |
1130 |
|
|
|
1131 |
|
|
|
1132 |
|
|
|
1133 |
|
|
static int |
1134 |
|
|
status_cmp (const void *ap, const void *bp) |
1135 |
|
|
{ |
1136 |
|
|
const struct status_table_s *a = ap; |
1137 |
|
|
const struct status_table_s *b = bp; |
1138 |
|
|
|
1139 |
|
|
return strcmp (a->name, b->name); |
1140 |
|
|
} |
1141 |
|
|
|
1142 |
|
|
|
1143 |
|
|
static gpgme_error_t |
1144 |
|
|
read_logging( _gpg_object_t gpg ) |
1145 |
|
|
{ |
1146 |
|
|
gpgme_ctx_t c; |
1147 |
|
|
int nread; |
1148 |
|
|
|
1149 |
|
|
c = gpg->logging.fnc_value; |
1150 |
|
|
if( !c ) |
1151 |
|
|
return mk_error( Invalid_Value ); |
1152 |
|
|
if( !c->use_logging ) |
1153 |
|
|
return 0; |
1154 |
|
|
|
1155 |
|
|
nread = _gpgme_io_read( gpg->logging.fd[0], |
1156 |
|
|
gpg->logging.buffer, |
1157 |
|
|
gpg->logging.bufsize ); |
1158 |
|
|
DEBUG1( "read_logging: got %d bytes", nread ); |
1159 |
|
|
if( nread == -1 ) |
1160 |
|
|
return mk_error( Read_Error ); |
1161 |
|
|
|
1162 |
|
|
if( !c->logging ) |
1163 |
|
|
gpgme_data_new( &c->logging ); |
1164 |
|
|
|
1165 |
|
|
if( !nread ) { |
1166 |
|
|
gpg->logging.eof = 1; |
1167 |
|
|
return 0; |
1168 |
|
|
} |
1169 |
|
|
|
1170 |
|
|
return gpgme_data_write( c->logging, gpg->logging.buffer, nread ); |
1171 |
|
|
} |
1172 |
|
|
|
1173 |
|
|
|
1174 |
|
|
/* |
1175 |
|
|
* Handle the status output of GnuPG. This function does read entire |
1176 |
|
|
* lines and passes them as C strings to the callback function (we can |
1177 |
|
|
* use C Strings because the status output is always UTF-8 encoded). |
1178 |
|
|
* Of course we have to buffer the lines to cope with long lines |
1179 |
|
|
* e.g. with a large user ID. Note: We can optimize this to only cope |
1180 |
|
|
* with status line code we know about and skip all other stuff |
1181 |
|
|
* without buffering (i.e. without extending the buffer). */ |
1182 |
|
|
static gpgme_error_t |
1183 |
|
|
read_status ( _gpg_object_t gpg ) |
1184 |
|
|
{ |
1185 |
|
|
char *p; |
1186 |
|
|
int nread; |
1187 |
|
|
size_t bufsize = gpg->status.bufsize; |
1188 |
|
|
char *buffer = gpg->status.buffer; |
1189 |
|
|
size_t readpos = gpg->status.readpos; |
1190 |
|
|
|
1191 |
|
|
assert (buffer); |
1192 |
|
|
if (bufsize - readpos < 256) { |
1193 |
|
|
/* need more room for the read */ |
1194 |
|
|
bufsize += 1024; |
1195 |
|
|
buffer = realloc (buffer, bufsize); |
1196 |
|
|
if ( !buffer ) |
1197 |
|
|
return mk_error (Out_Of_Core); |
1198 |
|
|
} |
1199 |
|
|
|
1200 |
|
|
|
1201 |
|
|
nread = _gpgme_io_read ( gpg->status.fd[0], |
1202 |
|
|
buffer+readpos, bufsize-readpos ); |
1203 |
|
|
if (nread == -1) |
1204 |
|
|
return mk_error(Read_Error); |
1205 |
|
|
|
1206 |
|
|
if (!nread) { |
1207 |
|
|
gpg->status.eof = 1; |
1208 |
|
|
if (gpg->status.fnc) |
1209 |
|
|
gpg->status.fnc ( gpg->status.fnc_value, STATUS_EOF, "" ); |
1210 |
|
|
return 0; |
1211 |
|
|
} |
1212 |
|
|
|
1213 |
|
|
while (nread > 0) { |
1214 |
|
|
for (p = buffer + readpos; nread; nread--, p++) { |
1215 |
|
|
if ( *p == '\n' ) { |
1216 |
|
|
/* (we require that the last line is terminated by a LF) */ |
1217 |
|
|
*p = 0; |
1218 |
|
|
/*DEBUG1("read_status: `%s'\n", buffer);*/ |
1219 |
|
|
if (!strncmp (buffer, "[GNUPG:] ", 9 ) |
1220 |
|
|
&& buffer[9] >= 'A' && buffer[9] <= 'Z' ) { |
1221 |
|
|
struct status_table_s t, *r; |
1222 |
|
|
char *rest; |
1223 |
|
|
|
1224 |
|
|
rest = strchr (buffer+9, ' '); |
1225 |
|
|
if ( !rest ) |
1226 |
|
|
rest = p; /* set to an empty string */ |
1227 |
|
|
else |
1228 |
|
|
*rest++ = 0; |
1229 |
|
|
|
1230 |
|
|
t.name = buffer+9; |
1231 |
|
|
/* (the status table as one extra element) */ |
1232 |
|
|
r = bsearch ( &t, status_table, DIM(status_table)-1, |
1233 |
|
|
sizeof t, status_cmp ); |
1234 |
|
|
if ( r ) { |
1235 |
|
|
if ( gpg->cmd.used |
1236 |
|
|
&& ( r->code == STATUS_GET_BOOL |
1237 |
|
|
|| r->code == STATUS_GET_LINE |
1238 |
|
|
|| r->code == STATUS_GET_HIDDEN )) { |
1239 |
|
|
gpg->cmd.code = r->code; |
1240 |
|
|
safe_free (gpg->cmd.keyword); |
1241 |
|
|
gpg->cmd.keyword = strdup (rest); |
1242 |
|
|
if ( !gpg->cmd.keyword ) |
1243 |
|
|
return mk_error (Out_Of_Core); |
1244 |
|
|
/* this should be the last thing we have received |
1245 |
|
|
* and the next thing will be that the command |
1246 |
|
|
* handler does its action */ |
1247 |
|
|
if ( nread > 1 ) |
1248 |
|
|
DEBUG0 ("ERROR, unexpected data in read_status"); |
1249 |
|
|
_gpgme_thaw_fd (gpg->cmd.fd); |
1250 |
|
|
} |
1251 |
|
|
else if ( gpg->status.fnc ) { |
1252 |
|
|
gpg->status.fnc( gpg->status.fnc_value, |
1253 |
|
|
r->code, rest ); |
1254 |
|
|
} |
1255 |
|
|
|
1256 |
|
|
if ( r->code == STATUS_END_STREAM ) { |
1257 |
|
|
if ( gpg->cmd.used ) |
1258 |
|
|
_gpgme_freeze_fd ( gpg->cmd.fd ); |
1259 |
|
|
} |
1260 |
|
|
} |
1261 |
|
|
} |
1262 |
|
|
/* To reuse the buffer for the next line we have to |
1263 |
|
|
* shift the remaining data to the buffer start and |
1264 |
|
|
* restart the loop Hmmm: We can optimize this |
1265 |
|
|
* function by looking forward in the buffer to see |
1266 |
|
|
* whether a second complete line is available and in |
1267 |
|
|
* this case avoid the memmove for this line. */ |
1268 |
|
|
nread--; p++; |
1269 |
|
|
if (nread) |
1270 |
|
|
memmove (buffer, p, nread); |
1271 |
|
|
readpos = 0; |
1272 |
|
|
break; /* the for loop */ |
1273 |
|
|
} |
1274 |
|
|
else |
1275 |
|
|
readpos++; |
1276 |
|
|
} |
1277 |
|
|
} |
1278 |
|
|
|
1279 |
|
|
/* Update the gpg object. */ |
1280 |
|
|
gpg->status.bufsize = bufsize; |
1281 |
|
|
gpg->status.buffer = buffer; |
1282 |
|
|
gpg->status.readpos = readpos; |
1283 |
|
|
return 0; |
1284 |
|
|
} |
1285 |
|
|
|
1286 |
|
|
|
1287 |
|
|
/* |
1288 |
|
|
* This colonline handler thing is not the clean way to do it. |
1289 |
|
|
* It might be better to enhance the gpgme_data_t object to act as |
1290 |
|
|
* a wrapper for a callback. Same goes for the status thing. |
1291 |
|
|
* For now we use this thing here becuase it is easier to implement. |
1292 |
|
|
*/ |
1293 |
|
|
static int |
1294 |
|
|
gpg_colon_line_handler ( void *opaque, int pid, int fd ) |
1295 |
|
|
{ |
1296 |
|
|
_gpg_object_t gpg = opaque; |
1297 |
|
|
gpgme_error_t rc = 0; |
1298 |
|
|
|
1299 |
|
|
assert ( fd == gpg->colon.fd[0] ); |
1300 |
|
|
rc = read_colon_line ( gpg ); |
1301 |
|
|
if ( rc ) { |
1302 |
|
|
DEBUG1 ("gpg_colon_line_handler: " |
1303 |
|
|
"read problem %d\n - stop", rc); |
1304 |
|
|
return 1; |
1305 |
|
|
} |
1306 |
|
|
|
1307 |
|
|
return gpg->colon.eof; |
1308 |
|
|
} |
1309 |
|
|
|
1310 |
|
|
static gpgme_error_t |
1311 |
|
|
read_colon_line ( _gpg_object_t gpg ) |
1312 |
|
|
{ |
1313 |
|
|
char *p; |
1314 |
|
|
int nread; |
1315 |
|
|
size_t bufsize = gpg->colon.bufsize; |
1316 |
|
|
char *buffer = gpg->colon.buffer; |
1317 |
|
|
size_t readpos = gpg->colon.readpos; |
1318 |
|
|
|
1319 |
|
|
assert (buffer); |
1320 |
|
|
if (bufsize - readpos < 256) { |
1321 |
|
|
/* need more room for the read */ |
1322 |
|
|
bufsize += 1024; |
1323 |
|
|
buffer = realloc (buffer, bufsize); |
1324 |
|
|
if ( !buffer ) |
1325 |
|
|
return mk_error (Out_Of_Core); |
1326 |
|
|
} |
1327 |
|
|
|
1328 |
|
|
|
1329 |
|
|
nread = _gpgme_io_read ( gpg->colon.fd[0], |
1330 |
|
|
buffer+readpos, bufsize-readpos ); |
1331 |
|
|
if (nread == -1) |
1332 |
|
|
return mk_error(Read_Error); |
1333 |
|
|
|
1334 |
|
|
if (!nread) { |
1335 |
|
|
gpg->colon.eof = 1; |
1336 |
|
|
assert (gpg->colon.fnc); |
1337 |
|
|
gpg->colon.fnc ( gpg->colon.fnc_value, NULL ); |
1338 |
|
|
return 0; |
1339 |
|
|
} |
1340 |
|
|
|
1341 |
|
|
while (nread > 0) { |
1342 |
|
|
for (p = buffer + readpos; nread; nread--, p++) { |
1343 |
|
|
if ( *p == '\n' ) { |
1344 |
|
|
/* (we require that the last line is terminated by a |
1345 |
|
|
* LF) and we skip empty lines. Note: we use UTF8 |
1346 |
|
|
* encoding and escaping of special characters |
1347 |
|
|
* We require at least one colon to cope with |
1348 |
|
|
* some other printed information. |
1349 |
|
|
*/ |
1350 |
|
|
*p = 0; |
1351 |
|
|
if ( gpg->colon.simple |
1352 |
|
|
|| (*buffer && strchr (buffer, ':')) ) { |
1353 |
|
|
assert (gpg->colon.fnc); |
1354 |
|
|
gpg->colon.fnc ( gpg->colon.fnc_value, buffer ); |
1355 |
|
|
} |
1356 |
|
|
|
1357 |
|
|
/* To reuse the buffer for the next line we have to |
1358 |
|
|
* shift the remaining data to the buffer start and |
1359 |
|
|
* restart the loop Hmmm: We can optimize this |
1360 |
|
|
* function by looking forward in the buffer to see |
1361 |
|
|
* whether a second complete line is available and in |
1362 |
|
|
* this case avoid the memmove for this line. */ |
1363 |
|
|
nread--; p++; |
1364 |
|
|
if (nread) |
1365 |
|
|
memmove (buffer, p, nread); |
1366 |
|
|
readpos = 0; |
1367 |
|
|
break; /* the for loop */ |
1368 |
|
|
} |
1369 |
|
|
else |
1370 |
|
|
readpos++; |
1371 |
|
|
} |
1372 |
|
|
} |
1373 |
|
|
|
1374 |
|
|
/* Update the gpg object. */ |
1375 |
|
|
gpg->colon.bufsize = bufsize; |
1376 |
|
|
gpg->colon.buffer = buffer; |
1377 |
|
|
gpg->colon.readpos = readpos; |
1378 |
|
|
return 0; |
1379 |
|
|
} |
1380 |
|
|
|
1381 |
|
|
|
1382 |
|
|
/* |
1383 |
|
|
* Here we handle --command-fd. This works closely together with |
1384 |
|
|
* the status handler. |
1385 |
|
|
*/ |
1386 |
|
|
|
1387 |
|
|
static int |
1388 |
|
|
command_cb ( void *opaque, char *buffer, size_t length, size_t *nread ) |
1389 |
|
|
{ |
1390 |
|
|
_gpg_object_t gpg = opaque; |
1391 |
|
|
const char *value; |
1392 |
|
|
int value_len; |
1393 |
|
|
|
1394 |
|
|
DEBUG0 ("command_cb: enter\n"); |
1395 |
|
|
assert (gpg->cmd.used); |
1396 |
|
|
if ( !buffer || !length || !nread ) |
1397 |
|
|
return 0; /* those values are reserved for extensions */ |
1398 |
|
|
*nread =0; |
1399 |
|
|
if( !gpg->cmd.code ) { |
1400 |
|
|
DEBUG0 ("command_cb: no code\n"); |
1401 |
|
|
return -1; |
1402 |
|
|
} |
1403 |
|
|
|
1404 |
|
|
if( !gpg->cmd.fnc ) { |
1405 |
|
|
DEBUG0 ("command_cb: no user cb\n"); |
1406 |
|
|
return -1; |
1407 |
|
|
} |
1408 |
|
|
|
1409 |
|
|
value = gpg->cmd.fnc ( gpg->cmd.fnc_value, |
1410 |
|
|
gpg->cmd.code, gpg->cmd.keyword ); |
1411 |
|
|
if( !value ) { |
1412 |
|
|
DEBUG0( "command_cb: no data from user cb\n" ); |
1413 |
|
|
gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value); |
1414 |
|
|
return -1; |
1415 |
|
|
} |
1416 |
|
|
|
1417 |
|
|
value_len = strlen (value); |
1418 |
|
|
if ( value_len+1 > length ) { |
1419 |
|
|
DEBUG0( "command_cb: too much data from user cb\n" ); |
1420 |
|
|
gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value); |
1421 |
|
|
return -1; |
1422 |
|
|
} |
1423 |
|
|
|
1424 |
|
|
memcpy ( buffer, value, value_len ); |
1425 |
|
|
if ( !value_len || (value_len && value[value_len-1] != '\n') ) |
1426 |
|
|
buffer[value_len++] = '\n'; |
1427 |
|
|
*nread = value_len; |
1428 |
|
|
|
1429 |
|
|
gpg->cmd.fnc( gpg->cmd.fnc_value, 0, value ); |
1430 |
|
|
gpg->cmd.code = 0; |
1431 |
|
|
/* and sleep again until read_status will wake us up again */ |
1432 |
|
|
_gpgme_freeze_fd ( gpg->cmd.fd ); |
1433 |
|
|
return 0; |
1434 |
|
|
} |
1435 |
|
|
|
1436 |
|
|
|
1437 |
|
|
|
1438 |
|
|
|