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

Generated by: LCOV version 1.13