LCOV - code coverage report
Current view: top level - src - import.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 93 176 52.8 %
Date: 2016-09-12 13:07:23 Functions: 7 12 58.3 %

          Line data    Source code
       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             : 
      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           8 : release_op_data (void *hook)
      49             : {
      50           8 :   op_data_t opd = (op_data_t) hook;
      51           8 :   gpgme_import_status_t import = opd->result.imports;
      52             : 
      53          29 :   while (import)
      54             :     {
      55          13 :       gpgme_import_status_t next = import->next;
      56          13 :       free (import->fpr);
      57          13 :       free (import);
      58          13 :       import = next;
      59             :     }
      60           8 : }
      61             : 
      62             : 
      63             : gpgme_import_result_t
      64           6 : gpgme_op_import_result (gpgme_ctx_t ctx)
      65             : {
      66             :   void *hook;
      67             :   op_data_t opd;
      68             :   gpgme_error_t err;
      69             : 
      70           6 :   TRACE_BEG (DEBUG_CTX, "gpgme_op_import_result", ctx);
      71             : 
      72           6 :   err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, &hook, -1, NULL);
      73           6 :   opd = hook;
      74           6 :   if (err || !opd)
      75             :     {
      76           0 :       TRACE_SUC0 ("result=(null)");
      77           0 :       return NULL;
      78             :     }
      79             : 
      80             : 
      81             :   if (_gpgme_debug_trace ())
      82             :     {
      83             :       gpgme_import_status_t impstat;
      84             :       int i;
      85             : 
      86           6 :       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           6 :       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           6 :       TRACE_LOG3 ("%i secret keys, %i imported, %i unchanged",
      95             :                   opd->result.secret_read, opd->result.secret_imported,
      96             :                   opd->result.secret_unchanged);
      97           6 :       TRACE_LOG2 ("%i skipped new keys, %i not imported",
      98             :                   opd->result.skipped_new_keys, opd->result.not_imported);
      99             : 
     100           6 :       impstat = opd->result.imports;
     101           6 :       i = 0;
     102          21 :       while (impstat)
     103             :         {
     104           9 :           TRACE_LOG4 ("import[%i] for %s = 0x%x (%s)",
     105             :                       i, impstat->fpr, impstat->status, impstat->result);
     106           9 :           impstat = impstat->next;
     107           9 :           i++;
     108             :         }
     109             :     }
     110             : 
     111           6 :   TRACE_SUC1 ("result=%p", &opd->result);
     112           6 :   return &opd->result;
     113             : }
     114             : 
     115             : 
     116             : static gpgme_error_t
     117          13 : 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          13 :   import = malloc (sizeof (*import));
     124          13 :   if (!import)
     125           0 :     return gpg_error_from_syserror ();
     126          13 :   import->next = NULL;
     127             : 
     128          13 :   gpg_err_set_errno (0);
     129          13 :   nr = strtol (args, &tail, 0);
     130          13 :   if (errno || args == tail || *tail != ' ')
     131             :     {
     132             :       /* The crypto backend does not behave.  */
     133           0 :       free (import);
     134           0 :       return trace_gpg_error (GPG_ERR_INV_ENGINE);
     135             :     }
     136          13 :   args = tail;
     137             : 
     138          13 :   if (problem)
     139             :     {
     140           0 :       switch (nr)
     141             :         {
     142             :         case 0:
     143             :         case 4:
     144             :         default:
     145           0 :           import->result = gpg_error (GPG_ERR_GENERAL);
     146           0 :           break;
     147             : 
     148             :         case 1:
     149           0 :           import->result = gpg_error (GPG_ERR_BAD_CERT);
     150           0 :           break;
     151             : 
     152             :         case 2:
     153           0 :           import->result = gpg_error (GPG_ERR_MISSING_ISSUER_CERT);
     154           0 :           break;
     155             : 
     156             :         case 3:
     157           0 :           import->result = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
     158           0 :           break;
     159             :         }
     160           0 :       import->status = 0;
     161             :     }
     162             :   else
     163             :     {
     164          13 :       import->result = gpg_error (GPG_ERR_NO_ERROR);
     165          13 :       import->status = nr;
     166             :     }
     167             : 
     168          39 :   while (*args == ' ')
     169          13 :     args++;
     170          13 :   tail = strchr (args, ' ');
     171          13 :   if (tail)
     172           0 :     *tail = '\0';
     173             : 
     174          13 :   import->fpr = strdup (args);
     175          13 :   if (!import->fpr)
     176             :     {
     177           0 :       free (import);
     178           0 :       return gpg_error_from_syserror ();
     179             :     }
     180             : 
     181          13 :   *import_status = import;
     182          13 :   return 0;
     183             : }
     184             : 
     185             : 
     186             : 
     187             : gpgme_error_t
     188           8 : parse_import_res (char *args, gpgme_import_result_t result)
     189             : {
     190             :   char *tail;
     191             : 
     192           8 :   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           8 :   PARSE_NEXT (result->considered);
     202           8 :   PARSE_NEXT (result->no_user_id);
     203           8 :   PARSE_NEXT (result->imported);
     204           8 :   PARSE_NEXT (result->imported_rsa);
     205           8 :   PARSE_NEXT (result->unchanged);
     206           8 :   PARSE_NEXT (result->new_user_ids);
     207           8 :   PARSE_NEXT (result->new_sub_keys);
     208           8 :   PARSE_NEXT (result->new_signatures);
     209           8 :   PARSE_NEXT (result->new_revocations);
     210           8 :   PARSE_NEXT (result->secret_read);
     211           8 :   PARSE_NEXT (result->secret_imported);
     212           8 :   PARSE_NEXT (result->secret_unchanged);
     213           8 :   PARSE_NEXT (result->skipped_new_keys);
     214           8 :   PARSE_NEXT (result->not_imported);
     215             : 
     216           6 :   return 0;
     217             : }
     218             : 
     219             : 
     220             : static gpgme_error_t
     221          45 : import_status_handler (void *priv, gpgme_status_code_t code, char *args)
     222             : {
     223          45 :   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
     224             :   gpgme_error_t err;
     225             :   void *hook;
     226             :   op_data_t opd;
     227             : 
     228          45 :   err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, &hook, -1, NULL);
     229          45 :   opd = hook;
     230          45 :   if (err)
     231           0 :     return err;
     232             : 
     233          45 :   switch (code)
     234             :     {
     235             :     case GPGME_STATUS_IMPORT_OK:
     236             :     case GPGME_STATUS_IMPORT_PROBLEM:
     237          13 :       err = parse_import (args, opd->lastp,
     238             :                           code == GPGME_STATUS_IMPORT_OK ? 0 : 1);
     239          13 :       if (err)
     240           0 :         return err;
     241             : 
     242          13 :       opd->lastp = &(*opd->lastp)->next;
     243          13 :       break;
     244             : 
     245             :     case GPGME_STATUS_IMPORT_RES:
     246           8 :       err = parse_import_res (args, &opd->result);
     247           8 :       break;
     248             : 
     249             :     default:
     250          24 :       break;
     251             :     }
     252          45 :   return 0;
     253             : }
     254             : 
     255             : 
     256             : static gpgme_error_t
     257           8 : _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           8 :   err = _gpgme_op_reset (ctx, synchronous);
     264           8 :   if (err)
     265           0 :     return err;
     266             : 
     267           8 :   err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, &hook,
     268             :                                sizeof (*opd), release_op_data);
     269           8 :   opd = hook;
     270           8 :   if (err)
     271           0 :     return err;
     272           8 :   opd->lastp = &opd->result.imports;
     273             : 
     274           8 :   if (!keydata)
     275           0 :     return gpg_error (GPG_ERR_NO_DATA);
     276             : 
     277           8 :   _gpgme_engine_set_status_handler (ctx->engine, import_status_handler, ctx);
     278             : 
     279           8 :   return _gpgme_engine_op_import (ctx->engine, keydata, NULL);
     280             : }
     281             : 
     282             : 
     283             : gpgme_error_t
     284           0 : gpgme_op_import_start (gpgme_ctx_t ctx, gpgme_data_t keydata)
     285             : {
     286             :   gpg_error_t err;
     287             : 
     288           0 :   TRACE_BEG1 (DEBUG_CTX, "gpgme_op_import_start", ctx,
     289             :               "keydata=%p", keydata);
     290             : 
     291           0 :   if (!ctx)
     292           0 :     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
     293             : 
     294           0 :   err = _gpgme_op_import_start (ctx, 0, keydata);
     295           0 :   return TRACE_ERR (err);
     296             : }
     297             : 
     298             : 
     299             : /* Import the key in KEYDATA into the keyring.  */
     300             : gpgme_error_t
     301           8 : gpgme_op_import (gpgme_ctx_t ctx, gpgme_data_t keydata)
     302             : {
     303             :   gpgme_error_t err;
     304             : 
     305           8 :   TRACE_BEG1 (DEBUG_CTX, "gpgme_op_import", ctx,
     306             :               "keydata=%p", keydata);
     307             : 
     308           8 :   if (!ctx)
     309           0 :     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
     310             : 
     311           8 :   err = _gpgme_op_import_start (ctx, 1, keydata);
     312           8 :   if (!err)
     313           8 :     err = _gpgme_wait_one (ctx);
     314           8 :   return TRACE_ERR (err);
     315             : }
     316             : 
     317             : 
     318             : 
     319             : static gpgme_error_t
     320           0 : _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           0 :   err = _gpgme_op_reset (ctx, synchronous);
     329           0 :   if (err)
     330           0 :     return err;
     331             : 
     332           0 :   err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, &hook,
     333             :                                sizeof (*opd), release_op_data);
     334           0 :   opd = hook;
     335           0 :   if (err)
     336           0 :     return err;
     337           0 :   opd->lastp = &opd->result.imports;
     338             : 
     339           0 :   if (!keys)
     340           0 :     return gpg_error (GPG_ERR_NO_DATA);
     341             : 
     342           0 :   for (idx=nkeys=0, firstidx=-1; keys[idx]; idx++)
     343             :     {
     344             :       /* We only consider keys of the current protocol.  */
     345           0 :       if (keys[idx]->protocol != ctx->protocol)
     346           0 :         continue;
     347           0 :       if (firstidx == -1)
     348           0 :         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           0 :       if (keys[idx]->keylist_mode != keys[firstidx]->keylist_mode)
     354           0 :         return gpg_error (GPG_ERR_CONFLICT);
     355           0 :       nkeys++;
     356             :     }
     357           0 :   if (!nkeys)
     358           0 :     return gpg_error (GPG_ERR_NO_DATA);
     359             : 
     360           0 :   _gpgme_engine_set_status_handler (ctx->engine, import_status_handler, ctx);
     361             : 
     362           0 :   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           0 : gpgme_op_import_keys_start (gpgme_ctx_t ctx, gpgme_key_t *keys)
     369             : {
     370             :   gpg_error_t err;
     371             : 
     372           0 :   TRACE_BEG (DEBUG_CTX, "gpgme_op_import_keys_start", ctx);
     373             : 
     374           0 :   if (!ctx)
     375           0 :     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
     376             : 
     377           0 :   if (_gpgme_debug_trace () && keys)
     378             :     {
     379           0 :       int i = 0;
     380             : 
     381           0 :       while (keys[i])
     382             :         {
     383           0 :           TRACE_LOG3 ("keys[%i] = %p (%s)", i, keys[i],
     384             :                       (keys[i]->subkeys && keys[i]->subkeys->fpr) ?
     385             :                       keys[i]->subkeys->fpr : "invalid");
     386           0 :           i++;
     387             :         }
     388             :     }
     389             : 
     390           0 :   err = _gpgme_op_import_keys_start (ctx, 0, keys);
     391           0 :   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           0 : gpgme_op_import_keys (gpgme_ctx_t ctx, gpgme_key_t *keys)
     408             : {
     409             :   gpgme_error_t err;
     410             : 
     411           0 :   TRACE_BEG (DEBUG_CTX, "gpgme_op_import_keys", ctx);
     412             : 
     413           0 :   if (!ctx)
     414           0 :     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
     415             : 
     416           0 :   if (_gpgme_debug_trace () && keys)
     417             :     {
     418           0 :       int i = 0;
     419             : 
     420           0 :       while (keys[i])
     421             :         {
     422           0 :           TRACE_LOG3 ("keys[%i] = %p (%s)", i, keys[i],
     423             :                       (keys[i]->subkeys && keys[i]->subkeys->fpr) ?
     424             :                       keys[i]->subkeys->fpr : "invalid");
     425           0 :           i++;
     426             :         }
     427             :     }
     428             : 
     429           0 :   err = _gpgme_op_import_keys_start (ctx, 1, keys);
     430           0 :   if (!err)
     431           0 :     err = _gpgme_wait_one (ctx);
     432           0 :   return TRACE_ERR (err);
     433             : }
     434             : 
     435             : 
     436             : /* Deprecated interface.  */
     437             : gpgme_error_t
     438           0 : gpgme_op_import_ext (gpgme_ctx_t ctx, gpgme_data_t keydata, int *nr)
     439             : {
     440           0 :   gpgme_error_t err = gpgme_op_import (ctx, keydata);
     441           0 :   if (!err && nr)
     442             :     {
     443           0 :       gpgme_import_result_t result = gpgme_op_import_result (ctx);
     444           0 :       *nr = result->considered;
     445             :     }
     446           0 :   return err;
     447             : }

Generated by: LCOV version 1.11