dd89c2d7f14c815bdd7d142628b40e125eebaadf
[gpgme.git] / gpgme / 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   };
55
56
57 /* The engine info.  */
58 static gpgme_engine_info_t engine_info;
59 DEFINE_STATIC_LOCK (engine_info_lock);
60
61 \f
62 /* Get the file name of the engine for PROTOCOL.  */
63 static const char *
64 engine_get_file_name (gpgme_protocol_t proto)
65 {
66   if (proto > DIM (engine_ops))
67     return NULL;
68
69   if (engine_ops[proto] && engine_ops[proto]->get_file_name)
70     return (*engine_ops[proto]->get_file_name) ();
71   else
72     return NULL;
73 }
74
75
76 /* Get a malloced string containing the version number of the engine
77    for PROTOCOL.  */
78 static char *
79 engine_get_version (gpgme_protocol_t proto, const char *file_name)
80 {
81   if (proto > DIM (engine_ops))
82     return NULL;
83
84   if (engine_ops[proto] && engine_ops[proto]->get_version)
85     return (*engine_ops[proto]->get_version) (file_name);
86   else
87     return NULL;
88 }
89
90
91 /* Get the required version number of the engine for PROTOCOL.  */
92 static const char *
93 engine_get_req_version (gpgme_protocol_t proto)
94 {
95   if (proto > DIM (engine_ops))
96     return NULL;
97
98   if (engine_ops[proto] && engine_ops[proto]->get_req_version)
99     return (*engine_ops[proto]->get_req_version) ();
100   else
101     return NULL;
102 }
103
104
105 /* Verify the version requirement for the engine for PROTOCOL.  */
106 gpgme_error_t
107 gpgme_engine_check_version (gpgme_protocol_t proto)
108 {
109   gpgme_error_t err;
110   gpgme_engine_info_t info;
111   int result;
112
113   LOCK (engine_info_lock);
114   info = engine_info;
115   if (!info)
116     {
117       /* Make sure it is initialized.  */
118       UNLOCK (engine_info_lock);
119       err = gpgme_get_engine_info (&info);
120       if (err)
121         return err;
122
123       LOCK (engine_info_lock);
124     }
125
126   while (info && info->protocol != proto)
127     info = info->next;
128
129   if (!info)
130     result = 0;
131   else
132     result = _gpgme_compare_versions (info->version,
133                                       info->req_version);
134
135   UNLOCK (engine_info_lock);
136   return result ? 0 : gpg_error (GPG_ERR_INV_ENGINE);
137 }
138
139
140 /* Release the engine info INFO.  */
141 void
142 _gpgme_engine_info_release (gpgme_engine_info_t info)
143 {
144   while (info)
145     {
146       gpgme_engine_info_t next_info = info->next;
147
148       assert (info->file_name);
149       free (info->file_name);
150       if (info->home_dir)
151         free (info->home_dir);
152       if (info->version)
153         free (info->version);
154       free (info);
155       info = next_info;
156     }
157 }
158
159
160 /* Get the information about the configured and installed engines.  A
161    pointer to the first engine in the statically allocated linked list
162    is returned in *INFO.  If an error occurs, it is returned.  The
163    returned data is valid until the next gpgme_set_engine_info.  */
164 gpgme_error_t
165 gpgme_get_engine_info (gpgme_engine_info_t *info)
166 {
167   LOCK (engine_info_lock);
168   if (!engine_info)
169     {
170       gpgme_engine_info_t *lastp = &engine_info;
171       gpgme_protocol_t proto_list[] = { GPGME_PROTOCOL_OpenPGP,
172                                         GPGME_PROTOCOL_CMS };
173       unsigned int proto;
174
175       for (proto = 0; proto < DIM (proto_list); proto++)
176         {
177           const char *ofile_name = engine_get_file_name (proto_list[proto]);
178           char *file_name;
179
180           if (!ofile_name)
181             continue;
182
183           file_name = strdup (ofile_name);
184
185           *lastp = malloc (sizeof (*engine_info));
186           if (!*lastp || !file_name)
187             {
188               int saved_errno = errno;
189
190               _gpgme_engine_info_release (engine_info);
191               engine_info = NULL;
192
193               if (file_name)
194                 free (file_name);
195
196               UNLOCK (engine_info_lock);
197               return gpg_error_from_errno (saved_errno);
198             }
199
200           (*lastp)->protocol = proto_list[proto];
201           (*lastp)->file_name = file_name;
202           (*lastp)->home_dir = NULL;
203           (*lastp)->version = engine_get_version (proto_list[proto], NULL);
204           (*lastp)->req_version = engine_get_req_version (proto_list[proto]);
205           (*lastp)->next = NULL;
206           lastp = &(*lastp)->next;
207         }
208     }
209
210   *info = engine_info;
211   UNLOCK (engine_info_lock);
212   return 0;
213 }
214
215
216 /* Get a deep copy of the engine info and return it in INFO.  */
217 gpgme_error_t
218 _gpgme_engine_info_copy (gpgme_engine_info_t *r_info)
219 {
220   gpgme_error_t err = 0;
221   gpgme_engine_info_t info;
222   gpgme_engine_info_t new_info;
223   gpgme_engine_info_t *lastp;
224
225   LOCK (engine_info_lock);
226   info = engine_info;
227   if (!info)
228     {
229       /* Make sure it is initialized.  */
230       UNLOCK (engine_info_lock);
231       err = gpgme_get_engine_info (&info);
232       if (err)
233         return err;
234
235       LOCK (engine_info_lock);
236     }
237
238   new_info = NULL;
239   lastp = &new_info;
240
241   while (info)
242     {
243       char *file_name;
244       char *home_dir;
245       char *version;
246
247       assert (info->file_name);
248       file_name = strdup (info->file_name);
249
250       if (info->home_dir)
251         {
252           home_dir = strdup (info->home_dir);
253           if (!home_dir)
254             err = gpg_error_from_errno (errno);
255         }
256       else
257         home_dir = NULL;
258
259       if (info->version)
260         {
261           version = strdup (info->version);
262           if (!version)
263             err = gpg_error_from_errno (errno);
264         }
265       else
266         version = NULL;
267
268       *lastp = malloc (sizeof (*engine_info));
269       if (!*lastp || !file_name || err)
270         {
271           int saved_errno = errno;
272
273           _gpgme_engine_info_release (new_info);
274
275           if (file_name)
276             free (file_name);
277           if (home_dir)
278             free (home_dir);
279           if (version)
280             free (version);
281
282           UNLOCK (engine_info_lock);
283           return gpg_error_from_errno (saved_errno);
284         }
285
286       (*lastp)->protocol = info->protocol;
287       (*lastp)->file_name = file_name;
288       (*lastp)->home_dir = home_dir;
289       (*lastp)->version = version;
290       (*lastp)->req_version = info->req_version;
291       (*lastp)->next = NULL;
292       lastp = &(*lastp)->next;
293
294       info = info->next;
295     }
296
297   *r_info = new_info;
298   UNLOCK (engine_info_lock);
299   return 0;
300 }
301
302
303 /* Set the engine info for the info list INFO, protocol PROTO, to the
304    file name FILE_NAME and the home directory HOME_DIR.  */
305 gpgme_error_t
306 _gpgme_set_engine_info (gpgme_engine_info_t info, gpgme_protocol_t proto,
307                         const char *file_name, const char *home_dir)
308 {
309   char *new_file_name;
310   char *new_home_dir;
311
312   /* FIXME: Use some PROTO_MAX definition.  */
313   if (proto > DIM (engine_ops))
314     return gpg_error (GPG_ERR_INV_VALUE);
315
316   while (info && info->protocol != proto)
317     info = info->next;
318
319   if (!info)
320     return gpg_error (GPG_ERR_INV_ENGINE);
321
322   /* Prepare new members.  */
323   if (file_name)
324     new_file_name = strdup (file_name);
325   else
326     {
327       const char *ofile_name = engine_get_file_name (proto);
328       assert (ofile_name);
329       new_file_name = strdup (ofile_name);
330     }
331   if (!new_file_name)
332     return gpg_error_from_errno (errno);
333
334   if (home_dir)
335     {
336       new_home_dir = strdup (home_dir);
337       if (!new_home_dir)
338         {
339           free (new_file_name);
340           return gpg_error_from_errno (errno);
341         }
342     }
343   else
344     new_home_dir = NULL;
345
346   /* Remove the old members.  */
347   assert (info->file_name);
348   free (info->file_name);
349   if (info->home_dir)
350     free (info->home_dir);
351   if (info->version)
352     free (info->version);
353
354   /* Install the new members.  */
355   info->file_name = new_file_name;
356   info->home_dir = new_home_dir;
357   info->version = engine_get_version (proto, new_file_name);
358
359   return 0;
360 }
361
362
363 /* Set the default engine info for the protocol PROTO to the file name
364    FILE_NAME and the home directory HOME_DIR.  */
365 gpgme_error_t
366 gpgme_set_engine_info (gpgme_protocol_t proto,
367                        const char *file_name, const char *home_dir)
368 {
369   gpgme_error_t err;
370   gpgme_engine_info_t info;
371
372   LOCK (engine_info_lock);
373   info = engine_info;
374   if (!info)
375     {
376       /* Make sure it is initialized.  */
377       UNLOCK (engine_info_lock);
378       err = gpgme_get_engine_info (&info);
379       if (err)
380         return err;
381
382       LOCK (engine_info_lock);
383     }
384
385   err = _gpgme_set_engine_info (info, proto, file_name, home_dir);
386   UNLOCK (engine_info_lock);
387   return err;
388 }
389
390 \f
391 gpgme_error_t
392 _gpgme_engine_new (gpgme_engine_info_t info, engine_t *r_engine)
393 {
394   engine_t engine;
395
396   if (!info->file_name || !info->version)
397     return gpg_error (GPG_ERR_INV_ENGINE);
398
399   engine = calloc (1, sizeof *engine);
400   if (!engine)
401     return gpg_error_from_errno (errno);
402
403   engine->ops = engine_ops[info->protocol];
404   if (engine->ops->new)
405     {
406       gpgme_error_t err;
407       err = (*engine->ops->new) (&engine->engine,
408                                  info->file_name, info->home_dir);
409       if (err)
410         {
411           free (engine);
412           return err;
413         }
414     }
415   else
416     engine->engine = NULL;
417
418   *r_engine = engine;
419   return 0;
420 }
421
422
423 void
424 _gpgme_engine_release (engine_t engine)
425 {
426   if (!engine)
427     return;
428
429   if (engine->ops->release)
430     (*engine->ops->release) (engine->engine);
431   free (engine);
432 }
433
434
435 void
436 _gpgme_engine_set_status_handler (engine_t engine,
437                                   engine_status_handler_t fnc, void *fnc_value)
438 {
439   if (!engine)
440     return;
441
442   if (engine->ops->set_status_handler)
443     (*engine->ops->set_status_handler) (engine->engine, fnc, fnc_value);
444 }
445
446
447 gpgme_error_t
448 _gpgme_engine_set_command_handler (engine_t engine,
449                                    engine_command_handler_t fnc,
450                                    void *fnc_value,
451                                    gpgme_data_t linked_data)
452 {
453   if (!engine)
454     return gpg_error (GPG_ERR_INV_VALUE);
455
456   if (!engine->ops->set_command_handler)
457     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
458
459   return (*engine->ops->set_command_handler) (engine->engine,
460                                               fnc, fnc_value, linked_data);
461 }
462
463 gpgme_error_t
464 _gpgme_engine_set_colon_line_handler (engine_t engine,
465                                       engine_colon_line_handler_t fnc,
466                                       void *fnc_value)
467 {
468   if (!engine)
469     return gpg_error (GPG_ERR_INV_VALUE);
470
471   if (!engine->ops->set_colon_line_handler)
472     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
473
474   return (*engine->ops->set_colon_line_handler) (engine->engine,
475                                                  fnc, fnc_value);
476 }
477
478 gpgme_error_t
479 _gpgme_engine_set_locale (engine_t engine, int category,
480                           const char *value)
481 {
482   if (!engine)
483     return gpg_error (GPG_ERR_INV_VALUE);
484
485   if (!engine->ops->set_locale)
486     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
487
488   return (*engine->ops->set_locale) (engine->engine, category, value);
489 }
490
491 gpgme_error_t
492 _gpgme_engine_op_decrypt (engine_t engine, gpgme_data_t ciph,
493                           gpgme_data_t plain)
494 {
495   if (!engine)
496     return gpg_error (GPG_ERR_INV_VALUE);
497
498   if (!engine->ops->decrypt)
499     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
500
501   return (*engine->ops->decrypt) (engine->engine, ciph, plain);
502 }
503
504 gpgme_error_t
505 _gpgme_engine_op_delete (engine_t engine, gpgme_key_t key,
506                          int allow_secret)
507 {
508   if (!engine)
509     return gpg_error (GPG_ERR_INV_VALUE);
510
511   if (!engine->ops->delete)
512     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
513
514   return (*engine->ops->delete) (engine->engine, key, allow_secret);
515 }
516
517
518 gpgme_error_t
519 _gpgme_engine_op_edit (engine_t engine, int type, gpgme_key_t key,
520                        gpgme_data_t out, gpgme_ctx_t ctx /* FIXME */)
521 {
522   if (!engine)
523     return gpg_error (GPG_ERR_INV_VALUE);
524
525   if (!engine->ops->edit)
526     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
527
528   return (*engine->ops->edit) (engine->engine, type, key, out, ctx);
529 }
530
531
532 gpgme_error_t
533 _gpgme_engine_op_encrypt (engine_t engine, gpgme_key_t recp[],
534                           gpgme_encrypt_flags_t flags,
535                           gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
536 {
537   if (!engine)
538     return gpg_error (GPG_ERR_INV_VALUE);
539
540   if (!engine->ops->encrypt)
541     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
542
543   return (*engine->ops->encrypt) (engine->engine, recp, flags, plain, ciph,
544                                   use_armor);
545 }
546
547
548 gpgme_error_t
549 _gpgme_engine_op_encrypt_sign (engine_t engine, gpgme_key_t recp[],
550                                gpgme_encrypt_flags_t flags,
551                                gpgme_data_t plain, gpgme_data_t ciph,
552                                int use_armor, gpgme_ctx_t ctx /* FIXME */)
553 {
554   if (!engine)
555     return gpg_error (GPG_ERR_INV_VALUE);
556
557   if (!engine->ops->encrypt_sign)
558     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
559
560   return (*engine->ops->encrypt_sign) (engine->engine, recp, flags,
561                                        plain, ciph, use_armor, ctx);
562 }
563
564
565 gpgme_error_t
566 _gpgme_engine_op_export (engine_t engine, const char *pattern,
567                          unsigned int reserved, gpgme_data_t keydata,
568                          int use_armor)
569 {
570   if (!engine)
571     return gpg_error (GPG_ERR_INV_VALUE);
572
573   if (!engine->ops->export)
574     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
575
576   return (*engine->ops->export) (engine->engine, pattern, reserved,
577                                  keydata, use_armor);
578 }
579
580
581 gpgme_error_t
582 _gpgme_engine_op_export_ext (engine_t engine, const char *pattern[],
583                              unsigned int reserved, gpgme_data_t keydata,
584                              int use_armor)
585 {
586   if (!engine)
587     return gpg_error (GPG_ERR_INV_VALUE);
588
589   if (!engine->ops->export_ext)
590     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
591
592   return (*engine->ops->export_ext) (engine->engine, pattern, reserved,
593                                      keydata, use_armor);
594 }
595
596
597 gpgme_error_t
598 _gpgme_engine_op_genkey (engine_t engine, gpgme_data_t help_data,
599                          int use_armor, gpgme_data_t pubkey,
600                          gpgme_data_t seckey)
601 {
602   if (!engine)
603     return gpg_error (GPG_ERR_INV_VALUE);
604
605   if (!engine->ops->genkey)
606     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
607
608   return (*engine->ops->genkey) (engine->engine, help_data, use_armor,
609                                  pubkey, seckey);
610 }
611
612
613 gpgme_error_t
614 _gpgme_engine_op_import (engine_t engine, gpgme_data_t keydata)
615 {
616   if (!engine)
617     return gpg_error (GPG_ERR_INV_VALUE);
618
619   if (!engine->ops->import)
620     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
621
622   return (*engine->ops->import) (engine->engine, keydata);
623 }
624
625
626 gpgme_error_t
627 _gpgme_engine_op_keylist (engine_t engine, const char *pattern,
628                           int secret_only, gpgme_keylist_mode_t mode)
629 {
630   if (!engine)
631     return gpg_error (GPG_ERR_INV_VALUE);
632
633   if (!engine->ops->keylist)
634     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
635
636   return (*engine->ops->keylist) (engine->engine, pattern, secret_only, mode);
637 }
638
639
640 gpgme_error_t
641 _gpgme_engine_op_keylist_ext (engine_t engine, const char *pattern[],
642                               int secret_only, int reserved,
643                               gpgme_keylist_mode_t mode)
644 {
645   if (!engine)
646     return gpg_error (GPG_ERR_INV_VALUE);
647
648   if (!engine->ops->keylist_ext)
649     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
650
651   return (*engine->ops->keylist_ext) (engine->engine, pattern, secret_only,
652                                       reserved, mode);
653 }
654
655
656 gpgme_error_t
657 _gpgme_engine_op_sign (engine_t engine, gpgme_data_t in, gpgme_data_t out,
658                        gpgme_sig_mode_t mode, int use_armor,
659                        int use_textmode, int include_certs,
660                        gpgme_ctx_t ctx /* FIXME */)
661 {
662   if (!engine)
663     return gpg_error (GPG_ERR_INV_VALUE);
664
665   if (!engine->ops->sign)
666     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
667
668   return (*engine->ops->sign) (engine->engine, in, out, mode, use_armor,
669                                use_textmode, include_certs, ctx);
670 }
671
672
673 gpgme_error_t
674 _gpgme_engine_op_trustlist (engine_t engine, const char *pattern)
675 {
676   if (!engine)
677     return gpg_error (GPG_ERR_INV_VALUE);
678
679   if (!engine->ops->trustlist)
680     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
681
682   return (*engine->ops->trustlist) (engine->engine, pattern);
683 }
684
685
686 gpgme_error_t
687 _gpgme_engine_op_verify (engine_t engine, gpgme_data_t sig,
688                          gpgme_data_t signed_text, gpgme_data_t plaintext)
689 {
690   if (!engine)
691     return gpg_error (GPG_ERR_INV_VALUE);
692
693   if (!engine->ops->verify)
694     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
695
696   return (*engine->ops->verify) (engine->engine, sig, signed_text, plaintext);
697 }
698
699
700 void
701 _gpgme_engine_set_io_cbs (engine_t engine, gpgme_io_cbs_t io_cbs)
702 {
703   if (!engine)
704     return;
705
706   (*engine->ops->set_io_cbs) (engine->engine, io_cbs);
707 }
708
709
710 void
711 _gpgme_engine_io_event (engine_t engine,
712                         gpgme_event_io_t type, void *type_data)
713 {
714   if (!engine)
715     return;
716
717   (*engine->ops->io_event) (engine->engine, type, type_data);
718 }
719
720
721 gpgme_error_t
722 _gpgme_engine_cancel (engine_t engine)
723 {
724   if (!engine)
725     return gpg_error (GPG_ERR_INV_VALUE);
726
727   if (!engine->ops->cancel)
728     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
729
730   return (*engine->ops->cancel) (engine->engine);
731 }