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