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

Annotation of /trunk/MyGPGME/rungpg.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (hide annotations)
Mon May 9 08:53:51 2005 UTC (19 years, 9 months ago) by twoaday
File MIME type: text/plain
File size: 41281 byte(s)
Some bug fixes for 'showpref'.

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 twoaday 7 char *path;
108    
109 twoaday 2 /* 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 twoaday 7 _gpgme_gpg_new (_gpg_object_t *r_gpg)
195 twoaday 2 {
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 twoaday 7 _pipe_close (int * fd)
278 twoaday 2 {
279 twoaday 7 if (fd[0] != -1)
280     _gpgme_io_close (fd[0]);
281     if (fd[1] != -1)
282     _gpgme_io_close (fd[1]);
283 twoaday 2 }
284    
285    
286     void
287 twoaday 7 _gpgme_gpg_release (_gpg_object_t *r_gpg)
288 twoaday 2 {
289     struct arg_and_data_s * a;
290     _gpg_object_t gpg = *r_gpg;
291    
292     if( !gpg )
293     return;
294 twoaday 7 safe_free (gpg->status.buffer);
295     safe_free (gpg->logging.buffer);
296     safe_free (gpg->colon.buffer);
297     safe_free (gpg->cmd.keyword);
298 twoaday 2 if (gpg->argv)
299     free_argv(gpg->argv);
300    
301 twoaday 7 safe_free (gpg->path);
302    
303 twoaday 2 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 twoaday 7 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 twoaday 2 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 twoaday 7 const char *optfile = _gpgme_get_gpg_optfile (0);
611 twoaday 2
612 twoaday 7 if (gpg->argv) {
613     free_argv (gpg->argv);
614 twoaday 2 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 twoaday 7 const char *gpg_path = _gpgme_get_gpg_path (0);
843 twoaday 2
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 twoaday 7 if (gpg->path)
926     gpg_path = gpg->path;
927     pid = _gpgme_io_spawn (gpg_path, gpg->argv, fd_child_list, fd_parent_list);
928 twoaday 2 safe_free (fd_child_list);
929 twoaday 7 if (pid == -1)
930 twoaday 2 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 twoaday 7 if (gpg->cmd.used)
978     _gpgme_freeze_fd (gpg->cmd.fd);
979 twoaday 2
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 twoaday 15 if (nwritten < 1) {
1073 twoaday 2 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 twoaday 15 if ((size_t)nwritten < nbytes) {
1080 twoaday 2 /* 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 twoaday 15 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 twoaday 2 return -1;
1439     }
1440    
1441 twoaday 15 memcpy (buffer, value, value_len);
1442     if (!value_len || (value_len && value[value_len-1] != '\n'))
1443 twoaday 2 buffer[value_len++] = '\n';
1444     *nread = value_len;
1445    
1446 twoaday 15 gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value);
1447 twoaday 2 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