LCOV - code coverage report
Current view: top level - src - engine-gpgconf.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 367 589 62.3 %
Date: 2018-11-14 16:53:58 Functions: 24 26 92.3 %

          Line data    Source code
       1             : /* engine-gpgconf.c - gpg-conf engine.
       2             :    Copyright (C) 2000 Werner Koch (dd9jn)
       3             :    Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2008,
       4             :                  2013 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             : 
      26             : #include <stdlib.h>
      27             : #include <string.h>
      28             : #ifdef HAVE_SYS_TYPES_H
      29             : # include <sys/types.h>
      30             : #endif
      31             : #include <assert.h>
      32             : #ifdef HAVE_UNISTD_H
      33             : # include <unistd.h>
      34             : #endif
      35             : #include <fcntl.h> /* FIXME */
      36             : #include <errno.h>
      37             : 
      38             : #include "gpgme.h"
      39             : #include "util.h"
      40             : #include "ops.h"
      41             : #include "wait.h"
      42             : #include "priv-io.h"
      43             : #include "sema.h"
      44             : 
      45             : #include "assuan.h"
      46             : #include "debug.h"
      47             : 
      48             : #include "engine-backend.h"
      49             : 
      50             : 
      51             : 
      52             : struct engine_gpgconf
      53             : {
      54             :   char *file_name;
      55             :   char *home_dir;
      56             :   char *version;
      57             : };
      58             : 
      59             : typedef struct engine_gpgconf *engine_gpgconf_t;
      60             : 
      61             : 
      62             : /* Return true if the engine's version is at least VERSION.  */
      63             : static int
      64           1 : have_gpgconf_version (engine_gpgconf_t gpgconf, const char *version)
      65             : {
      66           1 :   return _gpgme_compare_versions (gpgconf->version, version);
      67             : }
      68             : 
      69             : 
      70             : static char *
      71         100 : gpgconf_get_version (const char *file_name)
      72             : {
      73         100 :   return _gpgme_get_program_version (file_name ? file_name
      74             :                                      : _gpgme_get_default_gpgconf_name ());
      75             : }
      76             : 
      77             : 
      78             : static const char *
      79          98 : gpgconf_get_req_version (void)
      80             : {
      81          98 :   return "2.0.4";
      82             : }
      83             : 
      84             : 
      85             : static void
      86         198 : gpgconf_release (void *engine)
      87             : {
      88         198 :   engine_gpgconf_t gpgconf = engine;
      89             : 
      90         198 :   if (!gpgconf)
      91           0 :     return;
      92             : 
      93         198 :   if (gpgconf->file_name)
      94         198 :     free (gpgconf->file_name);
      95         198 :   if (gpgconf->home_dir)
      96           1 :     free (gpgconf->home_dir);
      97         198 :   if (gpgconf->version)
      98         198 :     free (gpgconf->version);
      99             : 
     100         198 :   free (gpgconf);
     101             : }
     102             : 
     103             : 
     104             : static gpgme_error_t
     105         198 : gpgconf_new (void **engine, const char *file_name, const char *home_dir,
     106             :              const char *version)
     107             : {
     108         198 :   gpgme_error_t err = 0;
     109             :   engine_gpgconf_t gpgconf;
     110             : 
     111         198 :   gpgconf = calloc (1, sizeof *gpgconf);
     112         198 :   if (!gpgconf)
     113           0 :     return gpg_error_from_syserror ();
     114             : 
     115         198 :   gpgconf->file_name = strdup (file_name ? file_name
     116             :                                : _gpgme_get_default_gpgconf_name ());
     117         198 :   if (!gpgconf->file_name)
     118           0 :     err = gpg_error_from_syserror ();
     119             : 
     120         198 :   if (!err && home_dir)
     121             :     {
     122           1 :       gpgconf->home_dir = strdup (home_dir);
     123           1 :       if (!gpgconf->home_dir)
     124           0 :         err = gpg_error_from_syserror ();
     125             :     }
     126             : 
     127         198 :   if (!err && version)
     128             :     {
     129         198 :       gpgconf->version = strdup (version);
     130         198 :       if (!gpgconf->version)
     131           0 :         err = gpg_error_from_syserror ();
     132             :     }
     133             : 
     134         198 :   if (err)
     135           0 :     gpgconf_release (gpgconf);
     136             :   else
     137         198 :     *engine = gpgconf;
     138             : 
     139         198 :   return err;
     140             : }
     141             : 
     142             : 
     143             : static void
     144       36769 : release_arg (gpgme_conf_arg_t arg, gpgme_conf_type_t alt_type)
     145             : {
     146       75989 :   while (arg)
     147             :     {
     148        2451 :       gpgme_conf_arg_t next = arg->next;
     149             : 
     150        2451 :       if (alt_type == GPGME_CONF_STRING)
     151        1243 :         free (arg->value.string);
     152        2451 :       free (arg);
     153        2451 :       arg = next;
     154             :     }
     155       36769 : }
     156             : 
     157             : 
     158             : static void
     159        5504 : release_opt (gpgme_conf_opt_t opt)
     160             : {
     161        5504 :   if (opt->name)
     162        5504 :     free (opt->name);
     163        5504 :   if (opt->description)
     164        4773 :     free (opt->description);
     165        5504 :   if (opt->argname)
     166        1806 :     free (opt->argname);
     167             : 
     168        5504 :   release_arg (opt->default_value, opt->alt_type);
     169        5504 :   if (opt->default_description)
     170           0 :     free (opt->default_description);
     171             : 
     172        5504 :   release_arg (opt->no_arg_value, opt->alt_type);
     173        5504 :   release_arg (opt->value, opt->alt_type);
     174        5504 :   release_arg (opt->new_value, opt->alt_type);
     175             : 
     176        5504 :   free (opt);
     177        5504 : }
     178             : 
     179             : 
     180             : static void
     181         258 : release_comp (gpgme_conf_comp_t comp)
     182             : {
     183             :   gpgme_conf_opt_t opt;
     184             : 
     185         258 :   if (comp->name)
     186         258 :     free (comp->name);
     187         258 :   if (comp->description)
     188         258 :     free (comp->description);
     189         258 :   if (comp->program_name)
     190         258 :     free (comp->program_name);
     191             : 
     192         258 :   opt = comp->options;
     193        6020 :   while (opt)
     194             :     {
     195        5504 :       gpgme_conf_opt_t next = opt->next;
     196        5504 :       release_opt (opt);
     197        5504 :       opt = next;
     198             :     }
     199             : 
     200         258 :   free (comp);
     201         258 : }
     202             : 
     203             : 
     204             : static void
     205         153 : gpgconf_config_release (gpgme_conf_comp_t conf)
     206             : {
     207         564 :   while (conf)
     208             :     {
     209         258 :       gpgme_conf_comp_t next = conf->next;
     210         258 :       release_comp (conf);
     211         258 :       conf = next;
     212             :     }
     213         153 : }
     214             : 
     215             : /* Read from gpgconf and pass line after line to the hook function.
     216             :    We put a limit of 64 k on the maximum size for a line.  This should
     217             :    allow for quite a long "group" line, which is usually the longest
     218             :    line (mine is currently ~3k).  */
     219             : static gpgme_error_t
     220         310 : gpgconf_read (void *engine, const char *arg1, char *arg2,
     221             :               gpgme_error_t (*cb) (void *hook, char *line),
     222             :               void *hook)
     223             : {
     224         310 :   struct engine_gpgconf *gpgconf = engine;
     225         310 :   gpgme_error_t err = 0;
     226             :   char *linebuf;
     227             :   size_t linebufsize;
     228             :   int linelen;
     229             :   char *argv[6];
     230         310 :   int argc = 0;
     231             :   int rp[2];
     232         310 :   struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
     233             :                                    {-1, -1} };
     234             :   int status;
     235             :   int nread;
     236         310 :   char *mark = NULL;
     237             : 
     238             :   /* _gpgme_engine_new guarantees that this is not NULL.  */
     239         310 :   argv[argc++] = gpgconf->file_name;
     240             : 
     241         310 :   if (gpgconf->home_dir && have_gpgconf_version (gpgconf, "2.1.13"))
     242             :     {
     243           1 :       argv[argc++] = (char*)"--homedir";
     244           1 :       argv[argc++] = gpgconf->home_dir;
     245             :     }
     246             : 
     247         310 :   argv[argc++] = (char*)arg1;
     248         310 :   argv[argc++] = arg2;
     249         310 :   argv[argc] = NULL;
     250         310 :   assert (argc < DIM (argv));
     251             : 
     252         310 :   if (_gpgme_io_pipe (rp, 1) < 0)
     253           0 :     return gpg_error_from_syserror ();
     254             : 
     255         310 :   cfd[0].fd = rp[1];
     256             : 
     257         310 :   status = _gpgme_io_spawn (gpgconf->file_name, argv,
     258             :                             IOSPAWN_FLAG_DETACHED, cfd, NULL, NULL, NULL);
     259         310 :   if (status < 0)
     260             :     {
     261           0 :       _gpgme_io_close (rp[0]);
     262           0 :       _gpgme_io_close (rp[1]);
     263           0 :       return gpg_error_from_syserror ();
     264             :     }
     265             : 
     266         310 :   linebufsize = 1024; /* Usually enough for conf lines.  */
     267         310 :   linebuf = malloc (linebufsize);
     268         310 :   if (!linebuf)
     269             :     {
     270           0 :       err = gpg_error_from_syserror ();
     271           0 :       goto leave;
     272             :     }
     273         310 :   linelen = 0;
     274             : 
     275        1104 :   while ((nread = _gpgme_io_read (rp[0], linebuf + linelen,
     276         794 :                                   linebufsize - linelen - 1)))
     277             :     {
     278             :       char *line;
     279         486 :       const char *lastmark = NULL;
     280             :       size_t nused;
     281             : 
     282         486 :       if (nread < 0)
     283             :         {
     284           0 :           err = gpg_error_from_syserror ();
     285           0 :           goto leave;
     286             :         }
     287             : 
     288         486 :       linelen += nread;
     289         486 :       linebuf[linelen] = '\0';
     290             : 
     291        6404 :       for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
     292             :         {
     293        5920 :           lastmark = mark;
     294        5920 :           if (mark > line && mark[-1] == '\r')
     295           0 :             mark[-1] = '\0';
     296             :           else
     297        5920 :             mark[0] = '\0';
     298             : 
     299             :           /* Got a full line.  Due to the CR removal code (which
     300             :              occurs only on Windows) we might be one-off and thus
     301             :              would see empty lines.  Don't pass them to the
     302             :              callback. */
     303        5920 :           err = *line? (*cb) (hook, line) : 0;
     304        5920 :           if (err)
     305           2 :             goto leave;
     306             :         }
     307             : 
     308         484 :       nused = lastmark? (lastmark + 1 - linebuf) : 0;
     309         484 :       memmove (linebuf, linebuf + nused, linelen - nused);
     310         484 :       linelen -= nused;
     311             : 
     312         484 :       if (!(linelen < linebufsize - 1))
     313             :         {
     314             :           char *newlinebuf;
     315             : 
     316           0 :           if (linelen <  8 * 1024 - 1)
     317           0 :             linebufsize = 8 * 1024;
     318           0 :           else if (linelen < 64 * 1024 - 1)
     319           0 :             linebufsize = 64 * 1024;
     320             :           else
     321             :             {
     322             :               /* We reached our limit - give up.  */
     323           0 :               err = gpg_error (GPG_ERR_LINE_TOO_LONG);
     324           0 :               goto leave;
     325             :             }
     326             : 
     327           0 :           newlinebuf = realloc (linebuf, linebufsize);
     328           0 :           if (!newlinebuf)
     329             :             {
     330           0 :               err = gpg_error_from_syserror ();
     331           0 :               goto leave;
     332             :             }
     333           0 :           linebuf = newlinebuf;
     334             :         }
     335             :     }
     336             : 
     337             :  leave:
     338         310 :   free (linebuf);
     339         310 :   _gpgme_io_close (rp[0]);
     340         310 :   return err;
     341             : }
     342             : 
     343             : 
     344             : static gpgme_error_t
     345         264 : gpgconf_config_load_cb (void *hook, char *line)
     346             : {
     347         264 :   gpgme_conf_comp_t *comp_p = hook;
     348         264 :   gpgme_conf_comp_t comp = *comp_p;
     349             : #define NR_FIELDS 16
     350             :   char *field[NR_FIELDS];
     351         264 :   int fields = 0;
     352             : 
     353        1320 :   while (line && fields < NR_FIELDS)
     354             :     {
     355         792 :       field[fields++] = line;
     356         792 :       line = strchr (line, ':');
     357         792 :       if (line)
     358         528 :         *(line++) = '\0';
     359             :     }
     360             : 
     361             :   /* We require at least the first 3 fields.  */
     362         264 :   if (fields < 2)
     363           0 :     return trace_gpg_error (GPG_ERR_INV_ENGINE);
     364             : 
     365             :   /* Find the pointer to the new component in the list.  */
     366         968 :   while (comp && comp->next)
     367         440 :     comp = comp->next;
     368         264 :   if (comp)
     369         220 :     comp_p = &comp->next;
     370             : 
     371         264 :   comp = calloc (1, sizeof (*comp));
     372         264 :   if (!comp)
     373           0 :     return gpg_error_from_syserror ();
     374             :   /* Prepare return value.  */
     375         264 :   comp->_last_opt_p = &comp->options;
     376         264 :   *comp_p = comp;
     377             : 
     378         264 :   comp->name = strdup (field[0]);
     379         264 :   if (!comp->name)
     380           0 :     return gpg_error_from_syserror ();
     381             : 
     382         264 :   comp->description = strdup (field[1]);
     383         264 :   if (!comp->description)
     384           0 :     return gpg_error_from_syserror ();
     385             : 
     386         264 :   if (fields >= 3)
     387             :     {
     388         264 :       comp->program_name = strdup (field[2]);
     389         264 :       if (!comp->program_name)
     390           0 :         return gpg_error_from_syserror ();
     391             :     }
     392             : 
     393         264 :   return 0;
     394             : }
     395             : 
     396             : 
     397             : static gpgme_error_t
     398       12584 : gpgconf_parse_option (gpgme_conf_opt_t opt,
     399             :                       gpgme_conf_arg_t *arg_p, char *line)
     400             : {
     401             :   gpgme_error_t err;
     402       12584 :   char *mark = NULL;
     403             : 
     404       12584 :   if (!line[0])
     405       11378 :     return 0;
     406             : 
     407        3618 :   while (line)
     408             :     {
     409             :       gpgme_conf_arg_t arg;
     410             : 
     411        1206 :       if (opt->type != GPGME_CONF_STRING)
     412         613 :         mark = strchr (line, ',');
     413        1206 :       if (mark)
     414           0 :         *mark = '\0';
     415             : 
     416        1206 :       arg = calloc (1, sizeof (*arg));
     417        1206 :       if (!arg)
     418           0 :         return gpg_error_from_syserror ();
     419        1206 :       *arg_p = arg;
     420        1206 :       arg_p = &arg->next;
     421             : 
     422        1206 :       if (*line == '\0')
     423           0 :         arg->no_arg = 1;
     424             :       else
     425             :         {
     426        1206 :           switch (opt->alt_type)
     427             :             {
     428             :               /* arg->value.count is an alias for arg->value.uint32.  */
     429             :             case GPGME_CONF_NONE:
     430             :             case GPGME_CONF_UINT32:
     431         525 :               arg->value.uint32 = strtoul (line, NULL, 0);
     432         525 :               break;
     433             : 
     434             :             case GPGME_CONF_INT32:
     435          88 :               arg->value.uint32 = strtol (line, NULL, 0);
     436          88 :               break;
     437             : 
     438             :             case GPGME_CONF_STRING:
     439             :               /* The complex types below are only here to silent the
     440             :                  compiler warning. */
     441             :             case GPGME_CONF_FILENAME:
     442             :             case GPGME_CONF_LDAP_SERVER:
     443             :             case GPGME_CONF_KEY_FPR:
     444             :             case GPGME_CONF_PUB_KEY:
     445             :             case GPGME_CONF_SEC_KEY:
     446             :             case GPGME_CONF_ALIAS_LIST:
     447             :               /* Skip quote character.  */
     448         593 :               line++;
     449             : 
     450         593 :               err = _gpgme_decode_percent_string (line, &arg->value.string,
     451             :                                                   0, 0);
     452         593 :               if (err)
     453           0 :                 return err;
     454         593 :               break;
     455             :             }
     456             :         }
     457             : 
     458             :       /* Find beginning of next value.  */
     459        1206 :       if (mark++ && *mark)
     460           0 :         line = mark;
     461             :       else
     462        1206 :         line = NULL;
     463             :     }
     464             : 
     465        1206 :   return 0;
     466             : }
     467             : 
     468             : 
     469             : static gpgme_error_t
     470        5632 : gpgconf_config_load_cb2 (void *hook, char *line)
     471             : {
     472             :   gpgme_error_t err;
     473        5632 :   gpgme_conf_comp_t comp = hook;
     474        5632 :   gpgme_conf_opt_t *opt_p = comp->_last_opt_p;
     475             :   gpgme_conf_opt_t opt;
     476             : #define NR_FIELDS 16
     477             :   char *field[NR_FIELDS];
     478        5632 :   int fields = 0;
     479             : 
     480       67584 :   while (line && fields < NR_FIELDS)
     481             :     {
     482       56320 :       field[fields++] = line;
     483       56320 :       line = strchr (line, ':');
     484       56320 :       if (line)
     485       50688 :         *(line++) = '\0';
     486             :     }
     487             : 
     488             :   /* We require at least the first 10 fields.  */
     489        5632 :   if (fields < 10)
     490           0 :     return trace_gpg_error (GPG_ERR_INV_ENGINE);
     491             : 
     492        5632 :   opt = calloc (1, sizeof (*opt));
     493        5632 :   if (!opt)
     494           0 :     return gpg_error_from_syserror ();
     495             : 
     496        5632 :   comp->_last_opt_p = &opt->next;
     497        5632 :   *opt_p = opt;
     498             : 
     499        5632 :   if (field[0][0])
     500             :     {
     501        5632 :       opt->name = strdup (field[0]);
     502        5632 :       if (!opt->name)
     503           0 :         return gpg_error_from_syserror ();
     504             :     }
     505             : 
     506        5632 :   opt->flags = strtoul (field[1], NULL, 0);
     507             : 
     508        5632 :   opt->level = strtoul (field[2], NULL, 0);
     509             : 
     510        5632 :   if (field[3][0])
     511             :     {
     512        4884 :       opt->description = strdup (field[3]);
     513        4884 :       if (!opt->description)
     514           0 :         return gpg_error_from_syserror ();
     515             :     }
     516             : 
     517        5632 :   opt->type = strtoul (field[4], NULL, 0);
     518             : 
     519        5632 :   opt->alt_type = strtoul (field[5], NULL, 0);
     520             : 
     521        5632 :   if (field[6][0])
     522             :     {
     523        1848 :       opt->argname = strdup (field[6]);
     524        1848 :       if (!opt->argname)
     525           0 :         return gpg_error_from_syserror ();
     526             :     }
     527             : 
     528        5632 :   if (opt->flags & GPGME_CONF_DEFAULT)
     529             :     {
     530        1320 :       err = gpgconf_parse_option (opt, &opt->default_value, field[7]);
     531        1320 :       if (err)
     532           0 :         return err;
     533             :     }
     534        4312 :   else if ((opt->flags & GPGME_CONF_DEFAULT_DESC) && field[7][0])
     535             :     {
     536           0 :       opt->default_description = strdup (field[7]);
     537           0 :       if (!opt->default_description)
     538           0 :         return gpg_error_from_syserror ();
     539             :     }
     540             : 
     541        5632 :   if (opt->flags & GPGME_CONF_NO_ARG_DESC)
     542             :     {
     543           0 :       opt->no_arg_description = strdup (field[8]);
     544           0 :       if (!opt->no_arg_description)
     545           0 :         return gpg_error_from_syserror ();
     546             :     }
     547             :   else
     548             :     {
     549        5632 :       err = gpgconf_parse_option (opt, &opt->no_arg_value, field[8]);
     550        5632 :       if (err)
     551           0 :         return err;
     552             :     }
     553             : 
     554        5632 :   err = gpgconf_parse_option (opt, &opt->value, field[9]);
     555        5632 :   if (err)
     556           0 :     return err;
     557             : 
     558        5632 :   return 0;
     559             : }
     560             : 
     561             : 
     562             : static gpgme_error_t
     563          44 : gpgconf_conf_load (void *engine, gpgme_conf_comp_t *comp_p)
     564             : {
     565             :   gpgme_error_t err;
     566          44 :   gpgme_conf_comp_t comp = NULL;
     567             :   gpgme_conf_comp_t cur_comp;
     568             : 
     569          44 :   *comp_p = NULL;
     570             : 
     571          44 :   err = gpgconf_read (engine, "--list-components", NULL,
     572             :                       gpgconf_config_load_cb, &comp);
     573          44 :   if (err)
     574             :     {
     575           0 :       gpgconf_release (comp);
     576           0 :       return err;
     577             :     }
     578             : 
     579          44 :   cur_comp = comp;
     580         352 :   while (!err && cur_comp)
     581             :     {
     582         264 :       err = gpgconf_read (engine, "--list-options", cur_comp->name,
     583             :                           gpgconf_config_load_cb2, cur_comp);
     584         264 :       cur_comp = cur_comp->next;
     585             :     }
     586             : 
     587          44 :   if (err)
     588             :     {
     589           0 :       gpgconf_release (comp);
     590           0 :       return err;
     591             :     }
     592             : 
     593          44 :   *comp_p = comp;
     594          44 :   return 0;
     595             : }
     596             : 
     597             : 
     598             : 
     599             : gpgme_error_t
     600        1271 : _gpgme_conf_arg_new (gpgme_conf_arg_t *arg_p,
     601             :                      gpgme_conf_type_t type, const void *value)
     602             : {
     603             :   gpgme_conf_arg_t arg;
     604             : 
     605        1271 :   arg = calloc (1, sizeof (*arg));
     606        1271 :   if (!arg)
     607           0 :     return gpg_error_from_syserror ();
     608             : 
     609        1271 :   if (!value)
     610           0 :     arg->no_arg = 1;
     611             :   else
     612             :     {
     613             :       /* We need to switch on type here because the alt-type is not
     614             :          yet known.  */
     615        1271 :       switch (type)
     616             :         {
     617             :         case GPGME_CONF_NONE:
     618             :         case GPGME_CONF_UINT32:
     619         516 :           arg->value.uint32 = *((unsigned int *) value);
     620         516 :           break;
     621             : 
     622             :         case GPGME_CONF_INT32:
     623          92 :           arg->value.int32 = *((int *) value);
     624          92 :           break;
     625             : 
     626             :         case GPGME_CONF_STRING:
     627             :         case GPGME_CONF_FILENAME:
     628             :         case GPGME_CONF_LDAP_SERVER:
     629             :         case GPGME_CONF_KEY_FPR:
     630             :         case GPGME_CONF_PUB_KEY:
     631             :         case GPGME_CONF_SEC_KEY:
     632             :         case GPGME_CONF_ALIAS_LIST:
     633         663 :           arg->value.string = strdup (value);
     634         663 :           if (!arg->value.string)
     635             :             {
     636           0 :               free (arg);
     637           0 :               return gpg_error_from_syserror ();
     638             :             }
     639         663 :           break;
     640             : 
     641             :         default:
     642           0 :           free (arg);
     643           0 :           return gpg_error (GPG_ERR_INV_VALUE);
     644             :         }
     645             :     }
     646             : 
     647        1271 :   *arg_p = arg;
     648        1271 :   return 0;
     649             : }
     650             : 
     651             : 
     652             : void
     653       14753 : _gpgme_conf_arg_release (gpgme_conf_arg_t arg, gpgme_conf_type_t type)
     654             : {
     655             :   /* Lacking the alt_type we need to switch on type here.  */
     656       14753 :   switch (type)
     657             :     {
     658             :     case GPGME_CONF_NONE:
     659             :     case GPGME_CONF_UINT32:
     660             :     case GPGME_CONF_INT32:
     661             :     case GPGME_CONF_STRING:
     662             :     default:
     663       14753 :       break;
     664             : 
     665             :     case GPGME_CONF_FILENAME:
     666             :     case GPGME_CONF_LDAP_SERVER:
     667             :     case GPGME_CONF_KEY_FPR:
     668             :     case GPGME_CONF_PUB_KEY:
     669             :     case GPGME_CONF_SEC_KEY:
     670             :     case GPGME_CONF_ALIAS_LIST:
     671           0 :       type = GPGME_CONF_STRING;
     672           0 :       break;
     673             :     }
     674             : 
     675       14753 :   release_arg (arg, type);
     676       14753 : }
     677             : 
     678             : 
     679             : gpgme_error_t
     680          42 : _gpgme_conf_opt_change (gpgme_conf_opt_t opt, int reset, gpgme_conf_arg_t arg)
     681             : {
     682          42 :   if (reset)
     683             :     {
     684           0 :       if (opt->new_value)
     685           0 :         release_arg (opt->new_value, opt->alt_type);
     686           0 :       opt->new_value = NULL;
     687           0 :       opt->change_value = 0;
     688             :     }
     689             :   else
     690             :     {
     691             :       /* Support self-assignment, for example for adding an item to an
     692             :          existing list.  */
     693          42 :       if (opt->new_value && arg != opt->new_value)
     694           0 :         release_arg (opt->new_value, opt->alt_type);
     695          42 :       opt->new_value = arg;
     696          42 :       opt->change_value = 1;
     697             :     }
     698          42 :   return 0;
     699             : }
     700             : 
     701             : 
     702             : /* FIXME: Major problem: We don't get errors from gpgconf.  */
     703             : 
     704             : static gpgme_error_t
     705          42 : gpgconf_write (void *engine, const char *arg1, char *arg2, gpgme_data_t conf)
     706             : {
     707          42 :   struct engine_gpgconf *gpgconf = engine;
     708          42 :   gpgme_error_t err = 0;
     709             : #define BUFLEN 1024
     710             :   char buf[BUFLEN];
     711          42 :   int buflen = 0;
     712             :   char *argv[7];
     713          42 :   int argc = 0;
     714          42 :   int rp[2] = { -1, -1 };
     715          42 :   int errp[2] = { -1, -1 };
     716          42 :   struct spawn_fd_item_s cfd[] = { {-1, 0 /* STDIN_FILENO */},
     717             :                                    {-1, 2 /* STDERR_FILENO */, -1},
     718             :                                    {-1, -1} };
     719             :   int status;
     720             :   int nwrite;
     721             : 
     722             :   /* _gpgme_engine_new guarantees that this is not NULL.  */
     723          42 :   argv[argc++] = gpgconf->file_name;
     724             : 
     725          42 :   if (gpgconf->home_dir && have_gpgconf_version (gpgconf, "2.1.13"))
     726             :     {
     727           0 :       argv[argc++] = (char*)"--homedir";
     728           0 :       argv[argc++] = gpgconf->home_dir;
     729             :     }
     730             : 
     731          42 :   argv[argc++] = (char*)"--runtime";
     732          42 :   argv[argc++] = (char*)arg1;
     733          42 :   argv[argc++] = arg2;
     734          42 :   argv[argc] = NULL;
     735          42 :   assert (argc < DIM (argv));
     736             : 
     737          42 :   if (_gpgme_io_pipe (rp, 0) < 0)
     738             :     {
     739           0 :       err = gpg_error_from_syserror ();
     740           0 :       goto leave;
     741             :     }
     742             : 
     743          42 :   if (_gpgme_io_pipe (errp, 1) < 0)
     744             :     {
     745           0 :       err = gpg_error_from_syserror ();
     746           0 :       goto leave;
     747             :     }
     748             : 
     749          42 :   cfd[0].fd = rp[0];
     750          42 :   cfd[1].fd = errp[1];
     751             : 
     752          42 :   status = _gpgme_io_spawn (gpgconf->file_name, argv,
     753             :                             IOSPAWN_FLAG_DETACHED, cfd, NULL, NULL, NULL);
     754          42 :   if (status < 0)
     755             :     {
     756           0 :       err = gpg_error_from_syserror ();
     757           0 :       goto leave;
     758             :     }
     759             : 
     760          42 :   rp[0] = -1;
     761          42 :   errp[1] = -1;
     762             : 
     763             :   for (;;)
     764             :     {
     765         126 :       if (buflen == 0)
     766             :         {
     767             :           do
     768             :             {
     769          84 :               buflen = gpgme_data_read (conf, buf, BUFLEN);
     770             :             }
     771          84 :           while (buflen < 0 && errno == EAGAIN);
     772             : 
     773          84 :           if (buflen < 0)
     774             :             {
     775           0 :               err = gpg_error_from_syserror ();
     776           0 :               goto leave;
     777             :             }
     778          84 :           else if (buflen == 0)
     779             :             {
     780             :               /* All is written.  */
     781          42 :               _gpgme_io_close (rp[1]);
     782          42 :               rp[1] = -1;
     783             : 
     784          10 :               for (;;)
     785             :                 {
     786             :                   do
     787             :                     {
     788          52 :                       buflen = _gpgme_io_read (errp[0], buf, BUFLEN);
     789             :                     }
     790          52 :                   while (buflen < 0 && errno == EAGAIN);
     791             : 
     792          52 :                   if (buflen == 0)
     793             :                     {
     794          42 :                       err = 0;
     795          42 :                       goto leave;
     796             :                     }
     797             :                   /* XXX: Do something useful with BUF.  */
     798             :                 }
     799             :             }
     800             :         }
     801             : 
     802             :       do
     803             :         {
     804          42 :           nwrite = _gpgme_io_write (rp[1], buf, buflen);
     805             :         }
     806          42 :       while (nwrite < 0 && errno == EAGAIN);
     807             : 
     808          42 :       if (nwrite > 0)
     809             :         {
     810          42 :           buflen -= nwrite;
     811          42 :           if (buflen > 0)
     812           0 :             memmove (&buf[0], &buf[nwrite], buflen);
     813             :         }
     814           0 :       else if (nwrite < 0)
     815             :         {
     816           0 :           err = gpg_error_from_syserror ();
     817           0 :           goto leave;
     818             :         }
     819             :     }
     820             : 
     821             :   assert (! "reached");
     822             : 
     823             :  leave:
     824          42 :   if (rp[0] != -1)
     825           0 :     _gpgme_io_close (rp[0]);
     826          42 :   if (rp[1] != -1)
     827           0 :   _gpgme_io_close (rp[1]);
     828          42 :   if (errp[0] != -1)
     829          42 :     _gpgme_io_close (errp[0]);
     830          42 :   if (errp[1] != -1)
     831           0 :   _gpgme_io_close (errp[1]);
     832             : 
     833          42 :   return err;
     834             : }
     835             : 
     836             : 
     837             : static gpgme_error_t
     838          31 : arg_to_data (gpgme_data_t conf, gpgme_conf_opt_t option, gpgme_conf_arg_t arg)
     839             : {
     840          31 :   gpgme_error_t err = 0;
     841          31 :   int amt = 0;
     842             :   char buf[16];
     843             : 
     844          93 :   while (amt >= 0 && arg)
     845             :     {
     846          31 :       switch (option->alt_type)
     847             :         {
     848             :         case GPGME_CONF_NONE:
     849             :         case GPGME_CONF_UINT32:
     850             :         default:
     851          10 :           snprintf (buf, sizeof (buf), "%u", arg->value.uint32);
     852          10 :           buf[sizeof (buf) - 1] = '\0';
     853          10 :           amt = gpgme_data_write (conf, buf, strlen (buf));
     854          10 :           break;
     855             : 
     856             :         case GPGME_CONF_INT32:
     857           0 :           snprintf (buf, sizeof (buf), "%i", arg->value.uint32);
     858           0 :           buf[sizeof (buf) - 1] = '\0';
     859           0 :           amt = gpgme_data_write (conf, buf, strlen (buf));
     860           0 :           break;
     861             : 
     862             : 
     863             :         case GPGME_CONF_STRING:
     864             :           /* The complex types below are only here to silent the
     865             :              compiler warning. */
     866             :         case GPGME_CONF_FILENAME:
     867             :         case GPGME_CONF_LDAP_SERVER:
     868             :         case GPGME_CONF_KEY_FPR:
     869             :         case GPGME_CONF_PUB_KEY:
     870             :         case GPGME_CONF_SEC_KEY:
     871             :         case GPGME_CONF_ALIAS_LIST:
     872          21 :           if (arg->value.string)
     873             :             {
     874             :               /* One quote character, and three times to allow for
     875             :                  percent escaping.  */
     876          21 :               char *ptr = arg->value.string;
     877          21 :               amt = gpgme_data_write (conf, "\"", 1);
     878          21 :               if (amt < 0)
     879           0 :                 break;
     880             : 
     881         352 :               while (!err && *ptr)
     882             :                 {
     883         310 :                   switch (*ptr)
     884             :                     {
     885             :                     case '%':
     886           0 :                       amt = gpgme_data_write (conf, "%25", 3);
     887           0 :                       break;
     888             : 
     889             :                     case ':':
     890          20 :                       amt = gpgme_data_write (conf, "%3a", 3);
     891          20 :                       break;
     892             : 
     893             :                     case ',':
     894           0 :                       amt = gpgme_data_write (conf, "%2c", 3);
     895           0 :                       break;
     896             : 
     897             :                     default:
     898         290 :                       amt = gpgme_data_write (conf, ptr, 1);
     899             :                     }
     900         310 :                   ptr++;
     901             :                 }
     902             :             }
     903          21 :           break;
     904             :         }
     905             : 
     906          31 :       if (amt < 0)
     907           0 :         break;
     908             : 
     909          31 :       arg = arg->next;
     910             :       /* Comma separator.  */
     911          31 :       if (arg)
     912           0 :         amt = gpgme_data_write (conf, ",", 1);
     913             :     }
     914             : 
     915          31 :   if (amt < 0)
     916           0 :     return gpg_error_from_syserror ();
     917             : 
     918          31 :   return 0;
     919             : }
     920             : 
     921             : 
     922             : static gpgme_error_t
     923         152 : gpgconf_conf_save (void *engine, gpgme_conf_comp_t comp)
     924             : {
     925             :   gpgme_error_t err;
     926         152 :   int amt = 0;
     927             :   /* We use a data object to store the new configuration.  */
     928             :   gpgme_data_t conf;
     929             :   gpgme_conf_opt_t option;
     930         152 :   int something_changed = 0;
     931             : 
     932         152 :   err = gpgme_data_new (&conf);
     933         152 :   if (err)
     934           0 :     return err;
     935             : 
     936         152 :   option = comp->options;
     937        3710 :   while (!err && amt >= 0 && option)
     938             :     {
     939        3406 :       if (option->change_value)
     940             :         {
     941          42 :           unsigned int flags = 0;
     942             :           char buf[16];
     943             : 
     944          42 :           something_changed = 1;
     945             : 
     946          42 :           amt = gpgme_data_write (conf, option->name, strlen (option->name));
     947          42 :           if (amt >= 0)
     948          42 :             amt = gpgme_data_write (conf, ":", 1);
     949          42 :           if (amt < 0)
     950           0 :             break;
     951             : 
     952          42 :           if (!option->new_value)
     953          11 :             flags |= GPGME_CONF_DEFAULT;
     954          42 :           snprintf (buf, sizeof (buf), "%u", flags);
     955          42 :           buf[sizeof (buf) - 1] = '\0';
     956             : 
     957          42 :           amt = gpgme_data_write (conf, buf, strlen (buf));
     958          42 :           if (amt >= 0)
     959          42 :             amt = gpgme_data_write (conf, ":", 1);
     960          42 :           if (amt < 0)
     961           0 :             break;
     962             : 
     963          42 :           if (option->new_value)
     964             :             {
     965          31 :               err = arg_to_data (conf, option, option->new_value);
     966          31 :               if (err)
     967           0 :                 break;
     968             :             }
     969          42 :           amt = gpgme_data_write (conf, "\n", 1);
     970             :         }
     971        3406 :       option = option->next;
     972             :     }
     973         152 :   if (!err && amt < 0)
     974           0 :     err = gpg_error_from_syserror ();
     975         152 :   if (err || !something_changed)
     976             :     goto bail;
     977             : 
     978          42 :   err = gpgme_data_seek (conf, 0, SEEK_SET);
     979          42 :   if (err)
     980           0 :     goto bail;
     981             : 
     982          42 :   err = gpgconf_write (engine, "--change-options", comp->name, conf);
     983             :  bail:
     984         152 :   gpgme_data_release (conf);
     985         152 :   return err;
     986             : }
     987             : 
     988             : 
     989             : struct gpgconf_config_dir_s
     990             : {
     991             :   const char *what;
     992             :   char *result;
     993             : };
     994             : 
     995             : /* Called for each line in the gpgconf --list-dirs output.  Searches
     996             :    for the desired line and returns the result, indicating success by
     997             :    a special error value GPG_ERR_USER_1 (which terminates the
     998             :    operation immediately).  */
     999             : static gpgme_error_t
    1000          24 : gpgconf_config_dir_cb (void *hook, char *line)
    1001             : {
    1002             :   /* This is an input- and output-parameter.  */
    1003          24 :   struct gpgconf_config_dir_s *data = (struct gpgconf_config_dir_s *) hook;
    1004          24 :   int len = strlen(data->what);
    1005             : 
    1006          24 :   if (!strncmp(line, data->what, len) && line[len] == ':')
    1007             :     {
    1008           2 :       char *result = strdup(&line[len + 1]);
    1009           2 :       if (!result)
    1010           0 :         return gpg_error_from_syserror ();
    1011           2 :       data->result = result;
    1012           2 :       return gpg_error(GPG_ERR_USER_1);
    1013             :     }
    1014          22 :   return 0;
    1015             : }
    1016             : 
    1017             : 
    1018             : /* Like gpgme_get_dirinfo, but uses the home directory of ENGINE and
    1019             :    does not cache the result.  */
    1020             : static gpgme_error_t
    1021           2 : gpgconf_conf_dir (void *engine, const char *what, char **result)
    1022             : {
    1023             :   gpgme_error_t err;
    1024             :   struct gpgconf_config_dir_s data;
    1025             : 
    1026           2 :   data.what = what;
    1027           2 :   data.result = NULL;
    1028           2 :   err = gpgconf_read (engine, "--list-dirs", NULL,
    1029             :                       gpgconf_config_dir_cb, &data);
    1030           2 :   if (gpg_err_code (err) == GPG_ERR_USER_1)
    1031             :     {
    1032             :       /* This signals to us that a result was found.  */
    1033           2 :       *result = data.result;
    1034           2 :       return 0;
    1035             :     }
    1036             : 
    1037           0 :   if (!err)
    1038           0 :     err = gpg_error(GPG_ERR_NOT_FOUND);
    1039           0 :   return 0;
    1040             : }
    1041             : 
    1042             : 
    1043             : /* Parse a line received from gpgconf --query-swdb.  This function may
    1044             :  * modify LINE.  The result is stored at RESULT.  */
    1045             : static gpg_error_t
    1046           0 : parse_swdb_line (char *line, gpgme_query_swdb_result_t result)
    1047             : {
    1048             :   char *field[9];
    1049           0 :   int fields = 0;
    1050             :   gpg_err_code_t ec;
    1051             : 
    1052           0 :   while (line && fields < DIM (field))
    1053             :     {
    1054           0 :       field[fields++] = line;
    1055           0 :       line = strchr (line, ':');
    1056           0 :       if (line)
    1057           0 :         *line++ = 0;
    1058             :     }
    1059             :   /* We require that all fields exists - gpgme emits all these fields
    1060             :    * even on error.  They might be empty, though. */
    1061           0 :   if (fields < 9)
    1062           0 :     return gpg_error (GPG_ERR_INV_ENGINE);
    1063             : 
    1064           0 :   free (result->name);
    1065           0 :   result->name = strdup (field[0]);
    1066           0 :   if (!result->name)
    1067           0 :     return gpg_error_from_syserror ();
    1068             : 
    1069           0 :   free (result->iversion);
    1070           0 :   result->iversion = strdup (field[1]);
    1071           0 :   if (!result->iversion)
    1072           0 :     return gpg_error_from_syserror ();
    1073             : 
    1074           0 :   result->urgent = (strtol (field[3], NULL, 10) > 0);
    1075             : 
    1076           0 :   ec = gpg_err_code (strtoul (field[4], NULL, 10));
    1077             : 
    1078           0 :   result->created  = _gpgme_parse_timestamp (field[5], NULL);
    1079           0 :   result->retrieved= _gpgme_parse_timestamp (field[6], NULL);
    1080             : 
    1081           0 :   free (result->version);
    1082           0 :   result->version  = strdup (field[7]);
    1083           0 :   if (!result->version)
    1084           0 :     return gpg_error_from_syserror ();
    1085             : 
    1086           0 :   result->reldate  = _gpgme_parse_timestamp (field[8], NULL);
    1087             : 
    1088             :   /* Set other flags.  */
    1089           0 :   result->warning = !!ec;
    1090           0 :   result->update = 0;
    1091           0 :   result->noinfo = 0;
    1092           0 :   result->unknown = 0;
    1093           0 :   result->tooold = 0;
    1094           0 :   result->error = 0;
    1095             : 
    1096           0 :   switch (*field[2])
    1097             :     {
    1098           0 :     case '-': result->warning = 1; break;
    1099           0 :     case '?': result->unknown = result->warning = 1; break;
    1100           0 :     case 'u': result->update = 1; break;
    1101           0 :     case 'c': break;
    1102           0 :     case 'n': break;
    1103             :     default:
    1104           0 :       result->warning = 1;
    1105           0 :       if (!ec)
    1106           0 :         ec = GPG_ERR_INV_ENGINE;
    1107           0 :       break;
    1108             :     }
    1109             : 
    1110           0 :   if (ec == GPG_ERR_TOO_OLD)
    1111           0 :     result->tooold = 1;
    1112           0 :   else if (ec == GPG_ERR_ENOENT)
    1113           0 :     result->noinfo = 1;
    1114           0 :   else if (ec)
    1115           0 :     result->error = 1;
    1116             : 
    1117             : 
    1118           0 :   return 0;
    1119             : }
    1120             : 
    1121             : 
    1122             : static gpgme_error_t
    1123           0 : gpgconf_query_swdb (void *engine,
    1124             :                     const char *name, const char *iversion,
    1125             :                     gpgme_query_swdb_result_t result)
    1126             : {
    1127           0 :   struct engine_gpgconf *gpgconf = engine;
    1128           0 :   gpgme_error_t err = 0;
    1129             :   char *linebuf;
    1130             :   size_t linebufsize;
    1131             :   int linelen;
    1132             :   char *argv[7];
    1133           0 :   int argc = 0;
    1134             :   int rp[2];
    1135           0 :   struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
    1136             :                                    {-1, -1} };
    1137             :   int status;
    1138             :   int nread;
    1139           0 :   char *mark = NULL;
    1140             : 
    1141           0 :   if (!have_gpgconf_version (gpgconf, "2.1.16"))
    1142           0 :     return gpg_error (GPG_ERR_ENGINE_TOO_OLD);
    1143             : 
    1144             :   /* _gpgme_engine_new guarantees that this is not NULL.  */
    1145           0 :   argv[argc++] = gpgconf->file_name;
    1146             : 
    1147           0 :   if (gpgconf->home_dir)
    1148             :     {
    1149           0 :       argv[argc++] = (char*)"--homedir";
    1150           0 :       argv[argc++] = gpgconf->home_dir;
    1151             :     }
    1152             : 
    1153           0 :   argv[argc++] = (char*)"--query-swdb";
    1154           0 :   argv[argc++] = (char*)name;
    1155           0 :   argv[argc++] = (char*)iversion;
    1156           0 :   argv[argc] = NULL;
    1157           0 :   assert (argc < DIM (argv));
    1158             : 
    1159           0 :   if (_gpgme_io_pipe (rp, 1) < 0)
    1160           0 :     return gpg_error_from_syserror ();
    1161             : 
    1162           0 :   cfd[0].fd = rp[1];
    1163             : 
    1164           0 :   status = _gpgme_io_spawn (gpgconf->file_name, argv,
    1165             :                             IOSPAWN_FLAG_DETACHED, cfd, NULL, NULL, NULL);
    1166           0 :   if (status < 0)
    1167             :     {
    1168           0 :       _gpgme_io_close (rp[0]);
    1169           0 :       _gpgme_io_close (rp[1]);
    1170           0 :       return gpg_error_from_syserror ();
    1171             :     }
    1172             : 
    1173           0 :   linebufsize = 2048; /* Same as used by gpgconf.  */
    1174           0 :   linebuf = malloc (linebufsize);
    1175           0 :   if (!linebuf)
    1176             :     {
    1177           0 :       err = gpg_error_from_syserror ();
    1178           0 :       goto leave;
    1179             :     }
    1180           0 :   linelen = 0;
    1181             : 
    1182           0 :   while ((nread = _gpgme_io_read (rp[0], linebuf + linelen,
    1183           0 :                                   linebufsize - linelen - 1)))
    1184             :     {
    1185             :       char *line;
    1186           0 :       const char *lastmark = NULL;
    1187             :       size_t nused;
    1188             : 
    1189           0 :       if (nread < 0)
    1190             :         {
    1191           0 :           err = gpg_error_from_syserror ();
    1192           0 :           goto leave;
    1193             :         }
    1194             : 
    1195           0 :       linelen += nread;
    1196           0 :       linebuf[linelen] = '\0';
    1197             : 
    1198           0 :       for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
    1199             :         {
    1200           0 :           lastmark = mark;
    1201           0 :           if (mark > line && mark[-1] == '\r')
    1202           0 :             mark[-1] = '\0';
    1203             :           else
    1204           0 :             mark[0] = '\0';
    1205             : 
    1206             :           /* Got a full line.  Due to the CR removal code (which
    1207             :              occurs only on Windows) we might be one-off and thus
    1208             :              would see empty lines.  */
    1209           0 :           if (*line)
    1210             :             {
    1211           0 :               err = parse_swdb_line (line, result);
    1212           0 :               goto leave; /* Ready.  */
    1213             :             }
    1214             :           else /* empty line.  */
    1215           0 :             err = 0;
    1216             :         }
    1217             : 
    1218           0 :       nused = lastmark? (lastmark + 1 - linebuf) : 0;
    1219           0 :       memmove (linebuf, linebuf + nused, linelen - nused);
    1220           0 :       linelen -= nused;
    1221             : 
    1222           0 :       if (!(linelen < linebufsize - 1))
    1223             :         {
    1224             :           char *newlinebuf;
    1225             : 
    1226           0 :           if (linelen <  8 * 1024 - 1)
    1227           0 :             linebufsize = 8 * 1024;
    1228           0 :           else if (linelen < 64 * 1024 - 1)
    1229           0 :             linebufsize = 64 * 1024;
    1230             :           else
    1231             :             {
    1232             :               /* We reached our limit - give up.  */
    1233           0 :               err = gpg_error (GPG_ERR_LINE_TOO_LONG);
    1234           0 :               goto leave;
    1235             :             }
    1236             : 
    1237           0 :           newlinebuf = realloc (linebuf, linebufsize);
    1238           0 :           if (!newlinebuf)
    1239             :             {
    1240           0 :               err = gpg_error_from_syserror ();
    1241           0 :               goto leave;
    1242             :             }
    1243           0 :           linebuf = newlinebuf;
    1244             :         }
    1245             :     }
    1246             : 
    1247             :  leave:
    1248           0 :   free (linebuf);
    1249           0 :   _gpgme_io_close (rp[0]);
    1250           0 :   return err;
    1251             : }
    1252             : 
    1253             : 
    1254             : static void
    1255         198 : gpgconf_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
    1256             : {
    1257             :   (void)engine;
    1258             :   (void)io_cbs;
    1259             :   /* Nothing to do.  */
    1260         198 : }
    1261             : 
    1262             : 
    1263             : /* Currently, we do not use the engine interface for the various
    1264             :    operations.  */
    1265             : void
    1266         153 : _gpgme_conf_release (gpgme_conf_comp_t conf)
    1267             : {
    1268         153 :   gpgconf_config_release (conf);
    1269         153 : }
    1270             : 
    1271             : 
    1272             : struct engine_ops _gpgme_engine_ops_gpgconf =
    1273             :   {
    1274             :     /* Static functions.  */
    1275             :     _gpgme_get_default_gpgconf_name,
    1276             :     NULL,
    1277             :     gpgconf_get_version,
    1278             :     gpgconf_get_req_version,
    1279             :     gpgconf_new,
    1280             : 
    1281             :     /* Member functions.  */
    1282             :     gpgconf_release,
    1283             :     NULL,               /* reset */
    1284             :     NULL,               /* set_status_cb */
    1285             :     NULL,               /* set_status_handler */
    1286             :     NULL,               /* set_command_handler */
    1287             :     NULL,               /* set_colon_line_handler */
    1288             :     NULL,               /* set_locale */
    1289             :     NULL,               /* set_protocol */
    1290             :     NULL,               /* set_engine_flags */
    1291             :     NULL,               /* decrypt */
    1292             :     NULL,               /* delete */
    1293             :     NULL,               /* edit */
    1294             :     NULL,               /* encrypt */
    1295             :     NULL,               /* encrypt_sign */
    1296             :     NULL,               /* export */
    1297             :     NULL,               /* export_ext */
    1298             :     NULL,               /* genkey */
    1299             :     NULL,               /* import */
    1300             :     NULL,               /* keylist */
    1301             :     NULL,               /* keylist_ext */
    1302             :     NULL,               /* keylist_data */
    1303             :     NULL,               /* keysign */
    1304             :     NULL,               /* tofu_policy */
    1305             :     NULL,               /* sign */
    1306             :     NULL,               /* trustlist */
    1307             :     NULL,               /* verify */
    1308             :     NULL,               /* getauditlog */
    1309             :     NULL,               /* opassuan_transact */
    1310             :     gpgconf_conf_load,
    1311             :     gpgconf_conf_save,
    1312             :     gpgconf_conf_dir,
    1313             :     gpgconf_query_swdb,
    1314             :     gpgconf_set_io_cbs,
    1315             :     NULL,               /* io_event */
    1316             :     NULL,               /* cancel */
    1317             :     NULL,               /* cancel_op */
    1318             :     NULL,               /* passwd */
    1319             :     NULL,               /* set_pinentry_mode */
    1320             :     NULL                /* opspawn */
    1321             :   };

Generated by: LCOV version 1.13