2006-02-22 Marcus Brinkmann <marcus@g10code.de>
[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 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                    const char *lc_ctype, const char *lc_messages)
394 {
395   engine_t engine;
396
397   if (!info->file_name || !info->version)
398     return gpg_error (GPG_ERR_INV_ENGINE);
399
400   engine = calloc (1, sizeof *engine);
401   if (!engine)
402     return gpg_error_from_errno (errno);
403
404   engine->ops = engine_ops[info->protocol];
405   if (engine->ops->new)
406     {
407       gpgme_error_t err = (*engine->ops->new) (&engine->engine,
408                                                info->file_name, info->home_dir,
409                                                lc_ctype, lc_messages);
410       if (err)
411         {
412           free (engine);
413           return err;
414         }
415     }
416   else
417     engine->engine = NULL;
418
419   *r_engine = engine;
420   return 0;
421 }
422
423
424 void
425 _gpgme_engine_release (engine_t engine)
426 {
427   if (!engine)
428     return;
429
430   if (engine->ops->release)
431     (*engine->ops->release) (engine->engine);
432   free (engine);
433 }
434
435
436 void
437 _gpgme_engine_set_status_handler (engine_t engine,
438                                   engine_status_handler_t fnc, void *fnc_value)
439 {
440   if (!engine)
441     return;
442
443   if (engine->ops->set_status_handler)
444     (*engine->ops->set_status_handler) (engine->engine, fnc, fnc_value);
445 }
446
447
448 gpgme_error_t
449 _gpgme_engine_set_command_handler (engine_t engine,
450                                    engine_command_handler_t fnc,
451                                    void *fnc_value,
452                                    gpgme_data_t linked_data)
453 {
454   if (!engine)
455     return gpg_error (GPG_ERR_INV_VALUE);
456
457   if (!engine->ops->set_command_handler)
458     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
459
460   return (*engine->ops->set_command_handler) (engine->engine,
461                                               fnc, fnc_value, linked_data);
462 }
463
464 gpgme_error_t
465 _gpgme_engine_set_colon_line_handler (engine_t engine,
466                                       engine_colon_line_handler_t fnc,
467                                       void *fnc_value)
468 {
469   if (!engine)
470     return gpg_error (GPG_ERR_INV_VALUE);
471
472   if (!engine->ops->set_colon_line_handler)
473     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
474
475   return (*engine->ops->set_colon_line_handler) (engine->engine,
476                                                  fnc, fnc_value);
477 }
478
479 gpgme_error_t
480 _gpgme_engine_op_decrypt (engine_t engine, gpgme_data_t ciph,
481                           gpgme_data_t plain)
482 {
483   if (!engine)
484     return gpg_error (GPG_ERR_INV_VALUE);
485
486   if (!engine->ops->decrypt)
487     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
488
489   return (*engine->ops->decrypt) (engine->engine, ciph, plain);
490 }
491
492 gpgme_error_t
493 _gpgme_engine_op_delete (engine_t engine, gpgme_key_t key,
494                          int allow_secret)
495 {
496   if (!engine)
497     return gpg_error (GPG_ERR_INV_VALUE);
498
499   if (!engine->ops->delete)
500     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
501
502   return (*engine->ops->delete) (engine->engine, key, allow_secret);
503 }
504
505
506 gpgme_error_t
507 _gpgme_engine_op_edit (engine_t engine, int type, gpgme_key_t key,
508                        gpgme_data_t out, gpgme_ctx_t ctx /* FIXME */)
509 {
510   if (!engine)
511     return gpg_error (GPG_ERR_INV_VALUE);
512
513   if (!engine->ops->edit)
514     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
515
516   return (*engine->ops->edit) (engine->engine, type, key, out, ctx);
517 }
518
519
520 gpgme_error_t
521 _gpgme_engine_op_encrypt (engine_t engine, gpgme_key_t recp[],
522                           gpgme_encrypt_flags_t flags,
523                           gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
524 {
525   if (!engine)
526     return gpg_error (GPG_ERR_INV_VALUE);
527
528   if (!engine->ops->encrypt)
529     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
530
531   return (*engine->ops->encrypt) (engine->engine, recp, flags, plain, ciph,
532                                   use_armor);
533 }
534
535
536 gpgme_error_t
537 _gpgme_engine_op_encrypt_sign (engine_t engine, gpgme_key_t recp[],
538                                gpgme_encrypt_flags_t flags,
539                                gpgme_data_t plain, gpgme_data_t ciph,
540                                int use_armor, gpgme_ctx_t ctx /* FIXME */)
541 {
542   if (!engine)
543     return gpg_error (GPG_ERR_INV_VALUE);
544
545   if (!engine->ops->encrypt_sign)
546     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
547
548   return (*engine->ops->encrypt_sign) (engine->engine, recp, flags,
549                                        plain, ciph, use_armor, ctx);
550 }
551
552
553 gpgme_error_t
554 _gpgme_engine_op_export (engine_t engine, const char *pattern,
555                          unsigned int reserved, gpgme_data_t keydata,
556                          int use_armor)
557 {
558   if (!engine)
559     return gpg_error (GPG_ERR_INV_VALUE);
560
561   if (!engine->ops->export)
562     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
563
564   return (*engine->ops->export) (engine->engine, pattern, reserved,
565                                  keydata, use_armor);
566 }
567
568
569 gpgme_error_t
570 _gpgme_engine_op_export_ext (engine_t engine, const char *pattern[],
571                              unsigned int reserved, gpgme_data_t keydata,
572                              int use_armor)
573 {
574   if (!engine)
575     return gpg_error (GPG_ERR_INV_VALUE);
576
577   if (!engine->ops->export_ext)
578     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
579
580   return (*engine->ops->export_ext) (engine->engine, pattern, reserved,
581                                      keydata, use_armor);
582 }
583
584
585 gpgme_error_t
586 _gpgme_engine_op_genkey (engine_t engine, gpgme_data_t help_data,
587                          int use_armor, gpgme_data_t pubkey,
588                          gpgme_data_t seckey)
589 {
590   if (!engine)
591     return gpg_error (GPG_ERR_INV_VALUE);
592
593   if (!engine->ops->genkey)
594     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
595
596   return (*engine->ops->genkey) (engine->engine, help_data, use_armor,
597                                  pubkey, seckey);
598 }
599
600
601 gpgme_error_t
602 _gpgme_engine_op_import (engine_t engine, gpgme_data_t keydata)
603 {
604   if (!engine)
605     return gpg_error (GPG_ERR_INV_VALUE);
606
607   if (!engine->ops->import)
608     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
609
610   return (*engine->ops->import) (engine->engine, keydata);
611 }
612
613
614 gpgme_error_t
615 _gpgme_engine_op_keylist (engine_t engine, const char *pattern,
616                           int secret_only, gpgme_keylist_mode_t mode)
617 {
618   if (!engine)
619     return gpg_error (GPG_ERR_INV_VALUE);
620
621   if (!engine->ops->keylist)
622     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
623
624   return (*engine->ops->keylist) (engine->engine, pattern, secret_only, mode);
625 }
626
627
628 gpgme_error_t
629 _gpgme_engine_op_keylist_ext (engine_t engine, const char *pattern[],
630                               int secret_only, int reserved,
631                               gpgme_keylist_mode_t mode)
632 {
633   if (!engine)
634     return gpg_error (GPG_ERR_INV_VALUE);
635
636   if (!engine->ops->keylist_ext)
637     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
638
639   return (*engine->ops->keylist_ext) (engine->engine, pattern, secret_only,
640                                       reserved, mode);
641 }
642
643
644 gpgme_error_t
645 _gpgme_engine_op_sign (engine_t engine, gpgme_data_t in, gpgme_data_t out,
646                        gpgme_sig_mode_t mode, int use_armor,
647                        int use_textmode, int include_certs,
648                        gpgme_ctx_t ctx /* FIXME */)
649 {
650   if (!engine)
651     return gpg_error (GPG_ERR_INV_VALUE);
652
653   if (!engine->ops->sign)
654     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
655
656   return (*engine->ops->sign) (engine->engine, in, out, mode, use_armor,
657                                use_textmode, include_certs, ctx);
658 }
659
660
661 gpgme_error_t
662 _gpgme_engine_op_trustlist (engine_t engine, const char *pattern)
663 {
664   if (!engine)
665     return gpg_error (GPG_ERR_INV_VALUE);
666
667   if (!engine->ops->trustlist)
668     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
669
670   return (*engine->ops->trustlist) (engine->engine, pattern);
671 }
672
673
674 gpgme_error_t
675 _gpgme_engine_op_verify (engine_t engine, gpgme_data_t sig,
676                          gpgme_data_t signed_text, gpgme_data_t plaintext)
677 {
678   if (!engine)
679     return gpg_error (GPG_ERR_INV_VALUE);
680
681   if (!engine->ops->verify)
682     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
683
684   return (*engine->ops->verify) (engine->engine, sig, signed_text, plaintext);
685 }
686
687
688 void
689 _gpgme_engine_set_io_cbs (engine_t engine, gpgme_io_cbs_t io_cbs)
690 {
691   if (!engine)
692     return;
693
694   (*engine->ops->set_io_cbs) (engine->engine, io_cbs);
695 }
696
697
698 void
699 _gpgme_engine_io_event (engine_t engine,
700                         gpgme_event_io_t type, void *type_data)
701 {
702   if (!engine)
703     return;
704
705   (*engine->ops->io_event) (engine->engine, type, type_data);
706 }
707
708
709 gpgme_error_t
710 _gpgme_engine_cancel (engine_t engine)
711 {
712   if (!engine)
713     return gpg_error (GPG_ERR_INV_VALUE);
714
715   if (!engine->ops->cancel)
716     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
717
718   return (*engine->ops->cancel) (engine->engine);
719 }