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

Generated by: LCOV version 1.11