diff options
Diffstat (limited to 'agent')
-rw-r--r-- | agent/ChangeLog | 73 | ||||
-rw-r--r-- | agent/agent.h | 31 | ||||
-rw-r--r-- | agent/cache.c | 2 | ||||
-rw-r--r-- | agent/command.c | 203 | ||||
-rw-r--r-- | agent/divert-scd.c | 23 | ||||
-rw-r--r-- | agent/findkey.c | 12 | ||||
-rw-r--r-- | agent/genkey.c | 50 | ||||
-rw-r--r-- | agent/gpg-agent.c | 187 | ||||
-rw-r--r-- | agent/pkdecrypt.c | 4 | ||||
-rw-r--r-- | agent/pksign.c | 8 | ||||
-rw-r--r-- | agent/protect-tool.c | 2 | ||||
-rw-r--r-- | agent/query.c | 50 | ||||
-rw-r--r-- | agent/simple-pwquery.c | 7 | ||||
-rw-r--r-- | agent/trustlist.c | 6 |
14 files changed, 501 insertions, 157 deletions
diff --git a/agent/ChangeLog b/agent/ChangeLog index c19193b23..dc1bedf55 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,3 +1,76 @@ +2002-12-04 Werner Koch <[email protected]> + + * gpg-agent.c: New variable config_filename. + (parse_rereadable_options): New. + (main): Use it here. Add setting of default values, set + config_filename. + (reread_configuration): Filled with actual code. + +2002-12-03 Werner Koch <[email protected]> + + * protect-tool.c (read_key): Don't run make_canonical on a NULL buffer. + + * command.c (parse_hexstring): New. + (cmd_sethash): Use it. + (parse_keygrip): New. + (cmd_havekey, cmd_sigkey): Use it. + (cmd_passwd): New. + * genkey.c (agent_protect_and_store): New. + (store_key): Add arg FORCE. + (agent_genkey): Pass false to this force of store_key. + +2002-11-13 Werner Koch <[email protected]> + + * gpg-agent.c (main): Switch all messages to utf-8. + + * simple-pwquery.c (agent_send_all_options): Use $GPG_TTY and + stdin with ttyname. + + * cache.c (new_data): Uiih - /sizeof d/sizeof *d/. + +2002-11-10 Werner Koch <[email protected]> + + * command.c (option_handler): Fix keep_tty check. + +2002-11-06 Werner Koch <[email protected]> + + * gpg-agent.c (main): Make sure we have a default ttyname. + * command.c (option_handler): Check opt.keep_tty here + * query.c (start_pinentry): but not anymore here. + +2002-11-05 Werner Koch <[email protected]> + + * agent.h (opt,server_control_s): Move display and lc_ variables + to the control struct so that they are per connection. + * gpg-agent.c (agent_init_default_ctrl): New. + (main): Assign those command line options to new default_* variables. + Reset DISPLAY in server mode so that tehre is no implicit default. + * command.c (start_command_handler): Initialize and deinitialize + the control values. + (option_handler): Work on the ctrl values and not on the opt. + * query.c (start_pinentry): New argument CTRL to set the display + connection specific. Changed all callers to pass this value. + (agent_askpin,agent_get_passphrase,agent_get_confirmation): Add + CTRL arg and pass it ot start_pinentry. + * command.c (cmd_get_passphrase): Pass CTRL argument. + * trustlist.c (agent_marktrusted): Add CTRL argument + * command.c (cmd_marktrusted): Pass CTRL argument + * divert-scd.c (ask_for_card): Add CTRL arg. + (divert_pksign,divert_pkdecrypt): Ditto. Changed caller. + (getpin_cb): Use OPAQUE to pass the CTRL variable. Changed both + users. + * findkey.c (unprotect): Add CTRL arg. + (agent_key_from_file): Ditto. + + * query.c (unlock_pinentry): Disconnect the pinentry so that we + start a new one for each request. This is required to support + clients with different environments (e.g. X magic cookies). + +2002-09-05 Neal H. Walfield <[email protected]> + + * gpg-agent.c (main) [USE_GNU_PTH]: No need to call + assuan_set_io_func as assuan is smart. + 2002-09-25 Werner Koch <[email protected]> * gpg-agent.c (handle_signal): Flush cache on SIGHUP. diff --git a/agent/agent.h b/agent/agent.h index 24267b06a..bd7b36a5d 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -1,5 +1,5 @@ /* agent.h - Global definitions for the agent - * Copyright (C) 2001 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -36,11 +36,6 @@ struct { int batch; /* batch mode */ const char *homedir; /* configuration directory name */ const char *pinentry_program; - char *display; - char *ttyname; - char *ttytype; - char *lc_ctype; - char *lc_messages; const char *scdaemon_program; int no_grab; /* don't let the pinentry grab the keyboard */ unsigned long def_cache_ttl; @@ -73,6 +68,11 @@ struct server_local_s; struct server_control_s { struct server_local_s *server_local; + char *display; + char *ttyname; + char *ttytype; + char *lc_ctype; + char *lc_messages; struct { int algo; unsigned char value[MAX_DIGEST_LEN]; @@ -107,6 +107,7 @@ enum { /*-- gpg-agent.c --*/ void agent_exit (int rc); /* also implemented in other tools */ +void agent_init_default_ctrl (struct server_control_s *ctrl); /*-- command.c --*/ void start_command_handler (int, int); @@ -114,16 +115,17 @@ void start_command_handler (int, int); /*-- findkey.c --*/ int agent_write_private_key (const unsigned char *grip, const void *buffer, size_t length, int force); -GCRY_SEXP agent_key_from_file (const unsigned char *grip, +GCRY_SEXP agent_key_from_file (CTRL ctrl, const unsigned char *grip, unsigned char **shadow_info, int ignore_cache); int agent_key_available (const unsigned char *grip); /*-- query.c --*/ -int agent_askpin (const char *desc_text, struct pin_entry_info_s *pininfo); -int agent_get_passphrase (char **retpass, +int agent_askpin (CTRL ctrl, + const char *desc_text, struct pin_entry_info_s *pininfo); +int agent_get_passphrase (CTRL ctrl, char **retpass, const char *desc, const char *prompt, const char *errtext); -int agent_get_confirmation (const char *desc, const char *ok, +int agent_get_confirmation (CTRL ctrl, const char *desc, const char *ok, const char *cancel); /*-- cache.c --*/ @@ -143,6 +145,7 @@ int agent_pkdecrypt (CTRL ctrl, const char *ciphertext, size_t ciphertextlen, /*-- genkey.c --*/ int agent_genkey (CTRL ctrl, const char *keyparam, size_t keyparmlen, FILE *outfp); +int agent_protect_and_store (CTRL ctrl, GCRY_SEXP s_skey); /*-- protect.c --*/ int agent_protect (const unsigned char *plainkey, const char *passphrase, @@ -160,13 +163,15 @@ int agent_get_shadow_info (const unsigned char *shadowkey, /*-- trustlist.c --*/ int agent_istrusted (const char *fpr); int agent_listtrusted (void *assuan_context); -int agent_marktrusted (const char *name, const char *fpr, int flag); +int agent_marktrusted (CTRL ctrl, const char *name, const char *fpr, int flag); /*-- divert-scd.c --*/ -int divert_pksign (const unsigned char *digest, size_t digestlen, int algo, +int divert_pksign (CTRL ctrl, + const unsigned char *digest, size_t digestlen, int algo, const unsigned char *shadow_info, unsigned char **r_sig); -int divert_pkdecrypt (const unsigned char *cipher, +int divert_pkdecrypt (CTRL ctrl, + const unsigned char *cipher, const unsigned char *shadow_info, char **r_buf, size_t *r_len); diff --git a/agent/cache.c b/agent/cache.c index 8f5bf9d3d..b6ab55085 100644 --- a/agent/cache.c +++ b/agent/cache.c @@ -67,7 +67,7 @@ new_data (const void *data, size_t length) secure storage provider*/ total = length + 32 - (length % 32); - d = gcry_malloc_secure (sizeof d + total - 1); + d = gcry_malloc_secure (sizeof *d + total - 1); if (d) { d->totallen = total; diff --git a/agent/command.c b/agent/command.c index 55ee8b84a..3573c27f8 100644 --- a/agent/command.c +++ b/agent/command.c @@ -77,6 +77,48 @@ has_option (const char *line, const char *name) return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n))); } +/* Parse a hex string. Return an Assuan error code or 0 on success and the + length of the parsed string in LEN. */ +static int +parse_hexstring (ASSUAN_CONTEXT ctx, const char *string, size_t *len) +{ + const char *p; + size_t n; + + /* parse the hash value */ + for (p=string, n=0; hexdigitp (p); p++, n++) + ; + if (*p) + return set_error (Parameter_Error, "invalid hexstring"); + if ((n&1)) + return set_error (Parameter_Error, "odd number of digits"); + *len = n; + return 0; +} + +/* Parse the keygrip in STRING into the provided buffer BUF. BUF must + provide space for 20 bytes. BUF is not changed if the fucntions + returns an error. */ +static int +parse_keygrip (ASSUAN_CONTEXT ctx, const char *string, unsigned char *buf) +{ + int rc; + size_t n; + const unsigned char *p; + + rc = parse_hexstring (ctx, string, &n); + if (rc) + return rc; + n /= 2; + if (n != 20) + return set_error (Parameter_Error, "invalid length of keygrip"); + + for (p=string, n=0; n < 20; p += 2, n++) + buf[n] = xtoi_2 (p); + + return 0; +} + @@ -136,6 +178,7 @@ cmd_listtrusted (ASSUAN_CONTEXT ctx, char *line) static int cmd_marktrusted (ASSUAN_CONTEXT ctx, char *line) { + CTRL ctrl = assuan_get_pointer (ctx); int rc, n, i; char *p; char fpr[41]; @@ -164,7 +207,7 @@ cmd_marktrusted (ASSUAN_CONTEXT ctx, char *line) while (spacep (p)) p++; - rc = agent_marktrusted (p, fpr, flag); + rc = agent_marktrusted (ctrl, p, fpr, flag); if (rc) log_error ("command marktrusted failed: %s\n", gnupg_strerror (rc)); return map_to_assuan_status (rc); @@ -179,23 +222,12 @@ cmd_marktrusted (ASSUAN_CONTEXT ctx, char *line) static int cmd_havekey (ASSUAN_CONTEXT ctx, char *line) { - int n; - char *p; + int rc; unsigned char buf[20]; - /* parse the hash value */ - for (p=line,n=0; hexdigitp (p); p++, n++) - ; - if (*p) - return set_error (Parameter_Error, "invalid hexstring"); - if ((n&1)) - return set_error (Parameter_Error, "odd number of digits"); - n /= 2; - if (n != 20) - return set_error (Parameter_Error, "invalid length of keygrip"); - - for (p=line, n=0; n < 20; p += 2, n++) - buf[n] = xtoi_2 (p); + rc = parse_keygrip (ctx, line, buf); + if (rc) + return rc; if (agent_key_available (buf)) return ASSUAN_No_Secret_Key; @@ -211,29 +243,17 @@ cmd_havekey (ASSUAN_CONTEXT ctx, char *line) static int cmd_sigkey (ASSUAN_CONTEXT ctx, char *line) { - int n; - char *p; + int rc; CTRL ctrl = assuan_get_pointer (ctx); - unsigned char *buf; - - /* parse the hash value */ - for (p=line,n=0; hexdigitp (p); p++, n++) - ; - if (*p) - return set_error (Parameter_Error, "invalid hexstring"); - if ((n&1)) - return set_error (Parameter_Error, "odd number of digits"); - n /= 2; - if (n != 20) - return set_error (Parameter_Error, "invalid length of keygrip"); - buf = ctrl->keygrip; - for (p=line, n=0; n < 20; p += 2, n++) - buf[n] = xtoi_2 (p); + rc = parse_keygrip (ctx, line, ctrl->keygrip); + if (rc) + return rc; ctrl->have_keygrip = 1; return 0; } + /* SETHASH <algonumber> <hexstring> The client can use this command to tell the server about the data @@ -241,7 +261,8 @@ cmd_sigkey (ASSUAN_CONTEXT ctx, char *line) static int cmd_sethash (ASSUAN_CONTEXT ctx, char *line) { - int n; + int rc; + size_t n; char *p; CTRL ctrl = assuan_get_pointer (ctx); unsigned char *buf; @@ -257,12 +278,9 @@ cmd_sethash (ASSUAN_CONTEXT ctx, char *line) ctrl->digest.algo = algo; /* parse the hash value */ - for (p=line,n=0; hexdigitp (p); p++, n++) - ; - if (*p) - return set_error (Parameter_Error, "invalid hexstring"); - if ((n&1)) - return set_error (Parameter_Error, "odd number of digits"); + rc = parse_hexstring (ctx, line, &n); + if (rc) + return rc; n /= 2; if (n != 16 && n != 20 && n != 24 && n != 32) return set_error (Parameter_Error, "unsupported length of hash"); @@ -386,6 +404,7 @@ plus_to_blank (char *s) static int cmd_get_passphrase (ASSUAN_CONTEXT ctx, char *line) { + CTRL ctrl = assuan_get_pointer (ctx); int rc; const char *pw; char *response; @@ -459,7 +478,7 @@ cmd_get_passphrase (ASSUAN_CONTEXT ctx, char *line) if (desc) plus_to_blank (desc); - rc = agent_get_passphrase (&response, desc, prompt, errtext); + rc = agent_get_passphrase (ctrl, &response, desc, prompt, errtext); if (!rc) { if (cacheid) @@ -520,52 +539,92 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line) +/* PASSWD <hexstring_with_keygrip> + + Change the passphrase/PID for the key identified by keygrip in LINE. */ +static int +cmd_passwd (ASSUAN_CONTEXT ctx, char *line) +{ + CTRL ctrl = assuan_get_pointer (ctx); + int rc; + unsigned char grip[20]; + GCRY_SEXP s_skey = NULL; + unsigned char *shadow_info = NULL; + + rc = parse_keygrip (ctx, line, grip); + if (rc) + return rc; /* we can't jump to leave because this is already an + Assuan error code. */ + + s_skey = agent_key_from_file (ctrl, grip, &shadow_info, 1); + if (!s_skey && !shadow_info) + rc = seterr (No_Secret_Key); + else if (!s_skey) + { + log_error ("changing a smartcard PIN is not yet supported\n"); + rc = seterr (Not_Implemented); + } + else + rc = agent_protect_and_store (ctrl, s_skey); + + gcry_sexp_release (s_skey); + xfree (shadow_info); + if (rc) + log_error ("command passwd failed: %s\n", gnupg_strerror (rc)); + return map_to_assuan_status (rc); +} + + + static int option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value) { CTRL ctrl = assuan_get_pointer (ctx); - /* FIXME: We should not change opt. here. It is not a problem right - now but as soon as we are allowing concurrent connections we mess - things up */ if (!strcmp (key, "display")) { - if (opt.display) - free (opt.display); - opt.display = strdup (value); - if (!opt.display) + if (ctrl->display) + free (ctrl->display); + ctrl->display = strdup (value); + if (!ctrl->display) return ASSUAN_Out_Of_Core; } else if (!strcmp (key, "ttyname")) { - if (opt.ttyname) - free (opt.ttyname); - opt.ttyname = strdup (value); - if (!opt.ttyname) - return ASSUAN_Out_Of_Core; + if (!opt.keep_tty) + { + if (ctrl->ttyname) + free (ctrl->ttyname); + ctrl->ttyname = strdup (value); + if (!ctrl->ttyname) + return ASSUAN_Out_Of_Core; + } } else if (!strcmp (key, "ttytype")) { - if (opt.ttytype) - free (opt.ttytype); - opt.ttytype = strdup (value); - if (!opt.ttytype) - return ASSUAN_Out_Of_Core; + if (!opt.keep_tty) + { + if (ctrl->ttytype) + free (ctrl->ttytype); + ctrl->ttytype = strdup (value); + if (!ctrl->ttytype) + return ASSUAN_Out_Of_Core; + } } else if (!strcmp (key, "lc-ctype")) { - if (opt.lc_ctype) - free (opt.lc_ctype); - opt.lc_ctype = strdup (value); - if (!opt.lc_ctype) + if (ctrl->lc_ctype) + free (ctrl->lc_ctype); + ctrl->lc_ctype = strdup (value); + if (!ctrl->lc_ctype) return ASSUAN_Out_Of_Core; } else if (!strcmp (key, "lc-messages")) { - if (opt.lc_messages) - free (opt.lc_messages); - opt.lc_messages = strdup (value); - if (!opt.lc_messages) + if (ctrl->lc_messages) + free (ctrl->lc_messages); + ctrl->lc_messages = strdup (value); + if (!ctrl->lc_messages) return ASSUAN_Out_Of_Core; } else if (!strcmp (key, "use-cache-for-signing")) @@ -599,6 +658,7 @@ register_commands (ASSUAN_CONTEXT ctx) { "LISTTRUSTED", 0, cmd_listtrusted }, { "MARKTRUSTED", 0, cmd_marktrusted }, { "LEARN", 0, cmd_learn }, + { "PASSWD", 0, cmd_passwd }, { "", ASSUAN_CMD_INPUT, NULL }, { "", ASSUAN_CMD_OUTPUT, NULL }, { NULL } @@ -630,6 +690,7 @@ start_command_handler (int listen_fd, int fd) struct server_control_s ctrl; memset (&ctrl, 0, sizeof ctrl); + agent_init_default_ctrl (&ctrl); if (listen_fd == -1 && fd == -1) { @@ -693,5 +754,15 @@ start_command_handler (int listen_fd, int fd) assuan_deinit_server (ctx); + if (ctrl.display) + free (ctrl.display); + if (ctrl.ttyname) + free (ctrl.ttyname); + if (ctrl.ttytype) + free (ctrl.ttytype); + if (ctrl.lc_ctype) + free (ctrl.lc_ctype); + if (ctrl.lc_messages) + free (ctrl.lc_messages); } diff --git a/agent/divert-scd.c b/agent/divert-scd.c index 40b6bcfa3..38f8173c0 100644 --- a/agent/divert-scd.c +++ b/agent/divert-scd.c @@ -34,7 +34,7 @@ static int -ask_for_card (const unsigned char *shadow_info, char **r_kid) +ask_for_card (CTRL ctrl, const unsigned char *shadow_info, char **r_kid) { int rc, i; const unsigned char *s; @@ -119,7 +119,7 @@ ask_for_card (const unsigned char *shadow_info, char **r_kid) } else { - rc = agent_get_confirmation (desc, NULL, NULL); + rc = agent_get_confirmation (ctrl, desc, NULL, NULL); free (desc); } } @@ -174,8 +174,7 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf) struct pin_entry_info_s *pi; int rc; char *desc; - - assert (!opaque); + CTRL ctrl = opaque; if (maxbuf < 2) return GNUPG_Invalid_Value; @@ -195,7 +194,7 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf) info? info:"", info? "')":"") < 0) desc = NULL; - rc = agent_askpin (desc?desc:info, pi); + rc = agent_askpin (ctrl, desc?desc:info, pi); free (desc); if (!rc) { @@ -210,7 +209,8 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf) int -divert_pksign (const unsigned char *digest, size_t digestlen, int algo, +divert_pksign (CTRL ctrl, + const unsigned char *digest, size_t digestlen, int algo, const unsigned char *shadow_info, unsigned char **r_sig) { int rc; @@ -220,7 +220,7 @@ divert_pksign (const unsigned char *digest, size_t digestlen, int algo, unsigned char *data; size_t ndata; - rc = ask_for_card (shadow_info, &kid); + rc = ask_for_card (ctrl, shadow_info, &kid); if (rc) return rc; @@ -229,7 +229,7 @@ divert_pksign (const unsigned char *digest, size_t digestlen, int algo, if (rc) return rc; - rc = agent_card_pksign (kid, getpin_cb, NULL, + rc = agent_card_pksign (kid, getpin_cb, ctrl, data, ndata, &sigval, &siglen); if (!rc) *r_sig = sigval; @@ -244,7 +244,8 @@ divert_pksign (const unsigned char *digest, size_t digestlen, int algo, key identified by SHADOW_INFO and return the plaintext in an allocated buffer in R_BUF. */ int -divert_pkdecrypt (const unsigned char *cipher, +divert_pkdecrypt (CTRL ctrl, + const unsigned char *cipher, const unsigned char *shadow_info, char **r_buf, size_t *r_len) { @@ -288,11 +289,11 @@ divert_pkdecrypt (const unsigned char *cipher, ciphertext = s; ciphertextlen = n; - rc = ask_for_card (shadow_info, &kid); + rc = ask_for_card (ctrl, shadow_info, &kid); if (rc) return rc; - rc = agent_card_pkdecrypt (kid, getpin_cb, NULL, + rc = agent_card_pkdecrypt (kid, getpin_cb, ctrl, ciphertext, ciphertextlen, &plaintext, &plaintextlen); if (!rc) diff --git a/agent/findkey.c b/agent/findkey.c index 8ec230fa0..96a1f360c 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -131,9 +131,10 @@ try_unprotect_cb (struct pin_entry_info_s *pi) /* Unprotect the canconical encoded S-expression key in KEYBUF. GRIP should be the hex encoded keygrip of that key to be used with the - cahing mechanism. */ + caching mechanism. */ static int -unprotect (unsigned char **keybuf, const unsigned char *grip, int ignore_cache) +unprotect (CTRL ctrl, + unsigned char **keybuf, const unsigned char *grip, int ignore_cache) { struct pin_entry_info_s *pi; struct try_unprotect_arg_s arg; @@ -176,7 +177,7 @@ unprotect (unsigned char **keybuf, const unsigned char *grip, int ignore_cache) arg.unprotected_key = NULL; pi->check_cb_arg = &arg; - rc = agent_askpin (NULL, pi); + rc = agent_askpin (ctrl, NULL, pi); if (!rc) { assert (arg.unprotected_key); @@ -197,7 +198,8 @@ unprotect (unsigned char **keybuf, const unsigned char *grip, int ignore_cache) With IGNORE_CACHE passed as true the passphrase is not taken from the cache.*/ GCRY_SEXP -agent_key_from_file (const unsigned char *grip, unsigned char **shadow_info, +agent_key_from_file (CTRL ctrl, + const unsigned char *grip, unsigned char **shadow_info, int ignore_cache) { int i, rc; @@ -271,7 +273,7 @@ agent_key_from_file (const unsigned char *grip, unsigned char **shadow_info, case PRIVATE_KEY_CLEAR: break; /* no unprotection needed */ case PRIVATE_KEY_PROTECTED: - rc = unprotect (&buf, grip, ignore_cache); + rc = unprotect (ctrl, &buf, grip, ignore_cache); if (rc) log_error ("failed to unprotect the secret key: %s\n", gnupg_strerror (rc)); diff --git a/agent/genkey.c b/agent/genkey.c index dccac94da..6def5cd8a 100644 --- a/agent/genkey.c +++ b/agent/genkey.c @@ -30,7 +30,7 @@ #include "i18n.h" static int -store_key (GCRY_SEXP private, const char *passphrase) +store_key (GCRY_SEXP private, const char *passphrase, int force) { int rc; char *buf; @@ -65,13 +65,13 @@ store_key (GCRY_SEXP private, const char *passphrase) buf = p; } - rc = agent_write_private_key (grip, buf, len, 0); + rc = agent_write_private_key (grip, buf, len, force); xfree (buf); return rc; } /* Callback function to compare the first entered PIN with the one - currently beeing entered. */ + currently being entered. */ static int reenter_compare_cb (struct pin_entry_info_s *pi) { @@ -119,9 +119,9 @@ agent_genkey (CTRL ctrl, const char *keyparam, size_t keyparamlen, pi2->check_cb = reenter_compare_cb; pi2->check_cb_arg = pi->pin; - rc = agent_askpin (text1, pi); + rc = agent_askpin (ctrl, text1, pi); if (!rc) - rc = agent_askpin (text2, pi2); + rc = agent_askpin (ctrl, text2, pi2); if (rc) return rc; if (!*pi->pin) @@ -162,7 +162,7 @@ agent_genkey (CTRL ctrl, const char *keyparam, size_t keyparamlen, /* store the secret key */ log_debug ("storing private key\n"); - rc = store_key (s_private, pi? pi->pin:NULL); + rc = store_key (s_private, pi? pi->pin:NULL, 0); xfree (pi); pi = NULL; gcry_sexp_release (s_private); if (rc) @@ -198,3 +198,41 @@ agent_genkey (CTRL ctrl, const char *keyparam, size_t keyparamlen, return 0; } + + +/* Apply a new passpahrse to the key S_SKEY and store it. */ +int +agent_protect_and_store (CTRL ctrl, GCRY_SEXP s_skey) +{ + struct pin_entry_info_s *pi, *pi2; + int rc; + + { + const char *text1 = _("Please enter the new passphrase"); + const char *text2 = _("Please re-enter this passphrase"); + + pi = gcry_calloc_secure (2, sizeof (*pi) + 100); + pi2 = pi + (sizeof *pi + 100); + pi->max_length = 100; + pi->max_tries = 3; + pi2->max_length = 100; + pi2->max_tries = 3; + pi2->check_cb = reenter_compare_cb; + pi2->check_cb_arg = pi->pin; + + rc = agent_askpin (ctrl, text1, pi); + if (!rc) + rc = agent_askpin (ctrl, text2, pi2); + if (rc) + return rc; + if (!*pi->pin) + { + xfree (pi); + pi = NULL; /* User does not want a passphrase. */ + } + } + + rc = store_key (s_skey, pi? pi->pin:NULL, 1); + xfree (pi); + return 0; +} diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index 3c823e5f6..780dfaddd 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -137,6 +137,18 @@ static int maybe_setuid = 1; /* Name of the communication socket */ static char socket_name[128]; +/* Default values for options passed to the pinentry. */ +static char *default_display; +static char *default_ttyname; +static char *default_ttytype; +static char *default_lc_ctype; +static char *default_lc_messages; + +/* Name of a config file, which will be reread on a HUP if it is not NULL. */ +static char *config_filename; + + +/* Local prototypes. */ static void create_directories (void); #ifdef USE_GNU_PTH static void handle_connections (int listen_fd); @@ -248,6 +260,51 @@ cleanup_sh (int sig) raise( sig ); } + +/* Handle options which are allowed to be reset after program start. + Return true when the current option in PARGS could be handled and + false if not. As a special feature, passing a value of NULL for + PARGS, resets the options to the default. */ +static int +parse_rereadable_options (ARGPARSE_ARGS *pargs) +{ + if (!pargs) + { /* reset mode */ + opt.quiet = 0; + opt.verbose = 0; + opt.debug = 0; + opt.no_grab = 0; + opt.pinentry_program = NULL; + opt.scdaemon_program = NULL; + opt.def_cache_ttl = 10*60; /* default to 10 minutes */ + opt.ignore_cache_for_signing = 0; + return 1; + } + + switch (pargs->r_opt) + { + case oQuiet: opt.quiet = 1; break; + case oVerbose: opt.verbose++; break; + + case oDebug: opt.debug |= pargs->r.ret_ulong; break; + case oDebugAll: opt.debug = ~0; break; + + case oNoGrab: opt.no_grab = 1; break; + + case oPinentryProgram: opt.pinentry_program = pargs->r.ret_str; break; + case oScdaemonProgram: opt.scdaemon_program = pargs->r.ret_str; break; + + case oDefCacheTTL: opt.def_cache_ttl = pargs->r.ret_ulong; break; + + case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break; + + default: + return 0; /* not handled */ + } + return 1; /* handled */ +} + + int main (int argc, char **argv ) { @@ -288,15 +345,14 @@ main (int argc, char **argv ) } assuan_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free); -#ifdef USE_GNU_PTH - assuan_set_io_func (pth_read, pth_write); -#endif gcry_set_log_handler (my_gcry_logger, NULL); gcry_control (GCRYCTL_USE_SECURE_RNDPOOL); may_coredump = disable_core_dumps (); + parse_rereadable_options (NULL); /* Reset them to default values. */ + shell = getenv ("SHELL"); if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") ) csh_style = 1; @@ -304,7 +360,6 @@ main (int argc, char **argv ) opt.homedir = getenv("GNUPGHOME"); if (!opt.homedir || !*opt.homedir) opt.homedir = GNUPG_DEFAULT_HOMEDIR; - opt.def_cache_ttl = 10*60; /* default to 10 minutes */ /* check whether we have a config file on the commandline */ @@ -375,14 +430,12 @@ main (int argc, char **argv ) while (optfile_parse( configfp, configname, &configlineno, &pargs, opts) ) { + if (parse_rereadable_options (&pargs)) + continue; /* Already handled */ switch (pargs.r_opt) { - case oQuiet: opt.quiet = 1; break; - case oVerbose: opt.verbose++; break; case oBatch: opt.batch=1; break; - case oDebug: opt.debug |= pargs.r.ret_ulong; break; - case oDebugAll: opt.debug = ~0; break; case oDebugWait: debug_wait = pargs.r.ret_int; break; case oOptions: @@ -399,7 +452,6 @@ main (int argc, char **argv ) case oNoOptions: break; /* no-options */ case oHomedir: opt.homedir = pargs.r.ret_str; break; case oNoDetach: nodetach = 1; break; - case oNoGrab: opt.no_grab = 1; break; case oLogFile: logfile = pargs.r.ret_str; break; case oCsh: csh_style = 1; break; case oSh: csh_style = 0; break; @@ -407,16 +459,12 @@ main (int argc, char **argv ) case oDaemon: is_daemon = 1; break; case oDisablePth: disable_pth = 1; break; - case oPinentryProgram: opt.pinentry_program = pargs.r.ret_str; break; - case oDisplay: opt.display = xstrdup (pargs.r.ret_str); break; - case oTTYname: opt.ttyname = xstrdup (pargs.r.ret_str); break; - case oTTYtype: opt.ttytype = xstrdup (pargs.r.ret_str); break; - case oLCctype: opt.lc_ctype = xstrdup (pargs.r.ret_str); break; - case oLCmessages: opt.lc_messages = xstrdup (pargs.r.ret_str); break; - case oScdaemonProgram: opt.scdaemon_program = pargs.r.ret_str; break; - case oDefCacheTTL: opt.def_cache_ttl = pargs.r.ret_ulong; break; + case oDisplay: default_display = xstrdup (pargs.r.ret_str); break; + case oTTYname: default_ttyname = xstrdup (pargs.r.ret_str); break; + case oTTYtype: default_ttytype = xstrdup (pargs.r.ret_str); break; + case oLCctype: default_lc_ctype = xstrdup (pargs.r.ret_str); break; + case oLCmessages: default_lc_messages = xstrdup (pargs.r.ret_str); break; - case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break; case oKeepTTY: opt.keep_tty = 1; break; case oKeepDISPLAY: opt.keep_display = 1; break; @@ -427,7 +475,8 @@ main (int argc, char **argv ) { fclose( configfp ); configfp = NULL; - xfree(configname); + /* Keep a copy of the name so that it can be read on SIGHUP. */ + config_filename = configname; configname = NULL; goto next_pass; } @@ -465,7 +514,22 @@ main (int argc, char **argv ) sleep (debug_wait); log_debug ("... okay\n"); } + + if (!pipe_server && !is_daemon) + log_info (_("please use the option `--daemon'" + " to run the program in the background\n")); +#ifdef ENABLE_NLS + /* gpg-agent usdually does not ooutput any messages becuase it runs + in the background. For log files it is acceptable to have + messages always encoded in utf-8. We switch here to utf-8, so + that commands like --help still give native messages. It is far + easier to swicthnonly once instead of for every message and it + actually helps when more then one thread is active (avoids + required an extra copy step). */ + bind_textdomain_codeset (PACKAGE, "UTF-8"); +#endif + /* now start with logging to a file if this is desired */ if (logfile) { @@ -473,16 +537,18 @@ main (int argc, char **argv ) log_set_prefix (NULL, 1|2|4); } + /* Make sure that we have a default ttyname. */ + if (!default_ttyname && ttyname (1)) + default_ttyname = xstrdup (ttyname (1)); + if (!default_ttytype && getenv ("TERM")) + default_ttytype = xstrdup (getenv ("TERM")); if (pipe_server) { /* this is the simple pipe based server */ start_command_handler (-1, -1); } else if (!is_daemon) - { - log_info (_("please use the option `--daemon'" - " to run the program in the background\n")); - } + ; else { /* regular server mode */ int fd; @@ -491,6 +557,13 @@ main (int argc, char **argv ) struct sockaddr_un serv_addr; char *p; + /* Remove the DISPLAY variable so that a pinentry does not + default to a specific display. There is still a default + display when gpg-agent weas started using --display or a + client requested this using an OPTION command. */ + if (!opt.keep_display) + unsetenv ("DISPLAY"); + *socket_name = 0; snprintf (socket_name, DIM(socket_name)-1, "/tmp/gpg-XXXXXX/S.gpg-agent"); @@ -702,10 +775,76 @@ agent_exit (int rc) } +void +agent_init_default_ctrl (struct server_control_s *ctrl) +{ + /* Note we ignore malloc errors because we can't do much about it + and the request will fail anyway shortly after this + initialization. */ + if (ctrl->display) + free (ctrl->display); + ctrl->display = default_display? strdup (default_display) : NULL; + + if (ctrl->ttyname) + free (ctrl->ttyname); + ctrl->ttyname = default_ttyname? strdup (default_ttyname) : NULL; + + if (ctrl->ttytype) + free (ctrl->ttytype); + ctrl->ttytype = default_ttytype? strdup (default_ttytype) : NULL; + + if (ctrl->lc_ctype) + free (ctrl->lc_ctype); + ctrl->lc_ctype = default_lc_ctype? strdup (default_lc_ctype) : NULL; + + if (ctrl->lc_messages) + free (ctrl->lc_messages); + ctrl->lc_messages = default_lc_messages? strdup (default_lc_messages) : NULL; +} + + +/* Reread parts of the configuration. Note, that this function is + obviously not thread-safe and should only be called from the PTH + signal handler. + + Fixme: Due to the way the argument parsing works, we create a + memory leak here for all string type arguments. There is currently + no clean way to tell whether the memory for the argument has been + allocated or points into the process' original arguments. Unless + we have a mechanism to tell this, we need to live on with this. */ static void reread_configuration (void) { - /* FIXME: Move parts of the option parsing to here. */ + ARGPARSE_ARGS pargs; + FILE *fp; + unsigned int configlineno = 0; + int dummy; + + if (!config_filename) + return; /* No config file. */ + + fp = fopen (config_filename, "r"); + if (!fp) + { + log_error (_("option file `%s': %s\n"), + config_filename, strerror(errno) ); + return; + } + + parse_rereadable_options (NULL); /* Start from the default values. */ + + memset (&pargs, 0, sizeof pargs); + dummy = 0; + pargs.argc = &dummy; + pargs.flags = 1; /* do not remove the args */ + while (optfile_parse (fp, config_filename, &configlineno, &pargs, opts) ) + { + if (pargs.r_opt < -1) + pargs.err = 1; /* Print a warning. */ + else /* Try to parse this option - ignore unchangeable ones. */ + parse_rereadable_options (&pargs); + } + fclose (fp); } diff --git a/agent/pkdecrypt.c b/agent/pkdecrypt.c index 6add3d467..094736c69 100644 --- a/agent/pkdecrypt.c +++ b/agent/pkdecrypt.c @@ -64,7 +64,7 @@ agent_pkdecrypt (CTRL ctrl, const char *ciphertext, size_t ciphertextlen, log_printhex ("keygrip:", ctrl->keygrip, 20); log_printhex ("cipher: ", ciphertext, ciphertextlen); } - s_skey = agent_key_from_file (ctrl->keygrip, &shadow_info, 0); + s_skey = agent_key_from_file (ctrl, ctrl->keygrip, &shadow_info, 0); if (!s_skey && !shadow_info) { log_error ("failed to read the secret key\n"); @@ -81,7 +81,7 @@ agent_pkdecrypt (CTRL ctrl, const char *ciphertext, size_t ciphertextlen, goto leave; } - rc = divert_pkdecrypt (ciphertext, shadow_info, &buf, &len ); + rc = divert_pkdecrypt (ctrl, ciphertext, shadow_info, &buf, &len ); if (rc) { log_error ("smartcard decryption failed: %s\n", gnupg_strerror (rc)); diff --git a/agent/pksign.c b/agent/pksign.c index 2acc63dd9..1d84d4870 100644 --- a/agent/pksign.c +++ b/agent/pksign.c @@ -1,5 +1,5 @@ /* pksign.c - public key signing (well, acually using a secret key) - * Copyright (C) 2001 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -98,7 +98,8 @@ agent_pksign (CTRL ctrl, FILE *outfp, int ignore_cache) if (!ctrl->have_keygrip) return seterr (No_Secret_Key); - s_skey = agent_key_from_file (ctrl->keygrip, &shadow_info, ignore_cache); + s_skey = agent_key_from_file (ctrl, + ctrl->keygrip, &shadow_info, ignore_cache); if (!s_skey && !shadow_info) { log_error ("failed to read the secret key\n"); @@ -110,7 +111,8 @@ agent_pksign (CTRL ctrl, FILE *outfp, int ignore_cache) { /* divert operation to the smartcard */ unsigned char *sigbuf; - rc = divert_pksign (ctrl->digest.value, + rc = divert_pksign (ctrl, + ctrl->digest.value, ctrl->digest.valuelen, ctrl->digest.algo, shadow_info, &sigbuf); diff --git a/agent/protect-tool.c b/agent/protect-tool.c index 1d706ea2b..d501abd79 100644 --- a/agent/protect-tool.c +++ b/agent/protect-tool.c @@ -275,6 +275,8 @@ read_key (const char *fname) unsigned char *key; buf = read_file (fname, &buflen); + if (!buf) + return NULL; key = make_canonical (fname, buf, buflen); xfree (buf); return key; diff --git a/agent/query.c b/agent/query.c index ee18a1483..a20e4fe7b 100644 --- a/agent/query.c +++ b/agent/query.c @@ -1,5 +1,5 @@ /* query.c - fork of the pinentry to query stuff from the user - * Copyright (C) 2001 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -56,9 +56,15 @@ struct entry_parm_s { +/* Unlock the pinentry so that another thread can start one and + disconnect that pinentry - we do this after the unlock so that a + stalled pinentry does not block other threads. Fixme: We should + have a timeout in Assuan for the disconnetc operation. */ static int unlock_pinentry (int rc) { + ASSUAN_CONTEXT ctx = entry_ctx; + #ifdef USE_GNU_PTH if (!pth_mutex_release (&entry_lock)) { @@ -67,6 +73,8 @@ unlock_pinentry (int rc) rc = GNUPG_Internal_Error; } #endif + entry_ctx = NULL; + assuan_disconnect (ctx); return rc; } @@ -75,7 +83,7 @@ unlock_pinentry (int rc) pinentry - we will serialize _all_ pinentry calls. */ static int -start_pinentry (void) +start_pinentry (CTRL ctrl) { int rc; const char *pgmname; @@ -96,7 +104,7 @@ start_pinentry (void) return 0; if (opt.verbose) - log_info ("no running PIN Entry - starting it\n"); + log_info ("starting a new PIN Entry\n"); if (fflush (NULL)) { @@ -111,12 +119,11 @@ start_pinentry (void) else pgmname++; - /* FIXME: We must do this thread specific */ argv[0] = pgmname; - if (opt.display && !opt.keep_display) + if (ctrl->display && !opt.keep_display) { argv[1] = "--display"; - argv[2] = opt.display; + argv[2] = ctrl->display; argv[3] = NULL; } else @@ -150,10 +157,10 @@ start_pinentry (void) NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return unlock_pinentry (map_assuan_err (rc)); - if (opt.ttyname && !opt.keep_tty) + if (ctrl->ttyname) { char *optstr; - if (asprintf (&optstr, "OPTION ttyname=%s", opt.ttyname) < 0 ) + if (asprintf (&optstr, "OPTION ttyname=%s", ctrl->ttyname) < 0 ) return unlock_pinentry (GNUPG_Out_Of_Core); rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL); @@ -161,30 +168,30 @@ start_pinentry (void) if (rc) return unlock_pinentry (map_assuan_err (rc)); } - if (opt.ttytype && !opt.keep_tty) + if (ctrl->ttytype) { char *optstr; - if (asprintf (&optstr, "OPTION ttytype=%s", opt.ttytype) < 0 ) + if (asprintf (&optstr, "OPTION ttytype=%s", ctrl->ttytype) < 0 ) return unlock_pinentry (GNUPG_Out_Of_Core); rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return unlock_pinentry (map_assuan_err (rc)); } - if (opt.lc_ctype) + if (ctrl->lc_ctype) { char *optstr; - if (asprintf (&optstr, "OPTION lc-ctype=%s", opt.lc_ctype) < 0 ) + if (asprintf (&optstr, "OPTION lc-ctype=%s", ctrl->lc_ctype) < 0 ) return unlock_pinentry (GNUPG_Out_Of_Core); rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return unlock_pinentry (map_assuan_err (rc)); } - if (opt.lc_messages) + if (ctrl->lc_messages) { char *optstr; - if (asprintf (&optstr, "OPTION lc-messages=%s", opt.lc_messages) < 0 ) + if (asprintf (&optstr, "OPTION lc-messages=%s", ctrl->lc_messages) < 0 ) return unlock_pinentry (GNUPG_Out_Of_Core); rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL); @@ -230,7 +237,8 @@ all_digitsp( const char *s) number here and repeat it as long as we have invalid formed numbers. */ int -agent_askpin (const char *desc_text, struct pin_entry_info_s *pininfo) +agent_askpin (CTRL ctrl, + const char *desc_text, struct pin_entry_info_s *pininfo) { int rc; char line[ASSUAN_LINELENGTH]; @@ -252,7 +260,7 @@ agent_askpin (const char *desc_text, struct pin_entry_info_s *pininfo) is_pin = desc_text && strstr (desc_text, "PIN"); - rc = start_pinentry (); + rc = start_pinentry (ctrl); if (rc) return rc; @@ -335,7 +343,8 @@ agent_askpin (const char *desc_text, struct pin_entry_info_s *pininfo) passphrase is returned in RETPASS as an hex encoded string to be freed by the caller */ int -agent_get_passphrase (char **retpass, const char *desc, const char *prompt, +agent_get_passphrase (CTRL ctrl, + char **retpass, const char *desc, const char *prompt, const char *errtext) { @@ -349,7 +358,7 @@ agent_get_passphrase (char **retpass, const char *desc, const char *prompt, if (opt.batch) return GNUPG_Bad_Passphrase; - rc = start_pinentry (); + rc = start_pinentry (ctrl); if (rc) return rc; @@ -417,12 +426,13 @@ agent_get_passphrase (char **retpass, const char *desc, const char *prompt, confirmed it, GNUPG_Not_Confirmed for what the text says or an other error. */ int -agent_get_confirmation (const char *desc, const char *ok, const char *cancel) +agent_get_confirmation (CTRL ctrl, + const char *desc, const char *ok, const char *cancel) { int rc; char line[ASSUAN_LINELENGTH]; - rc = start_pinentry (); + rc = start_pinentry (ctrl); if (rc) return rc; diff --git a/agent/simple-pwquery.c b/agent/simple-pwquery.c index 5bb08afec..afdc4e2a4 100644 --- a/agent/simple-pwquery.c +++ b/agent/simple-pwquery.c @@ -177,9 +177,10 @@ agent_send_all_options (int fd) return rc; } - if (ttyname (1)) - dft_ttyname = ttyname (1); - if (dft_ttyname) + dft_ttyname = getenv ("GPG_TTY"); + if ((!dft_ttyname || !*dft_ttyname) && ttyname (0)) + dft_ttyname = ttyname (0); + if (dft_ttyname && *dft_ttyname) { if ((rc=agent_send_option (fd, "ttyname", dft_ttyname))) return rc; diff --git a/agent/trustlist.c b/agent/trustlist.c index b6545f7de..9fc4623c6 100644 --- a/agent/trustlist.c +++ b/agent/trustlist.c @@ -228,7 +228,7 @@ agent_listtrusted (void *assuan_context) whether this is actual wants he want to do. */ int -agent_marktrusted (const char *name, const char *fpr, int flag) +agent_marktrusted (CTRL ctrl, const char *name, const char *fpr, int flag) { int rc; static char key[41]; @@ -254,7 +254,7 @@ agent_marktrusted (const char *name, const char *fpr, int flag) "has the fingerprint:%%0A" " %s", name, fpr) < 0 ) return GNUPG_Out_Of_Core; - rc = agent_get_confirmation (desc, "Correct", "No"); + rc = agent_get_confirmation (ctrl, desc, "Correct", "No"); free (desc); if (rc) return rc; @@ -265,7 +265,7 @@ agent_marktrusted (const char *name, const char *fpr, int flag) "to correctly certify user certificates?", name) < 0 ) return GNUPG_Out_Of_Core; - rc = agent_get_confirmation (desc, "Yes", "No"); + rc = agent_get_confirmation (ctrl, desc, "Yes", "No"); free (desc); if (rc) return rc; |