LCOV - code coverage report
Current view: top level - src - dirinfo.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 127 155 81.9 %
Date: 2015-11-05 17:14:26 Functions: 12 14 85.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 <http://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_AGENT_SOCKET,
      41             :     WANT_GPGCONF_NAME,
      42             :     WANT_GPG_NAME,
      43             :     WANT_GPGSM_NAME,
      44             :     WANT_G13_NAME,
      45             :     WANT_UISRV_SOCKET,
      46             :     WANT_GPG_ONE_MODE
      47             :   };
      48             : 
      49             : /* Values retrieved via gpgconf and cached here.  */
      50             : static struct {
      51             :   int  valid;         /* Cached information is valid.  */
      52             :   int  disable_gpgconf;
      53             :   char *homedir;
      54             :   char *agent_socket;
      55             :   char *gpgconf_name;
      56             :   char *gpg_name;
      57             :   char *gpgsm_name;
      58             :   char *g13_name;
      59             :   char *uisrv_socket;
      60             :   int  gpg_one_mode;  /* System is in gpg1 mode.  */
      61             : } dirinfo;
      62             : 
      63             : 
      64             : 
      65             : /* Helper function to be used only by gpgme_set_global_flag.  */
      66             : void
      67           0 : _gpgme_dirinfo_disable_gpgconf (void)
      68             : {
      69           0 :   dirinfo.disable_gpgconf = 1;
      70           0 : }
      71             : 
      72             : 
      73             : /* Parse the output of "gpgconf --list-dirs".  This function expects
      74             :    that DIRINFO_LOCK is held by the caller.  If COMPONENTS is set, the
      75             :    output of --list-components is expected. */
      76             : static void
      77         448 : parse_output (char *line, int components)
      78             : {
      79             :   char *value, *p;
      80             : 
      81         448 :   value = strchr (line, ':');
      82         448 :   if (!value)
      83           0 :     return;
      84         448 :   *value++ = 0;
      85         448 :   if (components)
      86             :     {
      87             :       /* Skip the second field.  */
      88         168 :       value = strchr (value, ':');
      89         168 :       if (!value)
      90           0 :         return;
      91         168 :       *value++ = 0;
      92             :     }
      93         448 :   p = strchr (value, ':');
      94         448 :   if (p)
      95           0 :     *p = 0;
      96         448 :   if (_gpgme_decode_percent_string (value, &value, strlen (value)+1, 0))
      97           0 :     return;
      98         448 :   if (!*value)
      99           0 :     return;
     100             : 
     101         448 :   if (components)
     102             :     {
     103         168 :       if (!strcmp (line, "gpg") && !dirinfo.gpg_name)
     104          28 :         dirinfo.gpg_name = strdup (value);
     105         140 :       else if (!strcmp (line, "gpgsm") && !dirinfo.gpgsm_name)
     106          28 :         dirinfo.gpgsm_name = strdup (value);
     107         112 :       else if (!strcmp (line, "g13") && !dirinfo.g13_name)
     108           0 :         dirinfo.g13_name = strdup (value);
     109             :     }
     110             :   else
     111             :     {
     112         280 :       if (!strcmp (line, "homedir") && !dirinfo.homedir)
     113          28 :         {
     114          28 :           const char name[] = "S.uiserver";
     115             : 
     116          28 :           dirinfo.homedir = strdup (value);
     117          28 :           if (dirinfo.homedir)
     118             :             {
     119          56 :               dirinfo.uisrv_socket = malloc (strlen (dirinfo
     120          28 :                                                      .homedir)
     121          28 :                                              + 1 + strlen (name) + 1);
     122          28 :               if (dirinfo.uisrv_socket)
     123          28 :                 strcpy (stpcpy (stpcpy (dirinfo.uisrv_socket, dirinfo.homedir),
     124             :                                 DIRSEP_S), name);
     125             :             }
     126             :         }
     127         252 :       else if (!strcmp (line, "agent-socket") && !dirinfo.agent_socket)
     128          28 :         dirinfo.agent_socket = strdup (value);
     129             :     }
     130             : }
     131             : 
     132             : 
     133             : /* Read the directory information from gpgconf.  This function expects
     134             :    that DIRINFO_LOCK is held by the caller.  PGNAME is the name of the
     135             :    gpgconf binary. If COMPONENTS is set, not the directories bit the
     136             :    name of the componeNts are read. */
     137             : static void
     138          56 : read_gpgconf_dirs (const char *pgmname, int components)
     139             : {
     140          56 :   char linebuf[1024] = {0};
     141          56 :   int linelen = 0;
     142             :   char * argv[3];
     143             :   int rp[2];
     144          56 :   struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
     145             :                                    {-1, -1} };
     146             :   int status;
     147             :   int nread;
     148          56 :   char *mark = NULL;
     149             : 
     150          56 :   argv[0] = (char *)pgmname;
     151          56 :   argv[1] = components? "--list-components" : "--list-dirs";
     152          56 :   argv[2] = NULL;
     153             : 
     154          56 :   if (_gpgme_io_pipe (rp, 1) < 0)
     155           0 :     return;
     156             : 
     157          56 :   cfd[0].fd = rp[1];
     158             : 
     159          56 :   status = _gpgme_io_spawn (pgmname, argv, IOSPAWN_FLAG_DETACHED,
     160             :                             cfd, NULL, NULL, NULL);
     161          56 :   if (status < 0)
     162             :     {
     163           0 :       _gpgme_io_close (rp[0]);
     164           0 :       _gpgme_io_close (rp[1]);
     165           0 :       return;
     166             :     }
     167             : 
     168             :   do
     169             :     {
     170         112 :       nread = _gpgme_io_read (rp[0],
     171             :                               linebuf + linelen,
     172             :                               sizeof linebuf - linelen - 1);
     173         112 :       if (nread > 0)
     174             :         {
     175             :           char *line;
     176          56 :           const char *lastmark = NULL;
     177             :           size_t nused;
     178             : 
     179          56 :           linelen += nread;
     180          56 :           linebuf[linelen] = '\0';
     181             : 
     182         504 :           for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
     183             :             {
     184         448 :               lastmark = mark;
     185         448 :               if (mark > line && mark[-1] == '\r')
     186           0 :                 mark[-1] = '\0';
     187             :               else
     188         448 :                 mark[0] = '\0';
     189             : 
     190         448 :               parse_output (line, components);
     191             :             }
     192             : 
     193          56 :           nused = lastmark? (lastmark + 1 - linebuf) : 0;
     194          56 :           memmove (linebuf, linebuf + nused, linelen - nused);
     195          56 :           linelen -= nused;
     196             :         }
     197             :     }
     198         112 :   while (nread > 0 && linelen < sizeof linebuf - 1);
     199             : 
     200          56 :   _gpgme_io_close (rp[0]);
     201             : }
     202             : 
     203             : 
     204             : static const char *
     205         383 : get_gpgconf_item (int what)
     206             : {
     207         383 :   const char *result = NULL;
     208             : 
     209         383 :   LOCK (dirinfo_lock);
     210         383 :   if (!dirinfo.valid)
     211             :     {
     212             :       char *pgmname;
     213             : 
     214          28 :       pgmname = dirinfo.disable_gpgconf? NULL : _gpgme_get_gpgconf_path ();
     215          28 :       if (pgmname && access (pgmname, F_OK))
     216             :         {
     217           0 :           _gpgme_debug (DEBUG_INIT,
     218             :                         "gpgme-dinfo: gpgconf='%s' [not installed]\n", pgmname);
     219           0 :           free (pgmname);
     220           0 :           pgmname = NULL; /* Not available.  */
     221             :         }
     222             :       else
     223          28 :         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: gpgconf='%s'\n",
     224             :                       pgmname? pgmname : "[null]");
     225          28 :       if (!pgmname)
     226             :         {
     227             :           /* Probably gpgconf is not installed.  Assume we are using
     228             :              GnuPG-1.  */
     229           0 :           dirinfo.gpg_one_mode = 1;
     230           0 :           pgmname = _gpgme_get_gpg_path ();
     231           0 :           if (pgmname)
     232           0 :             dirinfo.gpg_name = pgmname;
     233             :         }
     234             :       else
     235             :         {
     236          28 :           dirinfo.gpg_one_mode = 0;
     237          28 :           read_gpgconf_dirs (pgmname, 0);
     238          28 :           read_gpgconf_dirs (pgmname, 1);
     239          28 :           dirinfo.gpgconf_name = pgmname;
     240             :         }
     241             :       /* Even if the reading of the directories failed (e.g. due to an
     242             :          too old version gpgconf or no gpgconf at all), we need to
     243             :          mark the entries as valid so that we won't try over and over
     244             :          to read them.  Note further that we are not able to change
     245             :          the read values later because they are practically statically
     246             :          allocated.  */
     247          28 :       dirinfo.valid = 1;
     248          28 :       if (dirinfo.gpg_name)
     249          28 :         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:     gpg='%s'\n",
     250             :                       dirinfo.gpg_name);
     251          28 :       if (dirinfo.g13_name)
     252           0 :         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:     g13='%s'\n",
     253             :                       dirinfo.g13_name);
     254          28 :       if (dirinfo.gpgsm_name)
     255          28 :         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:   gpgsm='%s'\n",
     256             :                       dirinfo.gpgsm_name);
     257          28 :       if (dirinfo.homedir)
     258          28 :         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: homedir='%s'\n",
     259             :                       dirinfo.homedir);
     260          28 :       if (dirinfo.agent_socket)
     261          28 :         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:   agent='%s'\n",
     262             :                       dirinfo.agent_socket);
     263          28 :       if (dirinfo.uisrv_socket)
     264          28 :         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:   uisrv='%s'\n",
     265             :                       dirinfo.uisrv_socket);
     266             :     }
     267         383 :   switch (what)
     268             :     {
     269           1 :     case WANT_HOMEDIR: result = dirinfo.homedir; break;
     270          29 :     case WANT_AGENT_SOCKET: result = dirinfo.agent_socket; break;
     271          57 :     case WANT_GPGCONF_NAME: result = dirinfo.gpgconf_name; break;
     272          57 :     case WANT_GPG_NAME:   result = dirinfo.gpg_name; break;
     273          57 :     case WANT_GPGSM_NAME: result = dirinfo.gpgsm_name; break;
     274          29 :     case WANT_G13_NAME:   result = dirinfo.g13_name; break;
     275          29 :     case WANT_UISRV_SOCKET:  result = dirinfo.uisrv_socket; break;
     276         124 :     case WANT_GPG_ONE_MODE: result = dirinfo.gpg_one_mode? "1":NULL; break;
     277             :     }
     278         383 :   UNLOCK (dirinfo_lock);
     279         383 :   return result;
     280             : }
     281             : 
     282             : 
     283             : /* Return the default home directory.   Returns NULL if not known.  */
     284             : const char *
     285           0 : _gpgme_get_default_homedir (void)
     286             : {
     287           0 :   return get_gpgconf_item (WANT_HOMEDIR);
     288             : }
     289             : 
     290             : /* Return the default gpg-agent socket name.  Returns NULL if not known.  */
     291             : const char *
     292          28 : _gpgme_get_default_agent_socket (void)
     293             : {
     294          28 :   return get_gpgconf_item (WANT_AGENT_SOCKET);
     295             : }
     296             : 
     297             : /* Return the default gpg file name.  Returns NULL if not known.  */
     298             : const char *
     299          56 : _gpgme_get_default_gpg_name (void)
     300             : {
     301          56 :   return get_gpgconf_item (WANT_GPG_NAME);
     302             : }
     303             : 
     304             : /* Return the default gpgsm file name.  Returns NULL if not known.  */
     305             : const char *
     306          56 : _gpgme_get_default_gpgsm_name (void)
     307             : {
     308          56 :   return get_gpgconf_item (WANT_GPGSM_NAME);
     309             : }
     310             : 
     311             : /* Return the default g13 file name.  Returns NULL if not known.  */
     312             : const char *
     313          28 : _gpgme_get_default_g13_name (void)
     314             : {
     315          28 :   return get_gpgconf_item (WANT_G13_NAME);
     316             : }
     317             : 
     318             : /* Return the default gpgconf file name.  Returns NULL if not known.  */
     319             : const char *
     320          56 : _gpgme_get_default_gpgconf_name (void)
     321             : {
     322          56 :   return get_gpgconf_item (WANT_GPGCONF_NAME);
     323             : }
     324             : 
     325             : /* Return the default UI-server socket name.  Returns NULL if not
     326             :    known.  */
     327             : const char *
     328          28 : _gpgme_get_default_uisrv_socket (void)
     329             : {
     330          28 :   return get_gpgconf_item (WANT_UISRV_SOCKET);
     331             : }
     332             : 
     333             : /* Return true if we are in GnuPG-1 mode - ie. no gpgconf and agent
     334             :    being optional.  */
     335             : int
     336         124 : _gpgme_in_gpg_one_mode (void)
     337             : {
     338         124 :   return !!get_gpgconf_item (WANT_GPG_ONE_MODE);
     339             : }
     340             : 
     341             : 
     342             : 
     343             : /* Helper function to return the basename of the passed filename.  */
     344             : const char *
     345         132 : _gpgme_get_basename (const char *name)
     346             : {
     347             :   const char *s;
     348             : 
     349         132 :   if (!name || !*name)
     350           0 :     return name;
     351         668 :   for (s = name + strlen (name) -1; s >= name; s--)
     352         668 :     if (*s == '/'
     353             : #ifdef HAVE_W32_SYSTEM
     354             :         || *s == '\\' || *s == ':'
     355             : #endif
     356             :         )
     357         132 :       return s+1;
     358           0 :   return name;
     359             : }
     360             : 
     361             : 
     362             : /* Return default values for various directories and file names.  */
     363             : const char *
     364           7 : gpgme_get_dirinfo (const char *what)
     365             : {
     366           7 :   if (!what)
     367           0 :     return NULL;
     368           7 :   else if (!strcmp (what, "homedir"))
     369           1 :     return get_gpgconf_item (WANT_HOMEDIR);
     370           6 :   else if (!strcmp (what, "agent-socket"))
     371           1 :     return get_gpgconf_item (WANT_AGENT_SOCKET);
     372           5 :   else if (!strcmp (what, "uiserver-socket"))
     373           1 :     return get_gpgconf_item (WANT_UISRV_SOCKET);
     374           4 :   else if (!strcmp (what, "gpgconf-name"))
     375           1 :     return get_gpgconf_item (WANT_GPGCONF_NAME);
     376           3 :   else if (!strcmp (what, "gpg-name"))
     377           1 :     return get_gpgconf_item (WANT_GPG_NAME);
     378           2 :   else if (!strcmp (what, "gpgsm-name"))
     379           1 :     return get_gpgconf_item (WANT_GPGSM_NAME);
     380           1 :   else if (!strcmp (what, "g13-name"))
     381           1 :     return get_gpgconf_item (WANT_G13_NAME);
     382             :   else
     383           0 :     return NULL;
     384             : }

Generated by: LCOV version 1.11