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