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