LCOV - code coverage report
Current view: top level - src - dirinfo.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 174 202 86.1 %
Date: 2016-12-01 18:45:36 Functions: 13 15 86.7 %

          Line data    Source code
       1             : /* dirinfo.c - Get directory information
       2             :  * Copyright (C) 2009, 2013 g10 Code GmbH
       3             :  *
       4             :  * This file is part of GPGME.
       5             :  *
       6             :  * GPGME is free software; you can redistribute it and/or modify it
       7             :  * under the terms of the GNU Lesser General Public License as
       8             :  * published by the Free Software Foundation; either version 2.1 of
       9             :  * the License, or (at your option) any later version.
      10             :  *
      11             :  * GPGME is distributed in the hope that it will be useful, but
      12             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :  * Lesser General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU Lesser General Public
      17             :  * License along with this program; if not, see <https://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : #if HAVE_CONFIG_H
      21             : #include <config.h>
      22             : #endif
      23             : 
      24             : #include <stdlib.h>
      25             : #include <string.h>
      26             : 
      27             : #include "gpgme.h"
      28             : #include "util.h"
      29             : #include "priv-io.h"
      30             : #include "debug.h"
      31             : #include "sema.h"
      32             : #include "sys-util.h"
      33             : 
      34             : DEFINE_STATIC_LOCK (dirinfo_lock);
      35             : 
      36             : /* Constants used internally to select the data.  */
      37             : enum
      38             :   {
      39             :     WANT_HOMEDIR,
      40             :     WANT_SYSCONFDIR,
      41             :     WANT_BINDIR,
      42             :     WANT_LIBEXECDIR,
      43             :     WANT_LIBDIR,
      44             :     WANT_DATADIR,
      45             :     WANT_LOCALEDIR,
      46             :     WANT_AGENT_SOCKET,
      47             :     WANT_AGENT_SSH_SOCKET,
      48             :     WANT_DIRMNGR_SOCKET,
      49             :     WANT_UISRV_SOCKET,
      50             :     WANT_GPGCONF_NAME,
      51             :     WANT_GPG_NAME,
      52             :     WANT_GPGSM_NAME,
      53             :     WANT_G13_NAME,
      54             :     WANT_GPG_ONE_MODE
      55             :   };
      56             : 
      57             : /* Values retrieved via gpgconf and cached here.  */
      58             : static struct {
      59             :   int  valid;         /* Cached information is valid.  */
      60             :   int  disable_gpgconf;
      61             :   char *homedir;
      62             :   char *sysconfdir;
      63             :   char *bindir;
      64             :   char *libexecdir;
      65             :   char *libdir;
      66             :   char *datadir;
      67             :   char *localedir;
      68             :   char *agent_socket;
      69             :   char *agent_ssh_socket;
      70             :   char *dirmngr_socket;
      71             :   char *uisrv_socket;
      72             :   char *gpgconf_name;
      73             :   char *gpg_name;
      74             :   char *gpgsm_name;
      75             :   char *g13_name;
      76             :   int  gpg_one_mode;  /* System is in gpg1 mode.  */
      77             : } dirinfo;
      78             : 
      79             : 
      80             : 
      81             : /* Helper function to be used only by gpgme_set_global_flag.  */
      82             : void
      83           0 : _gpgme_dirinfo_disable_gpgconf (void)
      84             : {
      85           0 :   dirinfo.disable_gpgconf = 1;
      86           0 : }
      87             : 
      88             : 
      89             : /* Return the length of the directory part including the trailing
      90             :  * slash of NAME.  */
      91             : static size_t
      92          79 : dirname_len (const char *name)
      93             : {
      94          79 :   return _gpgme_get_basename (name) - name;
      95             : }
      96             : 
      97             : 
      98             : /* Parse the output of "gpgconf --list-dirs".  This function expects
      99             :    that DIRINFO_LOCK is held by the caller.  If COMPONENTS is set, the
     100             :    output of --list-components is expected. */
     101             : static void
     102        1501 : parse_output (char *line, int components)
     103             : {
     104             :   char *value, *p;
     105             :   size_t n;
     106             : 
     107        1501 :   value = strchr (line, ':');
     108        1501 :   if (!value)
     109           0 :     return;
     110        1501 :   *value++ = 0;
     111        1501 :   if (components)
     112             :     {
     113             :       /* Skip the second field.  */
     114         474 :       value = strchr (value, ':');
     115         474 :       if (!value)
     116           0 :         return;
     117         474 :       *value++ = 0;
     118             :     }
     119        1501 :   p = strchr (value, ':');
     120        1501 :   if (p)
     121           0 :     *p = 0;
     122        1501 :   if (_gpgme_decode_percent_string (value, &value, strlen (value)+1, 0))
     123           0 :     return;
     124        1501 :   if (!*value)
     125           0 :     return;
     126             : 
     127        1501 :   if (components)
     128             :     {
     129         474 :       if (!strcmp (line, "gpg") && !dirinfo.gpg_name)
     130          79 :         dirinfo.gpg_name = strdup (value);
     131         395 :       else if (!strcmp (line, "gpgsm") && !dirinfo.gpgsm_name)
     132          79 :         dirinfo.gpgsm_name = strdup (value);
     133         316 :       else if (!strcmp (line, "g13") && !dirinfo.g13_name)
     134           0 :         dirinfo.g13_name = strdup (value);
     135             :     }
     136             :   else
     137             :     {
     138        1027 :       if (!strcmp (line, "homedir") && !dirinfo.homedir)
     139          79 :         dirinfo.homedir = strdup (value);
     140         948 :       else if (!strcmp (line, "sysconfdir") && !dirinfo.sysconfdir)
     141          79 :         dirinfo.sysconfdir = strdup (value);
     142         869 :       else if (!strcmp (line, "bindir") && !dirinfo.bindir)
     143          79 :         dirinfo.bindir = strdup (value);
     144         790 :       else if (!strcmp (line, "libexecdir") && !dirinfo.libexecdir)
     145          79 :         dirinfo.libexecdir = strdup (value);
     146         711 :       else if (!strcmp (line, "libdir") && !dirinfo.libdir)
     147          79 :         dirinfo.libdir = strdup (value);
     148         632 :       else if (!strcmp (line, "datadir") && !dirinfo.datadir)
     149          79 :         dirinfo.datadir = strdup (value);
     150         553 :       else if (!strcmp (line, "localedir") && !dirinfo.localedir)
     151          79 :         dirinfo.localedir = strdup (value);
     152         474 :       else if (!strcmp (line, "agent-socket") && !dirinfo.agent_socket)
     153          79 :         {
     154          79 :           const char name[] = "S.uiserver";
     155             :           char *buffer;
     156             : 
     157          79 :           dirinfo.agent_socket = strdup (value);
     158          79 :           if (dirinfo.agent_socket)
     159             :             {
     160          79 :               n = dirname_len (dirinfo.agent_socket);
     161          79 :               buffer = malloc (n + strlen (name) + 1);
     162          79 :               if (buffer)
     163             :                 {
     164          79 :                   strncpy (buffer, dirinfo.agent_socket, n);
     165          79 :                   strcpy (buffer + n, name);
     166          79 :                   dirinfo.uisrv_socket = buffer;
     167             :                 }
     168             :             }
     169             :         }
     170         395 :       else if (!strcmp (line, "dirmngr-socket") && !dirinfo.dirmngr_socket)
     171          79 :         dirinfo.dirmngr_socket = strdup (value);
     172         316 :       else if (!strcmp (line, "agent-ssh-socket") && !dirinfo.agent_ssh_socket)
     173          79 :         dirinfo.agent_ssh_socket = strdup (value);
     174             :     }
     175             : }
     176             : 
     177             : 
     178             : /* Read the directory information from gpgconf.  This function expects
     179             :    that DIRINFO_LOCK is held by the caller.  PGNAME is the name of the
     180             :    gpgconf binary. If COMPONENTS is set, not the directories bit the
     181             :    name of the componeNts are read. */
     182             : static void
     183         158 : read_gpgconf_dirs (const char *pgmname, int components)
     184             : {
     185         158 :   char linebuf[1024] = {0};
     186         158 :   int linelen = 0;
     187             :   char * argv[3];
     188             :   int rp[2];
     189         158 :   struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
     190             :                                    {-1, -1} };
     191             :   int status;
     192             :   int nread;
     193         158 :   char *mark = NULL;
     194             : 
     195         158 :   argv[0] = (char *)pgmname;
     196         158 :   argv[1] = (char*)(components? "--list-components" : "--list-dirs");
     197         158 :   argv[2] = NULL;
     198             : 
     199         158 :   if (_gpgme_io_pipe (rp, 1) < 0)
     200           0 :     return;
     201             : 
     202         158 :   cfd[0].fd = rp[1];
     203             : 
     204         158 :   status = _gpgme_io_spawn (pgmname, argv, IOSPAWN_FLAG_DETACHED,
     205             :                             cfd, NULL, NULL, NULL);
     206         158 :   if (status < 0)
     207             :     {
     208           0 :       _gpgme_io_close (rp[0]);
     209           0 :       _gpgme_io_close (rp[1]);
     210           0 :       return;
     211             :     }
     212             : 
     213             :   do
     214             :     {
     215         316 :       nread = _gpgme_io_read (rp[0],
     216             :                               linebuf + linelen,
     217             :                               sizeof linebuf - linelen - 1);
     218         316 :       if (nread > 0)
     219             :         {
     220             :           char *line;
     221         158 :           const char *lastmark = NULL;
     222             :           size_t nused;
     223             : 
     224         158 :           linelen += nread;
     225         158 :           linebuf[linelen] = '\0';
     226             : 
     227        1659 :           for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
     228             :             {
     229        1501 :               lastmark = mark;
     230        1501 :               if (mark > line && mark[-1] == '\r')
     231           0 :                 mark[-1] = '\0';
     232             :               else
     233        1501 :                 mark[0] = '\0';
     234             : 
     235        1501 :               parse_output (line, components);
     236             :             }
     237             : 
     238         158 :           nused = lastmark? (lastmark + 1 - linebuf) : 0;
     239         158 :           memmove (linebuf, linebuf + nused, linelen - nused);
     240         158 :           linelen -= nused;
     241             :         }
     242             :     }
     243         316 :   while (nread > 0 && linelen < sizeof linebuf - 1);
     244             : 
     245         158 :   _gpgme_io_close (rp[0]);
     246             : }
     247             : 
     248             : 
     249             : static const char *
     250        1256 : get_gpgconf_item (int what)
     251             : {
     252        1256 :   const char *result = NULL;
     253             : 
     254        1256 :   LOCK (dirinfo_lock);
     255        1258 :   if (!dirinfo.valid)
     256             :     {
     257             :       char *pgmname;
     258             : 
     259          79 :       pgmname = dirinfo.disable_gpgconf? NULL : _gpgme_get_gpgconf_path ();
     260          79 :       if (pgmname && access (pgmname, F_OK))
     261             :         {
     262           0 :           _gpgme_debug (DEBUG_INIT,
     263             :                         "gpgme-dinfo: gpgconf='%s' [not installed]\n", pgmname);
     264           0 :           free (pgmname);
     265           0 :           pgmname = NULL; /* Not available.  */
     266             :         }
     267             :       else
     268          79 :         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: gpgconf='%s'\n",
     269             :                       pgmname? pgmname : "[null]");
     270          79 :       if (!pgmname)
     271             :         {
     272             :           /* Probably gpgconf is not installed.  Assume we are using
     273             :              GnuPG-1.  */
     274           0 :           dirinfo.gpg_one_mode = 1;
     275           0 :           pgmname = _gpgme_get_gpg_path ();
     276           0 :           if (pgmname)
     277           0 :             dirinfo.gpg_name = pgmname;
     278             :         }
     279             :       else
     280             :         {
     281          79 :           dirinfo.gpg_one_mode = 0;
     282          79 :           read_gpgconf_dirs (pgmname, 0);
     283          79 :           read_gpgconf_dirs (pgmname, 1);
     284          79 :           dirinfo.gpgconf_name = pgmname;
     285             :         }
     286             :       /* Even if the reading of the directories failed (e.g. due to an
     287             :          too old version gpgconf or no gpgconf at all), we need to
     288             :          mark the entries as valid so that we won't try over and over
     289             :          to read them.  Note further that we are not able to change
     290             :          the read values later because they are practically statically
     291             :          allocated.  */
     292          79 :       dirinfo.valid = 1;
     293          79 :       if (dirinfo.gpg_name)
     294          79 :         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:     gpg='%s'\n",
     295             :                       dirinfo.gpg_name);
     296          79 :       if (dirinfo.g13_name)
     297           0 :         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:     g13='%s'\n",
     298             :                       dirinfo.g13_name);
     299          79 :       if (dirinfo.gpgsm_name)
     300          79 :         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:   gpgsm='%s'\n",
     301             :                       dirinfo.gpgsm_name);
     302          79 :       if (dirinfo.homedir)
     303          79 :         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: homedir='%s'\n",
     304             :                       dirinfo.homedir);
     305          79 :       if (dirinfo.agent_socket)
     306          79 :         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:   agent='%s'\n",
     307             :                       dirinfo.agent_socket);
     308          79 :       if (dirinfo.agent_ssh_socket)
     309          79 :         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:     ssh='%s'\n",
     310             :                       dirinfo.agent_ssh_socket);
     311          79 :       if (dirinfo.dirmngr_socket)
     312          79 :         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: dirmngr='%s'\n",
     313             :                       dirinfo.dirmngr_socket);
     314          79 :       if (dirinfo.uisrv_socket)
     315          79 :         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:   uisrv='%s'\n",
     316             :                       dirinfo.uisrv_socket);
     317             :     }
     318        1258 :   switch (what)
     319             :     {
     320           1 :     case WANT_HOMEDIR:    result = dirinfo.homedir; break;
     321           1 :     case WANT_SYSCONFDIR: result = dirinfo.sysconfdir; break;
     322           1 :     case WANT_BINDIR:     result = dirinfo.bindir; break;
     323           1 :     case WANT_LIBEXECDIR: result = dirinfo.libexecdir; break;
     324           1 :     case WANT_LIBDIR:     result = dirinfo.libdir; break;
     325           1 :     case WANT_DATADIR:    result = dirinfo.datadir; break;
     326           1 :     case WANT_LOCALEDIR:  result = dirinfo.localedir; break;
     327          80 :     case WANT_AGENT_SOCKET: result = dirinfo.agent_socket; break;
     328           1 :     case WANT_AGENT_SSH_SOCKET: result = dirinfo.agent_ssh_socket; break;
     329           1 :     case WANT_DIRMNGR_SOCKET: result = dirinfo.dirmngr_socket; break;
     330         159 :     case WANT_GPGCONF_NAME: result = dirinfo.gpgconf_name; break;
     331         159 :     case WANT_GPG_NAME:   result = dirinfo.gpg_name; break;
     332         159 :     case WANT_GPGSM_NAME: result = dirinfo.gpgsm_name; break;
     333         159 :     case WANT_G13_NAME:   result = dirinfo.g13_name; break;
     334          80 :     case WANT_UISRV_SOCKET:  result = dirinfo.uisrv_socket; break;
     335         453 :     case WANT_GPG_ONE_MODE: result = dirinfo.gpg_one_mode? "1":NULL; break;
     336             :     }
     337        1258 :   UNLOCK (dirinfo_lock);
     338        1258 :   return result;
     339             : }
     340             : 
     341             : 
     342             : /* Return the default home directory.   Returns NULL if not known.  */
     343             : const char *
     344           0 : _gpgme_get_default_homedir (void)
     345             : {
     346           0 :   return get_gpgconf_item (WANT_HOMEDIR);
     347             : }
     348             : 
     349             : /* Return the default gpg-agent socket name.  Returns NULL if not known.  */
     350             : const char *
     351          79 : _gpgme_get_default_agent_socket (void)
     352             : {
     353          79 :   return get_gpgconf_item (WANT_AGENT_SOCKET);
     354             : }
     355             : 
     356             : /* Return the default gpg file name.  Returns NULL if not known.  */
     357             : const char *
     358         158 : _gpgme_get_default_gpg_name (void)
     359             : {
     360         158 :   return get_gpgconf_item (WANT_GPG_NAME);
     361             : }
     362             : 
     363             : /* Return the default gpgsm file name.  Returns NULL if not known.  */
     364             : const char *
     365         158 : _gpgme_get_default_gpgsm_name (void)
     366             : {
     367         158 :   return get_gpgconf_item (WANT_GPGSM_NAME);
     368             : }
     369             : 
     370             : /* Return the default g13 file name.  Returns NULL if not known.  */
     371             : const char *
     372         158 : _gpgme_get_default_g13_name (void)
     373             : {
     374         158 :   return get_gpgconf_item (WANT_G13_NAME);
     375             : }
     376             : 
     377             : /* Return the default gpgconf file name.  Returns NULL if not known.  */
     378             : const char *
     379         158 : _gpgme_get_default_gpgconf_name (void)
     380             : {
     381         158 :   return get_gpgconf_item (WANT_GPGCONF_NAME);
     382             : }
     383             : 
     384             : /* Return the default UI-server socket name.  Returns NULL if not
     385             :    known.  */
     386             : const char *
     387          79 : _gpgme_get_default_uisrv_socket (void)
     388             : {
     389          79 :   return get_gpgconf_item (WANT_UISRV_SOCKET);
     390             : }
     391             : 
     392             : /* Return true if we are in GnuPG-1 mode - ie. no gpgconf and agent
     393             :    being optional.  */
     394             : int
     395         451 : _gpgme_in_gpg_one_mode (void)
     396             : {
     397         451 :   return !!get_gpgconf_item (WANT_GPG_ONE_MODE);
     398             : }
     399             : 
     400             : 
     401             : 
     402             : /* Helper function to return the basename of the passed filename.  */
     403             : const char *
     404         540 : _gpgme_get_basename (const char *name)
     405             : {
     406             :   const char *s;
     407             : 
     408         540 :   if (!name || !*name)
     409           0 :     return name;
     410        3260 :   for (s = name + strlen (name) -1; s >= name; s--)
     411        3260 :     if (*s == '/'
     412             : #ifdef HAVE_W32_SYSTEM
     413             :         || *s == '\\' || *s == ':'
     414             : #endif
     415             :         )
     416         540 :       return s+1;
     417           0 :   return name;
     418             : }
     419             : 
     420             : 
     421             : /* Return default values for various directories and file names.  */
     422             : const char *
     423          15 : gpgme_get_dirinfo (const char *what)
     424             : {
     425          15 :   if (!what)
     426           0 :     return NULL;
     427          15 :   else if (!strcmp (what, "homedir"))
     428           1 :     return get_gpgconf_item (WANT_HOMEDIR);
     429          14 :   else if (!strcmp (what, "agent-socket"))
     430           1 :     return get_gpgconf_item (WANT_AGENT_SOCKET);
     431          13 :   else if (!strcmp (what, "uiserver-socket"))
     432           1 :     return get_gpgconf_item (WANT_UISRV_SOCKET);
     433          12 :   else if (!strcmp (what, "gpgconf-name"))
     434           1 :     return get_gpgconf_item (WANT_GPGCONF_NAME);
     435          11 :   else if (!strcmp (what, "gpg-name"))
     436           1 :     return get_gpgconf_item (WANT_GPG_NAME);
     437          10 :   else if (!strcmp (what, "gpgsm-name"))
     438           1 :     return get_gpgconf_item (WANT_GPGSM_NAME);
     439           9 :   else if (!strcmp (what, "g13-name"))
     440           1 :     return get_gpgconf_item (WANT_G13_NAME);
     441           8 :   else if (!strcmp (what, "agent-ssh-socket"))
     442           1 :     return get_gpgconf_item (WANT_AGENT_SSH_SOCKET);
     443           7 :   else if (!strcmp (what, "dirmngr-socket"))
     444           1 :     return get_gpgconf_item (WANT_DIRMNGR_SOCKET);
     445           6 :   else if (!strcmp (what, "sysconfdir"))
     446           1 :     return get_gpgconf_item (WANT_SYSCONFDIR);
     447           5 :   else if (!strcmp (what, "bindir"))
     448           1 :     return get_gpgconf_item (WANT_BINDIR);
     449           4 :   else if (!strcmp (what, "libexecdir"))
     450           1 :     return get_gpgconf_item (WANT_LIBEXECDIR);
     451           3 :   else if (!strcmp (what, "libdir"))
     452           1 :     return get_gpgconf_item (WANT_LIBDIR);
     453           2 :   else if (!strcmp (what, "datadir"))
     454           1 :     return get_gpgconf_item (WANT_DATADIR);
     455           1 :   else if (!strcmp (what, "localedir"))
     456           1 :     return get_gpgconf_item (WANT_LOCALEDIR);
     457             :   else
     458           0 :     return NULL;
     459             : }

Generated by: LCOV version 1.11