2002-07-28 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / gpgme / engine.c
1 /* engine.c 
2  *      Copyright (C) 2000 Werner Koch (dd9jn)
3  *      Copyright (C) 2001 g10 Code GmbH
4  *
5  * This file is part of GPGME.
6  *
7  * GPGME 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  * GPGME 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 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <time.h>
26 #include <sys/types.h>
27 #include <string.h>
28 #include <assert.h>
29
30 #include "gpgme.h"
31 #include "util.h"
32 #include "sema.h"
33 #include "io.h"
34
35 #include "engine.h"
36 #include "rungpg.h"
37 #include "engine-gpgsm.h"
38
39
40 struct engine_object_s
41   {
42     GpgmeProtocol protocol;
43
44     const char *path;
45     const char *version;
46
47     union
48       {
49         GpgObject gpg;
50         GpgsmObject gpgsm;
51       } engine;
52 };
53
54
55 struct reap_s
56 {
57   struct reap_s *next;
58   int pid;
59   time_t entered;
60   int term_send;
61 };
62
63 static struct reap_s *reap_list;
64 DEFINE_STATIC_LOCK (reap_list_lock);
65
66
67 /* Get the path of the engine for PROTOCOL.  */
68 const char *
69 _gpgme_engine_get_path (GpgmeProtocol proto)
70 {
71   switch (proto)
72     {
73     case GPGME_PROTOCOL_OpenPGP:
74       return _gpgme_get_gpg_path ();
75     case GPGME_PROTOCOL_CMS:
76       return _gpgme_get_gpgsm_path ();
77     default:
78       return NULL;
79     }
80 }
81
82
83 /* Get the version number of the engine for PROTOCOL.  */
84 const char *
85 _gpgme_engine_get_version (GpgmeProtocol proto)
86 {
87   switch (proto)
88     {
89     case GPGME_PROTOCOL_OpenPGP:
90       return _gpgme_gpg_get_version ();
91     case GPGME_PROTOCOL_CMS:
92       return _gpgme_gpgsm_get_version ();
93     default:
94       return NULL;
95     }
96 }
97
98
99 GpgmeError
100 gpgme_engine_check_version (GpgmeProtocol proto)
101 {
102   switch (proto)
103     {
104     case GPGME_PROTOCOL_OpenPGP:
105       return _gpgme_gpg_check_version ();
106     case GPGME_PROTOCOL_CMS:
107       return _gpgme_gpgsm_check_version ();
108     default:
109       return mk_error (Invalid_Value);
110     }
111 }
112
113
114 const char *
115 _gpgme_engine_get_info (GpgmeProtocol proto)
116 {
117   static const char fmt[] = " <engine>\n"
118     "  <protocol>%s</protocol>\n"
119     "  <version>%s</version>\n"
120     "  <path>%s</path>\n"
121     " </engine>\n";
122   static const char *const strproto[3] = { "OpenPGP", "CMS", NULL };
123   static const char *engine_info[3];  /* FIXME: MAX_PROTO + 1*/
124   DEFINE_STATIC_LOCK (engine_info_lock);
125
126   if (proto > 2 /* FIXME MAX_PROTO */ || !strproto[proto])
127     return NULL;
128
129   LOCK (engine_info_lock);
130   if (!engine_info[proto])
131     {
132       const char *path = _gpgme_engine_get_path (proto);
133       const char *version = _gpgme_engine_get_version (proto);
134
135       if (path && version)
136         {
137           char *info = xtrymalloc (strlen (fmt) + strlen (strproto[proto])
138                                    + strlen (path) + strlen (version) + 1);
139           if (!info)
140             info = " <engine>\n"
141               "  <error>Out of core</error>\n"
142               " </engine>";
143           else
144             sprintf (info, fmt, strproto[proto], version, path);
145           engine_info[proto] = info;
146         }
147     }
148   UNLOCK (engine_info_lock);
149   return engine_info[proto];
150 }
151
152
153 GpgmeError
154 _gpgme_engine_new (GpgmeProtocol proto, EngineObject *r_engine)
155 {
156   EngineObject engine;
157   GpgmeError err = 0;
158
159   engine = xtrycalloc (1, sizeof *engine);
160   if (!engine)
161     {
162       err = mk_error (Out_Of_Core);
163       goto leave;
164     }
165
166   engine->protocol = proto;
167   switch (proto)
168     {
169     case GPGME_PROTOCOL_OpenPGP:
170       err =_gpgme_gpg_new (&engine->engine.gpg);
171       break;
172     case GPGME_PROTOCOL_CMS:
173       err = _gpgme_gpgsm_new (&engine->engine.gpgsm);
174       if (err)
175         goto leave;
176       break;
177     default:
178       err = mk_error (Invalid_Value);
179     }
180   if (err)
181     goto leave;
182
183   engine->path = _gpgme_engine_get_path (proto);
184   engine->version = _gpgme_engine_get_version (proto);
185
186   if (!engine->path || !engine->version)
187     {
188       err = mk_error (Invalid_Engine);
189       goto leave;
190     }
191
192  leave:
193   if (err)
194     _gpgme_engine_release (engine);
195   else
196     *r_engine = engine;
197   
198   return err;
199 }
200
201
202 void
203 _gpgme_engine_release (EngineObject engine)
204 {
205   if (!engine)
206     return;
207
208   switch (engine->protocol)
209     {
210     case GPGME_PROTOCOL_OpenPGP:
211       _gpgme_gpg_release (engine->engine.gpg);
212       break;
213     case GPGME_PROTOCOL_CMS:
214       _gpgme_gpgsm_release (engine->engine.gpgsm);
215       break;
216     default:
217       break;
218     }
219   xfree (engine);
220 }
221
222
223 void
224 _gpgme_engine_set_verbosity (EngineObject engine, int verbosity)
225 {
226   if (!engine)
227     return;
228
229   switch (engine->protocol)
230     {
231     case GPGME_PROTOCOL_OpenPGP:
232       while (verbosity-- > 0)
233         _gpgme_gpg_add_arg (engine->engine.gpg, "--verbose");
234       break;
235     case GPGME_PROTOCOL_CMS:
236       /* FIXME */
237       break;
238     default:
239       break;
240     }
241 }
242
243 void
244 _gpgme_engine_set_status_handler (EngineObject engine,
245                                   GpgStatusHandler fnc, void *fnc_value)
246 {
247   if (!engine)
248     return;
249
250   switch (engine->protocol)
251     {
252     case GPGME_PROTOCOL_OpenPGP:
253       _gpgme_gpg_set_status_handler (engine->engine.gpg, fnc, fnc_value);
254       break;
255     case GPGME_PROTOCOL_CMS:
256       _gpgme_gpgsm_set_status_handler (engine->engine.gpgsm, fnc, fnc_value);
257       break;
258     default:
259       break;
260     }
261 }
262
263 GpgmeError
264 _gpgme_engine_set_command_handler (EngineObject engine,
265                                   GpgCommandHandler fnc, void *fnc_value,
266                                    GpgmeData linked_data)
267 {
268   if (!engine)
269     return mk_error (Invalid_Value);
270
271   switch (engine->protocol)
272     {
273     case GPGME_PROTOCOL_OpenPGP:
274       return _gpgme_gpg_set_command_handler (engine->engine.gpg,
275                                              fnc, fnc_value, linked_data);
276     case GPGME_PROTOCOL_CMS:
277       /* FIXME */
278       break;
279     default:
280       break;
281     }
282   return 0;
283 }
284
285 GpgmeError _gpgme_engine_set_colon_line_handler (EngineObject engine,
286                                                  GpgColonLineHandler fnc,
287                                                  void *fnc_value)
288 {
289   if (!engine)
290     return mk_error (Invalid_Value);
291
292   switch (engine->protocol)
293     {
294     case GPGME_PROTOCOL_OpenPGP:
295       return _gpgme_gpg_set_colon_line_handler (engine->engine.gpg, 
296                                                 fnc, fnc_value);
297     case GPGME_PROTOCOL_CMS:
298       _gpgme_gpgsm_set_colon_line_handler (engine->engine.gpgsm,
299                                            fnc, fnc_value);
300       break;
301
302     default:
303       break;
304     }
305   return 0;
306 }
307
308 GpgmeError
309 _gpgme_engine_op_decrypt (EngineObject engine, GpgmeData ciph, GpgmeData plain)
310 {
311   if (!engine)
312     return mk_error (Invalid_Value);
313
314   switch (engine->protocol)
315     {
316     case GPGME_PROTOCOL_OpenPGP:
317       return _gpgme_gpg_op_decrypt (engine->engine.gpg, ciph, plain);
318     case GPGME_PROTOCOL_CMS:
319       return _gpgme_gpgsm_op_decrypt (engine->engine.gpgsm, ciph, plain);
320     default:
321       break;
322     }
323   return 0;
324 }
325
326 GpgmeError
327 _gpgme_engine_op_delete (EngineObject engine, GpgmeKey key, int allow_secret)
328 {
329   if (!engine)
330     return mk_error (Invalid_Value);
331
332   switch (engine->protocol)
333     {
334     case GPGME_PROTOCOL_OpenPGP:
335       return _gpgme_gpg_op_delete (engine->engine.gpg, key, allow_secret);
336     case GPGME_PROTOCOL_CMS:
337       return _gpgme_gpgsm_op_delete (engine->engine.gpgsm, key, allow_secret);
338     default:
339       break;
340     }
341   return 0;
342 }
343
344
345 GpgmeError
346 _gpgme_engine_op_edit (EngineObject engine, GpgmeKey key, GpgmeData out)
347 {
348   if (!engine)
349     return mk_error (Invalid_Value);
350
351   switch (engine->protocol)
352     {
353     case GPGME_PROTOCOL_OpenPGP:
354       return _gpgme_gpg_op_edit (engine->engine.gpg, key, out);
355     case GPGME_PROTOCOL_CMS:
356       /* FIXME */
357       return mk_error (Not_Implemented);
358     default:
359       break;
360     }
361   return 0;
362 }
363
364 GpgmeError
365 _gpgme_engine_op_encrypt (EngineObject engine, GpgmeRecipients recp,
366                           GpgmeData plain, GpgmeData ciph, int use_armor)
367 {
368   if (!engine)
369     return mk_error (Invalid_Value);
370
371   switch (engine->protocol)
372     {
373     case GPGME_PROTOCOL_OpenPGP:
374       return _gpgme_gpg_op_encrypt (engine->engine.gpg, recp, plain, ciph,
375                                     use_armor);
376     case GPGME_PROTOCOL_CMS:
377       return _gpgme_gpgsm_op_encrypt (engine->engine.gpgsm, recp, plain, ciph,
378                                       use_armor);
379     default:
380       break;
381     }
382   return 0;
383 }
384
385
386 GpgmeError
387 _gpgme_engine_op_encrypt_sign (EngineObject engine, GpgmeRecipients recp,
388                                GpgmeData plain, GpgmeData ciph, int use_armor,
389                                GpgmeCtx ctx /* FIXME */)
390 {
391   if (!engine)
392     return mk_error (Invalid_Value);
393
394   switch (engine->protocol)
395     {
396     case GPGME_PROTOCOL_OpenPGP:
397       return _gpgme_gpg_op_encrypt_sign (engine->engine.gpg, recp, plain, ciph,
398                                          use_armor, ctx);
399     case GPGME_PROTOCOL_CMS:
400       return mk_error (Not_Implemented);
401     default:
402       break;
403     }
404   return 0;
405 }
406
407
408 GpgmeError
409 _gpgme_engine_op_export (EngineObject engine, GpgmeRecipients recp,
410                          GpgmeData keydata, int use_armor)
411 {
412   if (!engine)
413     return mk_error (Invalid_Value);
414
415   switch (engine->protocol)
416     {
417     case GPGME_PROTOCOL_OpenPGP:
418       return _gpgme_gpg_op_export (engine->engine.gpg, recp, keydata,
419                                    use_armor);
420     case GPGME_PROTOCOL_CMS:
421       return _gpgme_gpgsm_op_export (engine->engine.gpgsm, recp, keydata,
422                                      use_armor);
423     default:
424       break;
425     }
426   return 0;
427 }
428
429 GpgmeError
430 _gpgme_engine_op_genkey (EngineObject engine, GpgmeData help_data,
431                          int use_armor, GpgmeData pubkey, GpgmeData seckey)
432 {
433   if (!engine)
434     return mk_error (Invalid_Value);
435
436   switch (engine->protocol)
437     {
438     case GPGME_PROTOCOL_OpenPGP:
439       return _gpgme_gpg_op_genkey (engine->engine.gpg, help_data, use_armor,
440                                    pubkey, seckey);
441     case GPGME_PROTOCOL_CMS:
442       return _gpgme_gpgsm_op_genkey (engine->engine.gpgsm, help_data, use_armor,
443                                      pubkey, seckey);
444     default:
445       break;
446     }
447   return 0;
448 }
449
450 GpgmeError
451 _gpgme_engine_op_import (EngineObject engine, GpgmeData keydata)
452 {
453   if (!engine)
454     return mk_error (Invalid_Value);
455
456   switch (engine->protocol)
457     {
458     case GPGME_PROTOCOL_OpenPGP:
459       return _gpgme_gpg_op_import (engine->engine.gpg, keydata);
460     case GPGME_PROTOCOL_CMS:
461       return _gpgme_gpgsm_op_import (engine->engine.gpgsm, keydata);
462     default:
463       break;
464     }
465   return 0;
466 }
467
468
469 GpgmeError
470 _gpgme_engine_op_keylist (EngineObject engine, const char *pattern,
471                           int secret_only, int keylist_mode)
472 {
473   if (!engine)
474     return mk_error (Invalid_Value);
475
476   switch (engine->protocol)
477     {
478     case GPGME_PROTOCOL_OpenPGP:
479       return _gpgme_gpg_op_keylist (engine->engine.gpg, pattern, secret_only,
480                                     keylist_mode);
481     case GPGME_PROTOCOL_CMS:
482       return _gpgme_gpgsm_op_keylist (engine->engine.gpgsm, pattern, secret_only,
483                                       keylist_mode);
484     default:
485       break;
486     }
487   return 0;
488 }
489
490
491 GpgmeError
492 _gpgme_engine_op_keylist_ext (EngineObject engine, const char *pattern[],
493                               int secret_only, int reserved, int keylist_mode)
494 {
495   if (!engine)
496     return mk_error (Invalid_Value);
497
498   switch (engine->protocol)
499     {
500     case GPGME_PROTOCOL_OpenPGP:
501       return _gpgme_gpg_op_keylist_ext (engine->engine.gpg, pattern,
502                                         secret_only, reserved, keylist_mode);
503     case GPGME_PROTOCOL_CMS:
504       return _gpgme_gpgsm_op_keylist_ext (engine->engine.gpgsm, pattern,
505                                           secret_only, reserved, keylist_mode);
506     default:
507       break;
508     }
509   return 0;
510 }
511
512
513 GpgmeError
514 _gpgme_engine_op_sign (EngineObject engine, GpgmeData in, GpgmeData out,
515                        GpgmeSigMode mode, int use_armor,
516                        int use_textmode, int include_certs,
517                        GpgmeCtx ctx /* FIXME */)
518 {
519   if (!engine)
520     return mk_error (Invalid_Value);
521
522   switch (engine->protocol)
523     {
524     case GPGME_PROTOCOL_OpenPGP:
525       return _gpgme_gpg_op_sign (engine->engine.gpg, in, out, mode, use_armor,
526                                  use_textmode, ctx);
527     case GPGME_PROTOCOL_CMS:
528       return _gpgme_gpgsm_op_sign (engine->engine.gpgsm, in, out, mode,
529                                    use_armor, use_textmode, include_certs, ctx);
530       break;
531     default:
532       break;
533     }
534   return 0;
535 }
536
537 GpgmeError
538 _gpgme_engine_op_trustlist (EngineObject engine, const char *pattern)
539 {
540   if (!engine)
541     return mk_error (Invalid_Value);
542
543   switch (engine->protocol)
544     {
545     case GPGME_PROTOCOL_OpenPGP:
546       return _gpgme_gpg_op_trustlist (engine->engine.gpg, pattern);
547     case GPGME_PROTOCOL_CMS:
548       return _gpgme_gpgsm_op_trustlist (engine->engine.gpgsm, pattern);
549     default:
550       break;
551     }
552   return 0;
553 }
554
555 GpgmeError
556 _gpgme_engine_op_verify (EngineObject engine, GpgmeData sig, GpgmeData text)
557 {
558   if (!engine)
559     return mk_error (Invalid_Value);
560
561   switch (engine->protocol)
562     {
563     case GPGME_PROTOCOL_OpenPGP:
564       return _gpgme_gpg_op_verify (engine->engine.gpg, sig, text);
565     case GPGME_PROTOCOL_CMS:
566       return _gpgme_gpgsm_op_verify (engine->engine.gpgsm, sig, text);
567     default:
568       break;
569     }
570   return 0;
571 }
572
573 GpgmeError
574 _gpgme_engine_start (EngineObject engine, void *opaque)
575 {
576   if (!engine)
577     return mk_error (Invalid_Value);
578
579   switch (engine->protocol)
580     {
581     case GPGME_PROTOCOL_OpenPGP:
582       return _gpgme_gpg_spawn (engine->engine.gpg, opaque);
583     case GPGME_PROTOCOL_CMS:
584       return _gpgme_gpgsm_start (engine->engine.gpgsm, opaque);
585     default:
586       break;
587     }
588   return 0;
589 }
590
591 void
592 _gpgme_engine_set_io_cbs (EngineObject engine,
593                           struct GpgmeIOCbs *io_cbs)
594 {
595   if (!engine)
596     return;
597
598   switch (engine->protocol)
599     {
600     case GPGME_PROTOCOL_OpenPGP:
601       _gpgme_gpg_set_io_cbs (engine->engine.gpg, io_cbs);
602       break;
603     case GPGME_PROTOCOL_CMS:
604       _gpgme_gpgsm_set_io_cbs (engine->engine.gpgsm, io_cbs);
605       break;
606     default:
607       break;
608     }
609 }
610
611 void
612 _gpgme_engine_io_event (EngineObject engine,
613                         GpgmeEventIO type, void *type_data)
614 {
615   if (!engine)
616     return;
617
618   switch (engine->protocol)
619     {
620     case GPGME_PROTOCOL_OpenPGP:
621       _gpgme_gpg_io_event (engine->engine.gpg, type, type_data);
622       break;
623     case GPGME_PROTOCOL_CMS:
624       _gpgme_gpgsm_io_event (engine->engine.gpgsm, type, type_data);
625       break;
626     default:
627       break;
628     }
629 }
630
631 \f
632 void
633 _gpgme_engine_add_child_to_reap_list (void *buf, int buflen, pid_t pid)
634 {
635   /* Reuse the memory, so that we don't need to allocate another
636      memory block and to handle errors.  */
637   struct reap_s *child = buf;
638
639   assert (buflen >= sizeof *child);
640   memset (child, 0, sizeof *child);
641   child->pid = pid;
642   child->entered = time (NULL);
643   LOCK (reap_list_lock);
644   child->next = reap_list;
645   reap_list = child;
646   UNLOCK (reap_list_lock);
647 }
648
649 static void
650 do_reaping (void)
651 {
652   struct reap_s *r, *rlast;
653   static time_t last_check;
654   time_t cur_time = time (NULL);
655
656   /* A race does not matter here.  */
657   if (!last_check)
658     last_check = time (NULL);
659
660   if (last_check >= cur_time)
661     return;  /* We check only every second.  */
662
663   /* Fixme: it would be nice if to have a TRYLOCK here.  */
664   LOCK (reap_list_lock);
665   for (r = reap_list, rlast = NULL; r; rlast = r, r = r ? r->next : NULL)
666     {
667       int dummy1, dummy2;
668
669       if (_gpgme_io_waitpid (r->pid, 0, &dummy1, &dummy2))
670         {
671           /* The process has terminated - remove it from the queue.  */
672           void *p = r;
673           if (!rlast)
674             {
675               reap_list = r->next;
676               r = reap_list;
677             }
678           else
679             {
680               rlast->next = r->next;
681               r = rlast;
682             }
683           xfree (p);
684         }
685       else if (!r->term_send)
686         {
687           if (r->entered + 1 >= cur_time)
688             {
689               _gpgme_io_kill (r->pid, 0);
690               r->term_send = 1;
691               r->entered = cur_time;
692             }
693         }
694       else
695         {
696           /* Give it 5 second before we are going to send the killer.  */
697           if (r->entered + 5 >= cur_time)
698             {
699               _gpgme_io_kill (r->pid, 1);
700               r->entered = cur_time; /* Just in case we have to repeat it.  */
701             }
702         }
703     }
704   UNLOCK (reap_list_lock);  
705 }
706
707 void
708 _gpgme_engine_housecleaning (void)
709 {
710   do_reaping ();
711 }