/[winpt]/trunk/MyGPGME/rungpg.c
ViewVC logotype

Contents of /trunk/MyGPGME/rungpg.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 22 - (show annotations)
Wed Aug 10 11:33:35 2005 UTC (19 years, 6 months ago) by twoaday
File MIME type: text/plain
File size: 41275 byte(s)
2005-08-06  Timo Schulz  <twoaday@freakmail.de>
 
        * wptGPGME.cpp (keycache_update): Reload OpenPGP parts
        of the secret key.
        (keycache_init): cache name of secret keyring.
        * wptKeyList.cpp (keylist_upd_key): Do not add long keyid.
        (get_key_type): Do not assume 'ultimate' means key pair.
        * wptKeyEditDlgs.cpp (diff_time): New.
        (keyedit_addsubkey_dlg_proc): Changed design and use
        diff_time. Drop checks for invalid keylength (< 1024, > 4096)
        because the combo box automatically handles this.
        * wptKeyManager.cpp (km_set_implicit_trust): Return error code.
        * wptGPG.cpp (get_backup_name): New.
        (gnupg_backup_keyrings): Rotate backup names, from 0..3.
        * wptClipImportDialog.cpp (clip_import_dlg_proc): Free memory.
        * wptKeyManagerDlg.cpp (keymanager_dlg_proc): Use 0x short keyid and
        not the long keyid.


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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26