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 : }
|