aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <[email protected]>2016-08-11 10:26:09 +0000
committerJustus Winter <[email protected]>2016-08-11 10:49:30 +0000
commit14479e2515439c73e385f37e8c2b3fc517b038b9 (patch)
tree179c37c1dd47b48e26447acb9a4955f4b6205ccd
parentcommon: Remove simple password query error codes. (diff)
downloadgnupg-14479e2515439c73e385f37e8c2b3fc517b038b9.tar.gz
gnupg-14479e2515439c73e385f37e8c2b3fc517b038b9.zip
common: Rework the simple password query module.
* common/simple-pwquery.c (writen, readline): Drop. (agent_send_option, agent_send_all_options, agent_open): Just use libassuan. (simple_pw_set_socket): Simplify. (default_inq_cb): New function. (simple_pwquery, simple_query): Just use libassuan. * agent/Makefile.am (gpg_preset_passphrase_LDADD): Add libassuan. * tools/Makefile.am (symcryptrun_LDADD): Likewise. Signed-off-by: Justus Winter <[email protected]>
-rw-r--r--agent/Makefile.am2
-rw-r--r--common/simple-pwquery.c420
-rw-r--r--tools/Makefile.am2
3 files changed, 103 insertions, 321 deletions
diff --git a/agent/Makefile.am b/agent/Makefile.am
index 4be9090af..19700888b 100644
--- a/agent/Makefile.am
+++ b/agent/Makefile.am
@@ -85,7 +85,7 @@ gpg_preset_passphrase_SOURCES = \
# Needs $(NETLIBS) for libsimple-pwquery.la.
gpg_preset_passphrase_LDADD = \
- $(pwquery_libs) $(common_libs) \
+ $(pwquery_libs) $(common_libs) $(LIBASSUAN_LIBS) \
$(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) $(LIBINTL) $(NETLIBS) $(LIBICONV)
diff --git a/common/simple-pwquery.c b/common/simple-pwquery.c
index bd40fdfc1..240451b2e 100644
--- a/common/simple-pwquery.c
+++ b/common/simple-pwquery.c
@@ -17,10 +17,10 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-/* This module is intended as a standalone client implementation to
- gpg-agent's GET_PASSPHRASE command. In particular it does not use
- the Assuan library and can only cope with an already running
- gpg-agent. Some stuff is configurable in the header file. */
+/* This module is intended as a simple client implementation to
+ gpg-agent's GET_PASSPHRASE command. It can only cope with an
+ already running gpg-agent. Some stuff is configurable in the
+ header file. */
#ifdef HAVE_CONFIG_H
#include <config.h>
@@ -30,6 +30,7 @@
#include <string.h>
#include <errno.h>
#include <unistd.h>
+#include <assuan.h>
#ifdef HAVE_W32_SYSTEM
#include <winsock2.h>
#else
@@ -42,9 +43,8 @@
#define GNUPG_COMMON_NEED_AFLOCAL
#include "../common/mischelp.h"
-#ifdef HAVE_W32_SYSTEM
-#include "../common/w32-afunix.h"
-#endif
+#include "sysutils.h"
+#include "membuf.h"
#define SIMPLE_PWQUERY_IMPLEMENTATION 1
@@ -96,88 +96,11 @@ my_stpcpy(char *a,const char *b)
#endif
-
-/* Write NBYTES of BUF to file descriptor FD. */
-static int
-writen (int fd, const void *buf, size_t nbytes)
-{
- size_t nleft = nbytes;
- int nwritten;
-
- while (nleft > 0)
- {
-#ifdef HAVE_W32_SYSTEM
- nwritten = send (fd, buf, nleft, 0);
-#else
- nwritten = write (fd, buf, nleft);
-#endif
- if (nwritten < 0)
- {
- if (errno == EINTR)
- nwritten = 0;
- else {
-#ifdef SPWQ_USE_LOGGING
- log_error ("write failed: %s\n", strerror (errno));
-#endif
- return SPWQ_IO_ERROR;
- }
- }
- nleft -= nwritten;
- buf = (const char*)buf + nwritten;
- }
-
- return 0;
-}
-
-
-/* Read an entire line and return number of bytes read. */
-static int
-readline (int fd, char *buf, size_t buflen)
-{
- size_t nleft = buflen;
- char *p;
- int nread = 0;
-
- while (nleft > 0)
- {
-#ifdef HAVE_W32_SYSTEM
- int n = recv (fd, buf, nleft, 0);
-#else
- int n = read (fd, buf, nleft);
-#endif
- if (n < 0)
- {
- if (errno == EINTR)
- continue;
- return -(SPWQ_IO_ERROR);
- }
- else if (!n)
- {
- return -(SPWQ_PROTOCOL_ERROR); /* incomplete line */
- }
- p = buf;
- nleft -= n;
- buf += n;
- nread += n;
-
- for (; n && *p != '\n'; n--, p++)
- ;
- if (n)
- {
- break; /* At least one full line available - that's enough.
- This function is just a simple implementation, so
- it is okay to forget about pending bytes. */
- }
- }
-
- return nread;
-}
-
-
/* Send an option to the agent */
static int
-agent_send_option (int fd, const char *name, const char *value)
+agent_send_option (assuan_context_t ctx, const char *name, const char *value)
{
+ int err;
char buf[200];
int nread;
char *line;
@@ -188,28 +111,17 @@ agent_send_option (int fd, const char *name, const char *value)
return SPWQ_OUT_OF_CORE;
strcpy (stpcpy (stpcpy (stpcpy (
stpcpy (line, "OPTION "), name), "="), value), "\n");
- i = writen (fd, line, strlen (line));
- spwq_free (line);
- if (i)
- return i;
-
- /* get response */
- nread = readline (fd, buf, DIM(buf)-1);
- if (nread < 0)
- return -nread;
- if (nread < 3)
- return SPWQ_PROTOCOL_ERROR;
- if (buf[0] == 'O' && buf[1] == 'K' && (buf[2] == ' ' || buf[2] == '\n'))
- return 0; /* okay */
+ err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
- return SPWQ_ERR_RESPONSE;
+ spwq_free (line);
+ return err;
}
/* Send all available options to the agent. */
static int
-agent_send_all_options (int fd)
+agent_send_all_options (assuan_context_t ctx)
{
char *dft_display = NULL;
char *dft_ttyname = NULL;
@@ -221,7 +133,7 @@ agent_send_all_options (int fd)
dft_display = getenv ("DISPLAY");
if (dft_display)
{
- if ((rc = agent_send_option (fd, "display", dft_display)))
+ if ((rc = agent_send_option (ctx, "display", dft_display)))
return rc;
}
@@ -232,14 +144,14 @@ agent_send_all_options (int fd)
#endif
if (dft_ttyname && *dft_ttyname)
{
- if ((rc=agent_send_option (fd, "ttyname", dft_ttyname)))
+ if ((rc=agent_send_option (ctx, "ttyname", dft_ttyname)))
return rc;
}
dft_ttytype = getenv ("TERM");
if (dft_ttyname && dft_ttytype)
{
- if ((rc = agent_send_option (fd, "ttytype", dft_ttytype)))
+ if ((rc = agent_send_option (ctx, "ttytype", dft_ttytype)))
return rc;
}
@@ -260,7 +172,7 @@ agent_send_all_options (int fd)
}
dft_lc = setlocale (LC_CTYPE, "");
if (dft_ttyname && dft_lc)
- rc = agent_send_option (fd, "lc-ctype", dft_lc);
+ rc = agent_send_option (ctx, "lc-ctype", dft_lc);
if (old_lc)
{
setlocale (LC_CTYPE, old_lc);
@@ -282,7 +194,7 @@ agent_send_all_options (int fd)
}
dft_lc = setlocale (LC_MESSAGES, "");
if (dft_ttyname && dft_lc)
- rc = agent_send_option (fd, "lc-messages", dft_lc);
+ rc = agent_send_option (ctx, "lc-messages", dft_lc);
if (old_lc)
{
setlocale (LC_MESSAGES, old_lc);
@@ -300,7 +212,7 @@ agent_send_all_options (int fd)
{
/* We ignore errors here because older gpg-agents don't support
this option. */
- agent_send_option (fd, "xauthority", dft_xauthority);
+ agent_send_option (ctx, "xauthority", dft_xauthority);
}
/* Send the PINENTRY_USER_DATA variable. */
@@ -309,9 +221,14 @@ agent_send_all_options (int fd)
{
/* We ignore errors here because older gpg-agents don't support
this option. */
- agent_send_option (fd, "pinentry-user-data", dft_pinentry_user_data);
+ agent_send_option (ctx, "pinentry-user-data", dft_pinentry_user_data);
}
+ /* Tell the agent that we support Pinentry notifications. No
+ error checking so that it will work with older agents. */
+ assuan_transact (ctx, "OPTION allow-pinentry-notify",
+ NULL, NULL, NULL, NULL, NULL, NULL);
+
return 0;
}
@@ -321,7 +238,7 @@ agent_send_all_options (int fd)
the file descriptor for the connection. Return -1 in case of
error. */
static int
-agent_open (int *rfd)
+agent_open (assuan_context_t *ctx)
{
int rc;
int fd;
@@ -331,7 +248,6 @@ agent_open (int *rfd)
char line[200];
int nread;
- *rfd = -1;
infostr = default_gpg_agent_info;
if ( !infostr || !*infostr )
{
@@ -340,81 +256,35 @@ agent_open (int *rfd)
#endif
return SPWQ_NO_AGENT;
}
- p = spwq_malloc (strlen (infostr)+1);
- if (!p)
- return SPWQ_OUT_OF_CORE;
- strcpy (p, infostr);
- infostr = p;
-
- if ( !(p = strchr ( infostr, PATHSEP_C)) || p == infostr
- || (p-infostr)+1 >= sizeof client_addr.sun_path )
- {
- spwq_free (infostr);
- return SPWQ_NO_AGENT;
- }
- *p++ = 0;
-
- while (*p && *p != PATHSEP_C)
- p++;
-#ifdef HAVE_W32_SYSTEM
- fd = _w32_sock_new (AF_UNIX, SOCK_STREAM, 0);
-#else
- fd = socket (AF_UNIX, SOCK_STREAM, 0);
-#endif
- if (fd == -1)
- {
-#ifdef SPWQ_USE_LOGGING
- log_error ("can't create socket: %s\n", strerror(errno) );
-#endif
- spwq_free (infostr);
- return SPWQ_SYS_ERROR;
- }
-
- memset (&client_addr, 0, sizeof client_addr);
- client_addr.sun_family = AF_UNIX;
- strcpy (client_addr.sun_path, infostr);
- spwq_free (infostr);
- len = SUN_LEN (&client_addr);
+ rc = assuan_new (ctx);
+ if (rc)
+ return rc;
-#ifdef HAVE_W32_SYSTEM
- rc = _w32_sock_connect (fd, (struct sockaddr*)&client_addr, len );
-#else
- rc = connect (fd, (struct sockaddr*)&client_addr, len );
-#endif
- if (rc == -1)
+ rc = assuan_socket_connect (*ctx, infostr, 0, 0);
+ if (rc)
{
#ifdef SPWQ_USE_LOGGING
log_error (_("can't connect to '%s': %s\n"),
- client_addr.sun_path, strerror (errno));
+ infostr, gpg_strerror (rc));
#endif
- close (fd );
- return SPWQ_IO_ERROR;
+ goto errout;
}
- nread = readline (fd, line, DIM(line));
- if (nread < 3 || !(line[0] == 'O' && line[1] == 'K'
- && (line[2] == '\n' || line[2] == ' ')) )
- {
-#ifdef SPWQ_USE_LOGGING
- log_error ( _("communication problem with gpg-agent\n"));
-#endif
- close (fd );
- return SPWQ_PROTOCOL_ERROR;
- }
-
- rc = agent_send_all_options (fd);
+ rc = agent_send_all_options (*ctx);
if (rc)
{
#ifdef SPWQ_USE_LOGGING
log_error (_("problem setting the gpg-agent options\n"));
#endif
- close (fd);
- return rc;
+ goto errout;
}
- *rfd = fd;
return 0;
+
+ errout:
+ assuan_release (*ctx);
+ *ctx = NULL;
}
@@ -451,17 +321,37 @@ int
simple_pw_set_socket (const char *name)
{
spwq_free (default_gpg_agent_info);
+ default_gpg_agent_info = NULL;
if (name)
{
- default_gpg_agent_info = spwq_malloc (strlen (name) + 4 + 1);
+ default_gpg_agent_info = spwq_malloc (strlen (name) + 1);
if (!default_gpg_agent_info)
return SPWQ_OUT_OF_CORE;
- /* We don't know the PID thus we use 0. */
- strcpy (stpcpy (default_gpg_agent_info, name),
- PATHSEP_S "0" PATHSEP_S "1");
+ strcpy (default_gpg_agent_info, name);
+ }
+
+ return 0;
+}
+
+
+/* This is the default inquiry callback. It merely handles the
+ Pinentry notification. */
+static gpg_error_t
+default_inq_cb (void *opaque, const char *line)
+{
+ (void)opaque;
+
+ if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
+ {
+ gnupg_allow_set_foregound_window ((pid_t)strtoul (line+17, NULL, 10));
+ /* We do not return errors to avoid breaking other code. */
}
else
- default_gpg_agent_info = NULL;
+ {
+#ifdef SPWQ_USE_LOGGING
+ log_debug ("ignoring gpg-agent inquiry '%s'\n", line);
+#endif
+ }
return 0;
}
@@ -483,14 +373,15 @@ simple_pwquery (const char *cacheid,
int opt_check,
int *errorcode)
{
- int fd = -1;
+ assuan_context_t ctx;
+ membuf_t data;
int nread;
char *result = NULL;
char *pw = NULL;
char *p;
int rc, i;
- rc = agent_open (&fd);
+ rc = agent_open (&ctx);
if (rc)
goto leave;
@@ -530,73 +421,43 @@ simple_pwquery (const char *cacheid,
*p++ = ' ';
p = copy_and_escape (p, description);
*p++ = '\n';
- rc = writen (fd, line, p - line);
+
+ init_membuf_secure (&data, 64);
+
+ rc = assuan_transact (ctx, line, put_membuf_cb, &data,
+ default_inq_cb, NULL, NULL, NULL);
spwq_free (line);
- if (rc)
- goto leave;
- }
- /* get response */
- pw = spwq_secure_malloc (500);
- nread = readline (fd, pw, 499);
- if (nread < 0)
- {
- rc = -nread;
- goto leave;
- }
- if (nread < 3)
- {
- rc = SPWQ_PROTOCOL_ERROR;
- goto leave;
- }
+ /* Older Pinentries return the old assuan error code for canceled
+ which gets translated by libassuan to GPG_ERR_ASS_CANCELED and
+ not to the code for a user cancel. Fix this here. */
+ if (rc && gpg_err_source (rc)
+ && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
+ rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
- if (pw[0] == 'O' && pw[1] == 'K' && pw[2] == ' ')
- { /* we got a passphrase - convert it back from hex */
- size_t pwlen = 0;
+ if (rc)
+ {
+ void *p;
+ size_t n;
- for (i=3; i < nread && hexdigitp (pw+i); i+=2)
- pw[pwlen++] = xtoi_2 (pw+i);
- pw[pwlen] = 0; /* make a C String */
- result = pw;
- pw = NULL;
- }
- else if ((nread > 7 && !memcmp (pw, "ERR 111", 7)
- && (pw[7] == ' ' || pw[7] == '\n') )
- || ((nread > 4 && !memcmp (pw, "ERR ", 4)
- && (strtoul (pw+4, NULL, 0) & 0xffff) == 99)) )
- {
- /* 111 is the old Assuan code for canceled which might still
- be in use by old installations. 99 is GPG_ERR_CANCELED as
- used by modern gpg-agents; 0xffff is used to mask out the
- error source. */
-#ifdef SPWQ_USE_LOGGING
- log_info (_("canceled by user\n") );
-#endif
- *errorcode = 0; /* Special error code to indicate Cancel. */
- }
- else if (nread > 4 && !memcmp (pw, "ERR ", 4))
- {
- switch ( (strtoul (pw+4, NULL, 0) & 0xffff) )
- {
- case 85: rc = SPWQ_NO_PIN_ENTRY; break;
- default: rc = SPWQ_GENERAL_ERROR; break;
- }
- }
- else
- {
-#ifdef SPWQ_USE_LOGGING
- log_error (_("problem with the agent\n"));
-#endif
- rc = SPWQ_ERR_RESPONSE;
- }
+ p = get_membuf (&data, &n);
+ if (p)
+ wipememory (p, n);
+ spwq_free (p);
+ }
+ else
+ {
+ put_membuf (&data, "", 1);
+ result = get_membuf (&data, NULL);
+ if (pw == NULL)
+ rc = gpg_error_from_syserror ();
+ }
+ }
leave:
if (errorcode)
*errorcode = rc;
- if (fd != -1)
- close (fd);
- if (pw)
- spwq_secure_free (pw);
+ assuan_release (ctx);
return result;
}
@@ -628,96 +489,17 @@ simple_pwclear (const char *cacheid)
int
simple_query (const char *query)
{
- int fd = -1;
- int nread;
+ assuan_context_t ctx;
char response[500];
int have = 0;
int rc;
- rc = agent_open (&fd);
- if (rc)
- goto leave;
-
- rc = writen (fd, query, strlen (query));
+ rc = agent_open (&ctx);
if (rc)
- goto leave;
-
- while (1)
- {
- if (! have || ! strchr (response, '\n'))
- /* get response */
- {
- nread = readline (fd, &response[have],
- sizeof (response) - 1 /* NUL */ - have);
- if (nread < 0)
- {
- rc = -nread;
- goto leave;
- }
- have += nread;
- if (have < 3)
- {
- rc = SPWQ_PROTOCOL_ERROR;
- goto leave;
- }
- response[have] = 0;
- }
-
- if (response[0] == 'O' && response[1] == 'K')
- /* OK, do nothing. */;
- else if ((nread > 7 && !memcmp (response, "ERR 111", 7)
- && (response[7] == ' ' || response[7] == '\n') )
- || ((nread > 4 && !memcmp (response, "ERR ", 4)
- && (strtoul (response+4, NULL, 0) & 0xffff) == 99)) )
- {
- /* 111 is the old Assuan code for canceled which might still
- be in use by old installations. 99 is GPG_ERR_CANCELED as
- used by modern gpg-agents; 0xffff is used to mask out the
- error source. */
-#ifdef SPWQ_USE_LOGGING
- log_info (_("canceled by user\n") );
-#endif
- }
- else if (response[0] == 'S' && response[1] == ' ')
- {
- char *nextline;
- int consumed;
-
- nextline = strchr (response, '\n');
- if (! nextline)
- /* Point to the NUL. */
- nextline = &response[have];
- else
- /* Move past the \n. */
- nextline ++;
-
- consumed = (size_t) nextline - (size_t) response;
+ return rc;
- /* Skip any additional newlines. */
- while (consumed < have && response[consumed] == '\n')
- consumed ++;
+ rc = assuan_transact (ctx, query, NULL, NULL, NULL, NULL, NULL, NULL);
- have -= consumed;
-
- if (have)
- memmove (response, &response[consumed], have + 1);
-
- continue;
- }
- else
- {
-#ifdef SPWQ_USE_LOGGING
- log_error (_("problem with the agent (unexpected response \"%s\")\n"),
- response);
-#endif
- rc = SPWQ_ERR_RESPONSE;
- }
-
- break;
- }
-
- leave:
- if (fd != -1)
- close (fd);
+ assuan_release (ctx);
return rc;
}
diff --git a/tools/Makefile.am b/tools/Makefile.am
index bc159d9d3..12e581526 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -113,7 +113,7 @@ gpgparsemail_LDADD =
symcryptrun_SOURCES = symcryptrun.c
symcryptrun_LDADD = $(LIBUTIL_LIBS) $(common_libs) $(pwquery_libs) \
$(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) $(LIBINTL) \
- $(LIBICONV) $(NETLIBS) $(W32SOCKLIBS)
+ $(LIBICONV) $(NETLIBS) $(W32SOCKLIBS) $(LIBASSUAN_LIBS)
watchgnupg_SOURCES = watchgnupg.c
watchgnupg_LDADD = $(NETLIBS)