LCOV - code coverage report
Current view: top level - src - engine-gpgconf.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 4 410 1.0 %
Date: 2016-09-12 13:07:23 Functions: 2 21 9.5 %

          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 <http://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             : struct engine_gpgconf
      52             : {
      53             :   char *file_name;
      54             :   char *home_dir;
      55             : };
      56             : 
      57             : typedef struct engine_gpgconf *engine_gpgconf_t;
      58             : 
      59             : 
      60             : static char *
      61          56 : gpgconf_get_version (const char *file_name)
      62             : {
      63          56 :   return _gpgme_get_program_version (file_name ? file_name
      64             :                                      : _gpgme_get_default_gpgconf_name ());
      65             : }
      66             : 
      67             : 
      68             : static const char *
      69          56 : gpgconf_get_req_version (void)
      70             : {
      71          56 :   return "2.0.4";
      72             : }
      73             : 
      74             : 
      75             : static void
      76           0 : gpgconf_release (void *engine)
      77             : {
      78           0 :   engine_gpgconf_t gpgconf = engine;
      79             : 
      80           0 :   if (!gpgconf)
      81           0 :     return;
      82             : 
      83           0 :   if (gpgconf->file_name)
      84           0 :     free (gpgconf->file_name);
      85           0 :   if (gpgconf->home_dir)
      86           0 :     free (gpgconf->home_dir);
      87             : 
      88           0 :   free (gpgconf);
      89             : }
      90             : 
      91             : 
      92             : static gpgme_error_t
      93           0 : gpgconf_new (void **engine, const char *file_name, const char *home_dir,
      94             :              const char *version)
      95             : {
      96           0 :   gpgme_error_t err = 0;
      97             :   engine_gpgconf_t gpgconf;
      98             : 
      99             :   (void)version; /* Not yet used.  */
     100             : 
     101           0 :   gpgconf = calloc (1, sizeof *gpgconf);
     102           0 :   if (!gpgconf)
     103           0 :     return gpg_error_from_syserror ();
     104             : 
     105           0 :   gpgconf->file_name = strdup (file_name ? file_name
     106             :                                : _gpgme_get_default_gpgconf_name ());
     107           0 :   if (!gpgconf->file_name)
     108           0 :     err = gpg_error_from_syserror ();
     109             : 
     110           0 :   if (!err && home_dir)
     111             :     {
     112           0 :       gpgconf->home_dir = strdup (home_dir);
     113           0 :       if (!gpgconf->home_dir)
     114           0 :         err = gpg_error_from_syserror ();
     115             :     }
     116             : 
     117           0 :   if (err)
     118           0 :     gpgconf_release (gpgconf);
     119             :   else
     120           0 :     *engine = gpgconf;
     121             : 
     122           0 :   return err;
     123             : }
     124             : 
     125             : 
     126             : static void
     127           0 : release_arg (gpgme_conf_arg_t arg, gpgme_conf_type_t alt_type)
     128             : {
     129           0 :   while (arg)
     130             :     {
     131           0 :       gpgme_conf_arg_t next = arg->next;
     132             : 
     133           0 :       if (alt_type == GPGME_CONF_STRING)
     134           0 :         free (arg->value.string);
     135           0 :       free (arg);
     136           0 :       arg = next;
     137             :     }
     138           0 : }
     139             : 
     140             : 
     141             : static void
     142           0 : release_opt (gpgme_conf_opt_t opt)
     143             : {
     144           0 :   if (opt->name)
     145           0 :     free (opt->name);
     146           0 :   if (opt->description)
     147           0 :     free (opt->description);
     148           0 :   if (opt->argname)
     149           0 :     free (opt->argname);
     150             : 
     151           0 :   release_arg (opt->default_value, opt->alt_type);
     152           0 :   if (opt->default_description)
     153           0 :     free (opt->default_description);
     154             : 
     155           0 :   release_arg (opt->no_arg_value, opt->alt_type);
     156           0 :   release_arg (opt->value, opt->alt_type);
     157           0 :   release_arg (opt->new_value, opt->alt_type);
     158             : 
     159           0 :   free (opt);
     160           0 : }
     161             : 
     162             : 
     163             : static void
     164           0 : release_comp (gpgme_conf_comp_t comp)
     165             : {
     166             :   gpgme_conf_opt_t opt;
     167             : 
     168           0 :   if (comp->name)
     169           0 :     free (comp->name);
     170           0 :   if (comp->description)
     171           0 :     free (comp->description);
     172           0 :   if (comp->program_name)
     173           0 :     free (comp->program_name);
     174             : 
     175           0 :   opt = comp->options;
     176           0 :   while (opt)
     177             :     {
     178           0 :       gpgme_conf_opt_t next = opt->next;
     179           0 :       release_opt (opt);
     180           0 :       opt = next;
     181             :     }
     182             : 
     183           0 :   free (comp);
     184           0 : }
     185             : 
     186             : 
     187             : static void
     188           0 : gpgconf_config_release (gpgme_conf_comp_t conf)
     189             : {
     190           0 :   while (conf)
     191             :     {
     192           0 :       gpgme_conf_comp_t next = conf->next;
     193           0 :       release_comp (conf);
     194           0 :       conf = next;
     195             :     }
     196           0 : }
     197             : 
     198             : /* Read from gpgconf and pass line after line to the hook function.
     199             :    We put a limit of 64 k on the maximum size for a line.  This should
     200             :    allow for quite a long "group" line, which is usually the longest
     201             :    line (mine is currently ~3k).  */
     202             : static gpgme_error_t
     203           0 : gpgconf_read (void *engine, char *arg1, char *arg2,
     204             :               gpgme_error_t (*cb) (void *hook, char *line),
     205             :               void *hook)
     206             : {
     207           0 :   struct engine_gpgconf *gpgconf = engine;
     208           0 :   gpgme_error_t err = 0;
     209             :   char *linebuf;
     210             :   size_t linebufsize;
     211             :   int linelen;
     212           0 :   char *argv[4] = { NULL /* file_name */, NULL, NULL, NULL };
     213             :   int rp[2];
     214           0 :   struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
     215             :                                    {-1, -1} };
     216             :   int status;
     217             :   int nread;
     218           0 :   char *mark = NULL;
     219             : 
     220           0 :   argv[1] = arg1;
     221           0 :   argv[2] = arg2;
     222             : 
     223             : 
     224             :   /* FIXME: Deal with engine->home_dir.  */
     225             : 
     226             :   /* _gpgme_engine_new guarantees that this is not NULL.  */
     227           0 :   argv[0] = gpgconf->file_name;
     228             : 
     229           0 :   if (_gpgme_io_pipe (rp, 1) < 0)
     230           0 :     return gpg_error_from_syserror ();
     231             : 
     232           0 :   cfd[0].fd = rp[1];
     233             : 
     234           0 :   status = _gpgme_io_spawn (gpgconf->file_name, argv,
     235             :                             IOSPAWN_FLAG_DETACHED, cfd, NULL, NULL, NULL);
     236           0 :   if (status < 0)
     237             :     {
     238           0 :       _gpgme_io_close (rp[0]);
     239           0 :       _gpgme_io_close (rp[1]);
     240           0 :       return gpg_error_from_syserror ();
     241             :     }
     242             : 
     243           0 :   linebufsize = 1024; /* Usually enough for conf lines.  */
     244           0 :   linebuf = malloc (linebufsize);
     245           0 :   if (!linebuf)
     246             :     {
     247           0 :       err = gpg_error_from_syserror ();
     248           0 :       goto leave;
     249             :     }
     250           0 :   linelen = 0;
     251             : 
     252           0 :   while ((nread = _gpgme_io_read (rp[0], linebuf + linelen,
     253           0 :                                   linebufsize - linelen - 1)))
     254             :     {
     255             :       char *line;
     256           0 :       const char *lastmark = NULL;
     257             :       size_t nused;
     258             : 
     259           0 :       if (nread < 0)
     260             :         {
     261           0 :           err = gpg_error_from_syserror ();
     262           0 :           goto leave;
     263             :         }
     264             : 
     265           0 :       linelen += nread;
     266           0 :       linebuf[linelen] = '\0';
     267             : 
     268           0 :       for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
     269             :         {
     270           0 :           lastmark = mark;
     271           0 :           if (mark > line && mark[-1] == '\r')
     272           0 :             mark[-1] = '\0';
     273             :           else
     274           0 :             mark[0] = '\0';
     275             : 
     276             :           /* Got a full line.  Due to the CR removal code (which
     277             :              occurs only on Windows) we might be one-off and thus
     278             :              would see empty lines.  Don't pass them to the
     279             :              callback. */
     280           0 :           err = *line? (*cb) (hook, line) : 0;
     281           0 :           if (err)
     282           0 :             goto leave;
     283             :         }
     284             : 
     285           0 :       nused = lastmark? (lastmark + 1 - linebuf) : 0;
     286           0 :       memmove (linebuf, linebuf + nused, linelen - nused);
     287           0 :       linelen -= nused;
     288             : 
     289           0 :       if (!(linelen < linebufsize - 1))
     290             :         {
     291             :           char *newlinebuf;
     292             : 
     293           0 :           if (linelen <  8 * 1024 - 1)
     294           0 :             linebufsize = 8 * 1024;
     295           0 :           else if (linelen < 64 * 1024 - 1)
     296           0 :             linebufsize = 64 * 1024;
     297             :           else
     298             :             {
     299             :               /* We reached our limit - give up.  */
     300           0 :               err = gpg_error (GPG_ERR_LINE_TOO_LONG);
     301           0 :               goto leave;
     302             :             }
     303             : 
     304           0 :           newlinebuf = realloc (linebuf, linebufsize);
     305           0 :           if (!newlinebuf)
     306             :             {
     307           0 :               err = gpg_error_from_syserror ();
     308           0 :               goto leave;
     309             :             }
     310           0 :           linebuf = newlinebuf;
     311             :         }
     312             :     }
     313             : 
     314             :  leave:
     315           0 :   free (linebuf);
     316           0 :   _gpgme_io_close (rp[0]);
     317           0 :   return err;
     318             : }
     319             : 
     320             : 
     321             : static gpgme_error_t
     322           0 : gpgconf_config_load_cb (void *hook, char *line)
     323             : {
     324           0 :   gpgme_conf_comp_t *comp_p = hook;
     325           0 :   gpgme_conf_comp_t comp = *comp_p;
     326             : #define NR_FIELDS 16
     327             :   char *field[NR_FIELDS];
     328           0 :   int fields = 0;
     329             : 
     330           0 :   while (line && fields < NR_FIELDS)
     331             :     {
     332           0 :       field[fields++] = line;
     333           0 :       line = strchr (line, ':');
     334           0 :       if (line)
     335           0 :         *(line++) = '\0';
     336             :     }
     337             : 
     338             :   /* We require at least the first 3 fields.  */
     339           0 :   if (fields < 2)
     340           0 :     return trace_gpg_error (GPG_ERR_INV_ENGINE);
     341             : 
     342             :   /* Find the pointer to the new component in the list.  */
     343           0 :   while (comp && comp->next)
     344           0 :     comp = comp->next;
     345           0 :   if (comp)
     346           0 :     comp_p = &comp->next;
     347             : 
     348           0 :   comp = calloc (1, sizeof (*comp));
     349           0 :   if (!comp)
     350           0 :     return gpg_error_from_syserror ();
     351             :   /* Prepare return value.  */
     352           0 :   comp->_last_opt_p = &comp->options;
     353           0 :   *comp_p = comp;
     354             : 
     355           0 :   comp->name = strdup (field[0]);
     356           0 :   if (!comp->name)
     357           0 :     return gpg_error_from_syserror ();
     358             : 
     359           0 :   comp->description = strdup (field[1]);
     360           0 :   if (!comp->description)
     361           0 :     return gpg_error_from_syserror ();
     362             : 
     363           0 :   if (fields >= 3)
     364             :     {
     365           0 :       comp->program_name = strdup (field[2]);
     366           0 :       if (!comp->program_name)
     367           0 :         return gpg_error_from_syserror ();
     368             :     }
     369             : 
     370           0 :   return 0;
     371             : }
     372             : 
     373             : 
     374             : static gpgme_error_t
     375           0 : gpgconf_parse_option (gpgme_conf_opt_t opt,
     376             :                       gpgme_conf_arg_t *arg_p, char *line)
     377             : {
     378             :   gpgme_error_t err;
     379             :   char *mark;
     380             : 
     381           0 :   if (!line[0])
     382           0 :     return 0;
     383             : 
     384           0 :   while (line)
     385             :     {
     386             :       gpgme_conf_arg_t arg;
     387             : 
     388           0 :       mark = strchr (line, ',');
     389           0 :       if (mark)
     390           0 :         *mark = '\0';
     391             : 
     392           0 :       arg = calloc (1, sizeof (*arg));
     393           0 :       if (!arg)
     394           0 :         return gpg_error_from_syserror ();
     395           0 :       *arg_p = arg;
     396           0 :       arg_p = &arg->next;
     397             : 
     398           0 :       if (*line == '\0')
     399           0 :         arg->no_arg = 1;
     400             :       else
     401             :         {
     402           0 :           switch (opt->alt_type)
     403             :             {
     404             :               /* arg->value.count is an alias for arg->value.uint32.  */
     405             :             case GPGME_CONF_NONE:
     406             :             case GPGME_CONF_UINT32:
     407           0 :               arg->value.uint32 = strtoul (line, NULL, 0);
     408           0 :               break;
     409             : 
     410             :             case GPGME_CONF_INT32:
     411           0 :               arg->value.uint32 = strtol (line, NULL, 0);
     412           0 :               break;
     413             : 
     414             :             case GPGME_CONF_STRING:
     415             :               /* The complex types below are only here to silent the
     416             :                  compiler warning. */
     417             :             case GPGME_CONF_FILENAME:
     418             :             case GPGME_CONF_LDAP_SERVER:
     419             :             case GPGME_CONF_KEY_FPR:
     420             :             case GPGME_CONF_PUB_KEY:
     421             :             case GPGME_CONF_SEC_KEY:
     422             :             case GPGME_CONF_ALIAS_LIST:
     423             :               /* Skip quote character.  */
     424           0 :               line++;
     425             : 
     426           0 :               err = _gpgme_decode_percent_string (line, &arg->value.string,
     427             :                                                   0, 0);
     428           0 :               if (err)
     429           0 :                 return err;
     430           0 :               break;
     431             :             }
     432             :         }
     433             : 
     434             :       /* Find beginning of next value.  */
     435           0 :       if (mark++ && *mark)
     436           0 :         line = mark;
     437             :       else
     438           0 :         line = NULL;
     439             :     }
     440             : 
     441           0 :   return 0;
     442             : }
     443             : 
     444             : 
     445             : static gpgme_error_t
     446           0 : gpgconf_config_load_cb2 (void *hook, char *line)
     447             : {
     448             :   gpgme_error_t err;
     449           0 :   gpgme_conf_comp_t comp = hook;
     450           0 :   gpgme_conf_opt_t *opt_p = comp->_last_opt_p;
     451             :   gpgme_conf_opt_t opt;
     452             : #define NR_FIELDS 16
     453             :   char *field[NR_FIELDS];
     454           0 :   int fields = 0;
     455             : 
     456           0 :   while (line && fields < NR_FIELDS)
     457             :     {
     458           0 :       field[fields++] = line;
     459           0 :       line = strchr (line, ':');
     460           0 :       if (line)
     461           0 :         *(line++) = '\0';
     462             :     }
     463             : 
     464             :   /* We require at least the first 10 fields.  */
     465           0 :   if (fields < 10)
     466           0 :     return trace_gpg_error (GPG_ERR_INV_ENGINE);
     467             : 
     468           0 :   opt = calloc (1, sizeof (*opt));
     469           0 :   if (!opt)
     470           0 :     return gpg_error_from_syserror ();
     471             : 
     472           0 :   comp->_last_opt_p = &opt->next;
     473           0 :   *opt_p = opt;
     474             : 
     475           0 :   if (field[0][0])
     476             :     {
     477           0 :       opt->name = strdup (field[0]);
     478           0 :       if (!opt->name)
     479           0 :         return gpg_error_from_syserror ();
     480             :     }
     481             : 
     482           0 :   opt->flags = strtoul (field[1], NULL, 0);
     483             : 
     484           0 :   opt->level = strtoul (field[2], NULL, 0);
     485             : 
     486           0 :   if (field[3][0])
     487             :     {
     488           0 :       opt->description = strdup (field[3]);
     489           0 :       if (!opt->description)
     490           0 :         return gpg_error_from_syserror ();
     491             :     }
     492             : 
     493           0 :   opt->type = strtoul (field[4], NULL, 0);
     494             : 
     495           0 :   opt->alt_type = strtoul (field[5], NULL, 0);
     496             : 
     497           0 :   if (field[6][0])
     498             :     {
     499           0 :       opt->argname = strdup (field[6]);
     500           0 :       if (!opt->argname)
     501           0 :         return gpg_error_from_syserror ();
     502             :     }
     503             : 
     504           0 :   if (opt->flags & GPGME_CONF_DEFAULT)
     505             :     {
     506           0 :       err = gpgconf_parse_option (opt, &opt->default_value, field[7]);
     507           0 :       if (err)
     508           0 :         return err;
     509             :     }
     510           0 :   else if ((opt->flags & GPGME_CONF_DEFAULT_DESC) && field[7][0])
     511             :     {
     512           0 :       opt->default_description = strdup (field[7]);
     513           0 :       if (!opt->default_description)
     514           0 :         return gpg_error_from_syserror ();
     515             :     }
     516             : 
     517           0 :   if (opt->flags & GPGME_CONF_NO_ARG_DESC)
     518             :     {
     519           0 :       opt->no_arg_description = strdup (field[8]);
     520           0 :       if (!opt->no_arg_description)
     521           0 :         return gpg_error_from_syserror ();
     522             :     }
     523             :   else
     524             :     {
     525           0 :       err = gpgconf_parse_option (opt, &opt->no_arg_value, field[8]);
     526           0 :       if (err)
     527           0 :         return err;
     528             :     }
     529             : 
     530           0 :   err = gpgconf_parse_option (opt, &opt->value, field[9]);
     531           0 :   if (err)
     532           0 :     return err;
     533             : 
     534           0 :   return 0;
     535             : }
     536             : 
     537             : 
     538             : static gpgme_error_t
     539           0 : gpgconf_conf_load (void *engine, gpgme_conf_comp_t *comp_p)
     540             : {
     541             :   gpgme_error_t err;
     542           0 :   gpgme_conf_comp_t comp = NULL;
     543             :   gpgme_conf_comp_t cur_comp;
     544             : 
     545           0 :   *comp_p = NULL;
     546             : 
     547           0 :   err = gpgconf_read (engine, "--list-components", NULL,
     548             :                       gpgconf_config_load_cb, &comp);
     549           0 :   if (err)
     550             :     {
     551           0 :       gpgconf_release (comp);
     552           0 :       return err;
     553             :     }
     554             : 
     555           0 :   cur_comp = comp;
     556           0 :   while (!err && cur_comp)
     557             :     {
     558           0 :       err = gpgconf_read (engine, "--list-options", cur_comp->name,
     559             :                           gpgconf_config_load_cb2, cur_comp);
     560           0 :       cur_comp = cur_comp->next;
     561             :     }
     562             : 
     563           0 :   if (err)
     564             :     {
     565           0 :       gpgconf_release (comp);
     566           0 :       return err;
     567             :     }
     568             : 
     569           0 :   *comp_p = comp;
     570           0 :   return 0;
     571             : }
     572             : 
     573             : 
     574             : 
     575             : gpgme_error_t
     576           0 : _gpgme_conf_arg_new (gpgme_conf_arg_t *arg_p,
     577             :                      gpgme_conf_type_t type, const void *value)
     578             : {
     579             :   gpgme_conf_arg_t arg;
     580             : 
     581           0 :   arg = calloc (1, sizeof (*arg));
     582           0 :   if (!arg)
     583           0 :     return gpg_error_from_syserror ();
     584             : 
     585           0 :   if (!value)
     586           0 :     arg->no_arg = 1;
     587             :   else
     588             :     {
     589             :       /* We need to switch on type here because the alt-type is not
     590             :          yet known.  */
     591           0 :       switch (type)
     592             :         {
     593             :         case GPGME_CONF_NONE:
     594             :         case GPGME_CONF_UINT32:
     595           0 :           arg->value.uint32 = *((unsigned int *) value);
     596           0 :           break;
     597             : 
     598             :         case GPGME_CONF_INT32:
     599           0 :           arg->value.int32 = *((int *) value);
     600           0 :           break;
     601             : 
     602             :         case GPGME_CONF_STRING:
     603             :         case GPGME_CONF_FILENAME:
     604             :         case GPGME_CONF_LDAP_SERVER:
     605             :         case GPGME_CONF_KEY_FPR:
     606             :         case GPGME_CONF_PUB_KEY:
     607             :         case GPGME_CONF_SEC_KEY:
     608             :         case GPGME_CONF_ALIAS_LIST:
     609           0 :           arg->value.string = strdup (value);
     610           0 :           if (!arg->value.string)
     611             :             {
     612           0 :               free (arg);
     613           0 :               return gpg_error_from_syserror ();
     614             :             }
     615           0 :           break;
     616             : 
     617             :         default:
     618           0 :           free (arg);
     619           0 :           return gpg_error (GPG_ERR_INV_VALUE);
     620             :         }
     621             :     }
     622             : 
     623           0 :   *arg_p = arg;
     624           0 :   return 0;
     625             : }
     626             : 
     627             : 
     628             : void
     629           0 : _gpgme_conf_arg_release (gpgme_conf_arg_t arg, gpgme_conf_type_t type)
     630             : {
     631             :   /* Lacking the alt_type we need to switch on type here.  */
     632           0 :   switch (type)
     633             :     {
     634             :     case GPGME_CONF_NONE:
     635             :     case GPGME_CONF_UINT32:
     636             :     case GPGME_CONF_INT32:
     637             :     case GPGME_CONF_STRING:
     638             :     default:
     639           0 :       break;
     640             : 
     641             :     case GPGME_CONF_FILENAME:
     642             :     case GPGME_CONF_LDAP_SERVER:
     643             :     case GPGME_CONF_KEY_FPR:
     644             :     case GPGME_CONF_PUB_KEY:
     645             :     case GPGME_CONF_SEC_KEY:
     646             :     case GPGME_CONF_ALIAS_LIST:
     647           0 :       type = GPGME_CONF_STRING;
     648           0 :       break;
     649             :     }
     650             : 
     651           0 :   release_arg (arg, type);
     652           0 : }
     653             : 
     654             : 
     655             : gpgme_error_t
     656           0 : _gpgme_conf_opt_change (gpgme_conf_opt_t opt, int reset, gpgme_conf_arg_t arg)
     657             : {
     658           0 :   if (reset)
     659             :     {
     660           0 :       if (opt->new_value)
     661           0 :         release_arg (opt->new_value, opt->alt_type);
     662           0 :       opt->new_value = NULL;
     663           0 :       opt->change_value = 0;
     664             :     }
     665             :   else
     666             :     {
     667             :       /* Support self-assignment, for example for adding an item to an
     668             :          existing list.  */
     669           0 :       if (opt->new_value && arg != opt->new_value)
     670           0 :         release_arg (opt->new_value, opt->alt_type);
     671           0 :       opt->new_value = arg;
     672           0 :       opt->change_value = 1;
     673             :     }
     674           0 :   return 0;
     675             : }
     676             : 
     677             : 
     678             : /* FIXME: Major problem: We don't get errors from gpgconf.  */
     679             : 
     680             : static gpgme_error_t
     681           0 : gpgconf_write (void *engine, char *arg1, char *arg2, gpgme_data_t conf)
     682             : {
     683           0 :   struct engine_gpgconf *gpgconf = engine;
     684           0 :   gpgme_error_t err = 0;
     685             : #define BUFLEN 1024
     686             :   char buf[BUFLEN];
     687           0 :   int buflen = 0;
     688           0 :   char *argv[] = { NULL /* file_name */, arg1, arg2, 0 };
     689             :   int rp[2];
     690           0 :   struct spawn_fd_item_s cfd[] = { {-1, 0 /* STDIN_FILENO */}, {-1, -1} };
     691             :   int status;
     692             :   int nwrite;
     693             : 
     694             :   /* FIXME: Deal with engine->home_dir.  */
     695             : 
     696             :   /* _gpgme_engine_new guarantees that this is not NULL.  */
     697           0 :   argv[0] = gpgconf->file_name;
     698             : 
     699           0 :   if (_gpgme_io_pipe (rp, 0) < 0)
     700           0 :     return gpg_error_from_syserror ();
     701             : 
     702           0 :   cfd[0].fd = rp[0];
     703             : 
     704           0 :   status = _gpgme_io_spawn (gpgconf->file_name, argv,
     705             :                             IOSPAWN_FLAG_DETACHED, cfd, NULL, NULL, NULL);
     706           0 :   if (status < 0)
     707             :     {
     708           0 :       _gpgme_io_close (rp[0]);
     709           0 :       _gpgme_io_close (rp[1]);
     710           0 :       return gpg_error_from_syserror ();
     711             :     }
     712             : 
     713             :   for (;;)
     714             :     {
     715           0 :       if (buflen == 0)
     716             :         {
     717             :           do
     718             :             {
     719           0 :               buflen = gpgme_data_read (conf, buf, BUFLEN);
     720             :             }
     721           0 :           while (buflen < 0 && errno == EAGAIN);
     722             : 
     723           0 :           if (buflen < 0)
     724             :             {
     725           0 :               err = gpg_error_from_syserror ();
     726           0 :               _gpgme_io_close (rp[1]);
     727           0 :               return err;
     728             :             }
     729           0 :           else if (buflen == 0)
     730             :             {
     731             :               /* All is written.  */
     732           0 :               _gpgme_io_close (rp[1]);
     733           0 :               return 0;
     734             :             }
     735             :         }
     736             : 
     737             :       do
     738             :         {
     739           0 :           nwrite = _gpgme_io_write (rp[1], buf, buflen);
     740             :         }
     741           0 :       while (nwrite < 0 && errno == EAGAIN);
     742             : 
     743           0 :       if (nwrite > 0)
     744             :         {
     745           0 :           buflen -= nwrite;
     746           0 :           if (buflen > 0)
     747           0 :             memmove (&buf[0], &buf[nwrite], buflen);
     748             :         }
     749           0 :       else if (nwrite < 0)
     750             :         {
     751           0 :           _gpgme_io_close (rp[1]);
     752           0 :           return gpg_error_from_syserror ();
     753             :         }
     754           0 :     }
     755             : 
     756             :   return 0;
     757             : }
     758             : 
     759             : 
     760             : static gpgme_error_t
     761           0 : arg_to_data (gpgme_data_t conf, gpgme_conf_opt_t option, gpgme_conf_arg_t arg)
     762             : {
     763           0 :   gpgme_error_t err = 0;
     764           0 :   int amt = 0;
     765             :   char buf[16];
     766             : 
     767           0 :   while (amt >= 0 && arg)
     768             :     {
     769           0 :       switch (option->alt_type)
     770             :         {
     771             :         case GPGME_CONF_NONE:
     772             :         case GPGME_CONF_UINT32:
     773             :         default:
     774           0 :           snprintf (buf, sizeof (buf), "%u", arg->value.uint32);
     775           0 :           buf[sizeof (buf) - 1] = '\0';
     776           0 :           amt = gpgme_data_write (conf, buf, strlen (buf));
     777           0 :           break;
     778             : 
     779             :         case GPGME_CONF_INT32:
     780           0 :           snprintf (buf, sizeof (buf), "%i", arg->value.uint32);
     781           0 :           buf[sizeof (buf) - 1] = '\0';
     782           0 :           amt = gpgme_data_write (conf, buf, strlen (buf));
     783           0 :           break;
     784             : 
     785             : 
     786             :         case GPGME_CONF_STRING:
     787             :           /* The complex types below are only here to silent the
     788             :              compiler warning. */
     789             :         case GPGME_CONF_FILENAME:
     790             :         case GPGME_CONF_LDAP_SERVER:
     791             :         case GPGME_CONF_KEY_FPR:
     792             :         case GPGME_CONF_PUB_KEY:
     793             :         case GPGME_CONF_SEC_KEY:
     794             :         case GPGME_CONF_ALIAS_LIST:
     795           0 :           if (arg->value.string)
     796             :             {
     797             :               /* One quote character, and three times to allow for
     798             :                  percent escaping.  */
     799           0 :               char *ptr = arg->value.string;
     800           0 :               amt = gpgme_data_write (conf, "\"", 1);
     801           0 :               if (amt < 0)
     802           0 :                 break;
     803             : 
     804           0 :               while (!err && *ptr)
     805             :                 {
     806           0 :                   switch (*ptr)
     807             :                     {
     808             :                     case '%':
     809           0 :                       amt = gpgme_data_write (conf, "%25", 3);
     810           0 :                       break;
     811             : 
     812             :                     case ':':
     813           0 :                       amt = gpgme_data_write (conf, "%3a", 3);
     814           0 :                       break;
     815             : 
     816             :                     case ',':
     817           0 :                       amt = gpgme_data_write (conf, "%2c", 3);
     818           0 :                       break;
     819             : 
     820             :                     default:
     821           0 :                       amt = gpgme_data_write (conf, ptr, 1);
     822             :                     }
     823           0 :                   ptr++;
     824             :                 }
     825             :             }
     826           0 :           break;
     827             :         }
     828             : 
     829           0 :       if (amt < 0)
     830           0 :         break;
     831             : 
     832           0 :       arg = arg->next;
     833             :       /* Comma separator.  */
     834           0 :       if (arg)
     835           0 :         amt = gpgme_data_write (conf, ",", 1);
     836             :     }
     837             : 
     838           0 :   if (amt < 0)
     839           0 :     return gpg_error_from_syserror ();
     840             : 
     841           0 :   return 0;
     842             : }
     843             : 
     844             : 
     845             : static gpgme_error_t
     846           0 : gpgconf_conf_save (void *engine, gpgme_conf_comp_t comp)
     847             : {
     848             :   gpgme_error_t err;
     849           0 :   int amt = 0;
     850             :   /* We use a data object to store the new configuration.  */
     851             :   gpgme_data_t conf;
     852             :   gpgme_conf_opt_t option;
     853           0 :   int something_changed = 0;
     854             : 
     855           0 :   err = gpgme_data_new (&conf);
     856           0 :   if (err)
     857           0 :     return err;
     858             : 
     859           0 :   option = comp->options;
     860           0 :   while (!err && amt >= 0 && option)
     861             :     {
     862           0 :       if (option->change_value)
     863             :         {
     864           0 :           unsigned int flags = 0;
     865             :           char buf[16];
     866             : 
     867           0 :           something_changed = 1;
     868             : 
     869           0 :           amt = gpgme_data_write (conf, option->name, strlen (option->name));
     870           0 :           if (amt >= 0)
     871           0 :             amt = gpgme_data_write (conf, ":", 1);
     872           0 :           if (amt < 0)
     873           0 :             break;
     874             : 
     875           0 :           if (!option->new_value)
     876           0 :             flags |= GPGME_CONF_DEFAULT;
     877           0 :           snprintf (buf, sizeof (buf), "%u", flags);
     878           0 :           buf[sizeof (buf) - 1] = '\0';
     879             : 
     880           0 :           amt = gpgme_data_write (conf, buf, strlen (buf));
     881           0 :           if (amt >= 0)
     882           0 :             amt = gpgme_data_write (conf, ":", 1);
     883           0 :           if (amt < 0)
     884           0 :             break;
     885             : 
     886           0 :           if (option->new_value)
     887             :             {
     888           0 :               err = arg_to_data (conf, option, option->new_value);
     889           0 :               if (err)
     890           0 :                 break;
     891             :             }
     892           0 :           amt = gpgme_data_write (conf, "\n", 1);
     893             :         }
     894           0 :       option = option->next;
     895             :     }
     896           0 :   if (!err && amt < 0)
     897           0 :     err = gpg_error_from_syserror ();
     898           0 :   if (err || !something_changed)
     899             :     goto bail;
     900             : 
     901           0 :   err = gpgme_data_seek (conf, 0, SEEK_SET);
     902           0 :   if (err)
     903           0 :     goto bail;
     904             : 
     905           0 :   err = gpgconf_write (engine, "--change-options", comp->name, conf);
     906             :  bail:
     907           0 :   gpgme_data_release (conf);
     908           0 :   return err;
     909             : }
     910             : 
     911             : 
     912             : static void
     913           0 : gpgconf_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
     914             : {
     915             :   /* Nothing to do.  */
     916           0 : }
     917             : 
     918             : 
     919             : /* Currently, we do not use the engine interface for the various
     920             :    operations.  */
     921             : void
     922           0 : _gpgme_conf_release (gpgme_conf_comp_t conf)
     923             : {
     924           0 :   gpgconf_config_release (conf);
     925           0 : }
     926             : 
     927             : 
     928             : struct engine_ops _gpgme_engine_ops_gpgconf =
     929             :   {
     930             :     /* Static functions.  */
     931             :     _gpgme_get_default_gpgconf_name,
     932             :     NULL,
     933             :     gpgconf_get_version,
     934             :     gpgconf_get_req_version,
     935             :     gpgconf_new,
     936             : 
     937             :     /* Member functions.  */
     938             :     gpgconf_release,
     939             :     NULL,               /* reset */
     940             :     NULL,               /* set_status_cb */
     941             :     NULL,               /* set_status_handler */
     942             :     NULL,               /* set_command_handler */
     943             :     NULL,               /* set_colon_line_handler */
     944             :     NULL,               /* set_locale */
     945             :     NULL,               /* set_protocol */
     946             :     NULL,               /* decrypt */
     947             :     NULL,               /* decrypt_verify */
     948             :     NULL,               /* delete */
     949             :     NULL,               /* edit */
     950             :     NULL,               /* encrypt */
     951             :     NULL,               /* encrypt_sign */
     952             :     NULL,               /* export */
     953             :     NULL,               /* export_ext */
     954             :     NULL,               /* genkey */
     955             :     NULL,               /* import */
     956             :     NULL,               /* keylist */
     957             :     NULL,               /* keylist_ext */
     958             :     NULL,               /* sign */
     959             :     NULL,               /* trustlist */
     960             :     NULL,               /* verify */
     961             :     NULL,               /* getauditlog */
     962             :     NULL,               /* opassuan_transact */
     963             :     gpgconf_conf_load,
     964             :     gpgconf_conf_save,
     965             :     gpgconf_set_io_cbs,
     966             :     NULL,               /* io_event */
     967             :     NULL,               /* cancel */
     968             :     NULL,               /* cancel_op */
     969             :     NULL,               /* passwd */
     970             :     NULL,               /* set_pinentry_mode */
     971             :     NULL                /* opspawn */
     972             :   };

Generated by: LCOV version 1.11