summaryrefslogtreecommitdiff
path: root/g10/call-agent.c
diff options
context:
space:
mode:
Diffstat (limited to 'g10/call-agent.c')
-rw-r--r--g10/call-agent.c151
1 files changed, 107 insertions, 44 deletions
diff --git a/g10/call-agent.c b/g10/call-agent.c
index cded773..5669e04 100644
--- a/g10/call-agent.c
+++ b/g10/call-agent.c
@@ -1,6 +1,7 @@
/* call-agent.c - Divert GPG operations to the agent.
* Copyright (C) 2001, 2002, 2003, 2006, 2007,
* 2008, 2009 Free Software Foundation, Inc.
+ * Copyright (C) 2014 Werner Koch
*
* This file is part of GnuPG.
*
@@ -108,6 +109,95 @@ status_sc_op_failure (int rc)
}
+static gpg_error_t
+membuf_data_cb (void *opaque, const void *buffer, size_t length)
+{
+ membuf_t *data = opaque;
+
+ if (buffer)
+ put_membuf (data, buffer, length);
+ return 0;
+}
+
+
+/* This is the default inquiry callback. It mainly handles the
+ Pinentry notifications. */
+static gpg_error_t
+default_inq_cb (void *opaque, const char *line)
+{
+ (void)opaque;
+
+ if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
+ {
+ /* There is no working server mode yet thus we use
+ AllowSetForegroundWindow window right here. We might want to
+ do this anyway in case gpg is called on the console. */
+ gnupg_allow_set_foregound_window ((pid_t)strtoul (line+17, NULL, 10));
+ /* We do not pass errors to avoid breaking other code. */
+ }
+ else
+ log_debug ("ignoring gpg-agent inquiry `%s'\n", line);
+
+ return 0;
+}
+
+
+/* Check whether gnome-keyring hijacked the gpg-agent. */
+static void
+check_hijacking (assuan_context_t ctx)
+{
+ membuf_t mb;
+ char *string;
+
+ init_membuf (&mb, 64);
+
+ /* AGENT_ID is a command implemented by gnome-keyring-daemon. IT
+ does not reatun any data but an OK line with a remark. */
+ if (assuan_transact (ctx, "AGENT_ID",
+ membuf_data_cb, &mb, NULL, NULL, NULL, NULL))
+ {
+ xfree (get_membuf (&mb, NULL));
+ return; /* Error - Probably not hijacked. */
+ }
+ put_membuf (&mb, "", 1);
+ string = get_membuf (&mb, NULL);
+ if (!string || !*string)
+ {
+ /* Definitely hijacked - show a warning prompt. */
+ static int shown;
+ const char warn1[] =
+ "The GNOME keyring manager hijacked the GnuPG agent.";
+ const char warn2[] =
+ "GnuPG will not work properly - please configure that "
+ "tool to not interfere with the GnuPG system!";
+ log_info ("WARNING: %s\n", warn1);
+ log_info ("WARNING: %s\n", warn2);
+ /* (GPG_ERR_SOURCRE_GPG, GPG_ERR_NO_AGENT) */
+ write_status_text (STATUS_ERROR, "check_hijacking 33554509");
+ xfree (string);
+ string = strconcat (warn1, "\n\n", warn2, NULL);
+ if (string && !shown && !opt.batch)
+ {
+ /* NB: The Pinentry based prompt will only work if a
+ gnome-keyring manager passes invalid commands on to the
+ original gpg-agent. */
+ char *cmd, *cmdargs;
+
+ cmdargs = percent_plus_escape (string);
+ cmd = strconcat ("GET_CONFIRMATION ", cmdargs, NULL);
+ xfree (cmdargs);
+ if (cmd)
+ {
+ assuan_transact (ctx, cmd, NULL, NULL,
+ default_inq_cb, NULL,
+ NULL, NULL);
+ xfree (cmd);
+ shown = 1;
+ }
+ }
+ }
+ xfree (string);
+}
/* Try to connect to the agent via socket or fork it off and work by
@@ -138,6 +228,7 @@ start_agent (int for_card)
agents. */
assuan_transact (agent_ctx, "OPTION allow-pinentry-notify",
NULL, NULL, NULL, NULL, NULL, NULL);
+ check_hijacking (agent_ctx);
}
}
@@ -278,29 +369,6 @@ get_serialno_cb (void *opaque, const char *line)
}
-/* This is the default inquiry callback. It mainly handles the
- Pinentry notifications. */
-static gpg_error_t
-default_inq_cb (void *opaque, const char *line)
-{
- (void)opaque;
-
- if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
- {
- /* There is no working server mode yet thus we use
- AllowSetForegroundWindow window right here. We might want to
- do this anyway in case gpg is called on the console. */
- gnupg_allow_set_foregound_window ((pid_t)strtoul (line+17, NULL, 10));
- /* We do not pass errors to avoid breaking other code. */
- }
- else
- log_debug ("ignoring gpg-agent inquiry `%s'\n", line);
-
- return 0;
-}
-
-
-
/* Release the card info structure INFO. */
void
agent_release_card_info (struct agent_card_info_s *info)
@@ -942,17 +1010,6 @@ select_openpgp (const char *serialno)
-static gpg_error_t
-membuf_data_cb (void *opaque, const void *buffer, size_t length)
-{
- membuf_t *data = opaque;
-
- if (buffer)
- put_membuf (data, buffer, length);
- return 0;
-}
-
-
/* Helper returning a command option to describe the used hash
algorithm. See scd/command.c:cmd_pksign. */
static const char *
@@ -1034,7 +1091,7 @@ agent_scd_pksign (const char *serialno, int hashalgo,
/* Decrypt INDATA of length INDATALEN using the card identified by
- SERIALNO. Return the plaintext in a nwly allocated buffer stored
+ SERIALNO. Return the plaintext in a newly allocated buffer stored
at the address of R_BUF.
Note, we currently support only RSA or more exactly algorithms
@@ -1058,20 +1115,26 @@ agent_scd_pkdecrypt (const char *serialno,
return rc;
/* FIXME: use secure memory where appropriate */
- if (indatalen*2 + 50 > DIM(line))
- return gpg_error (GPG_ERR_GENERAL);
rc = select_openpgp (serialno);
if (rc)
return rc;
- sprintf (line, "SCD SETDATA ");
- p = line + strlen (line);
- for (i=0; i < indatalen ; i++, p += 2 )
- sprintf (p, "%02X", indata[i]);
- rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
- if (rc)
- return rc;
+ for (len = 0; len < indatalen;)
+ {
+ p = stpcpy (line, "SCD SETDATA ");
+ if (len)
+ p = stpcpy (p, "--append ");
+ for (i=0; len < indatalen && (i*2 < DIM(line)-50); i++, len++)
+ {
+ sprintf (p, "%02X", indata[len]);
+ p += 2;
+ }
+ rc = assuan_transact (agent_ctx, line,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ if (rc)
+ return rc;
+ }
init_membuf (&data, 1024);
snprintf (line, DIM(line)-1, "SCD PKDECRYPT %s", serialno);