python: Implement data callbacks.
[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_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 \f
65 /* Helper function to be used only by gpgme_set_global_flag.  */
66 void
67 _gpgme_dirinfo_disable_gpgconf (void)
68 {
69   dirinfo.disable_gpgconf = 1;
70 }
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 parse_output (char *line, int components)
78 {
79   char *value, *p;
80
81   value = strchr (line, ':');
82   if (!value)
83     return;
84   *value++ = 0;
85   if (components)
86     {
87       /* Skip the second field.  */
88       value = strchr (value, ':');
89       if (!value)
90         return;
91       *value++ = 0;
92     }
93   p = strchr (value, ':');
94   if (p)
95     *p = 0;
96   if (_gpgme_decode_percent_string (value, &value, strlen (value)+1, 0))
97     return;
98   if (!*value)
99     return;
100
101   if (components)
102     {
103       if (!strcmp (line, "gpg") && !dirinfo.gpg_name)
104         dirinfo.gpg_name = strdup (value);
105       else if (!strcmp (line, "gpgsm") && !dirinfo.gpgsm_name)
106         dirinfo.gpgsm_name = strdup (value);
107       else if (!strcmp (line, "g13") && !dirinfo.g13_name)
108         dirinfo.g13_name = strdup (value);
109     }
110   else
111     {
112       if (!strcmp (line, "homedir") && !dirinfo.homedir)
113         {
114           const char name[] = "S.uiserver";
115
116           dirinfo.homedir = strdup (value);
117           if (dirinfo.homedir)
118             {
119               dirinfo.uisrv_socket = malloc (strlen (dirinfo
120                                                      .homedir)
121                                              + 1 + strlen (name) + 1);
122               if (dirinfo.uisrv_socket)
123                 strcpy (stpcpy (stpcpy (dirinfo.uisrv_socket, dirinfo.homedir),
124                                 DIRSEP_S), name);
125             }
126         }
127       else if (!strcmp (line, "agent-socket") && !dirinfo.agent_socket)
128         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 read_gpgconf_dirs (const char *pgmname, int components)
139 {
140   char linebuf[1024] = {0};
141   int linelen = 0;
142   char * argv[3];
143   int rp[2];
144   struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
145                                    {-1, -1} };
146   int status;
147   int nread;
148   char *mark = NULL;
149
150   argv[0] = (char *)pgmname;
151   argv[1] = components? "--list-components" : "--list-dirs";
152   argv[2] = NULL;
153
154   if (_gpgme_io_pipe (rp, 1) < 0)
155     return;
156
157   cfd[0].fd = rp[1];
158
159   status = _gpgme_io_spawn (pgmname, argv, IOSPAWN_FLAG_DETACHED,
160                             cfd, NULL, NULL, NULL);
161   if (status < 0)
162     {
163       _gpgme_io_close (rp[0]);
164       _gpgme_io_close (rp[1]);
165       return;
166     }
167
168   do
169     {
170       nread = _gpgme_io_read (rp[0],
171                               linebuf + linelen,
172                               sizeof linebuf - linelen - 1);
173       if (nread > 0)
174         {
175           char *line;
176           const char *lastmark = NULL;
177           size_t nused;
178
179           linelen += nread;
180           linebuf[linelen] = '\0';
181
182           for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
183             {
184               lastmark = mark;
185               if (mark > line && mark[-1] == '\r')
186                 mark[-1] = '\0';
187               else
188                 mark[0] = '\0';
189
190               parse_output (line, components);
191             }
192
193           nused = lastmark? (lastmark + 1 - linebuf) : 0;
194           memmove (linebuf, linebuf + nused, linelen - nused);
195           linelen -= nused;
196         }
197     }
198   while (nread > 0 && linelen < sizeof linebuf - 1);
199
200   _gpgme_io_close (rp[0]);
201 }
202
203
204 static const char *
205 get_gpgconf_item (int what)
206 {
207   const char *result = NULL;
208
209   LOCK (dirinfo_lock);
210   if (!dirinfo.valid)
211     {
212       char *pgmname;
213
214       pgmname = dirinfo.disable_gpgconf? NULL : _gpgme_get_gpgconf_path ();
215       if (pgmname && access (pgmname, F_OK))
216         {
217           _gpgme_debug (DEBUG_INIT,
218                         "gpgme-dinfo: gpgconf='%s' [not installed]\n", pgmname);
219           free (pgmname);
220           pgmname = NULL; /* Not available.  */
221         }
222       else
223         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: gpgconf='%s'\n",
224                       pgmname? pgmname : "[null]");
225       if (!pgmname)
226         {
227           /* Probably gpgconf is not installed.  Assume we are using
228              GnuPG-1.  */
229           dirinfo.gpg_one_mode = 1;
230           pgmname = _gpgme_get_gpg_path ();
231           if (pgmname)
232             dirinfo.gpg_name = pgmname;
233         }
234       else
235         {
236           dirinfo.gpg_one_mode = 0;
237           read_gpgconf_dirs (pgmname, 0);
238           read_gpgconf_dirs (pgmname, 1);
239           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       dirinfo.valid = 1;
248       if (dirinfo.gpg_name)
249         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:     gpg='%s'\n",
250                       dirinfo.gpg_name);
251       if (dirinfo.g13_name)
252         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:     g13='%s'\n",
253                       dirinfo.g13_name);
254       if (dirinfo.gpgsm_name)
255         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:   gpgsm='%s'\n",
256                       dirinfo.gpgsm_name);
257       if (dirinfo.homedir)
258         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: homedir='%s'\n",
259                       dirinfo.homedir);
260       if (dirinfo.agent_socket)
261         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:   agent='%s'\n",
262                       dirinfo.agent_socket);
263       if (dirinfo.uisrv_socket)
264         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:   uisrv='%s'\n",
265                       dirinfo.uisrv_socket);
266     }
267   switch (what)
268     {
269     case WANT_HOMEDIR: result = dirinfo.homedir; break;
270     case WANT_AGENT_SOCKET: result = dirinfo.agent_socket; break;
271     case WANT_GPGCONF_NAME: result = dirinfo.gpgconf_name; break;
272     case WANT_GPG_NAME:   result = dirinfo.gpg_name; break;
273     case WANT_GPGSM_NAME: result = dirinfo.gpgsm_name; break;
274     case WANT_G13_NAME:   result = dirinfo.g13_name; break;
275     case WANT_UISRV_SOCKET:  result = dirinfo.uisrv_socket; break;
276     case WANT_GPG_ONE_MODE: result = dirinfo.gpg_one_mode? "1":NULL; break;
277     }
278   UNLOCK (dirinfo_lock);
279   return result;
280 }
281
282
283 /* Return the default home directory.   Returns NULL if not known.  */
284 const char *
285 _gpgme_get_default_homedir (void)
286 {
287   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 _gpgme_get_default_agent_socket (void)
293 {
294   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 _gpgme_get_default_gpg_name (void)
300 {
301   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 _gpgme_get_default_gpgsm_name (void)
307 {
308   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 _gpgme_get_default_g13_name (void)
314 {
315   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 _gpgme_get_default_gpgconf_name (void)
321 {
322   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 _gpgme_get_default_uisrv_socket (void)
329 {
330   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 _gpgme_in_gpg_one_mode (void)
337 {
338   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 _gpgme_get_basename (const char *name)
346 {
347   const char *s;
348
349   if (!name || !*name)
350     return name;
351   for (s = name + strlen (name) -1; s >= name; s--)
352     if (*s == '/'
353 #ifdef HAVE_W32_SYSTEM
354         || *s == '\\' || *s == ':'
355 #endif
356         )
357       return s+1;
358   return name;
359 }
360
361
362 /* Return default values for various directories and file names.  */
363 const char *
364 gpgme_get_dirinfo (const char *what)
365 {
366   if (!what)
367     return NULL;
368   else if (!strcmp (what, "homedir"))
369     return get_gpgconf_item (WANT_HOMEDIR);
370   else if (!strcmp (what, "agent-socket"))
371     return get_gpgconf_item (WANT_AGENT_SOCKET);
372   else if (!strcmp (what, "uiserver-socket"))
373     return get_gpgconf_item (WANT_UISRV_SOCKET);
374   else if (!strcmp (what, "gpgconf-name"))
375     return get_gpgconf_item (WANT_GPGCONF_NAME);
376   else if (!strcmp (what, "gpg-name"))
377     return get_gpgconf_item (WANT_GPG_NAME);
378   else if (!strcmp (what, "gpgsm-name"))
379     return get_gpgconf_item (WANT_GPGSM_NAME);
380   else if (!strcmp (what, "g13-name"))
381     return get_gpgconf_item (WANT_G13_NAME);
382   else
383     return NULL;
384 }