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