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

Generated by: LCOV version 1.11