Locate engine names only at runtime and prefer GnuPG-2.
[gpgme.git] / src / import.c
1 /* import.c - Import a key.
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 #if HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <string.h>
28
29 #include "gpgme.h"
30 #include "debug.h"
31 #include "context.h"
32 #include "ops.h"
33 #include "util.h"
34
35 \f
36 typedef struct
37 {
38   struct _gpgme_op_import_result result;
39
40   /* A pointer to the next pointer of the last import status in the
41      list.  This makes appending new imports painless while preserving
42      the order.  */
43   gpgme_import_status_t *lastp;
44 } *op_data_t;
45
46
47 static void
48 release_op_data (void *hook)
49 {
50   op_data_t opd = (op_data_t) hook;
51   gpgme_import_status_t import = opd->result.imports;
52
53   while (import)
54     {
55       gpgme_import_status_t next = import->next;
56       free (import->fpr);
57       free (import);
58       import = next;
59     }
60 }
61
62
63 gpgme_import_result_t
64 gpgme_op_import_result (gpgme_ctx_t ctx)
65 {
66   void *hook;
67   op_data_t opd;
68   gpgme_error_t err;
69
70   TRACE_BEG (DEBUG_CTX, "gpgme_op_import_result", ctx);
71
72   err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, &hook, -1, NULL);
73   opd = hook;
74   if (err || !opd)
75     {
76       TRACE_SUC0 ("result=(null)");
77       return NULL;
78     }
79
80
81   if (_gpgme_debug_trace ())
82     {
83       gpgme_import_status_t impstat;
84       int i;
85
86       TRACE_LOG5 ("%i considered, %i no UID, %i imported, %i imported RSA, "
87                   "%i unchanged", opd->result.considered,
88                   opd->result.no_user_id, opd->result.imported,
89                   opd->result.imported_rsa, opd->result.unchanged);
90       TRACE_LOG4 ("%i new UIDs, %i new sub keys, %i new signatures, "
91                   "%i new revocations", opd->result.new_user_ids,
92                   opd->result.new_sub_keys, opd->result.new_signatures,
93                   opd->result.new_revocations);
94       TRACE_LOG3 ("%i secret keys, %i imported, %i unchanged",
95                   opd->result.secret_read, opd->result.secret_imported,
96                   opd->result.secret_unchanged);
97       TRACE_LOG2 ("%i skipped new keys, %i not imported",
98                   opd->result.skipped_new_keys, opd->result.not_imported);
99
100       impstat = opd->result.imports;
101       i = 0;
102       while (impstat)
103         {
104           TRACE_LOG4 ("import[%i] for %s = 0x%x (%s)",
105                       i, impstat->fpr, impstat->status, impstat->result);
106           impstat = impstat->next;
107           i++;
108         }
109     }
110
111   TRACE_SUC1 ("result=%p", &opd->result);
112   return &opd->result;
113 }
114
115 \f
116 static gpgme_error_t
117 parse_import (char *args, gpgme_import_status_t *import_status, int problem)
118 {
119   gpgme_import_status_t import;
120   char *tail;
121   long int nr;
122
123   import = malloc (sizeof (*import));
124   if (!import)
125     return gpg_error_from_syserror ();
126   import->next = NULL;
127
128   gpg_err_set_errno (0);
129   nr = strtol (args, &tail, 0);
130   if (errno || args == tail || *tail != ' ')
131     {
132       /* The crypto backend does not behave.  */
133       free (import);
134       return trace_gpg_error (GPG_ERR_INV_ENGINE);
135     }
136   args = tail;
137
138   if (problem)
139     {
140       switch (nr)
141         {
142         case 0:
143         case 4:
144         default:
145           import->result = gpg_error (GPG_ERR_GENERAL);
146           break;
147
148         case 1:
149           import->result = gpg_error (GPG_ERR_BAD_CERT);
150           break;
151
152         case 2:
153           import->result = gpg_error (GPG_ERR_MISSING_ISSUER_CERT);
154           break;
155
156         case 3:
157           import->result = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
158           break;
159         }
160       import->status = 0;
161     }
162   else
163     {
164       import->result = gpg_error (GPG_ERR_NO_ERROR);
165       import->status = nr;
166     }
167
168   while (*args == ' ')
169     args++;
170   tail = strchr (args, ' ');
171   if (tail)
172     *tail = '\0';
173
174   import->fpr = strdup (args);
175   if (!import->fpr)
176     {
177       free (import);
178       return gpg_error_from_syserror ();
179     }
180
181   *import_status = import;
182   return 0;
183 }
184
185
186
187 gpgme_error_t
188 parse_import_res (char *args, gpgme_import_result_t result)
189 {
190   char *tail;
191
192   gpg_err_set_errno (0);
193
194 #define PARSE_NEXT(x)                                   \
195   (x) = strtol (args, &tail, 0);                        \
196   if (errno || args == tail || *tail != ' ')            \
197     /* The crypto backend does not behave.  */          \
198     return trace_gpg_error (GPG_ERR_INV_ENGINE);        \
199   args = tail;
200
201   PARSE_NEXT (result->considered);
202   PARSE_NEXT (result->no_user_id);
203   PARSE_NEXT (result->imported);
204   PARSE_NEXT (result->imported_rsa);
205   PARSE_NEXT (result->unchanged);
206   PARSE_NEXT (result->new_user_ids);
207   PARSE_NEXT (result->new_sub_keys);
208   PARSE_NEXT (result->new_signatures);
209   PARSE_NEXT (result->new_revocations);
210   PARSE_NEXT (result->secret_read);
211   PARSE_NEXT (result->secret_imported);
212   PARSE_NEXT (result->secret_unchanged);
213   PARSE_NEXT (result->skipped_new_keys);
214   PARSE_NEXT (result->not_imported);
215
216   return 0;
217 }
218
219
220 static gpgme_error_t
221 import_status_handler (void *priv, gpgme_status_code_t code, char *args)
222 {
223   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
224   gpgme_error_t err;
225   void *hook;
226   op_data_t opd;
227
228   err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, &hook, -1, NULL);
229   opd = hook;
230   if (err)
231     return err;
232
233   switch (code)
234     {
235     case GPGME_STATUS_IMPORT_OK:
236     case GPGME_STATUS_IMPORT_PROBLEM:
237       err = parse_import (args, opd->lastp,
238                           code == GPGME_STATUS_IMPORT_OK ? 0 : 1);
239       if (err)
240         return err;
241
242       opd->lastp = &(*opd->lastp)->next;
243       break;
244
245     case GPGME_STATUS_IMPORT_RES:
246       err = parse_import_res (args, &opd->result);
247       break;
248
249     default:
250       break;
251     }
252   return 0;
253 }
254
255
256 static gpgme_error_t
257 _gpgme_op_import_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t keydata)
258 {
259   gpgme_error_t err;
260   void *hook;
261   op_data_t opd;
262
263   err = _gpgme_op_reset (ctx, synchronous);
264   if (err)
265     return err;
266
267   err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, &hook,
268                                sizeof (*opd), release_op_data);
269   opd = hook;
270   if (err)
271     return err;
272   opd->lastp = &opd->result.imports;
273
274   if (!keydata)
275     return gpg_error (GPG_ERR_NO_DATA);
276
277   _gpgme_engine_set_status_handler (ctx->engine, import_status_handler, ctx);
278
279   return _gpgme_engine_op_import (ctx->engine, keydata, NULL);
280 }
281
282
283 gpgme_error_t
284 gpgme_op_import_start (gpgme_ctx_t ctx, gpgme_data_t keydata)
285 {
286   gpg_error_t err;
287
288   TRACE_BEG1 (DEBUG_CTX, "gpgme_op_import_start", ctx,
289               "keydata=%p", keydata);
290
291   if (!ctx)
292     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
293
294   err = _gpgme_op_import_start (ctx, 0, keydata);
295   return TRACE_ERR (err);
296 }
297
298
299 /* Import the key in KEYDATA into the keyring.  */
300 gpgme_error_t
301 gpgme_op_import (gpgme_ctx_t ctx, gpgme_data_t keydata)
302 {
303   gpgme_error_t err;
304
305   TRACE_BEG1 (DEBUG_CTX, "gpgme_op_import", ctx,
306               "keydata=%p", keydata);
307
308   if (!ctx)
309     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
310
311   err = _gpgme_op_import_start (ctx, 1, keydata);
312   if (!err)
313     err = _gpgme_wait_one (ctx);
314   return TRACE_ERR (err);
315 }
316
317
318 \f
319 static gpgme_error_t
320 _gpgme_op_import_keys_start (gpgme_ctx_t ctx, int synchronous,
321                              gpgme_key_t *keys)
322 {
323   gpgme_error_t err;
324   void *hook;
325   op_data_t opd;
326   int idx, firstidx, nkeys;
327
328   err = _gpgme_op_reset (ctx, synchronous);
329   if (err)
330     return err;
331
332   err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, &hook,
333                                sizeof (*opd), release_op_data);
334   opd = hook;
335   if (err)
336     return err;
337   opd->lastp = &opd->result.imports;
338
339   if (!keys)
340     return gpg_error (GPG_ERR_NO_DATA);
341
342   for (idx=nkeys=0, firstidx=-1; keys[idx]; idx++)
343     {
344       /* We only consider keys of the current protocol.  */
345       if (keys[idx]->protocol != ctx->protocol)
346         continue;
347       if (firstidx == -1)
348         firstidx = idx;
349       /* If a key has been found using a different key listing mode,
350          we bail out.  This makes the processing easier.  Fixme: To
351          allow a mix of keys we would need to sort them by key listing
352          mode and start two import operations one after the other.  */
353       if (keys[idx]->keylist_mode != keys[firstidx]->keylist_mode)
354         return gpg_error (GPG_ERR_CONFLICT);
355       nkeys++;
356     }
357   if (!nkeys)
358     return gpg_error (GPG_ERR_NO_DATA);
359
360   _gpgme_engine_set_status_handler (ctx->engine, import_status_handler, ctx);
361
362   return _gpgme_engine_op_import (ctx->engine, NULL, keys);
363 }
364
365
366 /* Asynchronous version of gpgme_op_import_key.  */
367 gpgme_error_t
368 gpgme_op_import_keys_start (gpgme_ctx_t ctx, gpgme_key_t *keys)
369 {
370   gpg_error_t err;
371
372   TRACE_BEG (DEBUG_CTX, "gpgme_op_import_keys_start", ctx);
373
374   if (!ctx)
375     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
376
377   if (_gpgme_debug_trace () && keys)
378     {
379       int i = 0;
380
381       while (keys[i])
382         {
383           TRACE_LOG3 ("keys[%i] = %p (%s)", i, keys[i],
384                       (keys[i]->subkeys && keys[i]->subkeys->fpr) ?
385                       keys[i]->subkeys->fpr : "invalid");
386           i++;
387         }
388     }
389
390   err = _gpgme_op_import_keys_start (ctx, 0, keys);
391   return TRACE_ERR (err);
392 }
393
394
395 /* Import the keys from the array KEYS into the keyring.  This
396    function allows to move a key from one engine to another as long as
397    they are compatible.  In particular it is used to actually import
398    keys retrieved from an external source (i.e. using
399    GPGME_KEYLIST_MODE_EXTERN).  It replaces the old workaround of
400    exporting and then importing a key as used to make an X.509 key
401    permanent.  This function automagically does the right thing.
402
403    KEYS is a NULL terminated array of gpgme key objects.  The result
404    is the usual import result structure.  Only keys matching the
405    current protocol are imported; other keys are ignored.  */
406 gpgme_error_t
407 gpgme_op_import_keys (gpgme_ctx_t ctx, gpgme_key_t *keys)
408 {
409   gpgme_error_t err;
410
411   TRACE_BEG (DEBUG_CTX, "gpgme_op_import_keys", ctx);
412
413   if (!ctx)
414     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
415
416   if (_gpgme_debug_trace () && keys)
417     {
418       int i = 0;
419
420       while (keys[i])
421         {
422           TRACE_LOG3 ("keys[%i] = %p (%s)", i, keys[i],
423                       (keys[i]->subkeys && keys[i]->subkeys->fpr) ?
424                       keys[i]->subkeys->fpr : "invalid");
425           i++;
426         }
427     }
428
429   err = _gpgme_op_import_keys_start (ctx, 1, keys);
430   if (!err)
431     err = _gpgme_wait_one (ctx);
432   return TRACE_ERR (err);
433 }
434
435
436 /* Deprecated interface.  */
437 gpgme_error_t
438 gpgme_op_import_ext (gpgme_ctx_t ctx, gpgme_data_t keydata, int *nr)
439 {
440   gpgme_error_t err = gpgme_op_import (ctx, keydata);
441   if (!err && nr)
442     {
443       gpgme_import_result_t result = gpgme_op_import_result (ctx);
444       *nr = result->considered;
445     }
446   return err;
447 }