2001-12-18 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 <assert.h>
28
29 #include "gpgme.h"
30 #include "util.h"
31 #include "sema.h"
32
33 #include "engine.h"
34 #include "rungpg.h"
35 #include "engine-gpgsm.h"
36
37 struct engine_object_s
38   {
39     GpgmeProtocol protocol;
40
41     const char *path;
42     const char *version;
43
44     union
45       {
46         GpgObject gpg;
47         GpgsmObject gpgsm;
48       } engine;
49 };
50
51 struct reap_s
52 {
53   struct reap_s *next;
54   int pid;
55   time_t entered;
56   int term_send;
57 };
58
59 static struct reap_s *reap_list;
60 DEFINE_STATIC_LOCK (reap_list_lock);
61
62 /* Get the path of the engine for PROTOCOL.  */
63 const char *
64 _gpgme_engine_get_path (GpgmeProtocol proto)
65 {
66   switch (proto)
67     {
68     case GPGME_PROTOCOL_OpenPGP:
69       return _gpgme_get_gpg_path ();
70     case GPGME_PROTOCOL_CMS:
71       return _gpgme_get_gpgsm_path ();
72     default:
73       return NULL;
74     }
75 }
76
77 /* Get the version number of the engine for PROTOCOL.  */
78 const char *
79 _gpgme_engine_get_version (GpgmeProtocol proto)
80 {
81   switch (proto)
82     {
83     case GPGME_PROTOCOL_OpenPGP:
84       return _gpgme_gpg_get_version ();
85     case GPGME_PROTOCOL_CMS:
86       return _gpgme_gpgsm_get_version ();
87     default:
88       return NULL;
89     }
90 }
91
92 GpgmeError
93 gpgme_engine_check_version (GpgmeProtocol proto)
94 {
95   switch (proto)
96     {
97     case GPGME_PROTOCOL_OpenPGP:
98       return _gpgme_gpg_check_version ();
99     case GPGME_PROTOCOL_CMS:
100       return _gpgme_gpgsm_check_version ();
101     default:
102       return mk_error (Invalid_Value);
103     }
104 }
105
106 GpgmeError
107 _gpgme_engine_new (GpgmeProtocol proto, EngineObject *r_engine)
108 {
109   EngineObject engine;
110   GpgmeError err = 0;
111
112   engine = xtrycalloc (1, sizeof *engine);
113   if (!engine)
114     {
115       err = mk_error (Out_Of_Core);
116       goto leave;
117     }
118
119   engine->protocol = proto;
120   switch (proto)
121     {
122     case GPGME_PROTOCOL_OpenPGP:
123       err =_gpgme_gpg_new (&engine->engine.gpg);
124       break;
125     case GPGME_PROTOCOL_CMS:
126       err = _gpgme_gpgsm_new (&engine->engine.gpgsm);
127       if (err)
128         goto leave;
129       break;
130     default:
131       err = mk_error (Invalid_Value);
132     }
133   if (err)
134     goto leave;
135
136   engine->path = _gpgme_engine_get_path (proto);
137   engine->version = _gpgme_engine_get_version (proto);
138
139   if (!engine->path || !engine->version)
140     {
141       err = mk_error (Invalid_Engine);
142       goto leave;
143     }
144
145  leave:
146   if (err)
147     _gpgme_engine_release (engine);
148   else
149     *r_engine = engine;
150   
151   return err;
152 }
153
154 void
155 _gpgme_engine_release (EngineObject engine)
156 {
157   if (!engine)
158     return;
159
160   switch (engine->protocol)
161     {
162     case GPGME_PROTOCOL_OpenPGP:
163       _gpgme_gpg_release (engine->engine.gpg);
164       break;
165     case GPGME_PROTOCOL_CMS:
166       _gpgme_gpgsm_release (engine->engine.gpgsm);
167       break;
168     default:
169       break;
170     }
171   xfree (engine);
172 }
173
174 void
175 _gpgme_engine_set_verbosity (EngineObject engine, int verbosity)
176 {
177   if (!engine)
178     return;
179
180   switch (engine->protocol)
181     {
182     case GPGME_PROTOCOL_OpenPGP:
183       while (verbosity-- > 0)
184         _gpgme_gpg_add_arg (engine->engine.gpg, "--verbose");
185       break;
186     case GPGME_PROTOCOL_CMS:
187       /* FIXME */
188       break;
189     default:
190       break;
191     }
192 }
193
194 void
195 _gpgme_engine_set_status_handler (EngineObject engine,
196                                   GpgStatusHandler fnc, void *fnc_value)
197 {
198   if (!engine)
199     return;
200
201   switch (engine->protocol)
202     {
203     case GPGME_PROTOCOL_OpenPGP:
204       _gpgme_gpg_set_status_handler (engine->engine.gpg, fnc, fnc_value);
205       break;
206     case GPGME_PROTOCOL_CMS:
207       _gpgme_gpgsm_set_status_handler (engine->engine.gpgsm, fnc, fnc_value);
208       break;
209     default:
210       break;
211     }
212 }
213
214 GpgmeError
215 _gpgme_engine_set_command_handler (EngineObject engine,
216                                   GpgCommandHandler fnc, void *fnc_value)
217 {
218   if (!engine)
219     return mk_error (Invalid_Value);
220
221   switch (engine->protocol)
222     {
223     case GPGME_PROTOCOL_OpenPGP:
224       return _gpgme_gpg_set_command_handler (engine->engine.gpg, fnc, fnc_value);
225     case GPGME_PROTOCOL_CMS:
226       /* FIXME */
227       break;
228     default:
229       break;
230     }
231   return 0;
232 }
233
234 GpgmeError _gpgme_engine_set_colon_line_handler (EngineObject engine,
235                                                  GpgColonLineHandler fnc,
236                                                  void *fnc_value)
237 {
238   if (!engine)
239     return mk_error (Invalid_Value);
240
241   switch (engine->protocol)
242     {
243     case GPGME_PROTOCOL_OpenPGP:
244       return _gpgme_gpg_set_colon_line_handler (engine->engine.gpg, 
245                                                 fnc, fnc_value);
246     case GPGME_PROTOCOL_CMS:
247       _gpgme_gpgsm_set_colon_line_handler (engine->engine.gpgsm,
248                                            fnc, fnc_value);
249       break;
250
251     default:
252       break;
253     }
254   return 0;
255 }
256
257 GpgmeError
258 _gpgme_engine_op_decrypt (EngineObject engine, GpgmeData ciph, GpgmeData plain)
259 {
260   if (!engine)
261     return mk_error (Invalid_Value);
262
263   switch (engine->protocol)
264     {
265     case GPGME_PROTOCOL_OpenPGP:
266       return _gpgme_gpg_op_decrypt (engine->engine.gpg, ciph, plain);
267     case GPGME_PROTOCOL_CMS:
268       return _gpgme_gpgsm_op_decrypt (engine->engine.gpgsm, ciph, plain);
269     default:
270       break;
271     }
272   return 0;
273 }
274
275 GpgmeError
276 _gpgme_engine_op_delete (EngineObject engine, GpgmeKey key, int allow_secret)
277 {
278   if (!engine)
279     return mk_error (Invalid_Value);
280
281   switch (engine->protocol)
282     {
283     case GPGME_PROTOCOL_OpenPGP:
284       return _gpgme_gpg_op_delete (engine->engine.gpg, key, allow_secret);
285     case GPGME_PROTOCOL_CMS:
286       return _gpgme_gpgsm_op_delete (engine->engine.gpgsm, key, allow_secret);
287     default:
288       break;
289     }
290   return 0;
291 }
292
293 GpgmeError
294 _gpgme_engine_op_encrypt (EngineObject engine, GpgmeRecipients recp,
295                           GpgmeData plain, GpgmeData ciph, int use_armor)
296 {
297   if (!engine)
298     return mk_error (Invalid_Value);
299
300   switch (engine->protocol)
301     {
302     case GPGME_PROTOCOL_OpenPGP:
303       return _gpgme_gpg_op_encrypt (engine->engine.gpg, recp, plain, ciph,
304                                     use_armor);
305     case GPGME_PROTOCOL_CMS:
306       return _gpgme_gpgsm_op_encrypt (engine->engine.gpgsm, recp, plain, ciph,
307                                       use_armor);
308     default:
309       break;
310     }
311   return 0;
312 }
313
314 GpgmeError
315 _gpgme_engine_op_export (EngineObject engine, GpgmeRecipients recp,
316                          GpgmeData keydata, int use_armor)
317 {
318   if (!engine)
319     return mk_error (Invalid_Value);
320
321   switch (engine->protocol)
322     {
323     case GPGME_PROTOCOL_OpenPGP:
324       return _gpgme_gpg_op_export (engine->engine.gpg, recp, keydata,
325                                    use_armor);
326     case GPGME_PROTOCOL_CMS:
327       return _gpgme_gpgsm_op_export (engine->engine.gpgsm, recp, keydata,
328                                      use_armor);
329     default:
330       break;
331     }
332   return 0;
333 }
334
335 GpgmeError
336 _gpgme_engine_op_genkey (EngineObject engine, GpgmeData help_data, int use_armor)
337 {
338   if (!engine)
339     return mk_error (Invalid_Value);
340
341   switch (engine->protocol)
342     {
343     case GPGME_PROTOCOL_OpenPGP:
344       return _gpgme_gpg_op_genkey (engine->engine.gpg, help_data, use_armor);
345     case GPGME_PROTOCOL_CMS:
346       return _gpgme_gpgsm_op_genkey (engine->engine.gpgsm, help_data, use_armor);
347     default:
348       break;
349     }
350   return 0;
351 }
352
353 GpgmeError
354 _gpgme_engine_op_import (EngineObject engine, GpgmeData keydata)
355 {
356   if (!engine)
357     return mk_error (Invalid_Value);
358
359   switch (engine->protocol)
360     {
361     case GPGME_PROTOCOL_OpenPGP:
362       return _gpgme_gpg_op_import (engine->engine.gpg, keydata);
363     case GPGME_PROTOCOL_CMS:
364       return _gpgme_gpgsm_op_import (engine->engine.gpgsm, keydata);
365     default:
366       break;
367     }
368   return 0;
369 }
370
371 GpgmeError
372 _gpgme_engine_op_keylist (EngineObject engine, const char *pattern, int secret_only,
373                           int keylist_mode)
374 {
375   if (!engine)
376     return mk_error (Invalid_Value);
377
378   switch (engine->protocol)
379     {
380     case GPGME_PROTOCOL_OpenPGP:
381       return _gpgme_gpg_op_keylist (engine->engine.gpg, pattern, secret_only,
382                                     keylist_mode);
383     case GPGME_PROTOCOL_CMS:
384       return _gpgme_gpgsm_op_keylist (engine->engine.gpgsm, pattern, secret_only,
385                                       keylist_mode);
386     default:
387       break;
388     }
389   return 0;
390 }
391
392 GpgmeError
393 _gpgme_engine_op_sign (EngineObject engine, GpgmeData in, GpgmeData out,
394                     GpgmeSigMode mode, int use_armor,
395                     int use_textmode, GpgmeCtx ctx /* FIXME */)
396 {
397   if (!engine)
398     return mk_error (Invalid_Value);
399
400   switch (engine->protocol)
401     {
402     case GPGME_PROTOCOL_OpenPGP:
403       return _gpgme_gpg_op_sign (engine->engine.gpg, in, out, mode, use_armor,
404                                  use_textmode, ctx);
405     case GPGME_PROTOCOL_CMS:
406       return _gpgme_gpgsm_op_sign (engine->engine.gpgsm, in, out, mode,
407                                    use_armor, use_textmode, ctx);
408       break;
409     default:
410       break;
411     }
412   return 0;
413 }
414
415 GpgmeError
416 _gpgme_engine_op_trustlist (EngineObject engine, const char *pattern)
417 {
418   if (!engine)
419     return mk_error (Invalid_Value);
420
421   switch (engine->protocol)
422     {
423     case GPGME_PROTOCOL_OpenPGP:
424       return _gpgme_gpg_op_trustlist (engine->engine.gpg, pattern);
425     case GPGME_PROTOCOL_CMS:
426       return _gpgme_gpgsm_op_trustlist (engine->engine.gpgsm, pattern);
427     default:
428       break;
429     }
430   return 0;
431 }
432
433 GpgmeError
434 _gpgme_engine_op_verify (EngineObject engine, GpgmeData sig, GpgmeData text)
435 {
436   if (!engine)
437     return mk_error (Invalid_Value);
438
439   switch (engine->protocol)
440     {
441     case GPGME_PROTOCOL_OpenPGP:
442       return _gpgme_gpg_op_verify (engine->engine.gpg, sig, text);
443     case GPGME_PROTOCOL_CMS:
444       return _gpgme_gpgsm_op_verify (engine->engine.gpgsm, sig, text);
445     default:
446       break;
447     }
448   return 0;
449 }
450
451 GpgmeError
452 _gpgme_engine_start (EngineObject engine, void *opaque)
453 {
454   if (!engine)
455     return mk_error (Invalid_Value);
456
457   switch (engine->protocol)
458     {
459     case GPGME_PROTOCOL_OpenPGP:
460       return _gpgme_gpg_spawn (engine->engine.gpg, opaque);
461     case GPGME_PROTOCOL_CMS:
462       return _gpgme_gpgsm_start (engine->engine.gpgsm, opaque);
463     default:
464       break;
465     }
466   return 0;
467 }
468
469 void
470 _gpgme_engine_add_child_to_reap_list (void *buf, int buflen, pid_t pid)
471 {
472   /* Reuse the memory, so that we don't need to allocate another
473      memory block and to handle errors.  */
474   struct reap_s *child = buf;
475
476   assert (buflen >= sizeof *child);
477   memset (child, 0, sizeof *child);
478   child->pid = pid;
479   child->entered = time (NULL);
480   LOCK(reap_list_lock);
481   child->next = reap_list;
482   reap_list = child;
483   UNLOCK(reap_list_lock);
484 }
485
486 static void
487 do_reaping (void)
488 {
489   struct reap_s *r, *rlast;
490   static time_t last_check;
491   time_t cur_time = time (NULL);
492
493   /* A race does not matter here.  */
494   if (!last_check)
495     last_check = time (NULL);
496
497   if (last_check >= cur_time)
498     return;  /* We check only every second.  */
499
500   /* Fixme: it would be nice if to have a TRYLOCK here.  */
501   LOCK (reap_list_lock);
502   for (r = reap_list, rlast = NULL; r; rlast = r, r = r ? r->next : NULL)
503     {
504       int dummy1, dummy2;
505
506       if (_gpgme_io_waitpid (r->pid, 0, &dummy1, &dummy2))
507         {
508           /* The process has terminated - remove it from the queue.  */
509           void *p = r;
510           if (!rlast)
511             {
512               reap_list = r->next;
513               r = reap_list;
514             }
515           else
516             {
517               rlast->next = r->next;
518               r = rlast;
519             }
520           xfree (p);
521         }
522       else if (!r->term_send)
523         {
524           if (r->entered + 1 >= cur_time)
525             {
526               _gpgme_io_kill (r->pid, 0);
527               r->term_send = 1;
528               r->entered = cur_time;
529             }
530         }
531       else
532         {
533           /* Give it 5 second before we are going to send the killer.  */
534           if (r->entered + 5 >= cur_time)
535             {
536               _gpgme_io_kill (r->pid, 1);
537               r->entered = cur_time; /* Just in case we have to repeat it.  */
538             }
539         }
540     }
541   UNLOCK (reap_list_lock);  
542 }
543
544 void
545 _gpgme_engine_housecleaning (void)
546 {
547   do_reaping ();
548 }