doc/
[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
217 void
218 _gpgme_engine_set_verbosity (EngineObject engine, int verbosity)
219 {
220   if (!engine)
221     return;
222
223   switch (engine->protocol)
224     {
225     case GPGME_PROTOCOL_OpenPGP:
226       while (verbosity-- > 0)
227         _gpgme_gpg_add_arg (engine->engine.gpg, "--verbose");
228       break;
229     case GPGME_PROTOCOL_CMS:
230       /* FIXME */
231       break;
232     default:
233       break;
234     }
235 }
236
237 void
238 _gpgme_engine_set_status_handler (EngineObject engine,
239                                   GpgStatusHandler fnc, void *fnc_value)
240 {
241   if (!engine)
242     return;
243
244   switch (engine->protocol)
245     {
246     case GPGME_PROTOCOL_OpenPGP:
247       _gpgme_gpg_set_status_handler (engine->engine.gpg, fnc, fnc_value);
248       break;
249     case GPGME_PROTOCOL_CMS:
250       _gpgme_gpgsm_set_status_handler (engine->engine.gpgsm, fnc, fnc_value);
251       break;
252     default:
253       break;
254     }
255 }
256
257 GpgmeError
258 _gpgme_engine_set_command_handler (EngineObject engine,
259                                   GpgCommandHandler fnc, void *fnc_value)
260 {
261   if (!engine)
262     return mk_error (Invalid_Value);
263
264   switch (engine->protocol)
265     {
266     case GPGME_PROTOCOL_OpenPGP:
267       return _gpgme_gpg_set_command_handler (engine->engine.gpg, fnc, fnc_value);
268     case GPGME_PROTOCOL_CMS:
269       /* FIXME */
270       break;
271     default:
272       break;
273     }
274   return 0;
275 }
276
277 GpgmeError _gpgme_engine_set_colon_line_handler (EngineObject engine,
278                                                  GpgColonLineHandler fnc,
279                                                  void *fnc_value)
280 {
281   if (!engine)
282     return mk_error (Invalid_Value);
283
284   switch (engine->protocol)
285     {
286     case GPGME_PROTOCOL_OpenPGP:
287       return _gpgme_gpg_set_colon_line_handler (engine->engine.gpg, 
288                                                 fnc, fnc_value);
289     case GPGME_PROTOCOL_CMS:
290       _gpgme_gpgsm_set_colon_line_handler (engine->engine.gpgsm,
291                                            fnc, fnc_value);
292       break;
293
294     default:
295       break;
296     }
297   return 0;
298 }
299
300 GpgmeError
301 _gpgme_engine_op_decrypt (EngineObject engine, GpgmeData ciph, GpgmeData plain)
302 {
303   if (!engine)
304     return mk_error (Invalid_Value);
305
306   switch (engine->protocol)
307     {
308     case GPGME_PROTOCOL_OpenPGP:
309       return _gpgme_gpg_op_decrypt (engine->engine.gpg, ciph, plain);
310     case GPGME_PROTOCOL_CMS:
311       return _gpgme_gpgsm_op_decrypt (engine->engine.gpgsm, ciph, plain);
312     default:
313       break;
314     }
315   return 0;
316 }
317
318 GpgmeError
319 _gpgme_engine_op_delete (EngineObject engine, GpgmeKey key, int allow_secret)
320 {
321   if (!engine)
322     return mk_error (Invalid_Value);
323
324   switch (engine->protocol)
325     {
326     case GPGME_PROTOCOL_OpenPGP:
327       return _gpgme_gpg_op_delete (engine->engine.gpg, key, allow_secret);
328     case GPGME_PROTOCOL_CMS:
329       return _gpgme_gpgsm_op_delete (engine->engine.gpgsm, key, allow_secret);
330     default:
331       break;
332     }
333   return 0;
334 }
335
336
337 GpgmeError
338 _gpgme_engine_op_encrypt (EngineObject engine, GpgmeRecipients recp,
339                           GpgmeData plain, GpgmeData ciph, int use_armor)
340 {
341   if (!engine)
342     return mk_error (Invalid_Value);
343
344   switch (engine->protocol)
345     {
346     case GPGME_PROTOCOL_OpenPGP:
347       return _gpgme_gpg_op_encrypt (engine->engine.gpg, recp, plain, ciph,
348                                     use_armor);
349     case GPGME_PROTOCOL_CMS:
350       return _gpgme_gpgsm_op_encrypt (engine->engine.gpgsm, recp, plain, ciph,
351                                       use_armor);
352     default:
353       break;
354     }
355   return 0;
356 }
357
358
359 GpgmeError
360 _gpgme_engine_op_encrypt_sign (EngineObject engine, GpgmeRecipients recp,
361                                GpgmeData plain, GpgmeData ciph, int use_armor,
362                                GpgmeCtx ctx /* FIXME */)
363 {
364   if (!engine)
365     return mk_error (Invalid_Value);
366
367   switch (engine->protocol)
368     {
369     case GPGME_PROTOCOL_OpenPGP:
370       return _gpgme_gpg_op_encrypt_sign (engine->engine.gpg, recp, plain, ciph,
371                                          use_armor, ctx);
372     case GPGME_PROTOCOL_CMS:
373       return mk_error (Not_Implemented);
374     default:
375       break;
376     }
377   return 0;
378 }
379
380
381 GpgmeError
382 _gpgme_engine_op_export (EngineObject engine, GpgmeRecipients recp,
383                          GpgmeData keydata, int use_armor)
384 {
385   if (!engine)
386     return mk_error (Invalid_Value);
387
388   switch (engine->protocol)
389     {
390     case GPGME_PROTOCOL_OpenPGP:
391       return _gpgme_gpg_op_export (engine->engine.gpg, recp, keydata,
392                                    use_armor);
393     case GPGME_PROTOCOL_CMS:
394       return _gpgme_gpgsm_op_export (engine->engine.gpgsm, recp, keydata,
395                                      use_armor);
396     default:
397       break;
398     }
399   return 0;
400 }
401
402 GpgmeError
403 _gpgme_engine_op_genkey (EngineObject engine, GpgmeData help_data,
404                          int use_armor, GpgmeData pubkey, GpgmeData seckey)
405 {
406   if (!engine)
407     return mk_error (Invalid_Value);
408
409   switch (engine->protocol)
410     {
411     case GPGME_PROTOCOL_OpenPGP:
412       return _gpgme_gpg_op_genkey (engine->engine.gpg, help_data, use_armor,
413                                    pubkey, seckey);
414     case GPGME_PROTOCOL_CMS:
415       return _gpgme_gpgsm_op_genkey (engine->engine.gpgsm, help_data, use_armor,
416                                      pubkey, seckey);
417     default:
418       break;
419     }
420   return 0;
421 }
422
423 GpgmeError
424 _gpgme_engine_op_import (EngineObject engine, GpgmeData keydata)
425 {
426   if (!engine)
427     return mk_error (Invalid_Value);
428
429   switch (engine->protocol)
430     {
431     case GPGME_PROTOCOL_OpenPGP:
432       return _gpgme_gpg_op_import (engine->engine.gpg, keydata);
433     case GPGME_PROTOCOL_CMS:
434       return _gpgme_gpgsm_op_import (engine->engine.gpgsm, keydata);
435     default:
436       break;
437     }
438   return 0;
439 }
440
441
442 GpgmeError
443 _gpgme_engine_op_keylist (EngineObject engine, const char *pattern,
444                           int secret_only, int keylist_mode)
445 {
446   if (!engine)
447     return mk_error (Invalid_Value);
448
449   switch (engine->protocol)
450     {
451     case GPGME_PROTOCOL_OpenPGP:
452       return _gpgme_gpg_op_keylist (engine->engine.gpg, pattern, secret_only,
453                                     keylist_mode);
454     case GPGME_PROTOCOL_CMS:
455       return _gpgme_gpgsm_op_keylist (engine->engine.gpgsm, pattern, secret_only,
456                                       keylist_mode);
457     default:
458       break;
459     }
460   return 0;
461 }
462
463
464 GpgmeError
465 _gpgme_engine_op_keylist_ext (EngineObject engine, const char *pattern[],
466                               int secret_only, int reserved, int keylist_mode)
467 {
468   if (!engine)
469     return mk_error (Invalid_Value);
470
471   switch (engine->protocol)
472     {
473     case GPGME_PROTOCOL_OpenPGP:
474       return _gpgme_gpg_op_keylist_ext (engine->engine.gpg, pattern,
475                                         secret_only, reserved, keylist_mode);
476     case GPGME_PROTOCOL_CMS:
477       return _gpgme_gpgsm_op_keylist_ext (engine->engine.gpgsm, pattern,
478                                           secret_only, reserved, keylist_mode);
479     default:
480       break;
481     }
482   return 0;
483 }
484
485
486 GpgmeError
487 _gpgme_engine_op_sign (EngineObject engine, GpgmeData in, GpgmeData out,
488                        GpgmeSigMode mode, int use_armor,
489                        int use_textmode, int include_certs,
490                        GpgmeCtx ctx /* FIXME */)
491 {
492   if (!engine)
493     return mk_error (Invalid_Value);
494
495   switch (engine->protocol)
496     {
497     case GPGME_PROTOCOL_OpenPGP:
498       return _gpgme_gpg_op_sign (engine->engine.gpg, in, out, mode, use_armor,
499                                  use_textmode, ctx);
500     case GPGME_PROTOCOL_CMS:
501       return _gpgme_gpgsm_op_sign (engine->engine.gpgsm, in, out, mode,
502                                    use_armor, use_textmode, include_certs, ctx);
503       break;
504     default:
505       break;
506     }
507   return 0;
508 }
509
510 GpgmeError
511 _gpgme_engine_op_trustlist (EngineObject engine, const char *pattern)
512 {
513   if (!engine)
514     return mk_error (Invalid_Value);
515
516   switch (engine->protocol)
517     {
518     case GPGME_PROTOCOL_OpenPGP:
519       return _gpgme_gpg_op_trustlist (engine->engine.gpg, pattern);
520     case GPGME_PROTOCOL_CMS:
521       return _gpgme_gpgsm_op_trustlist (engine->engine.gpgsm, pattern);
522     default:
523       break;
524     }
525   return 0;
526 }
527
528 GpgmeError
529 _gpgme_engine_op_verify (EngineObject engine, GpgmeData sig, GpgmeData text)
530 {
531   if (!engine)
532     return mk_error (Invalid_Value);
533
534   switch (engine->protocol)
535     {
536     case GPGME_PROTOCOL_OpenPGP:
537       return _gpgme_gpg_op_verify (engine->engine.gpg, sig, text);
538     case GPGME_PROTOCOL_CMS:
539       return _gpgme_gpgsm_op_verify (engine->engine.gpgsm, sig, text);
540     default:
541       break;
542     }
543   return 0;
544 }
545
546 GpgmeError
547 _gpgme_engine_start (EngineObject engine, void *opaque)
548 {
549   if (!engine)
550     return mk_error (Invalid_Value);
551
552   switch (engine->protocol)
553     {
554     case GPGME_PROTOCOL_OpenPGP:
555       return _gpgme_gpg_spawn (engine->engine.gpg, opaque);
556     case GPGME_PROTOCOL_CMS:
557       return _gpgme_gpgsm_start (engine->engine.gpgsm, opaque);
558     default:
559       break;
560     }
561   return 0;
562 }
563
564 void
565 _gpgme_engine_add_child_to_reap_list (void *buf, int buflen, pid_t pid)
566 {
567   /* Reuse the memory, so that we don't need to allocate another
568      memory block and to handle errors.  */
569   struct reap_s *child = buf;
570
571   assert (buflen >= sizeof *child);
572   memset (child, 0, sizeof *child);
573   child->pid = pid;
574   child->entered = time (NULL);
575   LOCK(reap_list_lock);
576   child->next = reap_list;
577   reap_list = child;
578   UNLOCK(reap_list_lock);
579 }
580
581 static void
582 do_reaping (void)
583 {
584   struct reap_s *r, *rlast;
585   static time_t last_check;
586   time_t cur_time = time (NULL);
587
588   /* A race does not matter here.  */
589   if (!last_check)
590     last_check = time (NULL);
591
592   if (last_check >= cur_time)
593     return;  /* We check only every second.  */
594
595   /* Fixme: it would be nice if to have a TRYLOCK here.  */
596   LOCK (reap_list_lock);
597   for (r = reap_list, rlast = NULL; r; rlast = r, r = r ? r->next : NULL)
598     {
599       int dummy1, dummy2;
600
601       if (_gpgme_io_waitpid (r->pid, 0, &dummy1, &dummy2))
602         {
603           /* The process has terminated - remove it from the queue.  */
604           void *p = r;
605           if (!rlast)
606             {
607               reap_list = r->next;
608               r = reap_list;
609             }
610           else
611             {
612               rlast->next = r->next;
613               r = rlast;
614             }
615           xfree (p);
616         }
617       else if (!r->term_send)
618         {
619           if (r->entered + 1 >= cur_time)
620             {
621               _gpgme_io_kill (r->pid, 0);
622               r->term_send = 1;
623               r->entered = cur_time;
624             }
625         }
626       else
627         {
628           /* Give it 5 second before we are going to send the killer.  */
629           if (r->entered + 5 >= cur_time)
630             {
631               _gpgme_io_kill (r->pid, 1);
632               r->entered = cur_time; /* Just in case we have to repeat it.  */
633             }
634         }
635     }
636   UNLOCK (reap_list_lock);  
637 }
638
639 void
640 _gpgme_engine_housecleaning (void)
641 {
642   do_reaping ();
643 }