Prefer GnuPG-2 engines over GnuPG-1.
[gpgme.git] / src / dirinfo.c
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_GPG_NAME,
42     WANT_GPGSM_NAME,
43     WANT_G13_NAME,
44     WANT_UISRV_SOCKET
45   };
46
47 /* Values retrieved via gpgconf and cached here.  */
48 static struct {
49   int  valid;         /* Cached information is valid.  */
50   char *homedir;
51   char *agent_socket;
52   char *gpg_name;
53   char *gpgsm_name;
54   char *g13_name;
55   char *uisrv_socket;
56 } dirinfo;
57
58
59 /* Parse the output of "gpgconf --list-dirs".  This function expects
60    that DIRINFO_LOCK is held by the caller.  If COMPONENTS is set, the
61    output of --list-components is expected. */
62 static void
63 parse_output (char *line, int components)
64 {
65   char *value, *p;
66
67   value = strchr (line, ':');
68   if (!value)
69     return;
70   *value++ = 0;
71   if (components)
72     {
73       /* Skip the second field.  */
74       value = strchr (value, ':');
75       if (!value)
76         return;
77       *value++ = 0;
78     }
79   p = strchr (value, ':');
80   if (p)
81     *p = 0;
82   if (_gpgme_decode_percent_string (value, &value, strlen (value)+1, 0))
83     return;
84   if (!*value)
85     return;
86
87   if (components)
88     {
89       if (!strcmp (line, "gpg") && !dirinfo.gpg_name)
90         dirinfo.gpg_name = strdup (value);
91       else if (!strcmp (line, "gpgsm") && !dirinfo.gpgsm_name)
92         dirinfo.gpgsm_name = strdup (value);
93       else if (!strcmp (line, "g13") && !dirinfo.g13_name)
94         dirinfo.g13_name = strdup (value);
95     }
96   else
97     {
98       if (!strcmp (line, "homedir") && !dirinfo.homedir)
99         {
100           const char name[] = "S.uiserver";
101
102           dirinfo.homedir = strdup (value);
103           if (dirinfo.homedir)
104             {
105               dirinfo.uisrv_socket = malloc (strlen (dirinfo
106                                                      .homedir)
107                                              + 1 + strlen (name) + 1);
108               if (dirinfo.uisrv_socket)
109                 strcpy (stpcpy (stpcpy (dirinfo.uisrv_socket, dirinfo.homedir),
110                                 DIRSEP_S), name);
111             }
112         }
113       else if (!strcmp (line, "agent-socket") && !dirinfo.agent_socket)
114         dirinfo.agent_socket = strdup (value);
115     }
116 }
117
118
119 /* Read the directory information from gpgconf.  This function expects
120    that DIRINFO_LOCK is held by the caller.  PGNAME is the name of the
121    gpgconf binary. If COMPONENTS is set, not the directories bit the
122    name of the componeNts are read. */
123 static void
124 read_gpgconf_dirs (const char *pgmname, int components)
125 {
126   char linebuf[1024] = {0};
127   int linelen = 0;
128   char * argv[3];
129   int rp[2];
130   struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
131                                    {-1, -1} };
132   int status;
133   int nread;
134   char *mark = NULL;
135
136   argv[0] = (char *)pgmname;
137   argv[1] = components? "--list-components" : "--list-dirs";
138   argv[2] = NULL;
139
140   if (_gpgme_io_pipe (rp, 1) < 0)
141     return;
142
143   cfd[0].fd = rp[1];
144
145   status = _gpgme_io_spawn (pgmname, argv, 0, cfd, NULL, NULL, NULL);
146   if (status < 0)
147     {
148       _gpgme_io_close (rp[0]);
149       _gpgme_io_close (rp[1]);
150       return;
151     }
152
153   do
154     {
155       nread = _gpgme_io_read (rp[0],
156                               linebuf + linelen,
157                               sizeof linebuf - linelen - 1);
158       if (nread > 0)
159         {
160           char *line;
161           const char *lastmark = NULL;
162           size_t nused;
163
164           linelen += nread;
165           linebuf[linelen] = '\0';
166
167           for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
168             {
169               lastmark = mark;
170               if (mark > line && mark[-1] == '\r')
171                 mark[-1] = '\0';
172               else
173                 mark[0] = '\0';
174
175               parse_output (line, components);
176             }
177
178           nused = lastmark? (lastmark + 1 - linebuf) : 0;
179           memmove (linebuf, linebuf + nused, linelen - nused);
180           linelen -= nused;
181         }
182     }
183   while (nread > 0 && linelen < sizeof linebuf - 1);
184
185   _gpgme_io_close (rp[0]);
186 }
187
188
189 static const char *
190 get_gpgconf_item (int what)
191 {
192   const char *result = NULL;
193
194   LOCK (dirinfo_lock);
195   if (!dirinfo.valid)
196     {
197       const char *pgmname;
198
199       pgmname = _gpgme_get_gpgconf_path ();
200       if (pgmname && access (pgmname, F_OK))
201         {
202           _gpgme_debug (DEBUG_INIT,
203                         "gpgme_dinfo: gpgconf='%s' [not installed]\n", pgmname);
204           pgmname = NULL; /* Not available.  */
205         }
206       else
207         _gpgme_debug (DEBUG_INIT, "gpgme_dinfo: gpgconf='%s'\n",
208                       pgmname? pgmname : "[null]");
209       if (!pgmname)
210         {
211           /* Probably gpgconf is not installed.  Assume we are using
212              GnuPG-1.  */
213           pgmname = _gpgme_get_gpg_path ();
214           if (pgmname)
215             dirinfo.gpg_name = strdup (pgmname);
216         }
217       else
218         {
219           read_gpgconf_dirs (pgmname, 0);
220           read_gpgconf_dirs (pgmname, 1);
221         }
222       /* Even if the reading of the directories failed (e.g. due to an
223          too old version gpgconf or no gpgconf at all), we need to
224          mark the entries as valid so that we won't try over and over
225          to read them.  Note further that we are not able to change
226          the read values later because they are practically statically
227          allocated.  */
228       dirinfo.valid = 1;
229       if (dirinfo.gpg_name)
230         _gpgme_debug (DEBUG_INIT, "gpgme_dinfo:     gpg='%s'\n",
231                       dirinfo.gpg_name);
232       if (dirinfo.g13_name)
233         _gpgme_debug (DEBUG_INIT, "gpgme_dinfo:     g13='%s'\n",
234                       dirinfo.g13_name);
235       if (dirinfo.gpgsm_name)
236         _gpgme_debug (DEBUG_INIT, "gpgme_dinfo:   gpgsm='%s'\n",
237                       dirinfo.gpgsm_name);
238       if (dirinfo.homedir)
239         _gpgme_debug (DEBUG_INIT, "gpgme_dinfo: homedir='%s'\n",
240                       dirinfo.homedir);
241       if (dirinfo.agent_socket)
242         _gpgme_debug (DEBUG_INIT, "gpgme_dinfo:   agent='%s'\n",
243                       dirinfo.agent_socket);
244       if (dirinfo.uisrv_socket)
245         _gpgme_debug (DEBUG_INIT, "gpgme_dinfo:   uisrv='%s'\n",
246                       dirinfo.uisrv_socket);
247     }
248   switch (what)
249     {
250     case WANT_HOMEDIR: result = dirinfo.homedir; break;
251     case WANT_AGENT_SOCKET: result = dirinfo.agent_socket; break;
252     case WANT_GPG_NAME:   result = dirinfo.gpg_name; break;
253     case WANT_GPGSM_NAME: result = dirinfo.gpgsm_name; break;
254     case WANT_G13_NAME:   result = dirinfo.g13_name; break;
255     case WANT_UISRV_SOCKET:  result = dirinfo.uisrv_socket; break;
256     }
257   UNLOCK (dirinfo_lock);
258   return result;
259 }
260
261
262 /* Return the default home directory.   Returns NULL if not known.  */
263 const char *
264 _gpgme_get_default_homedir (void)
265 {
266   return get_gpgconf_item (WANT_HOMEDIR);
267 }
268
269 /* Return the default gpg-agent socket name.  Returns NULL if not known.  */
270 const char *
271 _gpgme_get_default_agent_socket (void)
272 {
273   return get_gpgconf_item (WANT_AGENT_SOCKET);
274 }
275
276 /* Return the default gpg file name.  Returns NULL if not known.  */
277 const char *
278 _gpgme_get_default_gpg_name (void)
279 {
280   return get_gpgconf_item (WANT_GPG_NAME);
281 }
282
283 /* Return the default gpgsm file name.  Returns NULL if not known.  */
284 const char *
285 _gpgme_get_default_gpgsm_name (void)
286 {
287   return get_gpgconf_item (WANT_GPGSM_NAME);
288 }
289
290 /* Return the default g13 file name.  Returns NULL if not known.  */
291 const char *
292 _gpgme_get_default_g13_name (void)
293 {
294   return get_gpgconf_item (WANT_G13_NAME);
295 }
296
297 /* Return the default gpgconf file name.  Returns NULL if not known.
298    Because gpgconf is the binary used to retrieved all these default
299    names, this function is merely a simple wrapper around the function
300    used to locate this binary.  */
301 const char *
302 _gpgme_get_default_gpgconf_name (void)
303 {
304   return _gpgme_get_gpgconf_path ();
305 }
306
307 /* Return the default UI-server socket name.  Returns NULL if not
308    known.  */
309 const char *
310 _gpgme_get_default_uisrv_socket (void)
311 {
312   return get_gpgconf_item (WANT_UISRV_SOCKET);
313 }