* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
*/
#include <config.h>
#include "gpgsm.h"
#include <gcrypt.h>
#include <assuan.h>
-#include "i18n.h"
-#include "asshelp.h"
+#include "../common/i18n.h"
+#include "../common/asshelp.h"
#include "keydb.h" /* fixme: Move this to import.c */
-#include "membuf.h"
+#include "../common/membuf.h"
+#include "../common/shareddefs.h"
+#include "passphrase.h"
static assuan_context_t agent_ctx = NULL;
size_t keylen;
};
+struct default_inq_parm_s
+{
+ ctrl_t ctrl;
+ assuan_context_t ctx;
+};
\f
+/* Print a warning if the server's version number is less than our
+ version number. Returns an error code on a connection problem. */
+static gpg_error_t
+warn_version_mismatch (ctrl_t ctrl, assuan_context_t ctx,
+ const char *servername, int mode)
+{
+ gpg_error_t err;
+ char *serverversion;
+ const char *myversion = strusage (13);
+
+ err = get_assuan_server_version (ctx, mode, &serverversion);
+ if (err)
+ log_error (_("error getting version from '%s': %s\n"),
+ servername, gpg_strerror (err));
+ else if (compare_version_strings (serverversion, myversion) < 0)
+ {
+ char *warn;
+
+ warn = xtryasprintf (_("server '%s' is older than us (%s < %s)"),
+ servername, serverversion, myversion);
+ if (!warn)
+ err = gpg_error_from_syserror ();
+ else
+ {
+ log_info (_("WARNING: %s\n"), warn);
+ if (!opt.quiet)
+ {
+ log_info (_("Note: Outdated servers may lack important"
+ " security fixes.\n"));
+ log_info (_("Note: Use the command \"%s\" to restart them.\n"),
+ "gpgconf --kill all");
+ }
+ gpgsm_status2 (ctrl, STATUS_WARNING, "server_version_mismatch 0",
+ warn, NULL);
+ xfree (warn);
+ }
+ }
+ xfree (serverversion);
+ return err;
+}
+
+
/* Try to connect to the agent via socket or fork it off and work by
pipes. Handle the server's initial greeting */
static int
{
rc = start_new_gpg_agent (&agent_ctx,
GPG_ERR_SOURCE_DEFAULT,
- opt.homedir,
opt.agent_program,
opt.lc_ctype, opt.lc_messages,
opt.session_env,
- opt.verbose, DBG_ASSUAN,
+ opt.autostart, opt.verbose, DBG_IPC,
gpgsm_status2, ctrl);
- if (!rc)
+ if (!opt.autostart && gpg_err_code (rc) == GPG_ERR_NO_AGENT)
+ {
+ static int shown;
+
+ if (!shown)
+ {
+ shown = 1;
+ log_info (_("no gpg-agent running in this session\n"));
+ }
+ }
+ else if (!rc && !(rc = warn_version_mismatch (ctrl, agent_ctx,
+ GPG_AGENT_NAME, 0)))
{
/* Tell the agent that we support Pinentry notifications. No
error checking so that it will work also with older
agents. */
assuan_transact (agent_ctx, "OPTION allow-pinentry-notify",
NULL, NULL, NULL, NULL, NULL, NULL);
+
+ /* Pass on the pinentry mode. */
+ if (opt.pinentry_mode)
+ {
+ char *tmp = xasprintf ("OPTION pinentry-mode=%s",
+ str_pinentry_mode (opt.pinentry_mode));
+ rc = assuan_transact (agent_ctx, tmp,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ xfree (tmp);
+ if (rc)
+ log_error ("setting pinentry mode '%s' failed: %s\n",
+ str_pinentry_mode (opt.pinentry_mode),
+ gpg_strerror (rc));
+ }
+
+ /* Pass on the request origin. */
+ if (opt.request_origin)
+ {
+ char *tmp = xasprintf ("OPTION pretend-request-origin=%s",
+ str_request_origin (opt.request_origin));
+ rc = assuan_transact (agent_ctx, tmp,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ xfree (tmp);
+ if (rc)
+ log_error ("setting request origin '%s' failed: %s\n",
+ str_request_origin (opt.request_origin),
+ gpg_strerror (rc));
+ }
+
+ /* In DE_VS mode under Windows we require that the JENT RNG
+ * is active. */
+#ifdef HAVE_W32_SYSTEM
+ if (!rc && opt.compliance == CO_DE_VS)
+ {
+ if (assuan_transact (agent_ctx, "GETINFO jent_active",
+ NULL, NULL, NULL, NULL, NULL, NULL))
+ {
+ rc = gpg_error (GPG_ERR_FORBIDDEN);
+ log_error (_("%s is not compliant with %s mode\n"),
+ GPG_AGENT_NAME,
+ gnupg_compliance_option_string (opt.compliance));
+ gpgsm_status_with_error (ctrl, STATUS_ERROR,
+ "random-compliance", rc);
+ }
+ }
+#endif /*HAVE_W32_SYSTEM*/
+
}
}
return 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)
{
- gpg_error_t err;
- ctrl_t ctrl = opaque;
+ gpg_error_t err = 0;
+ struct default_inq_parm_s *parm = opaque;
+ ctrl_t ctrl = parm->ctrl;
if (has_leading_keyword (line, "PINENTRY_LAUNCHED"))
{
"PINENTRY_LAUNCHED");
/* We do not pass errors to avoid breaking other code. */
}
+ else if ((has_leading_keyword (line, "PASSPHRASE")
+ || has_leading_keyword (line, "NEW_PASSPHRASE"))
+ && opt.pinentry_mode == PINENTRY_MODE_LOOPBACK
+ && have_static_passphrase ())
+ {
+ const char *s = get_static_passphrase ();
+ err = assuan_send_data (parm->ctx, s, strlen (s));
+ }
else
log_error ("ignoring gpg-agent inquiry '%s'\n", line);
- return 0;
+ return err;
}
char *p, line[ASSUAN_LINELENGTH];
membuf_t data;
size_t len;
+ struct default_inq_parm_s inq_parm;
*r_buf = NULL;
rc = start_agent (ctrl);
if (rc)
return rc;
+ inq_parm.ctrl = ctrl;
+ inq_parm.ctx = agent_ctx;
if (digestlen*2 + 50 > DIM(line))
return gpg_error (GPG_ERR_GENERAL);
if (rc)
return rc;
- snprintf (line, DIM(line)-1, "SIGKEY %s", keygrip);
- line[DIM(line)-1] = 0;
+ snprintf (line, DIM(line), "SIGKEY %s", keygrip);
rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return rc;
if (desc)
{
- snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
- line[DIM(line)-1] = 0;
+ snprintf (line, DIM(line), "SETKEYDESC %s", desc);
rc = assuan_transact (agent_ctx, line,
NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
init_membuf (&data, 1024);
rc = assuan_transact (agent_ctx, "PKSIGN",
- membuf_data_cb, &data, default_inq_cb, ctrl,
+ put_membuf_cb, &data, default_inq_cb, &inq_parm,
NULL, NULL);
if (rc)
{
const char *hashopt;
unsigned char *sigbuf;
size_t sigbuflen;
+ struct default_inq_parm_s inq_parm;
(void)desc;
rc = start_agent (ctrl);
if (rc)
return rc;
+ inq_parm.ctrl = ctrl;
+ inq_parm.ctx = agent_ctx;
if (digestlen*2 + 50 > DIM(line))
return gpg_error (GPG_ERR_GENERAL);
init_membuf (&data, 1024);
- snprintf (line, DIM(line)-1, "SCD PKSIGN %s %s", hashopt, keyid);
- line[DIM(line)-1] = 0;
+ snprintf (line, DIM(line), "SCD PKSIGN %s %s", hashopt, keyid);
rc = assuan_transact (agent_ctx, line,
- membuf_data_cb, &data, default_inq_cb, ctrl,
+ put_membuf_cb, &data, default_inq_cb, &inq_parm,
NULL, NULL);
if (rc)
{
assuan_end_confidential (parm->ctx);
}
else
- rc = default_inq_cb (parm->ctrl, line);
+ {
+ struct default_inq_parm_s inq_parm = { parm->ctrl, parm->ctx };
+ rc = default_inq_cb (&inq_parm, line);
+ }
return rc;
}
return rc;
assert ( DIM(line) >= 50 );
- snprintf (line, DIM(line)-1, "SETKEY %s", keygrip);
- line[DIM(line)-1] = 0;
+ snprintf (line, DIM(line), "SETKEY %s", keygrip);
rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return rc;
if (desc)
{
- snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
- line[DIM(line)-1] = 0;
+ snprintf (line, DIM(line), "SETKEYDESC %s", desc);
rc = assuan_transact (agent_ctx, line,
NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
cipher_parm.ciphertext = ciphertext;
cipher_parm.ciphertextlen = ciphertextlen;
rc = assuan_transact (agent_ctx, "PKDECRYPT",
- membuf_data_cb, &data,
+ put_membuf_cb, &data,
inq_ciphertext_cb, &cipher_parm, NULL, NULL);
if (rc)
{
rc = assuan_send_data (parm->ctx, parm->sexp, parm->sexplen);
}
else
- rc = default_inq_cb (parm->ctrl, line);
+ {
+ struct default_inq_parm_s inq_parm = { parm->ctrl, parm->ctx };
+ rc = default_inq_cb (&inq_parm, line);
+ }
return rc;
}
if (!gk_parm.sexplen)
return gpg_error (GPG_ERR_INV_VALUE);
rc = assuan_transact (agent_ctx, "GENKEY",
- membuf_data_cb, &data,
+ put_membuf_cb, &data,
inq_genkey_parms, &gk_parm, NULL, NULL);
if (rc)
{
size_t len;
unsigned char *buf;
char line[ASSUAN_LINELENGTH];
+ struct default_inq_parm_s inq_parm;
*r_pubkey = NULL;
rc = start_agent (ctrl);
if (rc)
return rc;
+ inq_parm.ctrl = ctrl;
+ inq_parm.ctx = agent_ctx;
rc = assuan_transact (agent_ctx, "RESET",NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return rc;
- snprintf (line, DIM(line)-1, "%sREADKEY %s",
+ snprintf (line, DIM(line), "%sREADKEY %s",
fromcard? "SCD ":"", hexkeygrip);
- line[DIM(line)-1] = 0;
init_membuf (&data, 1024);
rc = assuan_transact (agent_ctx, line,
- membuf_data_cb, &data,
- default_inq_cb, ctrl, NULL, NULL);
+ put_membuf_cb, &data,
+ default_inq_cb, &inq_parm, NULL, NULL);
if (rc)
{
xfree (get_membuf (&data, &len));
}
-/* Callback for the gpgsm_agent_serialno fucntion. */
+/* Callback for the gpgsm_agent_serialno function. */
static gpg_error_t
scd_serialno_status_cb (void *opaque, const char *line)
{
{
int rc;
char *serialno = NULL;
+ struct default_inq_parm_s inq_parm;
*r_serialno = NULL;
rc = start_agent (ctrl);
if (rc)
return rc;
+ inq_parm.ctrl = ctrl;
+ inq_parm.ctx = agent_ctx;
rc = assuan_transact (agent_ctx, "SCD SERIALNO",
NULL, NULL,
- default_inq_cb, ctrl,
+ default_inq_cb, &inq_parm,
scd_serialno_status_cb, &serialno);
if (!rc && !serialno)
rc = gpg_error (GPG_ERR_INTERNAL);
\f
-/* Callback for the gpgsm_agent_serialno fucntion. */
+/* Callback for the gpgsm_agent_serialno function. */
static gpg_error_t
scd_keypairinfo_status_cb (void *opaque, const char *line)
{
{
int rc;
strlist_t list = NULL;
+ struct default_inq_parm_s inq_parm;
*r_list = NULL;
rc = start_agent (ctrl);
if (rc)
return rc;
+ inq_parm.ctrl = ctrl;
+ inq_parm.ctx = agent_ctx;
rc = assuan_transact (agent_ctx, "SCD LEARN --force",
NULL, NULL,
- default_inq_cb, ctrl,
+ default_inq_cb, &inq_parm,
scd_keypairinfo_status_cb, &list);
if (!rc && !list)
rc = gpg_error (GPG_ERR_NO_DATA);
if (hexfpr)
{
- snprintf (line, DIM(line)-1, "ISTRUSTED %s", hexfpr);
- line[DIM(line)-1] = 0;
+ snprintf (line, DIM(line), "ISTRUSTED %s", hexfpr);
}
else
{
return gpg_error (GPG_ERR_GENERAL);
}
- snprintf (line, DIM(line)-1, "ISTRUSTED %s", fpr);
- line[DIM(line)-1] = 0;
+ snprintf (line, DIM(line), "ISTRUSTED %s", fpr);
xfree (fpr);
}
int rc;
char *fpr, *dn, *dnfmt;
char line[ASSUAN_LINELENGTH];
+ struct default_inq_parm_s inq_parm;
rc = start_agent (ctrl);
if (rc)
return rc;
+ inq_parm.ctrl = ctrl;
+ inq_parm.ctx = agent_ctx;
fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
if (!fpr)
xfree (dn);
if (!dnfmt)
return gpg_error_from_syserror ();
- snprintf (line, DIM(line)-1, "MARKTRUSTED %s S %s", fpr, dnfmt);
- line[DIM(line)-1] = 0;
+ snprintf (line, DIM(line), "MARKTRUSTED %s S %s", fpr, dnfmt);
ksba_free (dnfmt);
xfree (fpr);
rc = assuan_transact (agent_ctx, line, NULL, NULL,
- default_inq_cb, ctrl, NULL, NULL);
+ default_inq_cb, &inq_parm, NULL, NULL);
return rc;
}
if (!hexkeygrip || strlen (hexkeygrip) != 40)
return gpg_error (GPG_ERR_INV_VALUE);
- snprintf (line, DIM(line)-1, "HAVEKEY %s", hexkeygrip);
- line[DIM(line)-1] = 0;
+ snprintf (line, DIM(line), "HAVEKEY %s", hexkeygrip);
rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
return rc;
{
int existed;
- if (!keydb_store_cert (cert, 0, &existed))
+ if (!keydb_store_cert (parm->ctrl, cert, 0, &existed))
{
if (opt.verbose > 1 && existed)
log_info ("certificate already in DB\n");
if (rc)
return rc;
+ rc = warn_version_mismatch (ctrl, agent_ctx, SCDAEMON_NAME, 2);
+ if (rc)
+ return rc;
+
init_membuf (&data, 4096);
learn_parm.error = 0;
learn_parm.ctrl = ctrl;
{
int rc;
char line[ASSUAN_LINELENGTH];
+ struct default_inq_parm_s inq_parm;
rc = start_agent (ctrl);
if (rc)
return rc;
+ inq_parm.ctrl = ctrl;
+ inq_parm.ctx = agent_ctx;
if (!hexkeygrip || strlen (hexkeygrip) != 40)
return gpg_error (GPG_ERR_INV_VALUE);
if (desc)
{
- snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
- line[DIM(line)-1] = 0;
+ snprintf (line, DIM(line), "SETKEYDESC %s", desc);
rc = assuan_transact (agent_ctx, line,
NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return rc;
}
- snprintf (line, DIM(line)-1, "PASSWD %s", hexkeygrip);
- line[DIM(line)-1] = 0;
+ snprintf (line, DIM(line), "PASSWD %s", hexkeygrip);
rc = assuan_transact (agent_ctx, line, NULL, NULL,
- default_inq_cb, ctrl, NULL, NULL);
+ default_inq_cb, &inq_parm, NULL, NULL);
return rc;
}
{
int rc;
char line[ASSUAN_LINELENGTH];
+ struct default_inq_parm_s inq_parm;
rc = start_agent (ctrl);
if (rc)
return rc;
+ inq_parm.ctrl = ctrl;
+ inq_parm.ctx = agent_ctx;
- snprintf (line, DIM(line)-1, "GET_CONFIRMATION %s", desc);
- line[DIM(line)-1] = 0;
+ snprintf (line, DIM(line), "GET_CONFIRMATION %s", desc);
rc = assuan_transact (agent_ctx, line, NULL, NULL,
- default_inq_cb, ctrl, NULL, NULL);
+ default_inq_cb, &inq_parm, NULL, NULL);
return rc;
}
if (!hexkeygrip || strlen (hexkeygrip) != 40)
return gpg_error (GPG_ERR_INV_VALUE);
- snprintf (line, DIM(line)-1, "KEYINFO %s", hexkeygrip);
- line[DIM(line)-1] = 0;
+ snprintf (line, DIM(line), "KEYINFO %s", hexkeygrip);
err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL,
keyinfo_status_cb, &serialno);
char line[ASSUAN_LINELENGTH];
char *arg4 = NULL;
membuf_t data;
+ struct default_inq_parm_s inq_parm;
*r_passphrase = NULL;
err = start_agent (ctrl);
if (err)
return err;
+ inq_parm.ctrl = ctrl;
+ inq_parm.ctx = agent_ctx;
if (desc_msg && *desc_msg && !(arg4 = percent_plus_escape (desc_msg)))
return gpg_error_from_syserror ();
- snprintf (line, DIM(line)-1, "GET_PASSPHRASE --data%s -- X X X %s",
+ snprintf (line, DIM(line), "GET_PASSPHRASE --data%s -- X X X %s",
repeat? " --repeat=1 --check --qualitybar":"",
arg4);
xfree (arg4);
init_membuf_secure (&data, 64);
err = assuan_transact (agent_ctx, line,
- membuf_data_cb, &data,
- default_inq_cb, NULL, NULL, NULL);
+ put_membuf_cb, &data,
+ default_inq_cb, &inq_parm, NULL, NULL);
if (err)
xfree (get_membuf (&data, NULL));
size_t len;
unsigned char *buf;
char line[ASSUAN_LINELENGTH];
+ struct default_inq_parm_s inq_parm;
*r_kek = NULL;
err = start_agent (ctrl);
if (err)
return err;
+ inq_parm.ctrl = ctrl;
+ inq_parm.ctx = agent_ctx;
- snprintf (line, DIM(line)-1, "KEYWRAP_KEY %s",
+ snprintf (line, DIM(line), "KEYWRAP_KEY %s",
forexport? "--export":"--import");
init_membuf_secure (&data, 64);
err = assuan_transact (agent_ctx, line,
- membuf_data_cb, &data,
- default_inq_cb, ctrl, NULL, NULL);
+ put_membuf_cb, &data,
+ default_inq_cb, &inq_parm, NULL, NULL);
if (err)
{
xfree (get_membuf (&data, &len));
assuan_end_confidential (parm->ctx);
}
else
- err = default_inq_cb (parm->ctrl, line);
+ {
+ struct default_inq_parm_s inq_parm = { parm->ctrl, parm->ctx };
+ err = default_inq_cb (&inq_parm, line);
+ }
return err;
}
size_t len;
unsigned char *buf;
char line[ASSUAN_LINELENGTH];
+ struct default_inq_parm_s inq_parm;
*r_result = NULL;
err = start_agent (ctrl);
if (err)
return err;
+ inq_parm.ctrl = ctrl;
+ inq_parm.ctx = agent_ctx;
if (desc)
{
- snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
+ snprintf (line, DIM(line), "SETKEYDESC %s", desc);
err = assuan_transact (agent_ctx, line,
NULL, NULL, NULL, NULL, NULL, NULL);
if (err)
return err;
}
- snprintf (line, DIM(line)-1, "EXPORT_KEY %s", keygrip);
+ snprintf (line, DIM(line), "EXPORT_KEY %s", keygrip);
init_membuf_secure (&data, 1024);
err = assuan_transact (agent_ctx, line,
- membuf_data_cb, &data,
- default_inq_cb, ctrl, NULL, NULL);
+ put_membuf_cb, &data,
+ default_inq_cb, &inq_parm, NULL, NULL);
if (err)
{
xfree (get_membuf (&data, &len));