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

Generated by: LCOV version 1.11