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

Annotation of /trunk/MyGPGME/rungpg.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (hide annotations)
Mon Jan 31 11:02:21 2005 UTC (20 years, 1 month ago) by twoaday
File MIME type: text/plain
File size: 40929 byte(s)
WinPT initial checkin.


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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26