LCOV - code coverage report
Current view: top level - src - dirinfo.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 180 208 86.5 %
Date: 2018-11-15 08:49:49 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_WKS_CLIENT_NAME,
      55             :     WANT_GPG_ONE_MODE
      56             :   };
      57             : 
      58             : /* Values retrieved via gpgconf and cached here.  */
      59             : static struct {
      60             :   int  valid;         /* Cached information is valid.  */
      61             :   int  disable_gpgconf;
      62             :   char *homedir;
      63             :   char *sysconfdir;
      64             :   char *bindir;
      65             :   char *libexecdir;
      66             :   char *libdir;
      67             :   char *datadir;
      68             :   char *localedir;
      69             :   char *agent_socket;
      70             :   char *agent_ssh_socket;
      71             :   char *dirmngr_socket;
      72             :   char *uisrv_socket;
      73             :   char *gpgconf_name;
      74             :   char *gpg_name;
      75             :   char *gpgsm_name;
      76             :   char *g13_name;
      77             :   char *gpg_wks_client_name;
      78             :   int  gpg_one_mode;  /* System is in gpg1 mode.  */
      79             : } dirinfo;
      80             : 
      81             : 
      82             : 
      83             : /* Helper function to be used only by gpgme_set_global_flag.  */
      84             : void
      85           0 : _gpgme_dirinfo_disable_gpgconf (void)
      86             : {
      87           0 :   dirinfo.disable_gpgconf = 1;
      88           0 : }
      89             : 
      90             : 
      91             : /* Return the length of the directory part including the trailing
      92             :  * slash of NAME.  */
      93             : static size_t
      94         117 : dirname_len (const char *name)
      95             : {
      96         117 :   return _gpgme_get_basename (name) - name;
      97             : }
      98             : 
      99             : 
     100             : /* Parse the output of "gpgconf --list-dirs".  This function expects
     101             :    that DIRINFO_LOCK is held by the caller.  If COMPONENTS is set, the
     102             :    output of --list-components is expected. */
     103             : static void
     104        2223 : parse_output (char *line, int components)
     105             : {
     106             :   char *value, *p;
     107             :   size_t n;
     108             : 
     109        2223 :   value = strchr (line, ':');
     110        2223 :   if (!value)
     111           0 :     return;
     112        2223 :   *value++ = 0;
     113        2223 :   if (components)
     114             :     {
     115             :       /* Skip the second field.  */
     116         702 :       value = strchr (value, ':');
     117         702 :       if (!value)
     118           0 :         return;
     119         702 :       *value++ = 0;
     120             :     }
     121        2223 :   p = strchr (value, ':');
     122        2223 :   if (p)
     123           0 :     *p = 0;
     124        2223 :   if (_gpgme_decode_percent_string (value, &value, strlen (value)+1, 0))
     125           0 :     return;
     126        2223 :   if (!*value)
     127           0 :     return;
     128             : 
     129        2223 :   if (components)
     130             :     {
     131         702 :       if (!strcmp (line, "gpg") && !dirinfo.gpg_name)
     132         117 :         dirinfo.gpg_name = strdup (value);
     133         585 :       else if (!strcmp (line, "gpgsm") && !dirinfo.gpgsm_name)
     134         117 :         dirinfo.gpgsm_name = strdup (value);
     135         468 :       else if (!strcmp (line, "g13") && !dirinfo.g13_name)
     136           0 :         dirinfo.g13_name = strdup (value);
     137             :     }
     138             :   else
     139             :     {
     140        1521 :       if (!strcmp (line, "homedir") && !dirinfo.homedir)
     141         117 :         dirinfo.homedir = strdup (value);
     142        1404 :       else if (!strcmp (line, "sysconfdir") && !dirinfo.sysconfdir)
     143         117 :         dirinfo.sysconfdir = strdup (value);
     144        1287 :       else if (!strcmp (line, "bindir") && !dirinfo.bindir)
     145         117 :         dirinfo.bindir = strdup (value);
     146        1170 :       else if (!strcmp (line, "libexecdir") && !dirinfo.libexecdir)
     147         117 :         dirinfo.libexecdir = strdup (value);
     148        1053 :       else if (!strcmp (line, "libdir") && !dirinfo.libdir)
     149         117 :         dirinfo.libdir = strdup (value);
     150         936 :       else if (!strcmp (line, "datadir") && !dirinfo.datadir)
     151         117 :         dirinfo.datadir = strdup (value);
     152         819 :       else if (!strcmp (line, "localedir") && !dirinfo.localedir)
     153         117 :         dirinfo.localedir = strdup (value);
     154         702 :       else if (!strcmp (line, "agent-socket") && !dirinfo.agent_socket)
     155         117 :         {
     156         117 :           const char name[] = "S.uiserver";
     157             :           char *buffer;
     158             : 
     159         117 :           dirinfo.agent_socket = strdup (value);
     160         117 :           if (dirinfo.agent_socket)
     161             :             {
     162         117 :               n = dirname_len (dirinfo.agent_socket);
     163         117 :               buffer = malloc (n + strlen (name) + 1);
     164         117 :               if (buffer)
     165             :                 {
     166         117 :                   strncpy (buffer, dirinfo.agent_socket, n);
     167         117 :                   strcpy (buffer + n, name);
     168         117 :                   dirinfo.uisrv_socket = buffer;
     169             :                 }
     170             :             }
     171             :         }
     172         585 :       else if (!strcmp (line, "dirmngr-socket") && !dirinfo.dirmngr_socket)
     173         117 :         dirinfo.dirmngr_socket = strdup (value);
     174         468 :       else if (!strcmp (line, "agent-ssh-socket") && !dirinfo.agent_ssh_socket)
     175         117 :         dirinfo.agent_ssh_socket = strdup (value);
     176             :     }
     177             : }
     178             : 
     179             : 
     180             : /* Read the directory information from gpgconf.  This function expects
     181             :    that DIRINFO_LOCK is held by the caller.  PGNAME is the name of the
     182             :    gpgconf binary. If COMPONENTS is set, not the directories bit the
     183             :    name of the componeNts are read. */
     184             : static void
     185         234 : read_gpgconf_dirs (const char *pgmname, int components)
     186             : {
     187         234 :   char linebuf[1024] = {0};
     188         234 :   int linelen = 0;
     189             :   char * argv[3];
     190             :   int rp[2];
     191         234 :   struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
     192             :                                    {-1, -1} };
     193             :   int status;
     194             :   int nread;
     195         234 :   char *mark = NULL;
     196             : 
     197         234 :   argv[0] = (char *)pgmname;
     198         234 :   argv[1] = (char*)(components? "--list-components" : "--list-dirs");
     199         234 :   argv[2] = NULL;
     200             : 
     201         234 :   if (_gpgme_io_pipe (rp, 1) < 0)
     202           0 :     return;
     203             : 
     204         234 :   cfd[0].fd = rp[1];
     205             : 
     206         234 :   status = _gpgme_io_spawn (pgmname, argv, IOSPAWN_FLAG_DETACHED,
     207             :                             cfd, NULL, NULL, NULL);
     208         234 :   if (status < 0)
     209             :     {
     210           0 :       _gpgme_io_close (rp[0]);
     211           0 :       _gpgme_io_close (rp[1]);
     212           0 :       return;
     213             :     }
     214             : 
     215             :   do
     216             :     {
     217         468 :       nread = _gpgme_io_read (rp[0],
     218             :                               linebuf + linelen,
     219             :                               sizeof linebuf - linelen - 1);
     220         468 :       if (nread > 0)
     221             :         {
     222             :           char *line;
     223         234 :           const char *lastmark = NULL;
     224             :           size_t nused;
     225             : 
     226         234 :           linelen += nread;
     227         234 :           linebuf[linelen] = '\0';
     228             : 
     229        2457 :           for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
     230             :             {
     231        2223 :               lastmark = mark;
     232        2223 :               if (mark > line && mark[-1] == '\r')
     233           0 :                 mark[-1] = '\0';
     234             :               else
     235        2223 :                 mark[0] = '\0';
     236             : 
     237        2223 :               parse_output (line, components);
     238             :             }
     239             : 
     240         234 :           nused = lastmark? (lastmark + 1 - linebuf) : 0;
     241         234 :           memmove (linebuf, linebuf + nused, linelen - nused);
     242         234 :           linelen -= nused;
     243             :         }
     244             :     }
     245         468 :   while (nread > 0 && linelen < sizeof linebuf - 1);
     246             : 
     247         234 :   _gpgme_io_close (rp[0]);
     248             : }
     249             : 
     250             : 
     251             : static const char *
     252        2104 : get_gpgconf_item (int what)
     253             : {
     254        2104 :   const char *result = NULL;
     255             : 
     256        2104 :   LOCK (dirinfo_lock);
     257        2105 :   if (!dirinfo.valid)
     258             :     {
     259             :       char *pgmname;
     260             : 
     261         117 :       pgmname = dirinfo.disable_gpgconf? NULL : _gpgme_get_gpgconf_path ();
     262         117 :       if (pgmname && access (pgmname, F_OK))
     263             :         {
     264           0 :           _gpgme_debug (DEBUG_INIT,
     265             :                         "gpgme-dinfo: gpgconf='%s' [not installed]\n", pgmname);
     266           0 :           free (pgmname);
     267           0 :           pgmname = NULL; /* Not available.  */
     268             :         }
     269             :       else
     270         117 :         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: gpgconf='%s'\n",
     271             :                       pgmname? pgmname : "[null]");
     272         117 :       if (!pgmname)
     273             :         {
     274             :           /* Probably gpgconf is not installed.  Assume we are using
     275             :              GnuPG-1.  */
     276           0 :           dirinfo.gpg_one_mode = 1;
     277           0 :           pgmname = _gpgme_get_gpg_path ();
     278           0 :           if (pgmname)
     279           0 :             dirinfo.gpg_name = pgmname;
     280             :         }
     281             :       else
     282             :         {
     283         117 :           dirinfo.gpg_one_mode = 0;
     284         117 :           read_gpgconf_dirs (pgmname, 0);
     285         117 :           read_gpgconf_dirs (pgmname, 1);
     286         117 :           dirinfo.gpgconf_name = pgmname;
     287             :         }
     288             :       /* Even if the reading of the directories failed (e.g. due to an
     289             :          too old version gpgconf or no gpgconf at all), we need to
     290             :          mark the entries as valid so that we won't try over and over
     291             :          to read them.  Note further that we are not able to change
     292             :          the read values later because they are practically statically
     293             :          allocated.  */
     294         117 :       dirinfo.valid = 1;
     295         117 :       if (dirinfo.gpg_name)
     296         117 :         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:     gpg='%s'\n",
     297             :                       dirinfo.gpg_name);
     298         117 :       if (dirinfo.g13_name)
     299           0 :         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:     g13='%s'\n",
     300             :                       dirinfo.g13_name);
     301         117 :       if (dirinfo.gpgsm_name)
     302         117 :         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:   gpgsm='%s'\n",
     303             :                       dirinfo.gpgsm_name);
     304         117 :       if (dirinfo.homedir)
     305         117 :         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: homedir='%s'\n",
     306             :                       dirinfo.homedir);
     307         117 :       if (dirinfo.agent_socket)
     308         117 :         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:   agent='%s'\n",
     309             :                       dirinfo.agent_socket);
     310         117 :       if (dirinfo.agent_ssh_socket)
     311         117 :         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:     ssh='%s'\n",
     312             :                       dirinfo.agent_ssh_socket);
     313         117 :       if (dirinfo.dirmngr_socket)
     314         117 :         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: dirmngr='%s'\n",
     315             :                       dirinfo.dirmngr_socket);
     316         117 :       if (dirinfo.uisrv_socket)
     317         117 :         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:   uisrv='%s'\n",
     318             :                       dirinfo.uisrv_socket);
     319             :     }
     320        2105 :   switch (what)
     321             :     {
     322           1 :     case WANT_HOMEDIR:    result = dirinfo.homedir; break;
     323           1 :     case WANT_SYSCONFDIR: result = dirinfo.sysconfdir; break;
     324           1 :     case WANT_BINDIR:     result = dirinfo.bindir; break;
     325           1 :     case WANT_LIBEXECDIR: result = dirinfo.libexecdir; break;
     326           1 :     case WANT_LIBDIR:     result = dirinfo.libdir; break;
     327           1 :     case WANT_DATADIR:    result = dirinfo.datadir; break;
     328           1 :     case WANT_LOCALEDIR:  result = dirinfo.localedir; break;
     329         120 :     case WANT_AGENT_SOCKET: result = dirinfo.agent_socket; break;
     330           1 :     case WANT_AGENT_SSH_SOCKET: result = dirinfo.agent_ssh_socket; break;
     331           1 :     case WANT_DIRMNGR_SOCKET: result = dirinfo.dirmngr_socket; break;
     332         237 :     case WANT_GPGCONF_NAME: result = dirinfo.gpgconf_name; break;
     333         400 :     case WANT_GPG_NAME:   result = dirinfo.gpg_name; break;
     334         235 :     case WANT_GPGSM_NAME: result = dirinfo.gpgsm_name; break;
     335         235 :     case WANT_G13_NAME:   result = dirinfo.g13_name; break;
     336         118 :     case WANT_UISRV_SOCKET:  result = dirinfo.uisrv_socket; break;
     337         750 :     case WANT_GPG_ONE_MODE: result = dirinfo.gpg_one_mode? "1":NULL; break;
     338             :     case WANT_GPG_WKS_CLIENT_NAME:
     339           1 :       if (!dirinfo.gpg_wks_client_name && dirinfo.libexecdir)
     340           1 :         dirinfo.gpg_wks_client_name = _gpgme_strconcat (dirinfo.libexecdir,
     341             :                                                         "/",
     342             :                                                         "gpg-wks-client",
     343             :                                                         NULL);
     344           1 :       result = dirinfo.gpg_wks_client_name;
     345           1 :       break;
     346             :     }
     347        2105 :   UNLOCK (dirinfo_lock);
     348        2105 :   return result;
     349             : }
     350             : 
     351             : 
     352             : /* Return the default home directory.   Returns NULL if not known.  */
     353             : const char *
     354           0 : _gpgme_get_default_homedir (void)
     355             : {
     356           0 :   return get_gpgconf_item (WANT_HOMEDIR);
     357             : }
     358             : 
     359             : /* Return the default gpg-agent socket name.  Returns NULL if not known.  */
     360             : const char *
     361         119 : _gpgme_get_default_agent_socket (void)
     362             : {
     363         119 :   return get_gpgconf_item (WANT_AGENT_SOCKET);
     364             : }
     365             : 
     366             : /* Return the default gpg file name.  Returns NULL if not known.  */
     367             : const char *
     368         399 : _gpgme_get_default_gpg_name (void)
     369             : {
     370         399 :   return get_gpgconf_item (WANT_GPG_NAME);
     371             : }
     372             : 
     373             : /* Return the default gpgsm file name.  Returns NULL if not known.  */
     374             : const char *
     375         234 : _gpgme_get_default_gpgsm_name (void)
     376             : {
     377         234 :   return get_gpgconf_item (WANT_GPGSM_NAME);
     378             : }
     379             : 
     380             : /* Return the default g13 file name.  Returns NULL if not known.  */
     381             : const char *
     382         234 : _gpgme_get_default_g13_name (void)
     383             : {
     384         234 :   return get_gpgconf_item (WANT_G13_NAME);
     385             : }
     386             : 
     387             : /* Return the default gpgconf file name.  Returns NULL if not known.  */
     388             : const char *
     389         236 : _gpgme_get_default_gpgconf_name (void)
     390             : {
     391         236 :   return get_gpgconf_item (WANT_GPGCONF_NAME);
     392             : }
     393             : 
     394             : /* Return the default UI-server socket name.  Returns NULL if not
     395             :    known.  */
     396             : const char *
     397         117 : _gpgme_get_default_uisrv_socket (void)
     398             : {
     399         117 :   return get_gpgconf_item (WANT_UISRV_SOCKET);
     400             : }
     401             : 
     402             : /* Return true if we are in GnuPG-1 mode - ie. no gpgconf and agent
     403             :    being optional.  */
     404             : int
     405         749 : _gpgme_in_gpg_one_mode (void)
     406             : {
     407         749 :   return !!get_gpgconf_item (WANT_GPG_ONE_MODE);
     408             : }
     409             : 
     410             : 
     411             : 
     412             : /* Helper function to return the basename of the passed filename.  */
     413             : const char *
     414         875 : _gpgme_get_basename (const char *name)
     415             : {
     416             :   const char *s;
     417             : 
     418         875 :   if (!name || !*name)
     419           0 :     return name;
     420        4452 :   for (s = name + strlen (name) -1; s >= name; s--)
     421        4452 :     if (*s == '/'
     422             : #ifdef HAVE_W32_SYSTEM
     423             :         || *s == '\\' || *s == ':'
     424             : #endif
     425             :         )
     426         875 :       return s+1;
     427           0 :   return name;
     428             : }
     429             : 
     430             : 
     431             : /* Return default values for various directories and file names.  */
     432             : const char *
     433          16 : gpgme_get_dirinfo (const char *what)
     434             : {
     435          16 :   if (!what)
     436           0 :     return NULL;
     437          16 :   else if (!strcmp (what, "homedir"))
     438           1 :     return get_gpgconf_item (WANT_HOMEDIR);
     439          15 :   else if (!strcmp (what, "agent-socket"))
     440           1 :     return get_gpgconf_item (WANT_AGENT_SOCKET);
     441          14 :   else if (!strcmp (what, "uiserver-socket"))
     442           1 :     return get_gpgconf_item (WANT_UISRV_SOCKET);
     443          13 :   else if (!strcmp (what, "gpgconf-name"))
     444           1 :     return get_gpgconf_item (WANT_GPGCONF_NAME);
     445          12 :   else if (!strcmp (what, "gpg-name"))
     446           1 :     return get_gpgconf_item (WANT_GPG_NAME);
     447          11 :   else if (!strcmp (what, "gpgsm-name"))
     448           1 :     return get_gpgconf_item (WANT_GPGSM_NAME);
     449          10 :   else if (!strcmp (what, "g13-name"))
     450           1 :     return get_gpgconf_item (WANT_G13_NAME);
     451           9 :   else if (!strcmp (what, "gpg-wks-client-name"))
     452           1 :     return get_gpgconf_item (WANT_GPG_WKS_CLIENT_NAME);
     453           8 :   else if (!strcmp (what, "agent-ssh-socket"))
     454           1 :     return get_gpgconf_item (WANT_AGENT_SSH_SOCKET);
     455           7 :   else if (!strcmp (what, "dirmngr-socket"))
     456           1 :     return get_gpgconf_item (WANT_DIRMNGR_SOCKET);
     457           6 :   else if (!strcmp (what, "sysconfdir"))
     458           1 :     return get_gpgconf_item (WANT_SYSCONFDIR);
     459           5 :   else if (!strcmp (what, "bindir"))
     460           1 :     return get_gpgconf_item (WANT_BINDIR);
     461           4 :   else if (!strcmp (what, "libexecdir"))
     462           1 :     return get_gpgconf_item (WANT_LIBEXECDIR);
     463           3 :   else if (!strcmp (what, "libdir"))
     464           1 :     return get_gpgconf_item (WANT_LIBDIR);
     465           2 :   else if (!strcmp (what, "datadir"))
     466           1 :     return get_gpgconf_item (WANT_DATADIR);
     467           1 :   else if (!strcmp (what, "localedir"))
     468           1 :     return get_gpgconf_item (WANT_LOCALEDIR);
     469             :   else
     470           0 :     return NULL;
     471             : }

Generated by: LCOV version 1.13