diff options
Diffstat (limited to 'g10/call-agent.c')
-rw-r--r-- | g10/call-agent.c | 151 |
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); |