cd94050d132ae9e27d15de5ef1864f6f6e816029
[gpgme.git] / src / export.c
1 /* export.c - Export a key.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001-2004, 2010, 2014 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, see <https://www.gnu.org/licenses/>.
19  */
20
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "gpgme.h"
28 #include "util.h"
29 #include "debug.h"
30 #include "context.h"
31 #include "ops.h"
32
33 \f
34 /* Local operation data.  */
35 typedef struct
36 {
37   gpg_error_t err;  /* Error encountered during the export.  */
38 } *op_data_t;
39
40
41 static void
42 release_op_data (void *hook)
43 {
44   op_data_t opd = (op_data_t) hook;
45
46   (void)opd;  /* Nothing to release here.  */
47 }
48
49
50 /* Parse an error status line.  Return the error location and the
51    error code.  The function may modify ARGS. */
52 static char *
53 parse_error (char *args, gpg_error_t *r_err)
54 {
55   char *where = strchr (args, ' ');
56   char *which;
57
58   if (where)
59     {
60       *where = '\0';
61       which = where + 1;
62
63       where = strchr (which, ' ');
64       if (where)
65         *where = '\0';
66
67       where = args;
68     }
69   else
70     {
71       *r_err = trace_gpg_error (GPG_ERR_INV_ENGINE);
72       return NULL;
73     }
74
75   *r_err = atoi (which);
76
77   return where;
78 }
79
80
81 static gpgme_error_t
82 export_status_handler (void *priv, gpgme_status_code_t code, char *args)
83 {
84   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
85   gpgme_error_t err;
86   void *hook;
87   op_data_t opd;
88   const char *loc;
89
90   err = _gpgme_op_data_lookup (ctx, OPDATA_EXPORT, &hook, -1, NULL);
91   opd = hook;
92   if (err)
93     return err;
94
95   switch (code)
96     {
97     case GPGME_STATUS_ERROR:
98       loc = parse_error (args, &err);
99       if (!loc)
100         return err;
101       else if (opd->err)
102         ; /* We only want to report the first error.  */
103       else if (!strcmp (loc, "keyserver_send"))
104         opd->err = err;
105       break;
106
107     default:
108       break;
109     }
110   return 0;
111 }
112
113
114 static gpgme_error_t
115 export_start (gpgme_ctx_t ctx, int synchronous, const char *pattern,
116               gpgme_export_mode_t mode, gpgme_data_t keydata)
117 {
118   gpgme_error_t err;
119   void *hook;
120   op_data_t opd;
121
122   if ((mode & ~(GPGME_EXPORT_MODE_EXTERN
123                 |GPGME_EXPORT_MODE_MINIMAL
124                 |GPGME_EXPORT_MODE_SECRET
125                 |GPGME_EXPORT_MODE_RAW
126                 |GPGME_EXPORT_MODE_PKCS12)))
127     return gpg_error (GPG_ERR_INV_VALUE); /* Invalid flags in MODE.  */
128
129   if ((mode & GPGME_EXPORT_MODE_SECRET))
130     {
131       if ((mode & GPGME_EXPORT_MODE_EXTERN))
132         return gpg_error (GPG_ERR_INV_FLAG);  /* Combination not allowed. */
133       if ((mode & GPGME_EXPORT_MODE_RAW)
134           && (mode & GPGME_EXPORT_MODE_PKCS12))
135         return gpg_error (GPG_ERR_INV_FLAG);  /* Combination not allowed. */
136
137       if (ctx->protocol != GPGME_PROTOCOL_CMS
138           && (mode & (GPGME_EXPORT_MODE_RAW|GPGME_EXPORT_MODE_PKCS12)))
139         return gpg_error (GPG_ERR_INV_FLAG);  /* Only supported for X.509.  */
140     }
141
142   if ((mode & GPGME_EXPORT_MODE_EXTERN))
143     {
144       if (keydata)
145         return gpg_error (GPG_ERR_INV_VALUE);
146     }
147   else
148     {
149       if (!keydata)
150         return gpg_error (GPG_ERR_INV_VALUE);
151     }
152
153   err = _gpgme_op_reset (ctx, synchronous);
154   if (err)
155     return err;
156
157   err = _gpgme_op_data_lookup (ctx, OPDATA_EXPORT, &hook,
158                                sizeof (*opd), release_op_data);
159   opd = hook;
160   if (err)
161     return err;
162
163   _gpgme_engine_set_status_handler (ctx->engine, export_status_handler, ctx);
164
165   return _gpgme_engine_op_export (ctx->engine, pattern, mode, keydata,
166                                   ctx->use_armor);
167 }
168
169
170 /* Export the keys listed in PATTERN into KEYDATA.  */
171 gpgme_error_t
172 gpgme_op_export_start (gpgme_ctx_t ctx, const char *pattern,
173                        gpgme_export_mode_t mode, gpgme_data_t keydata)
174 {
175   gpgme_error_t err;
176
177   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_export_start", ctx,
178               "pattern=%s, mode=0x%x, keydata=%p", pattern, mode, keydata);
179
180   if (!ctx)
181     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
182
183   err = export_start (ctx, 0, pattern, mode, keydata);
184   return TRACE_ERR (err);
185 }
186
187
188 /* Export the keys listed in PATTERN into KEYDATA.  */
189 gpgme_error_t
190 gpgme_op_export (gpgme_ctx_t ctx, const char *pattern,
191                  gpgme_export_mode_t mode, gpgme_data_t keydata)
192 {
193   gpgme_error_t err;
194
195   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_export", ctx,
196               "pattern=%s, mode=0x%x, keydata=%p", pattern, mode, keydata);
197
198   if (!ctx)
199     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
200
201   err = export_start (ctx, 1, pattern, mode, keydata);
202   if (!err)
203     err = _gpgme_wait_one (ctx);
204   return err;
205 }
206
207 \f
208 static gpgme_error_t
209 export_ext_start (gpgme_ctx_t ctx, int synchronous, const char *pattern[],
210                   gpgme_export_mode_t mode, gpgme_data_t keydata)
211 {
212   gpgme_error_t err;
213   void *hook;
214   op_data_t opd;
215
216   if ((mode & ~(GPGME_EXPORT_MODE_EXTERN
217                 |GPGME_EXPORT_MODE_MINIMAL
218                 |GPGME_EXPORT_MODE_SECRET
219                 |GPGME_EXPORT_MODE_RAW
220                 |GPGME_EXPORT_MODE_PKCS12)))
221     return gpg_error (GPG_ERR_INV_VALUE); /* Invalid flags in MODE.  */
222
223   if ((mode & GPGME_EXPORT_MODE_SECRET))
224     {
225       if ((mode & GPGME_EXPORT_MODE_EXTERN))
226         return gpg_error (GPG_ERR_INV_FLAG);  /* Combination not allowed. */
227       if ((mode & GPGME_EXPORT_MODE_RAW)
228           && (mode & GPGME_EXPORT_MODE_PKCS12))
229         return gpg_error (GPG_ERR_INV_FLAG);  /* Combination not allowed. */
230
231       if (ctx->protocol != GPGME_PROTOCOL_CMS
232           && (mode & (GPGME_EXPORT_MODE_RAW|GPGME_EXPORT_MODE_PKCS12)))
233         return gpg_error (GPG_ERR_INV_FLAG);  /* Only supported for X.509.  */
234     }
235
236   if ((mode & GPGME_EXPORT_MODE_EXTERN))
237     {
238       if (keydata)
239         return gpg_error (GPG_ERR_INV_VALUE);
240     }
241   else
242     {
243       if (!keydata)
244         return gpg_error (GPG_ERR_INV_VALUE);
245     }
246
247   err = _gpgme_op_reset (ctx, synchronous);
248   if (err)
249     return err;
250
251   err = _gpgme_op_data_lookup (ctx, OPDATA_EXPORT, &hook,
252                                sizeof (*opd), release_op_data);
253   opd = hook;
254   if (err)
255     return err;
256
257   _gpgme_engine_set_status_handler (ctx->engine, export_status_handler, ctx);
258
259   return _gpgme_engine_op_export_ext (ctx->engine, pattern, mode, keydata,
260                                       ctx->use_armor);
261 }
262
263
264 /* Export the keys listed in PATTERN into KEYDATA.  */
265 gpgme_error_t
266 gpgme_op_export_ext_start (gpgme_ctx_t ctx, const char *pattern[],
267                            gpgme_export_mode_t mode, gpgme_data_t keydata)
268 {
269   gpgme_error_t err;
270
271   TRACE_BEG2 (DEBUG_CTX, "gpgme_op_export_ext_start", ctx,
272               "mode=0x%x, keydata=%p", mode, keydata);
273
274   if (!ctx)
275     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
276
277   if (_gpgme_debug_trace () && pattern)
278     {
279       int i = 0;
280
281       while (pattern[i])
282         {
283           TRACE_LOG2 ("pattern[%i] = %s", i, pattern[i]);
284           i++;
285         }
286     }
287
288   err = export_ext_start (ctx, 0, pattern, mode, keydata);
289   return TRACE_ERR (err);
290 }
291
292
293 /* Export the keys listed in PATTERN into KEYDATA.  */
294 gpgme_error_t
295 gpgme_op_export_ext (gpgme_ctx_t ctx, const char *pattern[],
296                      gpgme_export_mode_t mode, gpgme_data_t keydata)
297 {
298   gpgme_error_t err;
299
300   TRACE_BEG2 (DEBUG_CTX, "gpgme_op_export_ext_start", ctx,
301               "mode=0x%x, keydata=%p", mode, keydata);
302
303   if (!ctx)
304     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
305
306   if (_gpgme_debug_trace () && pattern)
307     {
308       int i = 0;
309
310       while (pattern[i])
311         {
312           TRACE_LOG2 ("pattern[%i] = %s", i, pattern[i]);
313           i++;
314         }
315     }
316
317   err = export_ext_start (ctx, 1, pattern, mode, keydata);
318   if (!err)
319     {
320       err = _gpgme_wait_one (ctx);
321       if (!err)
322         {
323           /* For this synchronous operation we check for operational
324              errors and return them.  For asynchronous operations
325              there is currently no way to do this - we need to add a
326              gpgme_op_export_result function to fix that.  */
327           void *hook;
328           op_data_t opd;
329
330           err = _gpgme_op_data_lookup (ctx, OPDATA_EXPORT, &hook, -1, NULL);
331           opd = hook;
332           if (!err)
333             err = opd->err;
334         }
335     }
336
337   return TRACE_ERR (err);
338 }
339
340
341
342 \f
343
344 static gpgme_error_t
345 export_keys_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t keys[],
346                    gpgme_export_mode_t mode, gpgme_data_t keydata)
347 {
348   gpgme_error_t err;
349   int nkeys, idx;
350   char **pattern;
351
352   if (!keys)
353     return gpg_error (GPG_ERR_INV_VALUE);
354
355   /* Create a list of pattern from the keys.  */
356   for (idx=nkeys=0; keys[idx]; idx++)
357     if (keys[idx]->protocol == ctx->protocol)
358       nkeys++;
359   if (!nkeys)
360     return gpg_error (GPG_ERR_NO_DATA);
361
362   pattern = calloc (nkeys+1, sizeof *pattern);
363   if (!pattern)
364     return gpg_error_from_syserror ();
365
366   for (idx=nkeys=0; keys[idx]; idx++)
367     if (keys[idx]->protocol == ctx->protocol
368         && keys[idx]->subkeys
369         && keys[idx]->subkeys->fpr
370         && *keys[idx]->subkeys->fpr)
371       {
372         pattern[nkeys] = strdup (keys[idx]->subkeys->fpr);
373         if (!pattern[nkeys])
374           {
375             err = gpg_error_from_syserror ();
376             goto leave;
377           }
378         nkeys++;
379       }
380
381
382   /* Pass on to the regular function.  */
383   err = export_ext_start (ctx, synchronous, (const char**)pattern,
384                           mode, keydata);
385
386  leave:
387   for (idx=0; pattern[idx]; idx++)
388     free (pattern[idx]);
389   free (pattern);
390
391   return err;
392 }
393
394
395 /* Export the keys from the array KEYS into KEYDATA.  Only keys of the
396    current protocol are exported and only those which have a
397    fingerprint set; that is keys received with some external search
398    methods are silently skipped.  */
399 gpgme_error_t
400 gpgme_op_export_keys_start (gpgme_ctx_t ctx,
401                             gpgme_key_t keys[],
402                             gpgme_export_mode_t mode,
403                             gpgme_data_t keydata)
404 {
405   gpg_error_t err;
406
407   TRACE_BEG2 (DEBUG_CTX, "gpgme_op_export_keys_start", ctx,
408               "mode=0x%x, keydata=%p", mode, keydata);
409
410   if (!ctx)
411     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
412
413   if (_gpgme_debug_trace () && keys)
414     {
415       int i = 0;
416
417       while (keys[i])
418         {
419           TRACE_LOG3 ("keys[%i] = %p (%s)", i, keys[i],
420                       (keys[i]->subkeys && keys[i]->subkeys->fpr) ?
421                       keys[i]->subkeys->fpr : "invalid");
422           i++;
423         }
424     }
425
426   err = export_keys_start (ctx, 0, keys, mode, keydata);
427   return TRACE_ERR (err);
428 }
429
430 gpgme_error_t
431 gpgme_op_export_keys (gpgme_ctx_t ctx,
432                       gpgme_key_t keys[],
433                       gpgme_export_mode_t mode,
434                       gpgme_data_t keydata)
435 {
436   gpgme_error_t err;
437
438   TRACE_BEG2 (DEBUG_CTX, "gpgme_op_export_keys", ctx,
439               "mode=0x%x, keydata=%p", mode, keydata);
440
441   if (!ctx)
442     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
443
444   if (_gpgme_debug_trace () && keys)
445     {
446       int i = 0;
447
448       while (keys[i])
449         {
450           TRACE_LOG3 ("keys[%i] = %p (%s)", i, keys[i],
451                       (keys[i]->subkeys && keys[i]->subkeys->fpr) ?
452                       keys[i]->subkeys->fpr : "invalid");
453           i++;
454         }
455     }
456
457   err = export_keys_start (ctx, 1, keys, mode, keydata);
458   if (!err)
459     {
460       err = _gpgme_wait_one (ctx);
461       if (!err)
462         {
463           /* For this synchronous operation we check for operational
464              errors and return them.  For asynchronous operations
465              there is currently no way to do this - we need to add a
466              gpgme_op_export_result function to fix that.  */
467           void *hook;
468           op_data_t opd;
469
470           err = _gpgme_op_data_lookup (ctx, OPDATA_EXPORT, &hook, -1, NULL);
471           opd = hook;
472           if (!err)
473             err = opd->err;
474         }
475     }
476
477   return TRACE_ERR (err);
478 }
479