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

Contents of /trunk/MyGPGME/rungpg.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (show 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 /* 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