2009-01-26 10:21:10 +00:00
|
|
|
/* dirinfo.c - Get directory information
|
2013-08-02 13:25:23 +00:00
|
|
|
* Copyright (C) 2009, 2013 g10 Code GmbH
|
2009-01-26 10:21:10 +00:00
|
|
|
*
|
|
|
|
* This file is part of GPGME.
|
|
|
|
*
|
|
|
|
* GPGME is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU Lesser General Public License as
|
|
|
|
* published by the Free Software Foundation; either version 2.1 of
|
|
|
|
* the License, or (at your option) any later version.
|
2012-09-25 13:29:49 +00:00
|
|
|
*
|
2009-01-26 10:21:10 +00:00
|
|
|
* GPGME is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
2012-09-25 13:29:49 +00:00
|
|
|
*
|
2009-01-26 10:21:10 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#if HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "gpgme.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "priv-io.h"
|
|
|
|
#include "debug.h"
|
|
|
|
#include "sema.h"
|
2013-08-02 13:25:23 +00:00
|
|
|
#include "sys-util.h"
|
2009-01-26 10:21:10 +00:00
|
|
|
|
|
|
|
DEFINE_STATIC_LOCK (dirinfo_lock);
|
|
|
|
|
|
|
|
/* Constants used internally to select the data. */
|
2012-09-25 13:29:49 +00:00
|
|
|
enum
|
2009-01-26 10:21:10 +00:00
|
|
|
{
|
|
|
|
WANT_HOMEDIR,
|
2013-08-02 13:25:23 +00:00
|
|
|
WANT_AGENT_SOCKET,
|
|
|
|
WANT_GPG_NAME,
|
|
|
|
WANT_GPGSM_NAME,
|
|
|
|
WANT_G13_NAME,
|
|
|
|
WANT_UISRV_SOCKET
|
2009-01-26 10:21:10 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Values retrieved via gpgconf and cached here. */
|
|
|
|
static struct {
|
|
|
|
int valid; /* Cached information is valid. */
|
|
|
|
char *homedir;
|
|
|
|
char *agent_socket;
|
2013-08-02 13:25:23 +00:00
|
|
|
char *gpg_name;
|
|
|
|
char *gpgsm_name;
|
|
|
|
char *g13_name;
|
|
|
|
char *uisrv_socket;
|
2009-01-26 10:21:10 +00:00
|
|
|
} dirinfo;
|
|
|
|
|
|
|
|
|
|
|
|
/* Parse the output of "gpgconf --list-dirs". This function expects
|
2013-08-02 13:25:23 +00:00
|
|
|
that DIRINFO_LOCK is held by the caller. If COMPONENTS is set, the
|
|
|
|
output of --list-components is expected. */
|
2009-01-26 10:21:10 +00:00
|
|
|
static void
|
2013-08-02 13:25:23 +00:00
|
|
|
parse_output (char *line, int components)
|
2009-01-26 10:21:10 +00:00
|
|
|
{
|
|
|
|
char *value, *p;
|
|
|
|
|
|
|
|
value = strchr (line, ':');
|
|
|
|
if (!value)
|
|
|
|
return;
|
|
|
|
*value++ = 0;
|
2013-08-02 13:25:23 +00:00
|
|
|
if (components)
|
|
|
|
{
|
|
|
|
/* Skip the second field. */
|
|
|
|
value = strchr (value, ':');
|
|
|
|
if (!value)
|
|
|
|
return;
|
|
|
|
*value++ = 0;
|
|
|
|
}
|
2009-01-26 10:21:10 +00:00
|
|
|
p = strchr (value, ':');
|
|
|
|
if (p)
|
|
|
|
*p = 0;
|
|
|
|
if (_gpgme_decode_percent_string (value, &value, strlen (value)+1, 0))
|
|
|
|
return;
|
|
|
|
if (!*value)
|
|
|
|
return;
|
2012-09-25 13:29:49 +00:00
|
|
|
|
2013-08-02 13:25:23 +00:00
|
|
|
if (components)
|
|
|
|
{
|
|
|
|
if (!strcmp (line, "gpg") && !dirinfo.gpg_name)
|
|
|
|
dirinfo.gpg_name = strdup (value);
|
|
|
|
else if (!strcmp (line, "gpgsm") && !dirinfo.gpgsm_name)
|
|
|
|
dirinfo.gpgsm_name = strdup (value);
|
|
|
|
else if (!strcmp (line, "g13") && !dirinfo.g13_name)
|
|
|
|
dirinfo.g13_name = strdup (value);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!strcmp (line, "homedir") && !dirinfo.homedir)
|
|
|
|
{
|
|
|
|
const char name[] = "S.uiserver";
|
|
|
|
|
|
|
|
dirinfo.homedir = strdup (value);
|
|
|
|
if (dirinfo.homedir)
|
|
|
|
{
|
|
|
|
dirinfo.uisrv_socket = malloc (strlen (dirinfo
|
|
|
|
.homedir)
|
|
|
|
+ 1 + strlen (name) + 1);
|
|
|
|
if (dirinfo.uisrv_socket)
|
|
|
|
strcpy (stpcpy (stpcpy (dirinfo.uisrv_socket, dirinfo.homedir),
|
|
|
|
DIRSEP_S), name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!strcmp (line, "agent-socket") && !dirinfo.agent_socket)
|
|
|
|
dirinfo.agent_socket = strdup (value);
|
|
|
|
}
|
2009-01-26 10:21:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Read the directory information from gpgconf. This function expects
|
2013-08-02 13:25:23 +00:00
|
|
|
that DIRINFO_LOCK is held by the caller. PGNAME is the name of the
|
|
|
|
gpgconf binary. If COMPONENTS is set, not the directories bit the
|
|
|
|
name of the componeNts are read. */
|
2009-01-26 10:21:10 +00:00
|
|
|
static void
|
2013-08-02 13:25:23 +00:00
|
|
|
read_gpgconf_dirs (const char *pgmname, int components)
|
2009-01-26 10:21:10 +00:00
|
|
|
{
|
|
|
|
char linebuf[1024] = {0};
|
|
|
|
int linelen = 0;
|
|
|
|
char * argv[3];
|
|
|
|
int rp[2];
|
|
|
|
struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
|
|
|
|
{-1, -1} };
|
|
|
|
int status;
|
|
|
|
int nread;
|
|
|
|
char *mark = NULL;
|
|
|
|
|
|
|
|
argv[0] = (char *)pgmname;
|
2013-08-02 13:25:23 +00:00
|
|
|
argv[1] = components? "--list-components" : "--list-dirs";
|
2009-01-26 10:21:10 +00:00
|
|
|
argv[2] = NULL;
|
|
|
|
|
|
|
|
if (_gpgme_io_pipe (rp, 1) < 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
cfd[0].fd = rp[1];
|
|
|
|
|
2009-11-10 Marcus Brinkmann <marcus@g10code.de>
* configure.ac: Activate UIServer if FD passing is enabled and
Assuan is available.
m4/
2009-11-10 Marcus Brinkmann <marcus@g10code.de>
* libassuan.m4: Fix LIBASSUAN_VERSION.
src/
2009-11-10 Marcus Brinkmann <marcus@g10code.de>
* Makefile.am (uiserver_components): New variable.
(main_sources): Add it.
* ops.h, key.c (_gpgme_key_append_name): Take CONVERT argument,
implement it. Adjust callers.
(gpgme_key_from_uid): New function.
* gpgme.h.in (gpgme_protocol_t): Add GPGME_PROTOCOL_DEFAULT.
(gpgme_encrypt_flags_t): Add GPGME_ENCRYPT_PREPARE,
GPGME_ENCRYPT_EXPECT_SIGN.
(gpgme_set_sub_protocol, gpgme_key_from_uid): New functions.
* libgpgme.vers, gpgme.def: Add new functions.
* gpgme.c (gpgme_set_protocol): Add UIServer protocol.
(gpgme_set_sub_protocol): New function.
(gpgme_get_protocol_name): Add UIServer and default protocol.
* assuan-support.c: Return correct error values, implement
socketpair for POSIX.
* priv-io.h, posix-io.c, w32-io.c, w32-glib-io.c,
w32-qt-io.cpp (_gpgme_io_spawn): Add ATFORK and ATFORKVALUE
arguments. Implement it for POSIX. Adjust all callers.
* engine.h, engine-backend.h (_gpgme_engine_set_protocol)
(_gpgme_engine_op_decrypt_verify): New prototypes. Adjust all
users.
* engine.c (engine_ops, gpgme_get_engine_info): Add UIServer
engine.
(_gpgme_engine_set_protocol, _gpgme_engine_op_decrypt_verify): New
function.
* decrypt-verify.c (decrypt_verify_start): Call
_gpgme_engine_op_decrypt_verify.
* util.h, posix-util.c,
w32-util.c (_gpgme_get_uiserver_socket_path): New function.
* engine-gpgsm.c (gpgsm_set_fd): Fix _gpgme_io_pipe invocation.
* gpgme-tool.c: Some support for UIServer protocol.
* engine-uiserver.c: New file.
2009-11-10 09:07:19 +00:00
|
|
|
status = _gpgme_io_spawn (pgmname, argv, 0, cfd, NULL, NULL, NULL);
|
2009-01-26 10:21:10 +00:00
|
|
|
if (status < 0)
|
|
|
|
{
|
|
|
|
_gpgme_io_close (rp[0]);
|
|
|
|
_gpgme_io_close (rp[1]);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
2012-09-25 13:29:49 +00:00
|
|
|
nread = _gpgme_io_read (rp[0],
|
|
|
|
linebuf + linelen,
|
2009-01-26 10:21:10 +00:00
|
|
|
sizeof linebuf - linelen - 1);
|
|
|
|
if (nread > 0)
|
|
|
|
{
|
|
|
|
char *line;
|
|
|
|
const char *lastmark = NULL;
|
|
|
|
size_t nused;
|
|
|
|
|
|
|
|
linelen += nread;
|
|
|
|
linebuf[linelen] = '\0';
|
|
|
|
|
|
|
|
for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
|
|
|
|
{
|
|
|
|
lastmark = mark;
|
|
|
|
if (mark > line && mark[-1] == '\r')
|
|
|
|
mark[-1] = '\0';
|
|
|
|
else
|
|
|
|
mark[0] = '\0';
|
|
|
|
|
2013-08-02 13:25:23 +00:00
|
|
|
parse_output (line, components);
|
2009-01-26 10:21:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nused = lastmark? (lastmark + 1 - linebuf) : 0;
|
|
|
|
memmove (linebuf, linebuf + nused, linelen - nused);
|
|
|
|
linelen -= nused;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (nread > 0 && linelen < sizeof linebuf - 1);
|
2012-09-25 13:29:49 +00:00
|
|
|
|
2009-01-26 10:21:10 +00:00
|
|
|
_gpgme_io_close (rp[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const char *
|
2013-08-02 13:25:23 +00:00
|
|
|
get_gpgconf_item (int what)
|
2009-01-26 10:21:10 +00:00
|
|
|
{
|
|
|
|
const char *result = NULL;
|
|
|
|
|
|
|
|
LOCK (dirinfo_lock);
|
|
|
|
if (!dirinfo.valid)
|
|
|
|
{
|
2013-08-02 13:25:23 +00:00
|
|
|
const char *pgmname;
|
|
|
|
|
|
|
|
pgmname = _gpgme_get_gpgconf_path ();
|
|
|
|
if (pgmname && access (pgmname, F_OK))
|
|
|
|
{
|
|
|
|
_gpgme_debug (DEBUG_INIT,
|
|
|
|
"gpgme_dinfo: gpgconf='%s' [not installed]\n", pgmname);
|
|
|
|
pgmname = NULL; /* Not available. */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
_gpgme_debug (DEBUG_INIT, "gpgme_dinfo: gpgconf='%s'\n",
|
|
|
|
pgmname? pgmname : "[null]");
|
|
|
|
if (!pgmname)
|
|
|
|
{
|
|
|
|
/* Probably gpgconf is not installed. Assume we are using
|
|
|
|
GnuPG-1. */
|
|
|
|
pgmname = _gpgme_get_gpg_path ();
|
|
|
|
if (pgmname)
|
|
|
|
dirinfo.gpg_name = strdup (pgmname);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
read_gpgconf_dirs (pgmname, 0);
|
|
|
|
read_gpgconf_dirs (pgmname, 1);
|
|
|
|
}
|
2009-01-26 10:21:10 +00:00
|
|
|
/* Even if the reading of the directories failed (e.g. due to an
|
|
|
|
too old version gpgconf or no gpgconf at all), we need to
|
|
|
|
mark the entries as valid so that we won't try over and over
|
|
|
|
to read them. Note further that we are not able to change
|
|
|
|
the read values later because they are practically statically
|
|
|
|
allocated. */
|
|
|
|
dirinfo.valid = 1;
|
2013-08-02 13:25:23 +00:00
|
|
|
if (dirinfo.gpg_name)
|
|
|
|
_gpgme_debug (DEBUG_INIT, "gpgme_dinfo: gpg='%s'\n",
|
|
|
|
dirinfo.gpg_name);
|
|
|
|
if (dirinfo.g13_name)
|
|
|
|
_gpgme_debug (DEBUG_INIT, "gpgme_dinfo: g13='%s'\n",
|
|
|
|
dirinfo.g13_name);
|
|
|
|
if (dirinfo.gpgsm_name)
|
|
|
|
_gpgme_debug (DEBUG_INIT, "gpgme_dinfo: gpgsm='%s'\n",
|
|
|
|
dirinfo.gpgsm_name);
|
|
|
|
if (dirinfo.homedir)
|
|
|
|
_gpgme_debug (DEBUG_INIT, "gpgme_dinfo: homedir='%s'\n",
|
|
|
|
dirinfo.homedir);
|
|
|
|
if (dirinfo.agent_socket)
|
|
|
|
_gpgme_debug (DEBUG_INIT, "gpgme_dinfo: agent='%s'\n",
|
|
|
|
dirinfo.agent_socket);
|
|
|
|
if (dirinfo.uisrv_socket)
|
|
|
|
_gpgme_debug (DEBUG_INIT, "gpgme_dinfo: uisrv='%s'\n",
|
|
|
|
dirinfo.uisrv_socket);
|
2009-01-26 10:21:10 +00:00
|
|
|
}
|
|
|
|
switch (what)
|
|
|
|
{
|
|
|
|
case WANT_HOMEDIR: result = dirinfo.homedir; break;
|
|
|
|
case WANT_AGENT_SOCKET: result = dirinfo.agent_socket; break;
|
2013-08-02 13:25:23 +00:00
|
|
|
case WANT_GPG_NAME: result = dirinfo.gpg_name; break;
|
|
|
|
case WANT_GPGSM_NAME: result = dirinfo.gpgsm_name; break;
|
|
|
|
case WANT_G13_NAME: result = dirinfo.g13_name; break;
|
|
|
|
case WANT_UISRV_SOCKET: result = dirinfo.uisrv_socket; break;
|
2009-01-26 10:21:10 +00:00
|
|
|
}
|
|
|
|
UNLOCK (dirinfo_lock);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Return the default home directory. Returns NULL if not known. */
|
|
|
|
const char *
|
|
|
|
_gpgme_get_default_homedir (void)
|
|
|
|
{
|
2013-08-02 13:25:23 +00:00
|
|
|
return get_gpgconf_item (WANT_HOMEDIR);
|
2009-01-26 10:21:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the default gpg-agent socket name. Returns NULL if not known. */
|
|
|
|
const char *
|
|
|
|
_gpgme_get_default_agent_socket (void)
|
|
|
|
{
|
2013-08-02 13:25:23 +00:00
|
|
|
return get_gpgconf_item (WANT_AGENT_SOCKET);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the default gpg file name. Returns NULL if not known. */
|
|
|
|
const char *
|
|
|
|
_gpgme_get_default_gpg_name (void)
|
|
|
|
{
|
|
|
|
return get_gpgconf_item (WANT_GPG_NAME);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the default gpgsm file name. Returns NULL if not known. */
|
|
|
|
const char *
|
|
|
|
_gpgme_get_default_gpgsm_name (void)
|
|
|
|
{
|
|
|
|
return get_gpgconf_item (WANT_GPGSM_NAME);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the default g13 file name. Returns NULL if not known. */
|
|
|
|
const char *
|
|
|
|
_gpgme_get_default_g13_name (void)
|
|
|
|
{
|
|
|
|
return get_gpgconf_item (WANT_G13_NAME);
|
2009-01-26 10:21:10 +00:00
|
|
|
}
|
|
|
|
|
2013-08-02 13:25:23 +00:00
|
|
|
/* Return the default gpgconf file name. Returns NULL if not known.
|
|
|
|
Because gpgconf is the binary used to retrieved all these default
|
|
|
|
names, this function is merely a simple wrapper around the function
|
|
|
|
used to locate this binary. */
|
|
|
|
const char *
|
|
|
|
_gpgme_get_default_gpgconf_name (void)
|
|
|
|
{
|
|
|
|
return _gpgme_get_gpgconf_path ();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the default UI-server socket name. Returns NULL if not
|
|
|
|
known. */
|
|
|
|
const char *
|
|
|
|
_gpgme_get_default_uisrv_socket (void)
|
|
|
|
{
|
|
|
|
return get_gpgconf_item (WANT_UISRV_SOCKET);
|
|
|
|
}
|