2002-07-03 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 {
267   if (!engine)
268     return mk_error (Invalid_Value);
269
270   switch (engine->protocol)
271     {
272     case GPGME_PROTOCOL_OpenPGP:
273       return _gpgme_gpg_set_command_handler (engine->engine.gpg, fnc, fnc_value);
274     case GPGME_PROTOCOL_CMS:
275       /* FIXME */
276       break;
277     default:
278       break;
279     }
280   return 0;
281 }
282
283 GpgmeError _gpgme_engine_set_colon_line_handler (EngineObject engine,
284                                                  GpgColonLineHandler fnc,
285                                                  void *fnc_value)
286 {
287   if (!engine)
288     return mk_error (Invalid_Value);
289
290   switch (engine->protocol)
291     {
292     case GPGME_PROTOCOL_OpenPGP:
293       return _gpgme_gpg_set_colon_line_handler (engine->engine.gpg, 
294                                                 fnc, fnc_value);
295     case GPGME_PROTOCOL_CMS:
296       _gpgme_gpgsm_set_colon_line_handler (engine->engine.gpgsm,
297                                            fnc, fnc_value);
298       break;
299
300     default:
301       break;
302     }
303   return 0;
304 }
305
306 GpgmeError
307 _gpgme_engine_op_decrypt (EngineObject engine, GpgmeData ciph, GpgmeData plain)
308 {
309   if (!engine)
310     return mk_error (Invalid_Value);
311
312   switch (engine->protocol)
313     {
314     case GPGME_PROTOCOL_OpenPGP:
315       return _gpgme_gpg_op_decrypt (engine->engine.gpg, ciph, plain);
316     case GPGME_PROTOCOL_CMS:
317       return _gpgme_gpgsm_op_decrypt (engine->engine.gpgsm, ciph, plain);
318     default:
319       break;
320     }
321   return 0;
322 }
323
324 GpgmeError
325 _gpgme_engine_op_delete (EngineObject engine, GpgmeKey key, int allow_secret)
326 {
327   if (!engine)
328     return mk_error (Invalid_Value);
329
330   switch (engine->protocol)
331     {
332     case GPGME_PROTOCOL_OpenPGP:
333       return _gpgme_gpg_op_delete (engine->engine.gpg, key, allow_secret);
334     case GPGME_PROTOCOL_CMS:
335       return _gpgme_gpgsm_op_delete (engine->engine.gpgsm, key, allow_secret);
336     default:
337       break;
338     }
339   return 0;
340 }
341
342
343 GpgmeError
344 _gpgme_engine_op_encrypt (EngineObject engine, GpgmeRecipients recp,
345                           GpgmeData plain, GpgmeData ciph, int use_armor)
346 {
347   if (!engine)
348     return mk_error (Invalid_Value);
349
350   switch (engine->protocol)
351     {
352     case GPGME_PROTOCOL_OpenPGP:
353       return _gpgme_gpg_op_encrypt (engine->engine.gpg, recp, plain, ciph,
354                                     use_armor);
355     case GPGME_PROTOCOL_CMS:
356       return _gpgme_gpgsm_op_encrypt (engine->engine.gpgsm, recp, plain, ciph,
357                                       use_armor);
358     default:
359       break;
360     }
361   return 0;
362 }
363
364
365 GpgmeError
366 _gpgme_engine_op_encrypt_sign (EngineObject engine, GpgmeRecipients recp,
367                                GpgmeData plain, GpgmeData ciph, int use_armor,
368                                GpgmeCtx ctx /* FIXME */)
369 {
370   if (!engine)
371     return mk_error (Invalid_Value);
372
373   switch (engine->protocol)
374     {
375     case GPGME_PROTOCOL_OpenPGP:
376       return _gpgme_gpg_op_encrypt_sign (engine->engine.gpg, recp, plain, ciph,
377                                          use_armor, ctx);
378     case GPGME_PROTOCOL_CMS:
379       return mk_error (Not_Implemented);
380     default:
381       break;
382     }
383   return 0;
384 }
385
386
387 GpgmeError
388 _gpgme_engine_op_export (EngineObject engine, GpgmeRecipients recp,
389                          GpgmeData keydata, int use_armor)
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_export (engine->engine.gpg, recp, keydata,
398                                    use_armor);
399     case GPGME_PROTOCOL_CMS:
400       return _gpgme_gpgsm_op_export (engine->engine.gpgsm, recp, keydata,
401                                      use_armor);
402     default:
403       break;
404     }
405   return 0;
406 }
407
408 GpgmeError
409 _gpgme_engine_op_genkey (EngineObject engine, GpgmeData help_data,
410                          int use_armor, GpgmeData pubkey, GpgmeData seckey)
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_genkey (engine->engine.gpg, help_data, use_armor,
419                                    pubkey, seckey);
420     case GPGME_PROTOCOL_CMS:
421       return _gpgme_gpgsm_op_genkey (engine->engine.gpgsm, help_data, use_armor,
422                                      pubkey, seckey);
423     default:
424       break;
425     }
426   return 0;
427 }
428
429 GpgmeError
430 _gpgme_engine_op_import (EngineObject engine, GpgmeData keydata)
431 {
432   if (!engine)
433     return mk_error (Invalid_Value);
434
435   switch (engine->protocol)
436     {
437     case GPGME_PROTOCOL_OpenPGP:
438       return _gpgme_gpg_op_import (engine->engine.gpg, keydata);
439     case GPGME_PROTOCOL_CMS:
440       return _gpgme_gpgsm_op_import (engine->engine.gpgsm, keydata);
441     default:
442       break;
443     }
444   return 0;
445 }
446
447
448 GpgmeError
449 _gpgme_engine_op_keylist (EngineObject engine, const char *pattern,
450                           int secret_only, int keylist_mode)
451 {
452   if (!engine)
453     return mk_error (Invalid_Value);
454
455   switch (engine->protocol)
456     {
457     case GPGME_PROTOCOL_OpenPGP:
458       return _gpgme_gpg_op_keylist (engine->engine.gpg, pattern, secret_only,
459                                     keylist_mode);
460     case GPGME_PROTOCOL_CMS:
461       return _gpgme_gpgsm_op_keylist (engine->engine.gpgsm, pattern, secret_only,
462                                       keylist_mode);
463     default:
464       break;
465     }
466   return 0;
467 }
468
469
470 GpgmeError
471 _gpgme_engine_op_keylist_ext (EngineObject engine, const char *pattern[],
472                               int secret_only, int reserved, int keylist_mode)
473 {
474   if (!engine)
475     return mk_error (Invalid_Value);
476
477   switch (engine->protocol)
478     {
479     case GPGME_PROTOCOL_OpenPGP:
480       return _gpgme_gpg_op_keylist_ext (engine->engine.gpg, pattern,
481                                         secret_only, reserved, keylist_mode);
482     case GPGME_PROTOCOL_CMS:
483       return _gpgme_gpgsm_op_keylist_ext (engine->engine.gpgsm, pattern,
484                                           secret_only, reserved, keylist_mode);
485     default:
486       break;
487     }
488   return 0;
489 }
490
491
492 GpgmeError
493 _gpgme_engine_op_sign (EngineObject engine, GpgmeData in, GpgmeData out,
494                        GpgmeSigMode mode, int use_armor,
495                        int use_textmode, int include_certs,
496                        GpgmeCtx ctx /* FIXME */)
497 {
498   if (!engine)
499     return mk_error (Invalid_Value);
500
501   switch (engine->protocol)
502     {
503     case GPGME_PROTOCOL_OpenPGP:
504       return _gpgme_gpg_op_sign (engine->engine.gpg, in, out, mode, use_armor,
505                                  use_textmode, ctx);
506     case GPGME_PROTOCOL_CMS:
507       return _gpgme_gpgsm_op_sign (engine->engine.gpgsm, in, out, mode,
508                                    use_armor, use_textmode, include_certs, ctx);
509       break;
510     default:
511       break;
512     }
513   return 0;
514 }
515
516 GpgmeError
517 _gpgme_engine_op_trustlist (EngineObject engine, const char *pattern)
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_trustlist (engine->engine.gpg, pattern);
526     case GPGME_PROTOCOL_CMS:
527       return _gpgme_gpgsm_op_trustlist (engine->engine.gpgsm, pattern);
528     default:
529       break;
530     }
531   return 0;
532 }
533
534 GpgmeError
535 _gpgme_engine_op_verify (EngineObject engine, GpgmeData sig, GpgmeData text)
536 {
537   if (!engine)
538     return mk_error (Invalid_Value);
539
540   switch (engine->protocol)
541     {
542     case GPGME_PROTOCOL_OpenPGP:
543       return _gpgme_gpg_op_verify (engine->engine.gpg, sig, text);
544     case GPGME_PROTOCOL_CMS:
545       return _gpgme_gpgsm_op_verify (engine->engine.gpgsm, sig, text);
546     default:
547       break;
548     }
549   return 0;
550 }
551
552 GpgmeError
553 _gpgme_engine_start (EngineObject engine, void *opaque)
554 {
555   if (!engine)
556     return mk_error (Invalid_Value);
557
558   switch (engine->protocol)
559     {
560     case GPGME_PROTOCOL_OpenPGP:
561       return _gpgme_gpg_spawn (engine->engine.gpg, opaque);
562     case GPGME_PROTOCOL_CMS:
563       return _gpgme_gpgsm_start (engine->engine.gpgsm, opaque);
564     default:
565       break;
566     }
567   return 0;
568 }
569
570 void
571 _gpgme_engine_set_io_cbs (EngineObject engine,
572                           struct GpgmeIOCbs *io_cbs)
573 {
574   if (!engine)
575     return;
576
577   switch (engine->protocol)
578     {
579     case GPGME_PROTOCOL_OpenPGP:
580       _gpgme_gpg_set_io_cbs (engine->engine.gpg, io_cbs);
581       break;
582     case GPGME_PROTOCOL_CMS:
583       _gpgme_gpgsm_set_io_cbs (engine->engine.gpgsm, io_cbs);
584       break;
585     default:
586       break;
587     }
588 }
589
590 void
591 _gpgme_engine_io_event (EngineObject engine,
592                         GpgmeEventIO type, void *type_data)
593 {
594   if (!engine)
595     return;
596
597   switch (engine->protocol)
598     {
599     case GPGME_PROTOCOL_OpenPGP:
600       _gpgme_gpg_io_event (engine->engine.gpg, type, type_data);
601       break;
602     case GPGME_PROTOCOL_CMS:
603       _gpgme_gpgsm_io_event (engine->engine.gpgsm, type, type_data);
604       break;
605     default:
606       break;
607     }
608 }
609
610 \f
611 void
612 _gpgme_engine_add_child_to_reap_list (void *buf, int buflen, pid_t pid)
613 {
614   /* Reuse the memory, so that we don't need to allocate another
615      memory block and to handle errors.  */
616   struct reap_s *child = buf;
617
618   assert (buflen >= sizeof *child);
619   memset (child, 0, sizeof *child);
620   child->pid = pid;
621   child->entered = time (NULL);
622   LOCK (reap_list_lock);
623   child->next = reap_list;
624   reap_list = child;
625   UNLOCK (reap_list_lock);
626 }
627
628 static void
629 do_reaping (void)
630 {
631   struct reap_s *r, *rlast;
632   static time_t last_check;
633   time_t cur_time = time (NULL);
634
635   /* A race does not matter here.  */
636   if (!last_check)
637     last_check = time (NULL);
638
639   if (last_check >= cur_time)
640     return;  /* We check only every second.  */
641
642   /* Fixme: it would be nice if to have a TRYLOCK here.  */
643   LOCK (reap_list_lock);
644   for (r = reap_list, rlast = NULL; r; rlast = r, r = r ? r->next : NULL)
645     {
646       int dummy1, dummy2;
647
648       if (_gpgme_io_waitpid (r->pid, 0, &dummy1, &dummy2))
649         {
650           /* The process has terminated - remove it from the queue.  */
651           void *p = r;
652           if (!rlast)
653             {
654               reap_list = r->next;
655               r = reap_list;
656             }
657           else
658             {
659               rlast->next = r->next;
660               r = rlast;
661             }
662           xfree (p);
663         }
664       else if (!r->term_send)
665         {
666           if (r->entered + 1 >= cur_time)
667             {
668               _gpgme_io_kill (r->pid, 0);
669               r->term_send = 1;
670               r->entered = cur_time;
671             }
672         }
673       else
674         {
675           /* Give it 5 second before we are going to send the killer.  */
676           if (r->entered + 5 >= cur_time)
677             {
678               _gpgme_io_kill (r->pid, 1);
679               r->entered = cur_time; /* Just in case we have to repeat it.  */
680             }
681         }
682     }
683   UNLOCK (reap_list_lock);  
684 }
685
686 void
687 _gpgme_engine_housecleaning (void)
688 {
689   do_reaping ();
690 }