"Fossies" - the Fresh Open Source Software Archive

Member "gpgme-1.15.1/src/export.c" (8 Jan 2021, 12608 Bytes) of package /linux/privat/gpgme-1.15.1.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "export.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.15.0_vs_1.15.1.

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