LCOV - code coverage report
Current view: top level - src - keylist.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 413 576 71.7 %
Date: 2016-12-01 18:45:36 Functions: 18 19 94.7 %

          Line data    Source code
       1             : /* keylist.c - Listing keys.
       2             :    Copyright (C) 2000 Werner Koch (dd9jn)
       3             :    Copyright (C) 2001, 2002, 2003, 2004, 2006, 2007,
       4             :                  2008, 2009  g10 Code GmbH
       5             : 
       6             :    This file is part of GPGME.
       7             : 
       8             :    GPGME is free software; you can redistribute it and/or modify it
       9             :    under the terms of the GNU Lesser General Public License as
      10             :    published by the Free Software Foundation; either version 2.1 of
      11             :    the License, or (at your option) any later version.
      12             : 
      13             :    GPGME is distributed in the hope that it will be useful, but
      14             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :    Lesser General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU Lesser General Public
      19             :    License along with this program; if not, see <https://www.gnu.org/licenses/>.
      20             :  */
      21             : 
      22             : #if HAVE_CONFIG_H
      23             : #include <config.h>
      24             : #endif
      25             : #include <stdio.h>
      26             : #include <stdlib.h>
      27             : #include <string.h>
      28             : #ifdef HAVE_SYS_TYPES_H
      29             :   /* Solaris 8 needs sys/types.h before time.h.  */
      30             : # include <sys/types.h>
      31             : #endif
      32             : #include <time.h>
      33             : #include <assert.h>
      34             : #include <ctype.h>
      35             : #include <errno.h>
      36             : #include <limits.h>
      37             : 
      38             : /* Suppress warning for accessing deprecated member "class".  */
      39             : #define _GPGME_IN_GPGME
      40             : #include "gpgme.h"
      41             : #include "util.h"
      42             : #include "context.h"
      43             : #include "ops.h"
      44             : #include "debug.h"
      45             : 
      46             : 
      47             : struct key_queue_item_s
      48             : {
      49             :   struct key_queue_item_s *next;
      50             :   gpgme_key_t key;
      51             : };
      52             : 
      53             : typedef struct
      54             : {
      55             :   struct _gpgme_op_keylist_result result;
      56             : 
      57             :   /* The error code from ERROR keydb_search. */
      58             :   gpgme_error_t keydb_search_err;
      59             : 
      60             :   gpgme_key_t tmp_key;
      61             : 
      62             :   /* This points to the last uid in tmp_key.  */
      63             :   gpgme_user_id_t tmp_uid;
      64             : 
      65             :   /* This points to the last sig in tmp_uid.  */
      66             :   gpgme_key_sig_t tmp_keysig;
      67             : 
      68             :   /* Something new is available.  */
      69             :   int key_cond;
      70             :   struct key_queue_item_s *key_queue;
      71             : } *op_data_t;
      72             : 
      73             : 
      74             : static void
      75         294 : release_op_data (void *hook)
      76             : {
      77         294 :   op_data_t opd = (op_data_t) hook;
      78         294 :   struct key_queue_item_s *key = opd->key_queue;
      79             : 
      80         294 :   if (opd->tmp_key)
      81           6 :     gpgme_key_unref (opd->tmp_key);
      82             : 
      83             :   /* opd->tmp_uid and opd->tmp_keysig are actually part of opd->tmp_key,
      84             :      so we do not need to release them here.  */
      85             : 
      86         592 :   while (key)
      87             :     {
      88           4 :       struct key_queue_item_s *next = key->next;
      89             : 
      90           4 :       gpgme_key_unref (key->key);
      91           4 :       key = next;
      92             :     }
      93         294 : }
      94             : 
      95             : 
      96             : gpgme_keylist_result_t
      97          19 : gpgme_op_keylist_result (gpgme_ctx_t ctx)
      98             : {
      99             :   void *hook;
     100             :   op_data_t opd;
     101             :   gpgme_error_t err;
     102             : 
     103          19 :   TRACE_BEG (DEBUG_CTX, "gpgme_op_keylist_result", ctx);
     104             : 
     105          19 :   err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
     106          19 :   opd = hook;
     107          19 :   if (err || !opd)
     108             :     {
     109           0 :       TRACE_SUC0 ("result=(null)");
     110           0 :       return NULL;
     111             :     }
     112             : 
     113          19 :   TRACE_LOG1 ("truncated = %i", opd->result.truncated);
     114             : 
     115          19 :   TRACE_SUC1 ("result=%p", &opd->result);
     116          19 :   return &opd->result;
     117             : }
     118             : 
     119             : 
     120             : static gpgme_error_t
     121         647 : keylist_status_handler (void *priv, gpgme_status_code_t code, char *args)
     122             : {
     123         647 :   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
     124             :   gpgme_error_t err;
     125             :   void *hook;
     126             :   op_data_t opd;
     127             : 
     128             :   (void)args;
     129             : 
     130         647 :   err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
     131         648 :   opd = hook;
     132         648 :   if (err)
     133           0 :     return err;
     134             : 
     135         648 :   switch (code)
     136             :     {
     137             :     case GPGME_STATUS_TRUNCATED:
     138           0 :       opd->result.truncated = 1;
     139           0 :       break;
     140             : 
     141             :     case GPGME_STATUS_ERROR:
     142           0 :       err = _gpgme_parse_failure (args);
     143           0 :       if (!opd->keydb_search_err && !strcmp (args, "keydb_search"))
     144           0 :         opd->keydb_search_err = err;
     145           0 :       err = 0;
     146           0 :       break;
     147             : 
     148             :     default:
     149         648 :       break;
     150             :     }
     151         648 :   return err;
     152             : }
     153             : 
     154             : 
     155             : static void
     156        8588 : set_subkey_trust_info (gpgme_subkey_t subkey, const char *src)
     157             : {
     158       25764 :   while (*src && !isdigit (*src))
     159             :     {
     160        8588 :       switch (*src)
     161             :         {
     162             :         case 'e':
     163         312 :           subkey->expired = 1;
     164         312 :           break;
     165             : 
     166             :         case 'r':
     167           0 :           subkey->revoked = 1;
     168           0 :           break;
     169             : 
     170             :         case 'd':
     171             :           /* Note that gpg 1.3 won't print that anymore but only uses
     172             :              the capabilities field. */
     173           0 :           subkey->disabled = 1;
     174           0 :           break;
     175             : 
     176             :         case 'i':
     177           0 :           subkey->invalid = 1;
     178           0 :           break;
     179             :         }
     180        8588 :       src++;
     181             :     }
     182        8593 : }
     183             : 
     184             : 
     185             : static void
     186        3118 : set_mainkey_trust_info (gpgme_key_t key, const char *src)
     187             : {
     188             :   /* First set the trust info of the main key (the first subkey).  */
     189        3118 :   set_subkey_trust_info (key->subkeys, src);
     190             : 
     191             :   /* Now set the summarized trust info.  */
     192       12453 :   while (*src && !isdigit (*src))
     193             :     {
     194        4149 :       switch (*src)
     195             :         {
     196             :         case 'e':
     197           0 :           key->expired = 1;
     198           0 :           break;
     199             : 
     200             :         case 'r':
     201           0 :           key->revoked = 1;
     202           0 :           break;
     203             : 
     204             :         case 'd':
     205             :           /* Note that gpg 1.3 won't print that anymore but only uses
     206             :              the capabilities field.  However, it is still used for
     207             :              external key listings.  */
     208           0 :           key->disabled = 1;
     209           0 :           break;
     210             : 
     211             :         case 'i':
     212           0 :           key->invalid = 1;
     213           0 :           break;
     214             :         }
     215        4149 :       src++;
     216             :     }
     217        4150 : }
     218             : 
     219             : 
     220             : static void
     221        5196 : set_userid_flags (gpgme_key_t key, const char *src)
     222             : {
     223        5196 :   gpgme_user_id_t uid = key->_last_uid;
     224             : 
     225        5196 :   assert (uid);
     226             :   /* Look at letters and stop at the first digit.  */
     227       15587 :   while (*src && !isdigit (*src))
     228             :     {
     229        5195 :       switch (*src)
     230             :         {
     231             :         case 'r':
     232           0 :           uid->revoked = 1;
     233           0 :           break;
     234             : 
     235             :         case 'i':
     236           0 :           uid->invalid = 1;
     237           0 :           break;
     238             : 
     239             :         case 'n':
     240           6 :           uid->validity = GPGME_VALIDITY_NEVER;
     241           6 :           break;
     242             : 
     243             :         case 'm':
     244          10 :           uid->validity = GPGME_VALIDITY_MARGINAL;
     245          10 :           break;
     246             : 
     247             :         case 'f':
     248           2 :           uid->validity = GPGME_VALIDITY_FULL;
     249           2 :           break;
     250             : 
     251             :         case 'u':
     252          98 :           uid->validity = GPGME_VALIDITY_ULTIMATE;
     253          98 :           break;
     254             :         }
     255        5195 :       src++;
     256             :     }
     257        5195 : }
     258             : 
     259             : 
     260             : static void
     261        2192 : set_subkey_capability (gpgme_subkey_t subkey, const char *src)
     262             : {
     263       37784 :   while (*src)
     264             :     {
     265       33400 :       switch (*src)
     266             :         {
     267             :         case 'e':
     268        4306 :           subkey->can_encrypt = 1;
     269        4306 :           break;
     270             : 
     271             :         case 's':
     272        4289 :           subkey->can_sign = 1;
     273        4289 :           break;
     274             : 
     275             :         case 'c':
     276        4150 :           subkey->can_certify = 1;
     277        4150 :           break;
     278             : 
     279             :         case 'a':
     280        4126 :           subkey->can_authenticate = 1;
     281        4126 :           break;
     282             : 
     283             :         case 'q':
     284           0 :           subkey->is_qualified = 1;
     285           0 :           break;
     286             : 
     287             :         case 'd':
     288           0 :           subkey->disabled = 1;
     289           0 :           break;
     290             :         }
     291       33400 :       src++;
     292             :     }
     293        2192 : }
     294             : 
     295             : 
     296             : static void
     297        4148 : set_mainkey_capability (gpgme_key_t key, const char *src)
     298             : {
     299             :   /* First set the capabilities of the main key (the first subkey).  */
     300        4148 :   set_subkey_capability (key->subkeys, src);
     301             : 
     302       37265 :   while (*src)
     303             :     {
     304       28961 :       switch (*src)
     305             :         {
     306             :         case 'd':
     307             :         case 'D':
     308             :           /* Note, that this flag is also set using the key validity
     309             :              field for backward compatibility with gpg 1.2.  We use d
     310             :              and D, so that a future gpg version will be able to
     311             :              disable certain subkeys. Currently it is expected that
     312             :              gpg sets this for the primary key. */
     313           0 :           key->disabled = 1;
     314           0 :           break;
     315             : 
     316             :         case 'e':
     317             :         case 'E':
     318        4158 :           key->can_encrypt = 1;
     319        4158 :           break;
     320             : 
     321             :         case 's':
     322             :         case 'S':
     323        8269 :           key->can_sign = 1;
     324        8269 :           break;
     325             : 
     326             :         case 'c':
     327             :         case 'C':
     328        8304 :           key->can_certify = 1;
     329        8304 :           break;
     330             : 
     331             :         case 'a':
     332             :         case 'A':
     333        8246 :           key->can_authenticate = 1;
     334        8246 :           break;
     335             : 
     336             :         case 'q':
     337             :         case 'Q':
     338           0 :           key->is_qualified = 1;
     339           0 :           break;
     340             :         }
     341       28961 :       src++;
     342             :     }
     343        4152 : }
     344             : 
     345             : 
     346             : static void
     347        4151 : set_ownertrust (gpgme_key_t key, const char *src)
     348             : {
     349             :   /* Look at letters and stop at the first digit.  */
     350       12447 :   while (*src && !isdigit (*src))
     351             :     {
     352        4145 :       switch (*src)
     353             :         {
     354             :         case 'n':
     355           0 :           key->owner_trust = GPGME_VALIDITY_NEVER;
     356           0 :           break;
     357             : 
     358             :         case 'm':
     359           0 :           key->owner_trust = GPGME_VALIDITY_MARGINAL;
     360           0 :           break;
     361             : 
     362             :         case 'f':
     363           0 :           key->owner_trust = GPGME_VALIDITY_FULL;
     364           0 :           break;
     365             : 
     366             :         case 'u':
     367          36 :           key->owner_trust = GPGME_VALIDITY_ULTIMATE;
     368          36 :           break;
     369             : 
     370             :         default:
     371        4109 :           key->owner_trust = GPGME_VALIDITY_UNKNOWN;
     372        4109 :           break;
     373             :         }
     374        4145 :       src++;
     375             :     }
     376        4152 : }
     377             : 
     378             : 
     379             : /* Parse field 15 of a secret key or subkey.  This fields holds a
     380             :    reference to smartcards.  FIELD is the content of the field and we
     381             :    are allowed to modify it.  */
     382             : static gpg_error_t
     383          42 : parse_sec_field15 (gpgme_key_t key, gpgme_subkey_t subkey, char *field)
     384             : {
     385          42 :   if (!*field)
     386             :     ; /* Empty.  */
     387          14 :   else if (*field == '#')
     388             :     {
     389             :       /* This is a stub for an offline key.  We reset the SECRET flag
     390             :          of the subkey here.  Note that the secret flag of the entire
     391             :          key will be true even then.  We even explicitly set
     392             :          key->secret to make it works for GPGME_KEYLIST_MODE_WITH_SECRET. */
     393           0 :       subkey->secret = 0;
     394           0 :       key->secret = 1;
     395             :     }
     396          14 :   else if (strchr ("01234567890ABCDEFabcdef", *field))
     397             :     {
     398             :       /* Fields starts with a hex digit; thus it is a serial number.  */
     399           0 :       key->secret = 1;
     400           0 :       subkey->is_cardkey = 1;
     401           0 :       subkey->card_number = strdup (field);
     402           0 :       if (!subkey->card_number)
     403           0 :         return gpg_error_from_syserror ();
     404             :     }
     405          14 :   else if (*field == '+')
     406             :     {
     407          14 :       key->secret = 1;
     408          14 :       subkey->secret = 1;
     409             :     }
     410             :   else
     411             :     {
     412             :       /* RFU.  */
     413             :     }
     414             : 
     415          42 :   return 0;
     416             : }
     417             : 
     418             : 
     419             : /* Parse a tfs record.  */
     420             : static gpg_error_t
     421          13 : parse_tfs_record (gpgme_user_id_t uid, char **field, int nfield)
     422             : {
     423             :   gpg_error_t err;
     424             :   gpgme_tofu_info_t ti;
     425             :   unsigned long uval;
     426             : 
     427             :   /* We add only the first TOFU record in case future versions emit
     428             :    * several.  */
     429          13 :   if (uid->tofu)
     430           0 :     return 0;
     431             : 
     432             :   /* Check that we have enough fields and that the version is supported.  */
     433          13 :   if (nfield < 8 || atoi(field[1]) != 1)
     434           0 :     return trace_gpg_error (GPG_ERR_INV_ENGINE);
     435             : 
     436          13 :   ti = calloc (1, sizeof *ti);
     437          13 :   if (!ti)
     438           0 :     return gpg_error_from_syserror ();
     439             : 
     440             :   /* Note that we allow a value of up to 7 which is what we can store
     441             :    * in the ti->validity.  */
     442          13 :   err = _gpgme_strtoul_field (field[2], &uval);
     443          13 :   if (err || uval > 7)
     444             :     goto inv_engine;
     445          13 :   ti->validity = uval;
     446             : 
     447             :   /* Parse the sign-count.  */
     448          13 :   err = _gpgme_strtoul_field (field[3], &uval);
     449          13 :   if (err)
     450           0 :     goto inv_engine;
     451          13 :   if (uval > USHRT_MAX)
     452           0 :     uval = USHRT_MAX;
     453          13 :   ti->signcount = uval;
     454             : 
     455             :   /* Parse the encr-count.  */
     456          13 :   err = _gpgme_strtoul_field (field[4], &uval);
     457          13 :   if (err)
     458           0 :     goto inv_engine;
     459          13 :   if (uval > USHRT_MAX)
     460           0 :     uval = USHRT_MAX;
     461          13 :   ti->encrcount = uval;
     462             : 
     463             :   /* Parse the policy.  */
     464          13 :   if (!strcmp (field[5], "none"))
     465           0 :     ti->policy = GPGME_TOFU_POLICY_NONE;
     466          13 :   else if (!strcmp (field[5], "auto"))
     467           9 :     ti->policy = GPGME_TOFU_POLICY_AUTO;
     468           4 :   else if (!strcmp (field[5], "good"))
     469           2 :     ti->policy = GPGME_TOFU_POLICY_GOOD;
     470           2 :   else if (!strcmp (field[5], "bad"))
     471           2 :     ti->policy = GPGME_TOFU_POLICY_BAD;
     472           0 :   else if (!strcmp (field[5], "ask"))
     473           0 :     ti->policy = GPGME_TOFU_POLICY_ASK;
     474             :   else /* "unknown" and invalid policy strings.  */
     475           0 :     ti->policy = GPGME_TOFU_POLICY_UNKNOWN;
     476             : 
     477             :   /* Parse first and last seen timestamps.  */
     478          13 :   err = _gpgme_strtoul_field (field[6], &uval);
     479          13 :   if (err)
     480           0 :     goto inv_engine;
     481          13 :   ti->signfirst = uval;
     482          13 :   err = _gpgme_strtoul_field (field[7], &uval);
     483          13 :   if (err)
     484           0 :     goto inv_engine;
     485          13 :   ti->signlast = uval;
     486             : 
     487          13 :   if (nfield > 9)
     488             :     {
     489             :       /* This condition is only to allow for gpg 2.1.15 - can
     490             :        * eventually be removed.  */
     491          13 :       err = _gpgme_strtoul_field (field[8], &uval);
     492          13 :       if (err)
     493           0 :         goto inv_engine;
     494          13 :       ti->encrfirst = uval;
     495          13 :       err = _gpgme_strtoul_field (field[9], &uval);
     496          13 :       if (err)
     497           0 :         goto inv_engine;
     498          13 :       ti->encrlast = uval;
     499             :     }
     500             : 
     501             :   /* Ready.  */
     502          13 :   uid->tofu = ti;
     503          13 :   return 0;
     504             : 
     505             :  inv_engine:
     506           0 :   free (ti);
     507           0 :   return trace_gpg_error (GPG_ERR_INV_ENGINE);
     508             : }
     509             : 
     510             : 
     511             : /* We have read an entire key into tmp_key and should now finish it.
     512             :    It is assumed that this releases tmp_key.  */
     513             : static void
     514        4445 : finish_key (gpgme_ctx_t ctx, op_data_t opd)
     515             : {
     516        4445 :   gpgme_key_t key = opd->tmp_key;
     517             : 
     518        4445 :   opd->tmp_key = NULL;
     519        4445 :   opd->tmp_uid = NULL;
     520        4445 :   opd->tmp_keysig = NULL;
     521             : 
     522        4445 :   if (key)
     523        4168 :     _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_NEXT_KEY, key);
     524        4433 : }
     525             : 
     526             : 
     527             : /* Note: We are allowed to modify LINE.  */
     528             : static gpgme_error_t
     529       23034 : keylist_colon_handler (void *priv, char *line)
     530             : {
     531       23034 :   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
     532             :   enum
     533             :     {
     534             :       RT_NONE, RT_SIG, RT_UID, RT_TFS, RT_SUB, RT_PUB, RT_FPR, RT_GRP,
     535             :       RT_SSB, RT_SEC, RT_CRT, RT_CRS, RT_REV, RT_SPK
     536             :     }
     537       23034 :   rectype = RT_NONE;
     538             : #define NR_FIELDS 17
     539             :   char *field[NR_FIELDS];
     540       23034 :   int fields = 0;
     541             :   void *hook;
     542             :   op_data_t opd;
     543             :   gpgme_error_t err;
     544             :   gpgme_key_t key;
     545       23034 :   gpgme_subkey_t subkey = NULL;
     546       23034 :   gpgme_key_sig_t keysig = NULL;
     547             : 
     548       23034 :   err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
     549       23041 :   opd = hook;
     550       23041 :   if (err)
     551           0 :     return err;
     552             : 
     553       23041 :   key = opd->tmp_key;
     554             : 
     555       23041 :   TRACE2 (DEBUG_CTX, "gpgme:keylist_colon_handler", ctx,
     556             :           "key = %p, line = %s", key, line ? line : "(null)");
     557             : 
     558       23044 :   if (!line)
     559             :     {
     560             :       /* End Of File.  */
     561         294 :       finish_key (ctx, opd);
     562         285 :       return 0;
     563             :     }
     564             : 
     565      109289 :   while (line && fields < NR_FIELDS)
     566             :     {
     567       63789 :       field[fields++] = line;
     568       63789 :       line = strchr (line, ':');
     569       63789 :       if (line)
     570       60714 :         *(line++) = '\0';
     571             :     }
     572             : 
     573       22750 :   if (!strcmp (field[0], "sig"))
     574          30 :     rectype = RT_SIG;
     575       22720 :   else if (!strcmp (field[0], "rev"))
     576           0 :     rectype = RT_REV;
     577       22720 :   else if (!strcmp (field[0], "pub"))
     578        4121 :     rectype = RT_PUB;
     579       18599 :   else if (!strcmp (field[0], "sec"))
     580          26 :     rectype = RT_SEC;
     581       18573 :   else if (!strcmp (field[0], "crt"))
     582           4 :     rectype = RT_CRT;
     583       18569 :   else if (!strcmp (field[0], "crs"))
     584           2 :     rectype = RT_CRS;
     585       18567 :   else if (!strcmp (field[0], "fpr") && key)
     586        8613 :     rectype = RT_FPR;
     587        9954 :   else if (!strcmp (field[0], "grp") && key)
     588          42 :     rectype = RT_GRP;
     589        9912 :   else if (!strcmp (field[0], "uid") && key)
     590        5202 :     rectype = RT_UID;
     591        4710 :   else if (!strcmp (field[0], "tfs") && key)
     592          13 :     rectype = RT_TFS;
     593        4697 :   else if (!strcmp (field[0], "sub") && key)
     594        4425 :     rectype = RT_SUB;
     595         272 :   else if (!strcmp (field[0], "ssb") && key)
     596          16 :     rectype = RT_SSB;
     597         256 :   else if (!strcmp (field[0], "spk") && key)
     598           0 :     rectype = RT_SPK;
     599             :   else
     600         256 :     rectype = RT_NONE;
     601             : 
     602             :   /* Only look at signature and trust info records immediately
     603             :      following a user ID.  For this, clear the user ID pointer when
     604             :      encountering anything but a signature or trust record.  */
     605       22750 :   if (rectype != RT_SIG && rectype != RT_REV && rectype != RT_TFS)
     606        6976 :     opd->tmp_uid = NULL;
     607             : 
     608             :   /* Only look at subpackets immediately following a signature.  For
     609             :      this, clear the signature pointer when encountering anything but
     610             :      a subpacket.  */
     611       22750 :   if (rectype != RT_SPK)
     612        7014 :     opd->tmp_keysig = NULL;
     613             : 
     614       22750 :   switch (rectype)
     615             :     {
     616             :     case RT_PUB:
     617             :     case RT_SEC:
     618             :     case RT_CRT:
     619             :     case RT_CRS:
     620             :       /* Start a new keyblock.  */
     621        4155 :       err = _gpgme_key_new (&key);
     622        4151 :       if (err)
     623           0 :         return err;
     624        4151 :       key->keylist_mode = ctx->keylist_mode;
     625        4151 :       err = _gpgme_key_add_subkey (key, &subkey);
     626        4148 :       if (err)
     627             :         {
     628           0 :           gpgme_key_unref (key);
     629           0 :           return err;
     630             :         }
     631             : 
     632        4148 :       if (rectype == RT_SEC || rectype == RT_CRS)
     633          28 :         key->secret = subkey->secret = 1;
     634        4148 :       if (rectype == RT_CRT || rectype == RT_CRS)
     635           6 :         key->protocol = GPGME_PROTOCOL_CMS;
     636        4148 :       finish_key (ctx, opd);
     637        4146 :       opd->tmp_key = key;
     638             : 
     639             :       /* Field 2 has the trust info.  */
     640        4146 :       if (fields >= 2)
     641        4144 :         set_mainkey_trust_info (key, field[1]);
     642             : 
     643             :       /* Field 3 has the key length.  */
     644        4140 :       if (fields >= 3)
     645             :         {
     646        4144 :           int i = atoi (field[2]);
     647             :           /* Ignore invalid values.  */
     648        4138 :           if (i > 1)
     649        4142 :             subkey->length = i;
     650             :         }
     651             : 
     652             :       /* Field 4 has the public key algorithm.  */
     653        4134 :       if (fields >= 4)
     654             :         {
     655        4143 :           int i = atoi (field[3]);
     656        4145 :           if (i >= 1 && i < 128)
     657        4145 :             subkey->pubkey_algo = _gpgme_map_pk_algo (i, ctx->protocol);
     658             :         }
     659             : 
     660             :       /* Field 5 has the long keyid.  Allow short key IDs for the
     661             :          output of an external keyserver listing.  */
     662        4136 :       if (fields >= 5 && strlen (field[4]) <= DIM(subkey->_keyid) - 1)
     663        4139 :         strcpy (subkey->_keyid, field[4]);
     664             : 
     665             :       /* Field 6 has the timestamp (seconds).  */
     666        4136 :       if (fields >= 6)
     667        4138 :         subkey->timestamp = _gpgme_parse_timestamp (field[5], NULL);
     668             : 
     669             :       /* Field 7 has the expiration time (seconds).  */
     670        4140 :       if (fields >= 7)
     671        4142 :         subkey->expires = _gpgme_parse_timestamp (field[6], NULL);
     672             : 
     673             :       /* Field 8 has the X.509 serial number.  */
     674        4147 :       if (fields >= 8 && (rectype == RT_CRT || rectype == RT_CRS))
     675             :         {
     676           6 :           key->issuer_serial = strdup (field[7]);
     677           6 :           if (!key->issuer_serial)
     678           0 :             return gpg_error_from_syserror ();
     679             :         }
     680             : 
     681             :       /* Field 9 has the ownertrust.  */
     682        4147 :       if (fields >= 9)
     683        4147 :         set_ownertrust (key, field[8]);
     684             : 
     685             :       /* Field 10 is not used for gpg due to --fixed-list-mode option
     686             :          but GPGSM stores the issuer name.  */
     687        4146 :       if (fields >= 10 && (rectype == RT_CRT || rectype == RT_CRS))
     688           7 :         if (_gpgme_decode_c_string (field[9], &key->issuer_name, 0))
     689           0 :           return gpg_error (GPG_ERR_ENOMEM);    /* FIXME */
     690             : 
     691             :       /* Field 11 has the signature class.  */
     692             : 
     693             :       /* Field 12 has the capabilities.  */
     694        4145 :       if (fields >= 12)
     695        4144 :         set_mainkey_capability (key, field[11]);
     696             : 
     697             :       /* Field 15 carries special flags of a secret key.  */
     698        4147 :       if (fields >= 15
     699        4140 :           && (key->secret
     700        4115 :               || (ctx->keylist_mode & GPGME_KEYLIST_MODE_WITH_SECRET)))
     701             :         {
     702          25 :           err = parse_sec_field15 (key, subkey, field[14]);
     703          26 :           if (err)
     704           0 :             return err;
     705             :         }
     706             : 
     707             :       /* Field 17 has the curve name for ECC.  */
     708        4148 :       if (fields >= 17 && *field[16])
     709             :         {
     710           0 :           subkey->curve = strdup (field[16]);
     711           0 :           if (!subkey->curve)
     712           0 :             return gpg_error_from_syserror ();
     713             :         }
     714             : 
     715        4148 :       break;
     716             : 
     717             :     case RT_SUB:
     718             :     case RT_SSB:
     719             :       /* Start a new subkey.  */
     720        4441 :       err = _gpgme_key_add_subkey (key, &subkey);
     721        4432 :       if (err)
     722           0 :         return err;
     723             : 
     724        4432 :       if (rectype == RT_SSB)
     725          16 :         subkey->secret = 1;
     726             : 
     727             :       /* Field 2 has the trust info.  */
     728        4432 :       if (fields >= 2)
     729        4432 :         set_subkey_trust_info (subkey, field[1]);
     730             : 
     731             :       /* Field 3 has the key length.  */
     732        4439 :       if (fields >= 3)
     733             :         {
     734        4432 :           int i = atoi (field[2]);
     735             :           /* Ignore invalid values.  */
     736        4429 :           if (i > 1)
     737        4430 :             subkey->length = i;
     738             :         }
     739             : 
     740             :       /* Field 4 has the public key algorithm.  */
     741        4436 :       if (fields >= 4)
     742             :         {
     743        4432 :           int i = atoi (field[3]);
     744        4434 :           if (i >= 1 && i < 128)
     745        4435 :             subkey->pubkey_algo = _gpgme_map_pk_algo (i, ctx->protocol);
     746             :         }
     747             : 
     748             :       /* Field 5 has the long keyid.  */
     749        4436 :       if (fields >= 5 && strlen (field[4]) == DIM(subkey->_keyid) - 1)
     750        4429 :         strcpy (subkey->_keyid, field[4]);
     751             : 
     752             :       /* Field 6 has the timestamp (seconds).  */
     753        4436 :       if (fields >= 6)
     754        4431 :         subkey->timestamp = _gpgme_parse_timestamp (field[5], NULL);
     755             : 
     756             :       /* Field 7 has the expiration time (seconds).  */
     757        6463 :       if (fields >= 7)
     758        6459 :         subkey->expires = _gpgme_parse_timestamp (field[6], NULL);
     759             : 
     760             :       /* Field 8 is reserved (LID).  */
     761             :       /* Field 9 has the ownertrust.  */
     762             :       /* Field 10, the user ID, is n/a for a subkey.  */
     763             : 
     764             :       /* Field 11 has the signature class.  */
     765             : 
     766             :       /* Field 12 has the capabilities.  */
     767        6464 :       if (fields >= 12)
     768        6462 :         set_subkey_capability (subkey, field[11]);
     769             : 
     770             :       /* Field 15 carries special flags of a secret key. */
     771        4440 :       if (fields >= 15
     772        4438 :           && (key->secret
     773        4422 :               || (ctx->keylist_mode & GPGME_KEYLIST_MODE_WITH_SECRET)))
     774             :         {
     775          17 :           err = parse_sec_field15 (key, subkey, field[14]);
     776          16 :           if (err)
     777           0 :             return err;
     778             :         }
     779             : 
     780             :       /* Field 17 has the curve name for ECC.  */
     781        4439 :       if (fields >= 17 && *field[16])
     782             :         {
     783           0 :           subkey->curve = strdup (field[16]);
     784           0 :           if (!subkey->curve)
     785           0 :             return gpg_error_from_syserror ();
     786             :         }
     787             : 
     788        4439 :       break;
     789             : 
     790             :     case RT_UID:
     791             :       /* Field 2 has the trust info, and field 10 has the user ID.  */
     792        5207 :       if (fields >= 10)
     793             :         {
     794        5205 :           if (_gpgme_key_append_name (key, field[9], 1))
     795           0 :             return gpg_error (GPG_ERR_ENOMEM);  /* FIXME */
     796             :           else
     797             :             {
     798        5195 :               if (field[1])
     799        5195 :                 set_userid_flags (key, field[1]);
     800        5193 :               opd->tmp_uid = key->_last_uid;
     801             :             }
     802             :         }
     803        5195 :       break;
     804             : 
     805             :     case RT_TFS:
     806          13 :       if (opd->tmp_uid)
     807             :         {
     808          13 :           err = parse_tfs_record (opd->tmp_uid, field, fields);
     809          13 :           if (err)
     810           0 :             return err;
     811             :         }
     812          13 :       break;
     813             : 
     814             :     case RT_FPR:
     815             :       /* Field 10 has the fingerprint (take only the first one).  */
     816        8592 :       if (fields >= 10 && field[9] && *field[9])
     817             :         {
     818             :           /* Need to apply it to the last subkey because all subkeys
     819             :              do have fingerprints. */
     820        8617 :           subkey = key->_last_subkey;
     821        8617 :           if (!subkey->fpr)
     822             :             {
     823        8619 :               subkey->fpr = strdup (field[9]);
     824        8619 :               if (!subkey->fpr)
     825           0 :                 return gpg_error_from_syserror ();
     826             :             }
     827             :           /* If this is the first subkey, store the fingerprint also
     828             :              in the KEY object.  */
     829        8617 :           if (subkey == key->subkeys)
     830             :             {
     831        4152 :               if (key->fpr && strcmp (key->fpr, subkey->fpr))
     832             :                 {
     833             :                   /* FPR already set but mismatch: Should never happen.  */
     834           0 :                   return trace_gpg_error (GPG_ERR_INTERNAL);
     835             :                 }
     836        4152 :               if (!key->fpr)
     837             :                 {
     838        1271 :                   key->fpr = strdup (subkey->fpr);
     839        1271 :                   if (!key->fpr)
     840           0 :                     return gpg_error_from_syserror ();
     841             :                 }
     842             :             }
     843             :         }
     844             : 
     845             :       /* Field 13 has the gpgsm chain ID (take only the first one).  */
     846        8592 :       if (fields >= 13 && !key->chain_id && *field[12])
     847             :         {
     848           6 :           key->chain_id = strdup (field[12]);
     849           6 :           if (!key->chain_id)
     850           0 :             return gpg_error_from_syserror ();
     851             :         }
     852        8592 :       break;
     853             : 
     854             :     case RT_GRP:
     855             :       /* Field 10 has the keygrip.  */
     856          42 :       if (fields >= 10 && field[9] && *field[9])
     857             :         {
     858             :           /* Need to apply it to the last subkey because all subkeys
     859             :              have a keygrip. */
     860          42 :           subkey = key->_last_subkey;
     861          42 :           if (!subkey->keygrip)
     862             :             {
     863          42 :               subkey->keygrip = strdup (field[9]);
     864          42 :               if (!subkey->keygrip)
     865           0 :                 return gpg_error_from_syserror ();
     866             :             }
     867             :         }
     868          42 :       break;
     869             : 
     870             :     case RT_SIG:
     871             :     case RT_REV:
     872          30 :       if (!opd->tmp_uid)
     873           6 :         return 0;
     874             : 
     875             :       /* Start a new (revoked) signature.  */
     876          24 :       assert (opd->tmp_uid == key->_last_uid);
     877          24 :       keysig = _gpgme_key_add_sig (key, (fields >= 10) ? field[9] : NULL);
     878          24 :       if (!keysig)
     879           0 :         return gpg_error (GPG_ERR_ENOMEM);      /* FIXME */
     880             : 
     881             :       /* Field 2 has the calculated trust ('!', '-', '?', '%').  */
     882          24 :       if (fields >= 2)
     883          24 :         switch (field[1][0])
     884             :           {
     885             :           case '!':
     886          24 :             keysig->status = gpg_error (GPG_ERR_NO_ERROR);
     887          24 :             break;
     888             : 
     889             :           case '-':
     890           0 :             keysig->status = gpg_error (GPG_ERR_BAD_SIGNATURE);
     891           0 :             break;
     892             : 
     893             :           case '?':
     894           0 :             keysig->status = gpg_error (GPG_ERR_NO_PUBKEY);
     895           0 :             break;
     896             : 
     897             :           case '%':
     898           0 :             keysig->status = gpg_error (GPG_ERR_GENERAL);
     899           0 :             break;
     900             : 
     901             :           default:
     902           0 :             keysig->status = gpg_error (GPG_ERR_NO_ERROR);
     903           0 :             break;
     904             :           }
     905             : 
     906             :       /* Field 4 has the public key algorithm.  */
     907          24 :       if (fields >= 4)
     908             :         {
     909          24 :           int i = atoi (field[3]);
     910          24 :           if (i >= 1 && i < 128)
     911          24 :             keysig->pubkey_algo = _gpgme_map_pk_algo (i, ctx->protocol);
     912             :         }
     913             : 
     914             :       /* Field 5 has the long keyid.  */
     915          24 :       if (fields >= 5 && strlen (field[4]) == DIM(keysig->_keyid) - 1)
     916          24 :         strcpy (keysig->_keyid, field[4]);
     917             : 
     918             :       /* Field 6 has the timestamp (seconds).  */
     919          24 :       if (fields >= 6)
     920          24 :         keysig->timestamp = _gpgme_parse_timestamp (field[5], NULL);
     921             : 
     922             :       /* Field 7 has the expiration time (seconds).  */
     923          24 :       if (fields >= 7)
     924          24 :         keysig->expires = _gpgme_parse_timestamp (field[6], NULL);
     925             : 
     926             :       /* Field 11 has the signature class (eg, 0x30 means revoked).  */
     927          24 :       if (fields >= 11)
     928          24 :         if (field[10][0] && field[10][1])
     929             :           {
     930          24 :             int sig_class = _gpgme_hextobyte (field[10]);
     931          24 :             if (sig_class >= 0)
     932             :               {
     933          24 :                 keysig->sig_class = sig_class;
     934          24 :                 keysig->class = keysig->sig_class;
     935          24 :                 if (sig_class == 0x30)
     936           0 :                   keysig->revoked = 1;
     937             :               }
     938          24 :             if (field[10][2] == 'x')
     939          24 :               keysig->exportable = 1;
     940             :           }
     941             : 
     942          24 :       opd->tmp_keysig = keysig;
     943          24 :       break;
     944             : 
     945             :     case RT_SPK:
     946           0 :       if (!opd->tmp_keysig)
     947           0 :         return 0;
     948           0 :       assert (opd->tmp_keysig == key->_last_uid->_last_keysig);
     949             : 
     950           0 :       if (fields >= 4)
     951             :         {
     952             :           /* Field 2 has the subpacket type.  */
     953           0 :           int type = atoi (field[1]);
     954             : 
     955             :           /* Field 3 has the flags.  */
     956           0 :           int flags = atoi (field[2]);
     957             : 
     958             :           /* Field 4 has the length.  */
     959           0 :           int len = atoi (field[3]);
     960             : 
     961             :           /* Field 5 has the data.  */
     962           0 :           char *data = field[4];
     963             : 
     964             :           /* Type 20: Notation data.  */
     965             :           /* Type 26: Policy URL.  */
     966           0 :           if (type == 20 || type == 26)
     967             :             {
     968             :               gpgme_sig_notation_t notation;
     969             : 
     970          21 :               keysig = opd->tmp_keysig;
     971             : 
     972             :               /* At this time, any error is serious.  */
     973          21 :               err = _gpgme_parse_notation (&notation, type, flags, len, data);
     974           0 :               if (err)
     975           0 :                 return err;
     976             : 
     977             :               /* Add a new notation.  FIXME: Could be factored out.  */
     978           0 :               if (!keysig->notations)
     979           0 :                 keysig->notations = notation;
     980           0 :               if (keysig->_last_notation)
     981           0 :                 keysig->_last_notation->next = notation;
     982           0 :               keysig->_last_notation = notation;
     983             :             }
     984             :         }
     985             : 
     986             :     case RT_NONE:
     987             :       /* Unknown record.  */
     988         257 :       break;
     989             :     }
     990       22702 :   return 0;
     991             : }
     992             : 
     993             : 
     994             : void
     995        4160 : _gpgme_op_keylist_event_cb (void *data, gpgme_event_io_t type, void *type_data)
     996             : {
     997             :   gpgme_error_t err;
     998        4160 :   gpgme_ctx_t ctx = (gpgme_ctx_t) data;
     999        4160 :   gpgme_key_t key = (gpgme_key_t) type_data;
    1000             :   void *hook;
    1001             :   op_data_t opd;
    1002             :   struct key_queue_item_s *q, *q2;
    1003             : 
    1004        4160 :   assert (type == GPGME_EVENT_NEXT_KEY);
    1005             : 
    1006        4160 :   err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
    1007        4147 :   opd = hook;
    1008        4147 :   if (err)
    1009           0 :     return;
    1010             : 
    1011        4147 :   q = malloc (sizeof *q);
    1012        4147 :   if (!q)
    1013             :     {
    1014           0 :       gpgme_key_unref (key);
    1015             :       /* FIXME       return GPGME_Out_Of_Core; */
    1016           0 :       return;
    1017             :     }
    1018        4147 :   q->key = key;
    1019        4147 :   q->next = NULL;
    1020             :   /* FIXME: Use a tail pointer?  */
    1021        4147 :   if (!(q2 = opd->key_queue))
    1022        1767 :     opd->key_queue = q;
    1023             :   else
    1024             :     {
    1025        2380 :       for (; q2->next; q2 = q2->next)
    1026             :         ;
    1027        2380 :       q2->next = q;
    1028             :     }
    1029        4147 :   opd->key_cond = 1;
    1030             : }
    1031             : 
    1032             : 
    1033             : /* Start a keylist operation within CTX, searching for keys which
    1034             :    match PATTERN.  If SECRET_ONLY is true, only secret keys are
    1035             :    returned.  */
    1036             : gpgme_error_t
    1037         275 : gpgme_op_keylist_start (gpgme_ctx_t ctx, const char *pattern, int secret_only)
    1038             : {
    1039             :   gpgme_error_t err;
    1040             :   void *hook;
    1041             :   op_data_t opd;
    1042         275 :   int flags = 0;
    1043             : 
    1044         275 :   TRACE_BEG2 (DEBUG_CTX, "gpgme_op_keylist_start", ctx,
    1045             :               "pattern=%s, secret_only=%i", pattern, secret_only);
    1046             : 
    1047         277 :   if (!ctx)
    1048           0 :     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
    1049             : 
    1050         277 :   err = _gpgme_op_reset (ctx, 2);
    1051         274 :   if (err)
    1052           0 :     return TRACE_ERR (err);
    1053             : 
    1054         274 :   err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook,
    1055             :                                sizeof (*opd), release_op_data);
    1056         274 :   opd = hook;
    1057         274 :   if (err)
    1058           0 :     return TRACE_ERR (err);
    1059             : 
    1060         274 :   _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
    1061             : 
    1062         274 :   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
    1063             :                                               keylist_colon_handler, ctx);
    1064         274 :   if (err)
    1065           0 :     return TRACE_ERR (err);
    1066             : 
    1067         274 :   if (ctx->offline)
    1068           0 :     flags |= GPGME_ENGINE_FLAG_OFFLINE;
    1069             : 
    1070         274 :   err = _gpgme_engine_op_keylist (ctx->engine, pattern, secret_only,
    1071             :                                   ctx->keylist_mode, flags);
    1072         321 :   return TRACE_ERR (err);
    1073             : }
    1074             : 
    1075             : 
    1076             : /* Start a keylist operation within CTX, searching for keys which
    1077             :    match PATTERN.  If SECRET_ONLY is true, only secret keys are
    1078             :    returned.  */
    1079             : gpgme_error_t
    1080           0 : gpgme_op_keylist_ext_start (gpgme_ctx_t ctx, const char *pattern[],
    1081             :                             int secret_only, int reserved)
    1082             : {
    1083             :   gpgme_error_t err;
    1084             :   void *hook;
    1085             :   op_data_t opd;
    1086           0 :   int flags = 0;
    1087             : 
    1088           0 :   TRACE_BEG2 (DEBUG_CTX, "gpgme_op_keylist_ext_start", ctx,
    1089             :               "secret_only=%i, reserved=0x%x", secret_only, reserved);
    1090             : 
    1091           0 :   if (!ctx)
    1092           0 :     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
    1093             : 
    1094           0 :   err = _gpgme_op_reset (ctx, 2);
    1095           0 :   if (err)
    1096           0 :     return TRACE_ERR (err);
    1097             : 
    1098           0 :   err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook,
    1099             :                                sizeof (*opd), release_op_data);
    1100           0 :   opd = hook;
    1101           0 :   if (err)
    1102           0 :     return TRACE_ERR (err);
    1103             : 
    1104           0 :   _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
    1105           0 :   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
    1106             :                                               keylist_colon_handler, ctx);
    1107           0 :   if (err)
    1108           0 :     return TRACE_ERR (err);
    1109             : 
    1110           0 :   if (ctx->offline)
    1111           0 :     flags |= GPGME_ENGINE_FLAG_OFFLINE;
    1112             : 
    1113           0 :   err = _gpgme_engine_op_keylist_ext (ctx->engine, pattern, secret_only,
    1114             :                                       reserved, ctx->keylist_mode,
    1115             :                                       flags);
    1116           0 :   return TRACE_ERR (err);
    1117             : }
    1118             : 
    1119             : 
    1120             : /* Return the next key from the keylist in R_KEY.  */
    1121             : gpgme_error_t
    1122        4450 : gpgme_op_keylist_next (gpgme_ctx_t ctx, gpgme_key_t *r_key)
    1123             : {
    1124             :   gpgme_error_t err;
    1125             :   struct key_queue_item_s *queue_item;
    1126             :   void *hook;
    1127             :   op_data_t opd;
    1128             : 
    1129        4450 :   TRACE_BEG (DEBUG_CTX, "gpgme_op_keylist_next", ctx);
    1130             : 
    1131        4451 :   if (!ctx || !r_key)
    1132           0 :     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
    1133        4452 :   *r_key = NULL;
    1134        4452 :   if (!ctx)
    1135           0 :     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
    1136             : 
    1137        4452 :   err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
    1138        4454 :   opd = hook;
    1139        4454 :   if (err)
    1140           0 :     return TRACE_ERR (err);
    1141        4454 :   if (opd == NULL)
    1142           0 :     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
    1143             : 
    1144        4454 :   if (!opd->key_queue)
    1145             :     {
    1146        2082 :       err = _gpgme_wait_on_condition (ctx, &opd->key_cond, NULL);
    1147        2047 :       if (err)
    1148           0 :         return TRACE_ERR (err);
    1149             : 
    1150        2047 :       if (!opd->key_cond)
    1151         282 :         return TRACE_ERR (opd->keydb_search_err? opd->keydb_search_err
    1152             :                           /**/                 : gpg_error (GPG_ERR_EOF));
    1153             : 
    1154        1765 :       opd->key_cond = 0;
    1155        1765 :       assert (opd->key_queue);
    1156             :     }
    1157        4137 :   queue_item = opd->key_queue;
    1158        4137 :   opd->key_queue = queue_item->next;
    1159        4137 :   if (!opd->key_queue)
    1160        1762 :     opd->key_cond = 0;
    1161             : 
    1162        4137 :   *r_key = queue_item->key;
    1163        4137 :   free (queue_item);
    1164             : 
    1165        4137 :   return TRACE_SUC2 ("key=%p (%s)", *r_key,
    1166             :                      ((*r_key)->subkeys && (*r_key)->subkeys->fpr) ?
    1167             :                      (*r_key)->subkeys->fpr : "invalid");
    1168             : }
    1169             : 
    1170             : 
    1171             : /* Terminate a pending keylist operation within CTX.  */
    1172             : gpgme_error_t
    1173          23 : gpgme_op_keylist_end (gpgme_ctx_t ctx)
    1174             : {
    1175          23 :   TRACE (DEBUG_CTX, "gpgme_op_keylist_end", ctx);
    1176             : 
    1177          23 :   if (!ctx)
    1178           0 :     return gpg_error (GPG_ERR_INV_VALUE);
    1179             : 
    1180          23 :   return 0;
    1181             : }
    1182             : 
    1183             : 
    1184             : /* Get the key with the fingerprint FPR from the crypto backend.  If
    1185             :    SECRET is true, get the secret key.  */
    1186             : gpgme_error_t
    1187         117 : gpgme_get_key (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key,
    1188             :                int secret)
    1189             : {
    1190             :   gpgme_ctx_t listctx;
    1191             :   gpgme_error_t err;
    1192             :   gpgme_key_t key;
    1193             : 
    1194         117 :   TRACE_BEG2 (DEBUG_CTX, "gpgme_get_key", ctx,
    1195             :               "fpr=%s, secret=%i", fpr, secret);
    1196             : 
    1197         117 :   if (!ctx || !r_key || !fpr)
    1198           0 :     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
    1199             : 
    1200         117 :   if (strlen (fpr) < 8)      /* We have at least a key ID.  */
    1201           0 :     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
    1202             : 
    1203             :   /* FIXME: We use our own context because we have to avoid the user's
    1204             :      I/O callback handlers.  */
    1205         117 :   err = gpgme_new (&listctx);
    1206         117 :   if (err)
    1207           0 :     return TRACE_ERR (err);
    1208             :   {
    1209             :     gpgme_protocol_t proto;
    1210             :     gpgme_engine_info_t info;
    1211             : 
    1212             :     /* Clone the relevant state.  */
    1213         117 :     proto = gpgme_get_protocol (ctx);
    1214         117 :     gpgme_set_protocol (listctx, proto);
    1215         117 :     gpgme_set_keylist_mode (listctx, gpgme_get_keylist_mode (ctx));
    1216         117 :     info = gpgme_ctx_get_engine_info (ctx);
    1217         235 :     while (info && info->protocol != proto)
    1218           1 :       info = info->next;
    1219         117 :     if (info)
    1220         117 :       gpgme_ctx_set_engine_info (listctx, proto,
    1221         117 :                                  info->file_name, info->home_dir);
    1222             :   }
    1223             : 
    1224         117 :   err = gpgme_op_keylist_start (listctx, fpr, secret);
    1225         117 :   if (!err)
    1226         117 :     err = gpgme_op_keylist_next (listctx, r_key);
    1227         116 :   if (!err)
    1228             :     {
    1229             :     try_next_key:
    1230         112 :       err = gpgme_op_keylist_next (listctx, &key);
    1231         112 :       if (gpgme_err_code (err) == GPG_ERR_EOF)
    1232         112 :         err = 0;
    1233             :       else
    1234             :         {
    1235           0 :           if (!err
    1236           0 :               && *r_key && (*r_key)->subkeys && (*r_key)->subkeys->fpr
    1237           0 :               && key && key->subkeys && key->subkeys->fpr
    1238           0 :               && !strcmp ((*r_key)->subkeys->fpr, key->subkeys->fpr))
    1239             :             {
    1240             :               /* The fingerprint is identical.  We assume that this is
    1241             :                  the same key and don't mark it as an ambiguous.  This
    1242             :                  problem may occur with corrupted keyrings and has
    1243             :                  been noticed often with gpgsm.  In fact gpgsm uses a
    1244             :                  similar hack to sort out such duplicates but it can't
    1245             :                  do that while listing keys.  */
    1246           0 :               gpgme_key_unref (key);
    1247           0 :               goto try_next_key;
    1248             :             }
    1249           0 :           if (!err)
    1250             :             {
    1251           0 :               gpgme_key_unref (key);
    1252           0 :               err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
    1253             :             }
    1254           0 :           gpgme_key_unref (*r_key);
    1255             :         }
    1256             :     }
    1257         116 :   gpgme_release (listctx);
    1258         116 :   if (! err)
    1259             :     {
    1260         112 :       TRACE_LOG2 ("key=%p (%s)", *r_key,
    1261             :                   ((*r_key)->subkeys && (*r_key)->subkeys->fpr) ?
    1262             :                   (*r_key)->subkeys->fpr : "invalid");
    1263             :     }
    1264         116 :   return TRACE_ERR (err);
    1265             : }

Generated by: LCOV version 1.11