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