core: add experimental GPGME_EXPORT_MODE_NOUID.
[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_NOUID
127                 |GPGME_EXPORT_MODE_PKCS12)))
128     return gpg_error (GPG_ERR_INV_VALUE); /* Invalid flags in MODE.  */
129
130   if ((mode & GPGME_EXPORT_MODE_SECRET))
131     {
132       if ((mode & GPGME_EXPORT_MODE_EXTERN))
133         return gpg_error (GPG_ERR_INV_FLAG);  /* Combination not allowed. */
134       if ((mode & GPGME_EXPORT_MODE_RAW)
135           && (mode & GPGME_EXPORT_MODE_PKCS12))
136         return gpg_error (GPG_ERR_INV_FLAG);  /* Combination not allowed. */
137
138       if (ctx->protocol != GPGME_PROTOCOL_CMS
139           && (mode & (GPGME_EXPORT_MODE_RAW|GPGME_EXPORT_MODE_PKCS12)))
140         return gpg_error (GPG_ERR_INV_FLAG);  /* Only supported for X.509.  */
141     }
142
143   if ((mode & GPGME_EXPORT_MODE_EXTERN))
144     {
145       if (keydata)
146         return gpg_error (GPG_ERR_INV_VALUE);
147     }
148   else
149     {
150       if (!keydata)
151         return gpg_error (GPG_ERR_INV_VALUE);
152     }
153
154   err = _gpgme_op_reset (ctx, synchronous);
155   if (err)
156     return err;
157
158   err = _gpgme_op_data_lookup (ctx, OPDATA_EXPORT, &hook,
159                                sizeof (*opd), release_op_data);
160   opd = hook;
161   if (err)
162     return err;
163
164   _gpgme_engine_set_status_handler (ctx->engine, export_status_handler, ctx);
165
166   return _gpgme_engine_op_export (ctx->engine, pattern, mode, keydata,
167                                   ctx->use_armor);
168 }
169
170
171 /* Export the keys listed in PATTERN into KEYDATA.  */
172 gpgme_error_t
173 gpgme_op_export_start (gpgme_ctx_t ctx, const char *pattern,
174                        gpgme_export_mode_t mode, gpgme_data_t keydata)
175 {
176   gpgme_error_t err;
177
178   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_export_start", ctx,
179               "pattern=%s, mode=0x%x, keydata=%p", pattern, mode, keydata);
180
181   if (!ctx)
182     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
183
184   err = export_start (ctx, 0, pattern, mode, keydata);
185   return TRACE_ERR (err);
186 }
187
188
189 /* Export the keys listed in PATTERN into KEYDATA.  */
190 gpgme_error_t
191 gpgme_op_export (gpgme_ctx_t ctx, const char *pattern,
192                  gpgme_export_mode_t mode, gpgme_data_t keydata)
193 {
194   gpgme_error_t err;
195
196   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_export", ctx,
197               "pattern=%s, mode=0x%x, keydata=%p", pattern, mode, keydata);
198
199   if (!ctx)
200     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
201
202   err = export_start (ctx, 1, pattern, mode, keydata);
203   if (!err)
204     err = _gpgme_wait_one (ctx);
205   return err;
206 }
207
208 \f
209 static gpgme_error_t
210 export_ext_start (gpgme_ctx_t ctx, int synchronous, const char *pattern[],
211                   gpgme_export_mode_t mode, gpgme_data_t keydata)
212 {
213   gpgme_error_t err;
214   void *hook;
215   op_data_t opd;
216
217   if ((mode & ~(GPGME_EXPORT_MODE_EXTERN
218                 |GPGME_EXPORT_MODE_MINIMAL
219                 |GPGME_EXPORT_MODE_SECRET
220                 |GPGME_EXPORT_MODE_RAW
221                 |GPGME_EXPORT_MODE_PKCS12)))
222     return gpg_error (GPG_ERR_INV_VALUE); /* Invalid flags in MODE.  */
223
224   if ((mode & GPGME_EXPORT_MODE_SECRET))
225     {
226       if ((mode & GPGME_EXPORT_MODE_EXTERN))
227         return gpg_error (GPG_ERR_INV_FLAG);  /* Combination not allowed. */
228       if ((mode & GPGME_EXPORT_MODE_RAW)
229           && (mode & GPGME_EXPORT_MODE_PKCS12))
230         return gpg_error (GPG_ERR_INV_FLAG);  /* Combination not allowed. */
231
232       if (ctx->protocol != GPGME_PROTOCOL_CMS
233           && (mode & (GPGME_EXPORT_MODE_RAW|GPGME_EXPORT_MODE_PKCS12)))
234         return gpg_error (GPG_ERR_INV_FLAG);  /* Only supported for X.509.  */
235     }
236
237   if ((mode & GPGME_EXPORT_MODE_EXTERN))
238     {
239       if (keydata)
240         return gpg_error (GPG_ERR_INV_VALUE);
241     }
242   else
243     {
244       if (!keydata)
245         return gpg_error (GPG_ERR_INV_VALUE);
246     }
247
248   err = _gpgme_op_reset (ctx, synchronous);
249   if (err)
250     return err;
251
252   err = _gpgme_op_data_lookup (ctx, OPDATA_EXPORT, &hook,
253                                sizeof (*opd), release_op_data);
254   opd = hook;
255   if (err)
256     return err;
257
258   _gpgme_engine_set_status_handler (ctx->engine, export_status_handler, ctx);
259
260   return _gpgme_engine_op_export_ext (ctx->engine, pattern, mode, keydata,
261                                       ctx->use_armor);
262 }
263
264
265 /* Export the keys listed in PATTERN into KEYDATA.  */
266 gpgme_error_t
267 gpgme_op_export_ext_start (gpgme_ctx_t ctx, const char *pattern[],
268                            gpgme_export_mode_t mode, gpgme_data_t keydata)
269 {
270   gpgme_error_t err;
271
272   TRACE_BEG2 (DEBUG_CTX, "gpgme_op_export_ext_start", ctx,
273               "mode=0x%x, keydata=%p", mode, keydata);
274
275   if (!ctx)
276     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
277
278   if (_gpgme_debug_trace () && pattern)
279     {
280       int i = 0;
281
282       while (pattern[i])
283         {
284           TRACE_LOG2 ("pattern[%i] = %s", i, pattern[i]);
285           i++;
286         }
287     }
288
289   err = export_ext_start (ctx, 0, pattern, mode, keydata);
290   return TRACE_ERR (err);
291 }
292
293
294 /* Export the keys listed in PATTERN into KEYDATA.  */
295 gpgme_error_t
296 gpgme_op_export_ext (gpgme_ctx_t ctx, const char *pattern[],
297                      gpgme_export_mode_t mode, gpgme_data_t keydata)
298 {
299   gpgme_error_t err;
300
301   TRACE_BEG2 (DEBUG_CTX, "gpgme_op_export_ext_start", ctx,
302               "mode=0x%x, keydata=%p", mode, keydata);
303
304   if (!ctx)
305     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
306
307   if (_gpgme_debug_trace () && pattern)
308     {
309       int i = 0;
310
311       while (pattern[i])
312         {
313           TRACE_LOG2 ("pattern[%i] = %s", i, pattern[i]);
314           i++;
315         }
316     }
317
318   err = export_ext_start (ctx, 1, pattern, mode, keydata);
319   if (!err)
320     {
321       err = _gpgme_wait_one (ctx);
322       if (!err)
323         {
324           /* For this synchronous operation we check for operational
325              errors and return them.  For asynchronous operations
326              there is currently no way to do this - we need to add a
327              gpgme_op_export_result function to fix that.  */
328           void *hook;
329           op_data_t opd;
330
331           err = _gpgme_op_data_lookup (ctx, OPDATA_EXPORT, &hook, -1, NULL);
332           opd = hook;
333           if (!err)
334             err = opd->err;
335         }
336     }
337
338   return TRACE_ERR (err);
339 }
340
341
342
343 \f
344
345 static gpgme_error_t
346 export_keys_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t keys[],
347                    gpgme_export_mode_t mode, gpgme_data_t keydata)
348 {
349   gpgme_error_t err;
350   int nkeys, idx;
351   char **pattern;
352
353   if (!keys)
354     return gpg_error (GPG_ERR_INV_VALUE);
355
356   /* Create a list of pattern from the keys.  */
357   for (idx=nkeys=0; keys[idx]; idx++)
358     if (keys[idx]->protocol == ctx->protocol)
359       nkeys++;
360   if (!nkeys)
361     return gpg_error (GPG_ERR_NO_DATA);
362
363   pattern = calloc (nkeys+1, sizeof *pattern);
364   if (!pattern)
365     return gpg_error_from_syserror ();
366
367   for (idx=nkeys=0; keys[idx]; idx++)
368     if (keys[idx]->protocol == ctx->protocol
369         && keys[idx]->subkeys
370         && keys[idx]->subkeys->fpr
371         && *keys[idx]->subkeys->fpr)
372       {
373         pattern[nkeys] = strdup (keys[idx]->subkeys->fpr);
374         if (!pattern[nkeys])
375           {
376             err = gpg_error_from_syserror ();
377             goto leave;
378           }
379         nkeys++;
380       }
381
382
383   /* Pass on to the regular function.  */
384   err = export_ext_start (ctx, synchronous, (const char**)pattern,
385                           mode, keydata);
386
387  leave:
388   for (idx=0; pattern[idx]; idx++)
389     free (pattern[idx]);
390   free (pattern);
391
392   return err;
393 }
394
395
396 /* Export the keys from the array KEYS into KEYDATA.  Only keys of the
397    current protocol are exported and only those which have a
398    fingerprint set; that is keys received with some external search
399    methods are silently skipped.  */
400 gpgme_error_t
401 gpgme_op_export_keys_start (gpgme_ctx_t ctx,
402                             gpgme_key_t keys[],
403                             gpgme_export_mode_t mode,
404                             gpgme_data_t keydata)
405 {
406   gpg_error_t err;
407
408   TRACE_BEG2 (DEBUG_CTX, "gpgme_op_export_keys_start", ctx,
409               "mode=0x%x, keydata=%p", mode, keydata);
410
411   if (!ctx)
412     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
413
414   if (_gpgme_debug_trace () && keys)
415     {
416       int i = 0;
417
418       while (keys[i])
419         {
420           TRACE_LOG3 ("keys[%i] = %p (%s)", i, keys[i],
421                       (keys[i]->subkeys && keys[i]->subkeys->fpr) ?
422                       keys[i]->subkeys->fpr : "invalid");
423           i++;
424         }
425     }
426
427   err = export_keys_start (ctx, 0, keys, mode, keydata);
428   return TRACE_ERR (err);
429 }
430
431 gpgme_error_t
432 gpgme_op_export_keys (gpgme_ctx_t ctx,
433                       gpgme_key_t keys[],
434                       gpgme_export_mode_t mode,
435                       gpgme_data_t keydata)
436 {
437   gpgme_error_t err;
438
439   TRACE_BEG2 (DEBUG_CTX, "gpgme_op_export_keys", ctx,
440               "mode=0x%x, keydata=%p", mode, keydata);
441
442   if (!ctx)
443     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
444
445   if (_gpgme_debug_trace () && keys)
446     {
447       int i = 0;
448
449       while (keys[i])
450         {
451           TRACE_LOG3 ("keys[%i] = %p (%s)", i, keys[i],
452                       (keys[i]->subkeys && keys[i]->subkeys->fpr) ?
453                       keys[i]->subkeys->fpr : "invalid");
454           i++;
455         }
456     }
457
458   err = export_keys_start (ctx, 1, keys, mode, keydata);
459   if (!err)
460     {
461       err = _gpgme_wait_one (ctx);
462       if (!err)
463         {
464           /* For this synchronous operation we check for operational
465              errors and return them.  For asynchronous operations
466              there is currently no way to do this - we need to add a
467              gpgme_op_export_result function to fix that.  */
468           void *hook;
469           op_data_t opd;
470
471           err = _gpgme_op_data_lookup (ctx, OPDATA_EXPORT, &hook, -1, NULL);
472           opd = hook;
473           if (!err)
474             err = opd->err;
475         }
476     }
477
478   return TRACE_ERR (err);
479 }
480