cf3fe9fe8f65f6d09dfb1092aa849fd41756e2ed
[gpgme.git] / src / engine.c
1 /* engine.c - GPGME engine support.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003, 2004, 2006 g10 Code GmbH
4  
5    This file is part of GPGME.
6  
7    GPGME is free software; you can redistribute it and/or modify it
8    under the terms of the GNU Lesser General Public License as
9    published by the Free Software Foundation; either version 2.1 of
10    the License, or (at your option) any later version.
11    
12    GPGME is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16    
17    You should have received a copy of the GNU Lesser General Public
18    License along with this program; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20    02111-1307, USA.  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <assert.h>
29
30 #include "gpgme.h"
31 #include "util.h"
32 #include "sema.h"
33 #include "ops.h"
34
35 #include "engine.h"
36 #include "engine-backend.h"
37
38
39 struct engine
40 {
41   struct engine_ops *ops;
42   void *engine;
43 };
44
45
46 static struct engine_ops *engine_ops[] =
47   {
48     &_gpgme_engine_ops_gpg,             /* OpenPGP.  */
49 #ifdef ENABLE_GPGSM
50     &_gpgme_engine_ops_gpgsm,           /* CMS.  */
51 #else
52     NULL,
53 #endif
54 #ifdef ENABLE_GPGCONF
55     &_gpgme_engine_ops_gpgconf          /* gpg-conf.  */
56 #else
57     NULL
58 #endif
59   };
60
61
62 /* The engine info.  */
63 static gpgme_engine_info_t engine_info;
64 DEFINE_STATIC_LOCK (engine_info_lock);
65
66 \f
67 /* Get the file name of the engine for PROTOCOL.  */
68 static const char *
69 engine_get_file_name (gpgme_protocol_t proto)
70 {
71   if (proto > DIM (engine_ops))
72     return NULL;
73
74   if (engine_ops[proto] && engine_ops[proto]->get_file_name)
75     return (*engine_ops[proto]->get_file_name) ();
76   else
77     return NULL;
78 }
79
80
81 /* Get a malloced string containing the version number of the engine
82    for PROTOCOL.  */
83 static char *
84 engine_get_version (gpgme_protocol_t proto, const char *file_name)
85 {
86   if (proto > DIM (engine_ops))
87     return NULL;
88
89   if (engine_ops[proto] && engine_ops[proto]->get_version)
90     return (*engine_ops[proto]->get_version) (file_name);
91   else
92     return NULL;
93 }
94
95
96 /* Get the required version number of the engine for PROTOCOL.  */
97 static const char *
98 engine_get_req_version (gpgme_protocol_t proto)
99 {
100   if (proto > DIM (engine_ops))
101     return NULL;
102
103   if (engine_ops[proto] && engine_ops[proto]->get_req_version)
104     return (*engine_ops[proto]->get_req_version) ();
105   else
106     return NULL;
107 }
108
109
110 /* Verify the version requirement for the engine for PROTOCOL.  */
111 gpgme_error_t
112 gpgme_engine_check_version (gpgme_protocol_t proto)
113 {
114   gpgme_error_t err;
115   gpgme_engine_info_t info;
116   int result;
117
118   LOCK (engine_info_lock);
119   info = engine_info;
120   if (!info)
121     {
122       /* Make sure it is initialized.  */
123       UNLOCK (engine_info_lock);
124       err = gpgme_get_engine_info (&info);
125       if (err)
126         return err;
127
128       LOCK (engine_info_lock);
129     }
130
131   while (info && info->protocol != proto)
132     info = info->next;
133
134   if (!info)
135     result = 0;
136   else
137     result = _gpgme_compare_versions (info->version,
138                                       info->req_version);
139
140   UNLOCK (engine_info_lock);
141   return result ? 0 : gpg_error (GPG_ERR_INV_ENGINE);
142 }
143
144
145 /* Release the engine info INFO.  */
146 void
147 _gpgme_engine_info_release (gpgme_engine_info_t info)
148 {
149   while (info)
150     {
151       gpgme_engine_info_t next_info = info->next;
152
153       assert (info->file_name);
154       free (info->file_name);
155       if (info->home_dir)
156         free (info->home_dir);
157       if (info->version)
158         free (info->version);
159       free (info);
160       info = next_info;
161     }
162 }
163
164
165 /* Get the information about the configured and installed engines.  A
166    pointer to the first engine in the statically allocated linked list
167    is returned in *INFO.  If an error occurs, it is returned.  The
168    returned data is valid until the next gpgme_set_engine_info.  */
169 gpgme_error_t
170 gpgme_get_engine_info (gpgme_engine_info_t *info)
171 {
172   LOCK (engine_info_lock);
173   if (!engine_info)
174     {
175       gpgme_engine_info_t *lastp = &engine_info;
176       gpgme_protocol_t proto_list[] = { GPGME_PROTOCOL_OpenPGP,
177                                         GPGME_PROTOCOL_CMS,
178                                         GPGME_PROTOCOL_GPGCONF };
179       unsigned int proto;
180
181       for (proto = 0; proto < DIM (proto_list); proto++)
182         {
183           const char *ofile_name = engine_get_file_name (proto_list[proto]);
184           char *file_name;
185
186           if (!ofile_name)
187             continue;
188
189           file_name = strdup (ofile_name);
190
191           *lastp = malloc (sizeof (*engine_info));
192           if (!*lastp || !file_name)
193             {
194               int saved_errno = errno;
195
196               _gpgme_engine_info_release (engine_info);
197               engine_info = NULL;
198
199               if (file_name)
200                 free (file_name);
201
202               UNLOCK (engine_info_lock);
203               return gpg_error_from_errno (saved_errno);
204             }
205
206           (*lastp)->protocol = proto_list[proto];
207           (*lastp)->file_name = file_name;
208           (*lastp)->home_dir = NULL;
209           (*lastp)->version = engine_get_version (proto_list[proto], NULL);
210           (*lastp)->req_version = engine_get_req_version (proto_list[proto]);
211           (*lastp)->next = NULL;
212           lastp = &(*lastp)->next;
213         }
214     }
215
216   *info = engine_info;
217   UNLOCK (engine_info_lock);
218   return 0;
219 }
220
221
222 /* Get a deep copy of the engine info and return it in INFO.  */
223 gpgme_error_t
224 _gpgme_engine_info_copy (gpgme_engine_info_t *r_info)
225 {
226   gpgme_error_t err = 0;
227   gpgme_engine_info_t info;
228   gpgme_engine_info_t new_info;
229   gpgme_engine_info_t *lastp;
230
231   LOCK (engine_info_lock);
232   info = engine_info;
233   if (!info)
234     {
235       /* Make sure it is initialized.  */
236       UNLOCK (engine_info_lock);
237       err = gpgme_get_engine_info (&info);
238       if (err)
239         return err;
240
241       LOCK (engine_info_lock);
242     }
243
244   new_info = NULL;
245   lastp = &new_info;
246
247   while (info)
248     {
249       char *file_name;
250       char *home_dir;
251       char *version;
252
253       assert (info->file_name);
254       file_name = strdup (info->file_name);
255
256       if (info->home_dir)
257         {
258           home_dir = strdup (info->home_dir);
259           if (!home_dir)
260             err = gpg_error_from_errno (errno);
261         }
262       else
263         home_dir = NULL;
264
265       if (info->version)
266         {
267           version = strdup (info->version);
268           if (!version)
269             err = gpg_error_from_errno (errno);
270         }
271       else
272         version = NULL;
273
274       *lastp = malloc (sizeof (*engine_info));
275       if (!*lastp || !file_name || err)
276         {
277           int saved_errno = errno;
278
279           _gpgme_engine_info_release (new_info);
280
281           if (file_name)
282             free (file_name);
283           if (home_dir)
284             free (home_dir);
285           if (version)
286             free (version);
287
288           UNLOCK (engine_info_lock);
289           return gpg_error_from_errno (saved_errno);
290         }
291
292       (*lastp)->protocol = info->protocol;
293       (*lastp)->file_name = file_name;
294       (*lastp)->home_dir = home_dir;
295       (*lastp)->version = version;
296       (*lastp)->req_version = info->req_version;
297       (*lastp)->next = NULL;
298       lastp = &(*lastp)->next;
299
300       info = info->next;
301     }
302
303   *r_info = new_info;
304   UNLOCK (engine_info_lock);
305   return 0;
306 }
307
308
309 /* Set the engine info for the info list INFO, protocol PROTO, to the
310    file name FILE_NAME and the home directory HOME_DIR.  */
311 gpgme_error_t
312 _gpgme_set_engine_info (gpgme_engine_info_t info, gpgme_protocol_t proto,
313                         const char *file_name, const char *home_dir)
314 {
315   char *new_file_name;
316   char *new_home_dir;
317
318   /* FIXME: Use some PROTO_MAX definition.  */
319   if (proto > DIM (engine_ops))
320     return gpg_error (GPG_ERR_INV_VALUE);
321
322   while (info && info->protocol != proto)
323     info = info->next;
324
325   if (!info)
326     return gpg_error (GPG_ERR_INV_ENGINE);
327
328   /* Prepare new members.  */
329   if (file_name)
330     new_file_name = strdup (file_name);
331   else
332     {
333       const char *ofile_name = engine_get_file_name (proto);
334       assert (ofile_name);
335       new_file_name = strdup (ofile_name);
336     }
337   if (!new_file_name)
338     return gpg_error_from_errno (errno);
339
340   if (home_dir)
341     {
342       new_home_dir = strdup (home_dir);
343       if (!new_home_dir)
344         {
345           free (new_file_name);
346           return gpg_error_from_errno (errno);
347         }
348     }
349   else
350     new_home_dir = NULL;
351
352   /* Remove the old members.  */
353   assert (info->file_name);
354   free (info->file_name);
355   if (info->home_dir)
356     free (info->home_dir);
357   if (info->version)
358     free (info->version);
359
360   /* Install the new members.  */
361   info->file_name = new_file_name;
362   info->home_dir = new_home_dir;
363   info->version = engine_get_version (proto, new_file_name);
364
365   return 0;
366 }
367
368
369 /* Set the default engine info for the protocol PROTO to the file name
370    FILE_NAME and the home directory HOME_DIR.  */
371 gpgme_error_t
372 gpgme_set_engine_info (gpgme_protocol_t proto,
373                        const char *file_name, const char *home_dir)
374 {
375   gpgme_error_t err;
376   gpgme_engine_info_t info;
377
378   LOCK (engine_info_lock);
379   info = engine_info;
380   if (!info)
381     {
382       /* Make sure it is initialized.  */
383       UNLOCK (engine_info_lock);
384       err = gpgme_get_engine_info (&info);
385       if (err)
386         return err;
387
388       LOCK (engine_info_lock);
389     }
390
391   err = _gpgme_set_engine_info (info, proto, file_name, home_dir);
392   UNLOCK (engine_info_lock);
393   return err;
394 }
395
396 \f
397 gpgme_error_t
398 _gpgme_engine_new (gpgme_engine_info_t info, engine_t *r_engine)
399 {
400   engine_t engine;
401
402   if (!info->file_name || !info->version)
403     return gpg_error (GPG_ERR_INV_ENGINE);
404
405   engine = calloc (1, sizeof *engine);
406   if (!engine)
407     return gpg_error_from_errno (errno);
408
409   engine->ops = engine_ops[info->protocol];
410   if (engine->ops->new)
411     {
412       gpgme_error_t err;
413       err = (*engine->ops->new) (&engine->engine,
414                                  info->file_name, info->home_dir);
415       if (err)
416         {
417           free (engine);
418           return err;
419         }
420     }
421   else
422     engine->engine = NULL;
423
424   *r_engine = engine;
425   return 0;
426 }
427
428
429 gpgme_error_t
430 _gpgme_engine_reset (engine_t engine)
431 {
432   if (!engine)
433     return gpg_error (GPG_ERR_INV_VALUE);
434
435   if (!engine->ops->reset)
436     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
437
438   return (*engine->ops->reset) (engine->engine);
439 }
440
441
442 void
443 _gpgme_engine_release (engine_t engine)
444 {
445   if (!engine)
446     return;
447
448   if (engine->ops->release)
449     (*engine->ops->release) (engine->engine);
450   free (engine);
451 }
452
453
454 void
455 _gpgme_engine_set_status_handler (engine_t engine,
456                                   engine_status_handler_t fnc, void *fnc_value)
457 {
458   if (!engine)
459     return;
460
461   if (engine->ops->set_status_handler)
462     (*engine->ops->set_status_handler) (engine->engine, fnc, fnc_value);
463 }
464
465
466 gpgme_error_t
467 _gpgme_engine_set_command_handler (engine_t engine,
468                                    engine_command_handler_t fnc,
469                                    void *fnc_value,
470                                    gpgme_data_t linked_data)
471 {
472   if (!engine)
473     return gpg_error (GPG_ERR_INV_VALUE);
474
475   if (!engine->ops->set_command_handler)
476     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
477
478   return (*engine->ops->set_command_handler) (engine->engine,
479                                               fnc, fnc_value, linked_data);
480 }
481
482 gpgme_error_t
483 _gpgme_engine_set_colon_line_handler (engine_t engine,
484                                       engine_colon_line_handler_t fnc,
485                                       void *fnc_value)
486 {
487   if (!engine)
488     return gpg_error (GPG_ERR_INV_VALUE);
489
490   if (!engine->ops->set_colon_line_handler)
491     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
492
493   return (*engine->ops->set_colon_line_handler) (engine->engine,
494                                                  fnc, fnc_value);
495 }
496
497 gpgme_error_t
498 _gpgme_engine_set_locale (engine_t engine, int category,
499                           const char *value)
500 {
501   if (!engine)
502     return gpg_error (GPG_ERR_INV_VALUE);
503
504   if (!engine->ops->set_locale)
505     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
506
507   return (*engine->ops->set_locale) (engine->engine, category, value);
508 }
509
510 gpgme_error_t
511 _gpgme_engine_op_decrypt (engine_t engine, gpgme_data_t ciph,
512                           gpgme_data_t plain)
513 {
514   if (!engine)
515     return gpg_error (GPG_ERR_INV_VALUE);
516
517   if (!engine->ops->decrypt)
518     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
519
520   return (*engine->ops->decrypt) (engine->engine, ciph, plain);
521 }
522
523 gpgme_error_t
524 _gpgme_engine_op_delete (engine_t engine, gpgme_key_t key,
525                          int allow_secret)
526 {
527   if (!engine)
528     return gpg_error (GPG_ERR_INV_VALUE);
529
530   if (!engine->ops->delete)
531     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
532
533   return (*engine->ops->delete) (engine->engine, key, allow_secret);
534 }
535
536
537 gpgme_error_t
538 _gpgme_engine_op_edit (engine_t engine, int type, gpgme_key_t key,
539                        gpgme_data_t out, gpgme_ctx_t ctx /* FIXME */)
540 {
541   if (!engine)
542     return gpg_error (GPG_ERR_INV_VALUE);
543
544   if (!engine->ops->edit)
545     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
546
547   return (*engine->ops->edit) (engine->engine, type, key, out, ctx);
548 }
549
550
551 gpgme_error_t
552 _gpgme_engine_op_encrypt (engine_t engine, gpgme_key_t recp[],
553                           gpgme_encrypt_flags_t flags,
554                           gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
555 {
556   if (!engine)
557     return gpg_error (GPG_ERR_INV_VALUE);
558
559   if (!engine->ops->encrypt)
560     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
561
562   return (*engine->ops->encrypt) (engine->engine, recp, flags, plain, ciph,
563                                   use_armor);
564 }
565
566
567 gpgme_error_t
568 _gpgme_engine_op_encrypt_sign (engine_t engine, gpgme_key_t recp[],
569                                gpgme_encrypt_flags_t flags,
570                                gpgme_data_t plain, gpgme_data_t ciph,
571                                int use_armor, gpgme_ctx_t ctx /* FIXME */)
572 {
573   if (!engine)
574     return gpg_error (GPG_ERR_INV_VALUE);
575
576   if (!engine->ops->encrypt_sign)
577     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
578
579   return (*engine->ops->encrypt_sign) (engine->engine, recp, flags,
580                                        plain, ciph, use_armor, ctx);
581 }
582
583
584 gpgme_error_t
585 _gpgme_engine_op_export (engine_t engine, const char *pattern,
586                          unsigned int reserved, gpgme_data_t keydata,
587                          int use_armor)
588 {
589   if (!engine)
590     return gpg_error (GPG_ERR_INV_VALUE);
591
592   if (!engine->ops->export)
593     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
594
595   return (*engine->ops->export) (engine->engine, pattern, reserved,
596                                  keydata, use_armor);
597 }
598
599
600 gpgme_error_t
601 _gpgme_engine_op_export_ext (engine_t engine, const char *pattern[],
602                              unsigned int reserved, gpgme_data_t keydata,
603                              int use_armor)
604 {
605   if (!engine)
606     return gpg_error (GPG_ERR_INV_VALUE);
607
608   if (!engine->ops->export_ext)
609     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
610
611   return (*engine->ops->export_ext) (engine->engine, pattern, reserved,
612                                      keydata, use_armor);
613 }
614
615
616 gpgme_error_t
617 _gpgme_engine_op_genkey (engine_t engine, gpgme_data_t help_data,
618                          int use_armor, gpgme_data_t pubkey,
619                          gpgme_data_t seckey)
620 {
621   if (!engine)
622     return gpg_error (GPG_ERR_INV_VALUE);
623
624   if (!engine->ops->genkey)
625     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
626
627   return (*engine->ops->genkey) (engine->engine, help_data, use_armor,
628                                  pubkey, seckey);
629 }
630
631
632 gpgme_error_t
633 _gpgme_engine_op_import (engine_t engine, gpgme_data_t keydata)
634 {
635   if (!engine)
636     return gpg_error (GPG_ERR_INV_VALUE);
637
638   if (!engine->ops->import)
639     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
640
641   return (*engine->ops->import) (engine->engine, keydata);
642 }
643
644
645 gpgme_error_t
646 _gpgme_engine_op_keylist (engine_t engine, const char *pattern,
647                           int secret_only, gpgme_keylist_mode_t mode)
648 {
649   if (!engine)
650     return gpg_error (GPG_ERR_INV_VALUE);
651
652   if (!engine->ops->keylist)
653     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
654
655   return (*engine->ops->keylist) (engine->engine, pattern, secret_only, mode);
656 }
657
658
659 gpgme_error_t
660 _gpgme_engine_op_keylist_ext (engine_t engine, const char *pattern[],
661                               int secret_only, int reserved,
662                               gpgme_keylist_mode_t mode)
663 {
664   if (!engine)
665     return gpg_error (GPG_ERR_INV_VALUE);
666
667   if (!engine->ops->keylist_ext)
668     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
669
670   return (*engine->ops->keylist_ext) (engine->engine, pattern, secret_only,
671                                       reserved, mode);
672 }
673
674
675 gpgme_error_t
676 _gpgme_engine_op_sign (engine_t engine, gpgme_data_t in, gpgme_data_t out,
677                        gpgme_sig_mode_t mode, int use_armor,
678                        int use_textmode, int include_certs,
679                        gpgme_ctx_t ctx /* FIXME */)
680 {
681   if (!engine)
682     return gpg_error (GPG_ERR_INV_VALUE);
683
684   if (!engine->ops->sign)
685     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
686
687   return (*engine->ops->sign) (engine->engine, in, out, mode, use_armor,
688                                use_textmode, include_certs, ctx);
689 }
690
691
692 gpgme_error_t
693 _gpgme_engine_op_trustlist (engine_t engine, const char *pattern)
694 {
695   if (!engine)
696     return gpg_error (GPG_ERR_INV_VALUE);
697
698   if (!engine->ops->trustlist)
699     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
700
701   return (*engine->ops->trustlist) (engine->engine, pattern);
702 }
703
704
705 gpgme_error_t
706 _gpgme_engine_op_verify (engine_t engine, gpgme_data_t sig,
707                          gpgme_data_t signed_text, gpgme_data_t plaintext)
708 {
709   if (!engine)
710     return gpg_error (GPG_ERR_INV_VALUE);
711
712   if (!engine->ops->verify)
713     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
714
715   return (*engine->ops->verify) (engine->engine, sig, signed_text, plaintext);
716 }
717
718
719 gpgme_error_t
720 _gpgme_engine_op_getauditlog (engine_t engine, gpgme_data_t output,
721                               unsigned int flags)
722 {
723   if (!engine)
724     return gpg_error (GPG_ERR_INV_VALUE);
725
726   if (!engine->ops->getauditlog)
727     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
728
729   return (*engine->ops->getauditlog) (engine->engine, output, flags);
730 }
731
732
733 gpgme_error_t
734 _gpgme_engine_op_conf_load (engine_t engine, gpgme_conf_comp_t *conf_p)
735 {
736   if (!engine)
737     return gpg_error (GPG_ERR_INV_VALUE);
738
739   if (!engine->ops->conf_load)
740     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
741
742   return (*engine->ops->conf_load) (engine->engine, conf_p);
743 }
744
745
746 gpgme_error_t
747 _gpgme_engine_op_conf_save (engine_t engine, gpgme_conf_comp_t conf)
748 {
749   if (!engine)
750     return gpg_error (GPG_ERR_INV_VALUE);
751
752   if (!engine->ops->conf_save)
753     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
754
755   return (*engine->ops->conf_save) (engine->engine, conf);
756 }
757
758
759 void
760 _gpgme_engine_set_io_cbs (engine_t engine, gpgme_io_cbs_t io_cbs)
761 {
762   if (!engine)
763     return;
764
765   (*engine->ops->set_io_cbs) (engine->engine, io_cbs);
766 }
767
768
769 void
770 _gpgme_engine_io_event (engine_t engine,
771                         gpgme_event_io_t type, void *type_data)
772 {
773   if (!engine)
774     return;
775
776   (*engine->ops->io_event) (engine->engine, type, type_data);
777 }
778
779
780 gpgme_error_t
781 _gpgme_engine_cancel (engine_t engine)
782 {
783   if (!engine)
784     return gpg_error (GPG_ERR_INV_VALUE);
785
786   if (!engine->ops->cancel)
787     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
788
789   return (*engine->ops->cancel) (engine->engine);
790 }