LCOV - code coverage report
Current view: top level - src - keylist.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 468 617 75.9 %
Date: 2018-11-15 08:49:49 Functions: 21 21 100.0 %

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

Generated by: LCOV version 1.13