From b11106ebf0e34caae45a68b87fb81f63faf2004f Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 29 Jan 2004 20:17:27 +0000 Subject: [PATCH] * agent.h (server_control_s): Add connection_fd field. * command.c (start_command_handler): Init it here. * gpg-agent.c (agent_init_default_ctrl): and here. * call-scd.c: Add the CTRL arg to all functions calling start_scd and pass it to start_scd. Changed all callers (start_scd): Keep track of the current active connection. (agent_reset_scd): New. * command.c (start_command_handler): Call it here. * learncard.c (agent_handle_learn): Add arg CTRL; changed caller. (send_cert_back): Ditto. --- agent/ChangeLog | 15 ++++++- agent/agent.h | 23 ++++++---- agent/call-scd.c | 107 +++++++++++++++++++++++++++++++++++---------- agent/command.c | 6 ++- agent/divert-scd.c | 15 +++++-- agent/gpg-agent.c | 2 + agent/learncard.c | 16 +++---- 7 files changed, 138 insertions(+), 46 deletions(-) diff --git a/agent/ChangeLog b/agent/ChangeLog index 73b9c4596..4cdaadef6 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,3 +1,16 @@ +2004-01-29 Werner Koch + + * agent.h (server_control_s): Add connection_fd field. + * command.c (start_command_handler): Init it here. + * gpg-agent.c (agent_init_default_ctrl): and here. + * call-scd.c: Add the CTRL arg to all functions calling start_scd + and pass it to start_scd. Changed all callers + (start_scd): Keep track of the current active connection. + (agent_reset_scd): New. + * command.c (start_command_handler): Call it here. + * learncard.c (agent_handle_learn): Add arg CTRL; changed caller. + (send_cert_back): Ditto. + 2004-01-28 Werner Koch * trustlist.c (agent_marktrusted): Check whether the trustlist is @@ -18,7 +31,7 @@ * findkey.c (agent_key_from_file): Now return an error code so that we have more detailed error messages in the upper layers. - This fixes the handling pinentry's cancel button. + This fixes the handling of pinentry's cancel button. * pksign.c (agent_pksign): Changed accordingly. * pkdecrypt.c (agent_pkdecrypt): Ditto. * command.c (cmd_passwd): Ditto. diff --git a/agent/agent.h b/agent/agent.h index 95b0ba4cd..b70a4ae2d 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -83,6 +83,7 @@ struct server_local_s; struct server_control_s { struct server_local_s *server_local; + int connection_fd; /* -1 or an identifier for the current connection. */ char *display; char *ttyname; char *ttytype; @@ -98,6 +99,7 @@ struct server_control_s { }; typedef struct server_control_s *CTRL; +typedef struct server_control_s *ctrl_t; struct pin_entry_info_s { @@ -194,33 +196,38 @@ int divert_generic_cmd (CTRL ctrl, const char *cmdline, void *assuan_context); /*-- call-scd.c --*/ -int agent_card_learn (void (*kpinfo_cb)(void*, const char *), +int agent_reset_scd (ctrl_t ctrl); +int agent_card_learn (ctrl_t ctrl, + void (*kpinfo_cb)(void*, const char *), void *kpinfo_cb_arg, void (*certinfo_cb)(void*, const char *), void *certinfo_cb_arg, void (*sinfo_cb)(void*, const char *, size_t, const char *), void *sinfo_cb_arg); -int agent_card_serialno (char **r_serialno); -int agent_card_pksign (const char *keyid, +int agent_card_serialno (ctrl_t ctrl, char **r_serialno); +int agent_card_pksign (ctrl_t ctrl, + const char *keyid, int (*getpin_cb)(void *, const char *, char*, size_t), void *getpin_cb_arg, const unsigned char *indata, size_t indatalen, char **r_buf, size_t *r_buflen); -int agent_card_pkdecrypt (const char *keyid, +int agent_card_pkdecrypt (ctrl_t ctrl, + const char *keyid, int (*getpin_cb)(void *, const char *, char*,size_t), void *getpin_cb_arg, const unsigned char *indata, size_t indatalen, char **r_buf, size_t *r_buflen); -int agent_card_readcert (const char *id, char **r_buf, size_t *r_buflen); -int agent_card_readkey (const char *id, unsigned char **r_buf); -int agent_card_scd (const char *cmdline, +int agent_card_readcert (ctrl_t ctrl, + const char *id, char **r_buf, size_t *r_buflen); +int agent_card_readkey (ctrl_t ctrl, const char *id, unsigned char **r_buf); +int agent_card_scd (ctrl_t ctrl, const char *cmdline, int (*getpin_cb)(void *, const char *, char*, size_t), void *getpin_cb_arg, void *assuan_context); /*-- learncard.c --*/ -int agent_handle_learn (void *assuan_context); +int agent_handle_learn (ctrl_t ctrl, void *assuan_context); #endif /*AGENT_H*/ diff --git a/agent/call-scd.c b/agent/call-scd.c index f205fb074..0bb365ced 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -50,6 +50,17 @@ static ASSUAN_CONTEXT scd_ctx = NULL; #ifdef USE_GNU_PTH static pth_mutex_t scd_lock = PTH_MUTEX_INIT; #endif +/* We need to keep track of the connection currently using the SCD. + For a pipe server this is all a NOP becuase the connection will + always have the conenction indicator -1. agent_reset_scd releases + the active connection; i.e. sets it back to -1, so that a new + connection can start using the SCD. If we eventually allow + multiple SCD session we will either make scdaemon multi-threaded or + fork of a new scdaemon and let it see how it can get access to a + reader. +*/ +static int active_connection_fd = -1; +static int active_connection = 0; /* callback parameter for learn card */ struct learn_parm_s { @@ -162,9 +173,10 @@ atfork_cb (void *opaque, int where) } -/* Fork off the SCdaemon if this has not already been done */ +/* Fork off the SCdaemon if this has not already been done. Note that + this fucntion alos locks the daemon. */ static int -start_scd (void) +start_scd (ctrl_t ctrl) { int rc; const char *pgmname; @@ -182,9 +194,20 @@ start_scd (void) #endif if (scd_ctx) - return 0; /* No need to serialize things because the agent is - expected to tun as a single-thread (or may be in - future using libpth) */ + { + /* If we are not the connection currently using the SCD, return + an error. */ + if (!active_connection) + { + active_connection_fd = ctrl->connection_fd; + active_connection = 1; + } + else if (ctrl->connection_fd != active_connection_fd) + return unlock_scd (gpg_error (GPG_ERR_CONFLICT)); + + /* Okay, we scdaemon already started and used by us. */ + return 0; + } if (opt.verbose) log_info ("no running SCdaemon - starting it\n"); @@ -226,13 +249,45 @@ start_scd (void) return unlock_scd (gpg_error (GPG_ERR_NO_SCDAEMON)); } scd_ctx = ctx; - + active_connection_fd = ctrl->connection_fd; + active_connection = 1; + if (DBG_ASSUAN) log_debug ("connection to SCdaemon established\n"); + return 0; } + +/* Reset the SCD if it has been used. */ +int +agent_reset_scd (ctrl_t ctrl) +{ + int rc = 0; + +#ifdef USE_GNU_PTH + if (!pth_mutex_acquire (&scd_lock, 0, NULL)) + { + log_error ("failed to acquire the SCD lock for reset\n"); + return gpg_error (GPG_ERR_INTERNAL); + } +#endif + if (active_connection && active_connection_fd == ctrl->connection_fd) + { + if (scd_ctx) + rc = assuan_transact (scd_ctx, "RESET", NULL, NULL, + NULL, NULL, NULL, NULL); + active_connection_fd = -1; + active_connection = 0; + } + + return unlock_scd (map_assuan_err (rc)); +} + + + + static AssuanError learn_status_cb (void *opaque, const char *line) @@ -264,7 +319,8 @@ learn_status_cb (void *opaque, const char *line) /* Perform the learn command and return a list of all private keys stored on the card. */ int -agent_card_learn (void (*kpinfo_cb)(void*, const char *), +agent_card_learn (ctrl_t ctrl, + void (*kpinfo_cb)(void*, const char *), void *kpinfo_cb_arg, void (*certinfo_cb)(void*, const char *), void *certinfo_cb_arg, @@ -274,7 +330,7 @@ agent_card_learn (void (*kpinfo_cb)(void*, const char *), int rc; struct learn_parm_s parm; - rc = start_scd (); + rc = start_scd (ctrl); if (rc) return rc; @@ -330,12 +386,12 @@ get_serialno_cb (void *opaque, const char *line) /* Return the serial number of the card or an appropriate error. The serial number is returned as a hexstring. */ int -agent_card_serialno (char **r_serialno) +agent_card_serialno (ctrl_t ctrl, char **r_serialno) { int rc; char *serialno = NULL; - rc = start_scd (); + rc = start_scd (ctrl); if (rc) return rc; @@ -405,7 +461,8 @@ inq_needpin (void *opaque, const char *line) /* Create a signature using the current card */ int -agent_card_pksign (const char *keyid, +agent_card_pksign (ctrl_t ctrl, + const char *keyid, int (*getpin_cb)(void *, const char *, char*, size_t), void *getpin_cb_arg, const unsigned char *indata, size_t indatalen, @@ -420,7 +477,7 @@ agent_card_pksign (const char *keyid, size_t sigbuflen; *r_buf = NULL; - rc = start_scd (); + rc = start_scd (ctrl); if (rc) return rc; @@ -476,11 +533,12 @@ agent_card_pksign (const char *keyid, /* Decipher INDATA using the current card. Note that the returned value is */ int -agent_card_pkdecrypt (const char *keyid, - int (*getpin_cb)(void *, const char *, char*, size_t), - void *getpin_cb_arg, - const unsigned char *indata, size_t indatalen, - char **r_buf, size_t *r_buflen) +agent_card_pkdecrypt (ctrl_t ctrl, + const char *keyid, + int (*getpin_cb)(void *, const char *, char*, size_t), + void *getpin_cb_arg, + const unsigned char *indata, size_t indatalen, + char **r_buf, size_t *r_buflen) { int rc, i; char *p, line[ASSUAN_LINELENGTH]; @@ -489,7 +547,7 @@ agent_card_pkdecrypt (const char *keyid, size_t len; *r_buf = NULL; - rc = start_scd (); + rc = start_scd (ctrl); if (rc) return rc; @@ -531,7 +589,8 @@ agent_card_pkdecrypt (const char *keyid, /* Read a certificate with ID into R_BUF and R_BUFLEN. */ int -agent_card_readcert (const char *id, char **r_buf, size_t *r_buflen) +agent_card_readcert (ctrl_t ctrl, + const char *id, char **r_buf, size_t *r_buflen) { int rc; char line[ASSUAN_LINELENGTH]; @@ -539,7 +598,7 @@ agent_card_readcert (const char *id, char **r_buf, size_t *r_buflen) size_t len; *r_buf = NULL; - rc = start_scd (); + rc = start_scd (ctrl); if (rc) return rc; @@ -567,7 +626,7 @@ agent_card_readcert (const char *id, char **r_buf, size_t *r_buflen) /* Read a key with ID and return it in an allocate buffer pointed to by r_BUF as a valid S-expression. */ int -agent_card_readkey (const char *id, unsigned char **r_buf) +agent_card_readkey (ctrl_t ctrl, const char *id, unsigned char **r_buf) { int rc; char line[ASSUAN_LINELENGTH]; @@ -575,7 +634,7 @@ agent_card_readkey (const char *id, unsigned char **r_buf) size_t len, buflen; *r_buf = NULL; - rc = start_scd (); + rc = start_scd (ctrl); if (rc) return rc; @@ -642,14 +701,14 @@ pass_data_thru (void *opaque, const void *buffer, size_t length) mechanism to pass everything verbatim to SCDAEMOPN. The PIN inquirey is handled inside gpg-agent. */ int -agent_card_scd (const char *cmdline, +agent_card_scd (ctrl_t ctrl, const char *cmdline, int (*getpin_cb)(void *, const char *, char*, size_t), void *getpin_cb_arg, void *assuan_context) { int rc; struct inq_needpin_s inqparm; - rc = start_scd (); + rc = start_scd (ctrl); if (rc) return rc; diff --git a/agent/command.c b/agent/command.c index 0406ea439..aec48e194 100644 --- a/agent/command.c +++ b/agent/command.c @@ -579,9 +579,10 @@ cmd_get_confirmation (ASSUAN_CONTEXT ctx, char *line) static int cmd_learn (ASSUAN_CONTEXT ctx, char *line) { + ctrl_t ctrl = assuan_get_pointer (ctx); int rc; - rc = agent_handle_learn (has_option (line, "--send")? ctx : NULL); + rc = agent_handle_learn (ctrl, has_option (line, "--send")? ctx : NULL); if (rc) log_error ("command learn failed: %s\n", gpg_strerror (rc)); return map_to_assuan_status (rc); @@ -771,6 +772,7 @@ start_command_handler (int listen_fd, int fd) else { rc = assuan_init_connected_socket_server (&ctx, fd); + ctrl.connection_fd = fd; } if (rc) { @@ -816,6 +818,8 @@ start_command_handler (int listen_fd, int fd) } } + /* Reset the SCD if needed. */ + agent_reset_scd (&ctrl); assuan_deinit_server (ctx); if (ctrl.display) diff --git a/agent/divert-scd.c b/agent/divert-scd.c index 283150ad3..455d23068 100644 --- a/agent/divert-scd.c +++ b/agent/divert-scd.c @@ -81,7 +81,7 @@ ask_for_card (CTRL ctrl, const unsigned char *shadow_info, char **r_kid) for (;;) { - rc = agent_card_serialno (&serialno); + rc = agent_card_serialno (ctrl, &serialno); if (!rc) { log_debug ("detected card with S/N %s\n", serialno); @@ -108,6 +108,13 @@ ask_for_card (CTRL ctrl, const unsigned char *shadow_info, char **r_kid) if (!rc) { + /* We better reset the SCD now. This is kludge requred + because the scdaemon is currently not always able to + detect the presence of a card. With a fully working + scdaemon this would not be required; i.e. the pkcs#15 + support does not require it becuase OpenSC correclty + detects a present card. */ + agent_reset_scd (ctrl); if (asprintf (&desc, "%s:%%0A%%0A" " \"%.*s\"", @@ -230,7 +237,7 @@ divert_pksign (CTRL ctrl, if (rc) return rc; - rc = agent_card_pksign (kid, getpin_cb, ctrl, + rc = agent_card_pksign (ctrl, kid, getpin_cb, ctrl, data, ndata, &sigval, &siglen); if (!rc) *r_sig = sigval; @@ -294,7 +301,7 @@ divert_pkdecrypt (CTRL ctrl, if (rc) return rc; - rc = agent_card_pkdecrypt (kid, getpin_cb, ctrl, + rc = agent_card_pkdecrypt (ctrl, kid, getpin_cb, ctrl, ciphertext, ciphertextlen, &plaintext, &plaintextlen); if (!rc) @@ -310,7 +317,7 @@ divert_pkdecrypt (CTRL ctrl, int divert_generic_cmd (CTRL ctrl, const char *cmdline, void *assuan_context) { - return agent_card_scd (cmdline, getpin_cb, ctrl, assuan_context); + return agent_card_scd (ctrl, cmdline, getpin_cb, ctrl, assuan_context); } diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index 47420117e..22537aa3b 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -784,6 +784,8 @@ agent_exit (int rc) void agent_init_default_ctrl (struct server_control_s *ctrl) { + ctrl->connection_fd = -1; + /* Note we ignore malloc errors because we can't do much about it and the request will fail anyway shortly after this initialization. */ diff --git a/agent/learncard.c b/agent/learncard.c index a76f2652a..76e8986f8 100644 --- a/agent/learncard.c +++ b/agent/learncard.c @@ -255,13 +255,13 @@ make_shadow_info (const char *serialno, const char *idstring) } static int -send_cert_back (const char *id, void *assuan_context) +send_cert_back (ctrl_t ctrl, const char *id, void *assuan_context) { int rc; char *derbuf; size_t derbuflen; - rc = agent_card_readcert (id, &derbuf, &derbuflen); + rc = agent_card_readcert (ctrl, id, &derbuf, &derbuflen); if (rc) { log_error ("error reading certificate: %s\n", @@ -287,7 +287,7 @@ send_cert_back (const char *id, void *assuan_context) /* Perform the learn operation. If ASSUAN_CONTEXT is not NULL all new certificates are send via Assuan */ int -agent_handle_learn (void *assuan_context) +agent_handle_learn (ctrl_t ctrl, void *assuan_context) { int rc; struct kpinfo_cb_parm_s parm; @@ -313,12 +313,12 @@ agent_handle_learn (void *assuan_context) memset (&sparm, 0, sizeof sparm); /* Check whether a card is present and get the serial number */ - rc = agent_card_serialno (&serialno); + rc = agent_card_serialno (ctrl, &serialno); if (rc) goto leave; /* now gather all the available info */ - rc = agent_card_learn (kpinfo_cb, &parm, certinfo_cb, &cparm, + rc = agent_card_learn (ctrl, kpinfo_cb, &parm, certinfo_cb, &cparm, sinfo_cb, &sparm); if (!rc && (parm.error || cparm.error || sparm.error)) rc = parm.error? parm.error : cparm.error? cparm.error : sparm.error; @@ -354,7 +354,7 @@ agent_handle_learn (void *assuan_context) if (assuan_context) { - rc = send_cert_back (citem->id, assuan_context); + rc = send_cert_back (ctrl, citem->id, assuan_context); if (rc) goto leave; citem->done = 1; @@ -380,7 +380,7 @@ agent_handle_learn (void *assuan_context) continue; /* unknown - store it */ - rc = agent_card_readkey (item->id, &pubkey); + rc = agent_card_readkey (ctrl, item->id, &pubkey); if (rc) { log_debug ("agent_card_readkey failed: %s\n", gpg_strerror (rc)); @@ -430,7 +430,7 @@ agent_handle_learn (void *assuan_context) } if (!citem) { - rc = send_cert_back (item->id, assuan_context); + rc = send_cert_back (ctrl, item->id, assuan_context); if (rc) goto leave; }