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