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