1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-11-04 20:38:50 +01:00

Merge branch 'STABLE-BRANCH-2-2' into master

This commit is contained in:
Werner Koch 2018-03-27 08:48:00 +02:00
commit d4dc4245bf
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
36 changed files with 516 additions and 135 deletions

View File

@ -453,9 +453,9 @@ void initialize_module_cache (void);
void deinitialize_module_cache (void); void deinitialize_module_cache (void);
void agent_cache_housekeeping (void); void agent_cache_housekeeping (void);
void agent_flush_cache (void); void agent_flush_cache (void);
int agent_put_cache (const char *key, cache_mode_t cache_mode, int agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode,
const char *data, int ttl); const char *data, int ttl);
char *agent_get_cache (const char *key, cache_mode_t cache_mode); char *agent_get_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode);
void agent_store_cache_hit (const char *key); void agent_store_cache_hit (const char *key);

View File

@ -58,6 +58,7 @@ struct cache_item_s {
int ttl; /* max. lifetime given in seconds, -1 one means infinite */ int ttl; /* max. lifetime given in seconds, -1 one means infinite */
struct secret_data_s *pw; struct secret_data_s *pw;
cache_mode_t cache_mode; cache_mode_t cache_mode;
int restricted; /* The value of ctrl->restricted is part of the key. */
char key[1]; char key[1];
}; };
@ -202,8 +203,8 @@ housekeeping (void)
if (r->pw && r->ttl >= 0 && r->accessed + r->ttl < current) if (r->pw && r->ttl >= 0 && r->accessed + r->ttl < current)
{ {
if (DBG_CACHE) if (DBG_CACHE)
log_debug (" expired '%s' (%ds after last access)\n", log_debug (" expired '%s'.%d (%ds after last access)\n",
r->key, r->ttl); r->key, r->restricted, r->ttl);
release_data (r->pw); release_data (r->pw);
r->pw = NULL; r->pw = NULL;
r->accessed = current; r->accessed = current;
@ -224,8 +225,8 @@ housekeeping (void)
if (r->pw && r->created + maxttl < current) if (r->pw && r->created + maxttl < current)
{ {
if (DBG_CACHE) if (DBG_CACHE)
log_debug (" expired '%s' (%lus after creation)\n", log_debug (" expired '%s'.%d (%lus after creation)\n",
r->key, opt.max_cache_ttl); r->key, r->restricted, opt.max_cache_ttl);
release_data (r->pw); release_data (r->pw);
r->pw = NULL; r->pw = NULL;
r->accessed = current; r->accessed = current;
@ -233,15 +234,15 @@ housekeeping (void)
} }
/* Third, make sure that we don't have too many items in the list. /* Third, make sure that we don't have too many items in the list.
Expire old and unused entries after 30 minutes */ * Expire old and unused entries after 30 minutes. */
for (rprev=NULL, r=thecache; r; ) for (rprev=NULL, r=thecache; r; )
{ {
if (!r->pw && r->ttl >= 0 && r->accessed + 60*30 < current) if (!r->pw && r->ttl >= 0 && r->accessed + 60*30 < current)
{ {
ITEM r2 = r->next; ITEM r2 = r->next;
if (DBG_CACHE) if (DBG_CACHE)
log_debug (" removed '%s' (mode %d) (slot not used for 30m)\n", log_debug (" removed '%s'.%d (mode %d) (slot not used for 30m)\n",
r->key, r->cache_mode); r->key, r->restricted, r->cache_mode);
xfree (r); xfree (r);
if (!rprev) if (!rprev)
thecache = r2; thecache = r2;
@ -296,7 +297,7 @@ agent_flush_cache (void)
if (r->pw) if (r->pw)
{ {
if (DBG_CACHE) if (DBG_CACHE)
log_debug (" flushing '%s'\n", r->key); log_debug (" flushing '%s'.%d\n", r->key, r->restricted);
release_data (r->pw); release_data (r->pw);
r->pw = NULL; r->pw = NULL;
r->accessed = 0; r->accessed = 0;
@ -326,20 +327,21 @@ cache_mode_equal (cache_mode_t a, cache_mode_t b)
set infinite timeout. CACHE_MODE is stored with the cache entry set infinite timeout. CACHE_MODE is stored with the cache entry
and used to select different timeouts. */ and used to select different timeouts. */
int int
agent_put_cache (const char *key, cache_mode_t cache_mode, agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode,
const char *data, int ttl) const char *data, int ttl)
{ {
gpg_error_t err = 0; gpg_error_t err = 0;
ITEM r; ITEM r;
int res; int res;
int restricted = ctrl? ctrl->restricted : -1;
res = npth_mutex_lock (&cache_lock); res = npth_mutex_lock (&cache_lock);
if (res) if (res)
log_fatal ("failed to acquire cache mutex: %s\n", strerror (res)); log_fatal ("failed to acquire cache mutex: %s\n", strerror (res));
if (DBG_CACHE) if (DBG_CACHE)
log_debug ("agent_put_cache '%s' (mode %d) requested ttl=%d\n", log_debug ("agent_put_cache '%s'.%d (mode %d) requested ttl=%d\n",
key, cache_mode, ttl); key, restricted, cache_mode, ttl);
housekeeping (); housekeeping ();
if (!ttl) if (!ttl)
@ -358,6 +360,7 @@ agent_put_cache (const char *key, cache_mode_t cache_mode,
if (((cache_mode != CACHE_MODE_USER if (((cache_mode != CACHE_MODE_USER
&& cache_mode != CACHE_MODE_NONCE) && cache_mode != CACHE_MODE_NONCE)
|| cache_mode_equal (r->cache_mode, cache_mode)) || cache_mode_equal (r->cache_mode, cache_mode))
&& r->restricted == restricted
&& !strcmp (r->key, key)) && !strcmp (r->key, key))
break; break;
} }
@ -386,6 +389,7 @@ agent_put_cache (const char *key, cache_mode_t cache_mode,
else else
{ {
strcpy (r->key, key); strcpy (r->key, key);
r->restricted = restricted;
r->created = r->accessed = gnupg_get_time (); r->created = r->accessed = gnupg_get_time ();
r->ttl = ttl; r->ttl = ttl;
r->cache_mode = cache_mode; r->cache_mode = cache_mode;
@ -415,13 +419,14 @@ agent_put_cache (const char *key, cache_mode_t cache_mode,
make use of CACHE_MODE except for CACHE_MODE_NONCE and make use of CACHE_MODE except for CACHE_MODE_NONCE and
CACHE_MODE_USER. */ CACHE_MODE_USER. */
char * char *
agent_get_cache (const char *key, cache_mode_t cache_mode) agent_get_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode)
{ {
gpg_error_t err; gpg_error_t err;
ITEM r; ITEM r;
char *value = NULL; char *value = NULL;
int res; int res;
int last_stored = 0; int last_stored = 0;
int restricted = ctrl? ctrl->restricted : -1;
if (cache_mode == CACHE_MODE_IGNORE) if (cache_mode == CACHE_MODE_IGNORE)
return NULL; return NULL;
@ -439,8 +444,8 @@ agent_get_cache (const char *key, cache_mode_t cache_mode)
} }
if (DBG_CACHE) if (DBG_CACHE)
log_debug ("agent_get_cache '%s' (mode %d)%s ...\n", log_debug ("agent_get_cache '%s'.%d (mode %d)%s ...\n",
key, cache_mode, key, ctrl->restricted, cache_mode,
last_stored? " (stored cache key)":""); last_stored? " (stored cache key)":"");
housekeeping (); housekeeping ();
@ -450,6 +455,7 @@ agent_get_cache (const char *key, cache_mode_t cache_mode)
&& ((cache_mode != CACHE_MODE_USER && ((cache_mode != CACHE_MODE_USER
&& cache_mode != CACHE_MODE_NONCE) && cache_mode != CACHE_MODE_NONCE)
|| cache_mode_equal (r->cache_mode, cache_mode)) || cache_mode_equal (r->cache_mode, cache_mode))
&& r->restricted == restricted
&& !strcmp (r->key, key)) && !strcmp (r->key, key))
{ {
/* Note: To avoid races KEY may not be accessed anymore below. */ /* Note: To avoid races KEY may not be accessed anymore below. */
@ -472,8 +478,8 @@ agent_get_cache (const char *key, cache_mode_t cache_mode)
{ {
xfree (value); xfree (value);
value = NULL; value = NULL;
log_error ("retrieving cache entry '%s' failed: %s\n", log_error ("retrieving cache entry '%s'.%d failed: %s\n",
key, gpg_strerror (err)); key, restricted, gpg_strerror (err));
} }
break; break;
} }

View File

@ -3145,7 +3145,7 @@ ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec,
goto out; goto out;
/* Cache this passphrase. */ /* Cache this passphrase. */
err = agent_put_cache (key_grip, CACHE_MODE_SSH, pi->pin, ttl); err = agent_put_cache (ctrl, key_grip, CACHE_MODE_SSH, pi->pin, ttl);
if (err) if (err)
goto out; goto out;

View File

@ -199,14 +199,14 @@ clear_nonce_cache (ctrl_t ctrl)
{ {
if (ctrl->server_local->last_cache_nonce) if (ctrl->server_local->last_cache_nonce)
{ {
agent_put_cache (ctrl->server_local->last_cache_nonce, agent_put_cache (ctrl, ctrl->server_local->last_cache_nonce,
CACHE_MODE_NONCE, NULL, 0); CACHE_MODE_NONCE, NULL, 0);
xfree (ctrl->server_local->last_cache_nonce); xfree (ctrl->server_local->last_cache_nonce);
ctrl->server_local->last_cache_nonce = NULL; ctrl->server_local->last_cache_nonce = NULL;
} }
if (ctrl->server_local->last_passwd_nonce) if (ctrl->server_local->last_passwd_nonce)
{ {
agent_put_cache (ctrl->server_local->last_passwd_nonce, agent_put_cache (ctrl, ctrl->server_local->last_passwd_nonce,
CACHE_MODE_NONCE, NULL, 0); CACHE_MODE_NONCE, NULL, 0);
xfree (ctrl->server_local->last_passwd_nonce); xfree (ctrl->server_local->last_passwd_nonce);
ctrl->server_local->last_passwd_nonce = NULL; ctrl->server_local->last_passwd_nonce = NULL;
@ -930,7 +930,7 @@ cmd_genkey (assuan_context_t ctx, char *line)
} }
else if (passwd_nonce) else if (passwd_nonce)
newpasswd = agent_get_cache (passwd_nonce, CACHE_MODE_NONCE); newpasswd = agent_get_cache (ctrl, passwd_nonce, CACHE_MODE_NONCE);
rc = agent_genkey (ctrl, cache_nonce, (char*)value, valuelen, no_protection, rc = agent_genkey (ctrl, cache_nonce, (char*)value, valuelen, no_protection,
newpasswd, opt_preset, &outbuf); newpasswd, opt_preset, &outbuf);
@ -1179,7 +1179,7 @@ do_one_keyinfo (ctrl_t ctrl, const unsigned char *grip, assuan_context_t ctx,
/* Here we have a little race by doing the cache check separately /* Here we have a little race by doing the cache check separately
from the retrieval function. Given that the cache flag is only a from the retrieval function. Given that the cache flag is only a
hint, it should not really matter. */ hint, it should not really matter. */
pw = agent_get_cache (hexgrip, CACHE_MODE_NORMAL); pw = agent_get_cache (ctrl, hexgrip, CACHE_MODE_NORMAL);
cached = pw ? "1" : "-"; cached = pw ? "1" : "-";
xfree (pw); xfree (pw);
@ -1484,7 +1484,7 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
if (!strcmp (desc, "X")) if (!strcmp (desc, "X"))
desc = NULL; desc = NULL;
pw = cacheid ? agent_get_cache (cacheid, CACHE_MODE_USER) : NULL; pw = cacheid ? agent_get_cache (ctrl, cacheid, CACHE_MODE_USER) : NULL;
if (pw) if (pw)
{ {
rc = send_back_passphrase (ctx, opt_data, pw); rc = send_back_passphrase (ctx, opt_data, pw);
@ -1551,7 +1551,7 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
if (!rc) if (!rc)
{ {
if (cacheid) if (cacheid)
agent_put_cache (cacheid, CACHE_MODE_USER, response, 0); agent_put_cache (ctrl, cacheid, CACHE_MODE_USER, response, 0);
rc = send_back_passphrase (ctx, opt_data, response); rc = send_back_passphrase (ctx, opt_data, response);
} }
xfree (response); xfree (response);
@ -1593,7 +1593,8 @@ cmd_clear_passphrase (assuan_context_t ctx, char *line)
if (!*cacheid || strlen (cacheid) > 50) if (!*cacheid || strlen (cacheid) > 50)
return set_error (GPG_ERR_ASS_PARAMETER, "invalid length of cacheID"); return set_error (GPG_ERR_ASS_PARAMETER, "invalid length of cacheID");
agent_put_cache (cacheid, opt_normal ? CACHE_MODE_NORMAL : CACHE_MODE_USER, agent_put_cache (ctrl, cacheid,
opt_normal ? CACHE_MODE_NORMAL : CACHE_MODE_USER,
NULL, 0); NULL, 0);
agent_clear_passphrase (ctrl, cacheid, agent_clear_passphrase (ctrl, cacheid,
@ -1770,7 +1771,7 @@ cmd_passwd (assuan_context_t ctx, char *line)
passwd_nonce = bin2hex (buf, 12, NULL); passwd_nonce = bin2hex (buf, 12, NULL);
} }
if (passwd_nonce if (passwd_nonce
&& !agent_put_cache (passwd_nonce, CACHE_MODE_NONCE, && !agent_put_cache (ctrl, passwd_nonce, CACHE_MODE_NONCE,
passphrase, CACHE_TTL_NONCE)) passphrase, CACHE_TTL_NONCE))
{ {
assuan_write_status (ctx, "PASSWD_NONCE", passwd_nonce); assuan_write_status (ctx, "PASSWD_NONCE", passwd_nonce);
@ -1785,7 +1786,7 @@ cmd_passwd (assuan_context_t ctx, char *line)
char *newpass = NULL; char *newpass = NULL;
if (passwd_nonce) if (passwd_nonce)
newpass = agent_get_cache (passwd_nonce, CACHE_MODE_NONCE); newpass = agent_get_cache (ctrl, passwd_nonce, CACHE_MODE_NONCE);
err = agent_protect_and_store (ctrl, s_skey, &newpass); err = agent_protect_and_store (ctrl, s_skey, &newpass);
if (!err && passphrase) if (!err && passphrase)
{ {
@ -1800,7 +1801,7 @@ cmd_passwd (assuan_context_t ctx, char *line)
cache_nonce = bin2hex (buf, 12, NULL); cache_nonce = bin2hex (buf, 12, NULL);
} }
if (cache_nonce if (cache_nonce
&& !agent_put_cache (cache_nonce, CACHE_MODE_NONCE, && !agent_put_cache (ctrl, cache_nonce, CACHE_MODE_NONCE,
passphrase, CACHE_TTL_NONCE)) passphrase, CACHE_TTL_NONCE))
{ {
assuan_write_status (ctx, "CACHE_NONCE", cache_nonce); assuan_write_status (ctx, "CACHE_NONCE", cache_nonce);
@ -1820,7 +1821,7 @@ cmd_passwd (assuan_context_t ctx, char *line)
passwd_nonce = bin2hex (buf, 12, NULL); passwd_nonce = bin2hex (buf, 12, NULL);
} }
if (passwd_nonce if (passwd_nonce
&& !agent_put_cache (passwd_nonce, CACHE_MODE_NONCE, && !agent_put_cache (ctrl, passwd_nonce, CACHE_MODE_NONCE,
newpass, CACHE_TTL_NONCE)) newpass, CACHE_TTL_NONCE))
{ {
assuan_write_status (ctx, "PASSWD_NONCE", passwd_nonce); assuan_write_status (ctx, "PASSWD_NONCE", passwd_nonce);
@ -1834,7 +1835,7 @@ cmd_passwd (assuan_context_t ctx, char *line)
{ {
char hexgrip[40+1]; char hexgrip[40+1];
bin2hex(grip, 20, hexgrip); bin2hex(grip, 20, hexgrip);
err = agent_put_cache (hexgrip, CACHE_MODE_ANY, newpass, err = agent_put_cache (ctrl, hexgrip, CACHE_MODE_ANY, newpass,
ctrl->cache_ttl_opt_preset); ctrl->cache_ttl_opt_preset);
} }
xfree (newpass); xfree (newpass);
@ -1939,7 +1940,7 @@ cmd_preset_passphrase (assuan_context_t ctx, char *line)
if (!rc) if (!rc)
{ {
rc = agent_put_cache (grip_clear, CACHE_MODE_ANY, passphrase, ttl); rc = agent_put_cache (ctrl, grip_clear, CACHE_MODE_ANY, passphrase, ttl);
if (opt_inquire) if (opt_inquire)
xfree (passphrase); xfree (passphrase);
} }
@ -2174,7 +2175,7 @@ cmd_import_key (assuan_context_t ctx, char *line)
cache_nonce = bin2hex (buf, 12, NULL); cache_nonce = bin2hex (buf, 12, NULL);
} }
if (cache_nonce if (cache_nonce
&& !agent_put_cache (cache_nonce, CACHE_MODE_NONCE, && !agent_put_cache (ctrl, cache_nonce, CACHE_MODE_NONCE,
passphrase, CACHE_TTL_NONCE)) passphrase, CACHE_TTL_NONCE))
assuan_write_status (ctx, "CACHE_NONCE", cache_nonce); assuan_write_status (ctx, "CACHE_NONCE", cache_nonce);
} }
@ -2336,7 +2337,7 @@ cmd_export_key (assuan_context_t ctx, char *line)
cache_nonce = bin2hex (buf, 12, NULL); cache_nonce = bin2hex (buf, 12, NULL);
} }
if (cache_nonce if (cache_nonce
&& !agent_put_cache (cache_nonce, CACHE_MODE_NONCE, && !agent_put_cache (ctrl, cache_nonce, CACHE_MODE_NONCE,
passphrase, CACHE_TTL_NONCE)) passphrase, CACHE_TTL_NONCE))
{ {
assuan_write_status (ctx, "CACHE_NONCE", cache_nonce); assuan_write_status (ctx, "CACHE_NONCE", cache_nonce);
@ -3101,6 +3102,21 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
ctrl->s2k_count = 0; ctrl->s2k_count = 0;
} }
} }
else if (!strcmp (key, "pretend-request-origin"))
{
log_assert (!ctrl->restricted);
switch (parse_request_origin (value))
{
case REQUEST_ORIGIN_LOCAL: ctrl->restricted = 0; break;
case REQUEST_ORIGIN_REMOTE: ctrl->restricted = 1; break;
case REQUEST_ORIGIN_BROWSER: ctrl->restricted = 2; break;
default:
err = gpg_error (GPG_ERR_INV_VALUE);
/* Better pretend to be remote in case of a bad value. */
ctrl->restricted = 1;
break;
}
}
else else
err = gpg_error (GPG_ERR_UNKNOWN_OPTION); err = gpg_error (GPG_ERR_UNKNOWN_OPTION);

View File

@ -951,7 +951,7 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp, int dontcare_exist,
{ {
char *cache_value; char *cache_value;
cache_value = agent_get_cache (cache_nonce, CACHE_MODE_NONCE); cache_value = agent_get_cache (ctrl, cache_nonce, CACHE_MODE_NONCE);
if (cache_value) if (cache_value)
{ {
if (strlen (cache_value) < pi->max_length) if (strlen (cache_value) < pi->max_length)

View File

@ -511,7 +511,7 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
{ {
char *pw; char *pw;
pw = agent_get_cache (cache_nonce, CACHE_MODE_NONCE); pw = agent_get_cache (ctrl, cache_nonce, CACHE_MODE_NONCE);
if (pw) if (pw)
{ {
rc = agent_unprotect (ctrl, *keybuf, pw, NULL, &result, &resultlen); rc = agent_unprotect (ctrl, *keybuf, pw, NULL, &result, &resultlen);
@ -536,7 +536,7 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
char *pw; char *pw;
retry: retry:
pw = agent_get_cache (hexgrip, cache_mode); pw = agent_get_cache (ctrl, hexgrip, cache_mode);
if (pw) if (pw)
{ {
rc = agent_unprotect (ctrl, *keybuf, pw, NULL, &result, &resultlen); rc = agent_unprotect (ctrl, *keybuf, pw, NULL, &result, &resultlen);
@ -574,7 +574,7 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
We can often avoid the passphrase entry in the second We can often avoid the passphrase entry in the second
step. We do this only in normal mode, so not to step. We do this only in normal mode, so not to
interfere with unrelated cache entries. */ interfere with unrelated cache entries. */
pw = agent_get_cache (NULL, cache_mode); pw = agent_get_cache (ctrl, NULL, cache_mode);
if (pw) if (pw)
{ {
rc = agent_unprotect (ctrl, *keybuf, pw, NULL, rc = agent_unprotect (ctrl, *keybuf, pw, NULL,
@ -670,7 +670,7 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
else else
{ {
/* Passphrase is fine. */ /* Passphrase is fine. */
agent_put_cache (hexgrip, cache_mode, pi->pin, agent_put_cache (ctrl, hexgrip, cache_mode, pi->pin,
lookup_ttl? lookup_ttl (hexgrip) : 0); lookup_ttl? lookup_ttl (hexgrip) : 0);
agent_store_cache_hit (hexgrip); agent_store_cache_hit (hexgrip);
if (r_passphrase && *pi->pin) if (r_passphrase && *pi->pin)

View File

@ -468,7 +468,7 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce,
passphrase = NULL; passphrase = NULL;
else else
{ {
passphrase_buffer = agent_get_cache (cache_nonce, CACHE_MODE_NONCE); passphrase_buffer = agent_get_cache (ctrl, cache_nonce, CACHE_MODE_NONCE);
passphrase = passphrase_buffer; passphrase = passphrase_buffer;
} }
@ -528,7 +528,7 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce,
} }
if (cache_nonce if (cache_nonce
&& !no_protection && !no_protection
&& !agent_put_cache (cache_nonce, CACHE_MODE_NONCE, && !agent_put_cache (ctrl, cache_nonce, CACHE_MODE_NONCE,
passphrase, ctrl->cache_ttl_opt_preset)) passphrase, ctrl->cache_ttl_opt_preset))
agent_write_status (ctrl, "CACHE_NONCE", cache_nonce, NULL); agent_write_status (ctrl, "CACHE_NONCE", cache_nonce, NULL);
if (preset && !no_protection) if (preset && !no_protection)
@ -538,7 +538,7 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce,
if (gcry_pk_get_keygrip (s_private, grip)) if (gcry_pk_get_keygrip (s_private, grip))
{ {
bin2hex(grip, 20, hexgrip); bin2hex(grip, 20, hexgrip);
rc = agent_put_cache (hexgrip, CACHE_MODE_ANY, passphrase, rc = agent_put_cache (ctrl, hexgrip, CACHE_MODE_ANY, passphrase,
ctrl->cache_ttl_opt_preset); ctrl->cache_ttl_opt_preset);
} }
} }

View File

@ -749,8 +749,9 @@ agent_key_available (const unsigned char *grip)
} }
char * char *
agent_get_cache (const char *key, cache_mode_t cache_mode) agent_get_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode)
{ {
(void)ctrl;
(void)key; (void)key;
(void)cache_mode; (void)cache_mode;
return NULL; return NULL;

View File

@ -69,3 +69,38 @@ str_pinentry_mode (pinentry_mode_t mode)
} }
return "?"; return "?";
} }
/* Parse VALUE and return an integer representing a request_origin_t.
* (-1) is returned for an invalid VALUE. */
int
parse_request_origin (const char *value)
{
int result;
if (!strcmp (value, "none") || !strcmp (value, "local"))
result = REQUEST_ORIGIN_LOCAL;
else if (!strcmp (value, "remote"))
result = REQUEST_ORIGIN_REMOTE;
else if (!strcmp (value, "browser"))
result = REQUEST_ORIGIN_BROWSER;
else
result = -1;
return result;
}
/* Return the string representation for the request origin. Returns
* "?" for an invalid mode. */
const char *
str_request_origin (request_origin_t mode)
{
switch (mode)
{
case REQUEST_ORIGIN_LOCAL: return "local";
case REQUEST_ORIGIN_REMOTE: return "remote";
case REQUEST_ORIGIN_BROWSER: return "browser";
}
return "?";
}

View File

@ -39,10 +39,23 @@ typedef enum
pinentry_mode_t; pinentry_mode_t;
/* Values for the request origin. */
typedef enum
{
REQUEST_ORIGIN_LOCAL = 0,
REQUEST_ORIGIN_REMOTE,
REQUEST_ORIGIN_BROWSER
}
request_origin_t;
/*-- agent-opt.c --*/ /*-- agent-opt.c --*/
int parse_pinentry_mode (const char *value); int parse_pinentry_mode (const char *value);
const char *str_pinentry_mode (pinentry_mode_t mode); const char *str_pinentry_mode (pinentry_mode_t mode);
int parse_request_origin (const char *value);
const char *str_request_origin (request_origin_t mode);
#endif /*GNUPG_COMMON_SHAREDDEFS_H*/ #endif /*GNUPG_COMMON_SHAREDDEFS_H*/

View File

@ -650,7 +650,7 @@ have_android_system=no
use_simple_gettext=no use_simple_gettext=no
use_ldapwrapper=yes use_ldapwrapper=yes
mmap_needed=yes mmap_needed=yes
require_pipe_to_unblock_pselect=no require_pipe_to_unblock_pselect=yes
case "${host}" in case "${host}" in
*-mingw32*) *-mingw32*)
# special stuff for Windoze NT # special stuff for Windoze NT
@ -665,6 +665,7 @@ case "${host}" in
have_w32_system=yes have_w32_system=yes
require_iconv=no require_iconv=no
use_ldapwrapper=no # Fixme: Do this only for CE. use_ldapwrapper=no # Fixme: Do this only for CE.
require_pipe_to_unblock_pselect=no
case "${host}" in case "${host}" in
*-mingw32ce*) *-mingw32ce*)
have_w32ce_system=yes have_w32ce_system=yes

View File

@ -85,7 +85,7 @@ DVIPS = TEXINPUTS="$(srcdir)$(PATH_SEPARATOR)$$TEXINPUTS" dvips
AM_MAKEINFOFLAGS = -I $(srcdir) --css-ref=/share/site.css AM_MAKEINFOFLAGS = -I $(srcdir) --css-ref=/share/site.css
YAT2M_OPTIONS = -I $(srcdir) \ YAT2M_OPTIONS = -I $(srcdir) \
--release "GnuPG @PACKAGE_VERSION@" --source "GNU Privacy Guard 2.1" --release "GnuPG @PACKAGE_VERSION@" --source "GNU Privacy Guard 2.2"
myman_sources = gnupg7.texi gpg.texi gpgsm.texi gpg-agent.texi \ myman_sources = gnupg7.texi gpg.texi gpgsm.texi gpg-agent.texi \
dirmngr.texi scdaemon.texi tools.texi wks.texi dirmngr.texi scdaemon.texi tools.texi wks.texi

View File

@ -1581,6 +1581,27 @@ option is valid for the entire session or until reset to 0. This
option is useful if the key is later used on boxes which are either option is useful if the key is later used on boxes which are either
much slower or faster than the actual box. much slower or faster than the actual box.
@item pretend-request-origin
This option switches the connection into a restricted mode which
handles all further commands in the same way as they would be handled
when originating from the extra or browser socket. Note that this
option is not available in the restricted mode. Valid values for this
option are:
@table @code
@item none
@itemx local
This is a NOP and leaves the connection in the standard way.
@item remote
Pretend to come from a remote origin in the same way as connections
from the @option{--extra-socket}.
@item browser
Pretend to come from a local web browser in the same way as connections
from the @option{--browser-socket}.
@end table
@end table @end table

View File

@ -1126,7 +1126,9 @@ all affected self-signatures is set one second ahead.
@opindex passwd @opindex passwd
Change the passphrase of the secret key belonging to the certificate Change the passphrase of the secret key belonging to the certificate
specified as @var{user-id}. This is a shortcut for the sub-command specified as @var{user-id}. This is a shortcut for the sub-command
@code{passwd} of the edit key menu. @code{passwd} of the edit key menu. When using together with the
option @option{--dry-run} this will not actually change the passphrase
but check that the current passphrase is correct.
@end table @end table
@ -2213,8 +2215,8 @@ handy in case where an encrypted message contains a bogus key ID.
@opindex skip-hidden-recipients @opindex skip-hidden-recipients
@opindex no-skip-hidden-recipients @opindex no-skip-hidden-recipients
During decryption skip all anonymous recipients. This option helps in During decryption skip all anonymous recipients. This option helps in
the case that people use the hidden recipients feature to hide there the case that people use the hidden recipients feature to hide their
own encrypt-to key from others. If oneself has many secret keys this own encrypt-to key from others. If one has many secret keys this
may lead to a major annoyance because all keys are tried in turn to may lead to a major annoyance because all keys are tried in turn to
decrypt something which was not really intended for it. The drawback decrypt something which was not really intended for it. The drawback
of this option is that it is currently not possible to decrypt a of this option is that it is currently not possible to decrypt a
@ -3177,6 +3179,15 @@ are:
Pinentry the user is not prompted again if he enters a bad password. Pinentry the user is not prompted again if he enters a bad password.
@end table @end table
@item --request-origin @var{origin}
@opindex request-origin
Tell gpg to assume that the operation ultimately originated at
@var{origin}. Depending on the origin certain restrictions are applied
and the Pinentry may include an extra note on the origin. Supported
values for @var{origin} are: @code{local} which is the default,
@code{remote} to indicate a remote origin or @code{browser} for an
operation requested by a web browser.
@item --command-fd @var{n} @item --command-fd @var{n}
@opindex command-fd @opindex command-fd
This is a replacement for the deprecated shared-memory IPC mode. This is a replacement for the deprecated shared-memory IPC mode.

View File

@ -765,6 +765,15 @@ are:
Pinentry the user is not prompted again if he enters a bad password. Pinentry the user is not prompted again if he enters a bad password.
@end table @end table
@item --request-origin @var{origin}
@opindex request-origin
Tell gpgsm to assume that the operation ultimately originated at
@var{origin}. Depending on the origin certain restrictions are applied
and the Pinentry may include an extra note on the origin. Supported
values for @var{origin} are: @code{local} which is the default,
@code{remote} to indicate a remote origin or @code{browser} for an
operation requested by a web browser.
@item --no-common-certs-import @item --no-common-certs-import
@opindex no-common-certs-import @opindex no-common-certs-import
Suppress the import of common certificates on keybox creation. Suppress the import of common certificates on keybox creation.

View File

@ -289,6 +289,23 @@ start_agent (ctrl_t ctrl, int flag_for_card)
} }
} }
/* 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));
write_status_error ("set_request_origin", rc);
}
}
/* In DE_VS mode under Windows we require that the JENT RNG /* In DE_VS mode under Windows we require that the JENT RNG
* is active. */ * is active. */
#ifdef HAVE_W32_SYSTEM #ifdef HAVE_W32_SYSTEM
@ -591,6 +608,8 @@ learn_status_cb (void *opaque, const char *line)
parm->extcap.ki = abool; parm->extcap.ki = abool;
else if (!strcmp (p, "aac")) else if (!strcmp (p, "aac"))
parm->extcap.aac = abool; parm->extcap.aac = abool;
else if (!strcmp (p, "kdf"))
parm->extcap.kdf = abool;
else if (!strcmp (p, "si")) else if (!strcmp (p, "si"))
parm->status_indicator = strtoul (p2, NULL, 10); parm->status_indicator = strtoul (p2, NULL, 10);
} }

View File

@ -67,6 +67,7 @@ struct agent_card_info_s
struct { struct {
unsigned int ki:1; /* Key import available. */ unsigned int ki:1; /* Key import available. */
unsigned int aac:1; /* Algorithm attributes are changeable. */ unsigned int aac:1; /* Algorithm attributes are changeable. */
unsigned int kdf:1; /* KDF object to support PIN hashing available. */
} extcap; } extcap;
unsigned int status_indicator; unsigned int status_indicator;
}; };

View File

@ -659,7 +659,7 @@ current_card_status (ctrl_t ctrl, estream_t fp,
/* Print all available information for specific card with SERIALNO. /* Print all available information for specific card with SERIALNO.
Print all available information for current card when SERIALNO is NULL. Print all available information for current card when SERIALNO is NULL.
Or print llfor all cards when SERIALNO is "all". */ Or print for all cards when SERIALNO is "all". */
void void
card_status (ctrl_t ctrl, estream_t fp, const char *serialno) card_status (ctrl_t ctrl, estream_t fp, const char *serialno)
{ {
@ -1797,6 +1797,7 @@ factory_reset (void)
scd apdu 00 20 00 83 08 40 40 40 40 40 40 40 40 scd apdu 00 20 00 83 08 40 40 40 40 40 40 40 40
scd apdu 00 e6 00 00 scd apdu 00 e6 00 00
scd apdu 00 44 00 00 scd apdu 00 44 00 00
scd reset
/echo Card has been reset to factory defaults /echo Card has been reset to factory defaults
but tries to find out something about the card first. but tries to find out something about the card first.
@ -1809,7 +1810,7 @@ factory_reset (void)
else if (err) else if (err)
{ {
log_error (_("OpenPGP card not available: %s\n"), gpg_strerror (err)); log_error (_("OpenPGP card not available: %s\n"), gpg_strerror (err));
return; goto leave;
} }
if (!termstate) if (!termstate)
@ -1859,10 +1860,16 @@ factory_reset (void)
command because there is no machinery in scdaemon to catch command because there is no machinery in scdaemon to catch
the verify command and ask for the PIN when the "APDU" the verify command and ask for the PIN when the "APDU"
command is used. */ command is used. */
/* Here, the length of dummy wrong PIN is 32-byte, also
supporting authentication with KDF DO. */
for (i=0; i < 4; i++) for (i=0; i < 4; i++)
send_apdu ("00200081084040404040404040", "VERIFY", 0xffff); send_apdu ("0020008120"
"40404040404040404040404040404040"
"40404040404040404040404040404040", "VERIFY", 0xffff);
for (i=0; i < 4; i++) for (i=0; i < 4; i++)
send_apdu ("00200083084040404040404040", "VERIFY", 0xffff); send_apdu ("0020008320"
"40404040404040404040404040404040"
"40404040404040404040404040404040", "VERIFY", 0xffff);
/* Send terminate datafile command. */ /* Send terminate datafile command. */
err = send_apdu ("00e60000", "TERMINATE DF", 0x6985); err = send_apdu ("00e60000", "TERMINATE DF", 0x6985);
@ -1878,8 +1885,16 @@ factory_reset (void)
/* Finally we reset the card reader once more. */ /* Finally we reset the card reader once more. */
err = send_apdu (NULL, "RESET", 0); err = send_apdu (NULL, "RESET", 0);
if (err)
goto leave; /* Then, connect the card again. */
if (!err)
{
char *serialno0;
err = agent_scd_serialno (&serialno0, NULL);
if (!err)
xfree (serialno0);
}
leave: leave:
xfree (answer); xfree (answer);
@ -1887,6 +1902,104 @@ factory_reset (void)
} }
#define USER_PIN_DEFAULT "123456"
#define ADMIN_PIN_DEFAULT "12345678"
#define KDF_DATA_LENGTH 110
/* Generate KDF data. */
static gpg_error_t
gen_kdf_data (unsigned char *data)
{
const unsigned char h0[] = { 0x81, 0x01, 0x03,
0x82, 0x01, 0x08,
0x83, 0x04 };
const unsigned char h1[] = { 0x84, 0x08 };
const unsigned char h2[] = { 0x85, 0x08 };
const unsigned char h3[] = { 0x86, 0x08 };
const unsigned char h4[] = { 0x87, 0x20 };
const unsigned char h5[] = { 0x88, 0x20 };
unsigned char *p, *salt_user, *salt_admin;
unsigned char s2k_char;
unsigned int iterations;
unsigned char count_4byte[4];
gpg_error_t err = 0;
p = data;
s2k_char = encode_s2k_iterations (0);
iterations = S2K_DECODE_COUNT (s2k_char);
count_4byte[0] = (iterations >> 24) & 0xff;
count_4byte[1] = (iterations >> 16) & 0xff;
count_4byte[2] = (iterations >> 8) & 0xff;
count_4byte[3] = (iterations & 0xff);
memcpy (p, h0, sizeof h0);
p += sizeof h0;
memcpy (p, count_4byte, sizeof count_4byte);
p += sizeof count_4byte;
memcpy (p, h1, sizeof h1);
salt_user = (p += sizeof h1);
gcry_randomize (p, 8, GCRY_STRONG_RANDOM);
p += 8;
memcpy (p, h2, sizeof h2);
p += sizeof h2;
gcry_randomize (p, 8, GCRY_STRONG_RANDOM);
p += 8;
memcpy (p, h3, sizeof h3);
salt_admin = (p += sizeof h3);
gcry_randomize (p, 8, GCRY_STRONG_RANDOM);
p += 8;
memcpy (p, h4, sizeof h4);
p += sizeof h4;
err = gcry_kdf_derive (USER_PIN_DEFAULT, strlen (USER_PIN_DEFAULT),
GCRY_KDF_ITERSALTED_S2K, DIGEST_ALGO_SHA256,
salt_user, 8, iterations, 32, p);
p += 32;
if (!err)
{
memcpy (p, h5, sizeof h5);
p += sizeof h5;
err = gcry_kdf_derive (ADMIN_PIN_DEFAULT, strlen (ADMIN_PIN_DEFAULT),
GCRY_KDF_ITERSALTED_S2K, DIGEST_ALGO_SHA256,
salt_admin, 8, iterations, 32, p);
}
return err;
}
/* Setup KDF data object which is used for PIN authentication. */
static void
kdf_setup (void)
{
struct agent_card_info_s info;
gpg_error_t err;
unsigned char kdf_data[KDF_DATA_LENGTH];
memset (&info, 0, sizeof info);
err = agent_scd_getattr ("EXTCAP", &info);
if (err)
{
log_error (_("error getting card info: %s\n"), gpg_strerror (err));
return;
}
if (!info.extcap.kdf)
{
log_error (_("This command is not supported by this card\n"));
goto leave;
}
if (!(err = gen_kdf_data (kdf_data))
&& !(err = agent_scd_setattr ("KDF", kdf_data, KDF_DATA_LENGTH, NULL)))
err = agent_scd_getattr ("KDF", &info);
if (err)
log_error (_("error for setup KDF: %s\n"), gpg_strerror (err));
leave:
agent_release_card_info (&info);
}
/* Data used by the command parser. This needs to be outside of the /* Data used by the command parser. This needs to be outside of the
function scope to allow readline based command completion. */ function scope to allow readline based command completion. */
@ -1896,7 +2009,7 @@ enum cmdids
cmdQUIT, cmdADMIN, cmdHELP, cmdLIST, cmdDEBUG, cmdVERIFY, cmdQUIT, cmdADMIN, cmdHELP, cmdLIST, cmdDEBUG, cmdVERIFY,
cmdNAME, cmdURL, cmdFETCH, cmdLOGIN, cmdLANG, cmdSEX, cmdCAFPR, cmdNAME, cmdURL, cmdFETCH, cmdLOGIN, cmdLANG, cmdSEX, cmdCAFPR,
cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT, cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT,
cmdREADCERT, cmdUNBLOCK, cmdFACTORYRESET, cmdREADCERT, cmdUNBLOCK, cmdFACTORYRESET, cmdKDFSETUP,
cmdINVCMD cmdINVCMD
}; };
@ -1930,6 +2043,7 @@ static struct
{ "verify" , cmdVERIFY, 0, N_("verify the PIN and list all data")}, { "verify" , cmdVERIFY, 0, N_("verify the PIN and list all data")},
{ "unblock" , cmdUNBLOCK,0, N_("unblock the PIN using a Reset Code") }, { "unblock" , cmdUNBLOCK,0, N_("unblock the PIN using a Reset Code") },
{ "factory-reset", cmdFACTORYRESET, 1, N_("destroy all keys and data")}, { "factory-reset", cmdFACTORYRESET, 1, N_("destroy all keys and data")},
{ "kdf-setup", cmdKDFSETUP, 1, N_("setup KDF for PIN authentication")},
/* Note, that we do not announce these command yet. */ /* Note, that we do not announce these command yet. */
{ "privatedo", cmdPRIVATEDO, 0, NULL }, { "privatedo", cmdPRIVATEDO, 0, NULL },
{ "readcert", cmdREADCERT, 0, NULL }, { "readcert", cmdREADCERT, 0, NULL },
@ -2213,6 +2327,10 @@ card_edit (ctrl_t ctrl, strlist_t commands)
factory_reset (); factory_reset ();
break; break;
case cmdKDFSETUP:
kdf_setup ();
break;
case cmdQUIT: case cmdQUIT:
goto leave; goto leave;

View File

@ -428,6 +428,7 @@ enum cmd_and_opt_values
oDisableSignerUID, oDisableSignerUID,
oSender, oSender,
oKeyOrigin, oKeyOrigin,
oRequestOrigin,
oNoop oNoop
}; };
@ -719,6 +720,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_s (oPassphraseFile, "passphrase-file", "@"), ARGPARSE_s_s (oPassphraseFile, "passphrase-file", "@"),
ARGPARSE_s_i (oPassphraseRepeat,"passphrase-repeat", "@"), ARGPARSE_s_i (oPassphraseRepeat,"passphrase-repeat", "@"),
ARGPARSE_s_s (oPinentryMode, "pinentry-mode", "@"), ARGPARSE_s_s (oPinentryMode, "pinentry-mode", "@"),
ARGPARSE_s_s (oRequestOrigin, "request-origin", "@"),
ARGPARSE_s_i (oCommandFD, "command-fd", "@"), ARGPARSE_s_i (oCommandFD, "command-fd", "@"),
ARGPARSE_s_s (oCommandFile, "command-file", "@"), ARGPARSE_s_s (oCommandFile, "command-file", "@"),
ARGPARSE_s_n (oQuickRandom, "debug-quick-random", "@"), ARGPARSE_s_n (oQuickRandom, "debug-quick-random", "@"),
@ -3158,6 +3160,12 @@ main (int argc, char **argv)
log_error (_("invalid pinentry mode '%s'\n"), pargs.r.ret_str); log_error (_("invalid pinentry mode '%s'\n"), pargs.r.ret_str);
break; break;
case oRequestOrigin:
opt.request_origin = parse_request_origin (pargs.r.ret_str);
if (opt.request_origin == -1)
log_error (_("invalid request origin '%s'\n"), pargs.r.ret_str);
break;
case oCommandFD: case oCommandFD:
opt.command_fd = translate_sys2libc_fd_int (pargs.r.ret_int, 0); opt.command_fd = translate_sys2libc_fd_int (pargs.r.ret_int, 0);
if (! gnupg_fd_valid (opt.command_fd)) if (! gnupg_fd_valid (opt.command_fd))

View File

@ -24,6 +24,10 @@
correct value and may be of advantage if we ever have to do correct value and may be of advantage if we ever have to do
special things. */ special things. */
#ifdef HAVE_W32_SYSTEM
# define WIN32_LEAN_AND_MEAN 1
#endif
#ifdef GPG_ERR_SOURCE_DEFAULT #ifdef GPG_ERR_SOURCE_DEFAULT
#error GPG_ERR_SOURCE_DEFAULT already defined #error GPG_ERR_SOURCE_DEFAULT already defined
#endif #endif

View File

@ -1134,8 +1134,10 @@ change_passphrase (ctrl_t ctrl, kbnode_t keyblock)
if (err) if (err)
goto leave; goto leave;
/* Note that when using --dry-run we don't change the
* passphrase but merely verify the current passphrase. */
desc = gpg_format_keydesc (ctrl, pk, FORMAT_KEYDESC_NORMAL, 1); desc = gpg_format_keydesc (ctrl, pk, FORMAT_KEYDESC_NORMAL, 1);
err = agent_passwd (ctrl, hexgrip, desc, 0, err = agent_passwd (ctrl, hexgrip, desc, !!opt.dry_run,
&cache_nonce, &passwd_nonce); &cache_nonce, &passwd_nonce);
xfree (desc); xfree (desc);

View File

@ -42,6 +42,7 @@
#include <time.h> #include <time.h>
#include <process.h> #include <process.h>
#ifdef HAVE_WINSOCK2_H #ifdef HAVE_WINSOCK2_H
# define WIN32_LEAN_AND_MEAN 1
# include <winsock2.h> # include <winsock2.h>
#endif #endif
#include <windows.h> #include <windows.h>

View File

@ -278,6 +278,7 @@ struct
int passphrase_repeat; int passphrase_repeat;
int pinentry_mode; int pinentry_mode;
int request_origin;
int unwrap_encryption; int unwrap_encryption;
int only_sign_text_ids; int only_sign_text_ids;

View File

@ -971,10 +971,10 @@ skip_packet (IOBUF inp, int pkttype, unsigned long pktlen, int partial)
} }
/* Read PKTLEN bytes form INP and return them in a newly allocated /* Read PKTLEN bytes from INP and return them in a newly allocated
buffer. In case of an error (including reading fewer than PKTLEN * buffer. In case of an error (including reading fewer than PKTLEN
bytes from INP before EOF is returned), NULL is returned and an * bytes from INP before EOF is returned), NULL is returned and an
error message is logged. */ * error message is logged. */
static void * static void *
read_rest (IOBUF inp, size_t pktlen) read_rest (IOBUF inp, size_t pktlen)
{ {
@ -1741,6 +1741,8 @@ enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype,
} }
if (buflen < n) if (buflen < n)
goto too_short; goto too_short;
if (!buflen)
goto no_type_byte;
type = *buffer; type = *buffer;
if (type & 0x80) if (type & 0x80)
{ {
@ -1815,6 +1817,13 @@ enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype,
if (start) if (start)
*start = -1; *start = -1;
return NULL; return NULL;
no_type_byte:
if (opt.verbose)
log_info ("type octet missing in subpacket\n");
if (start)
*start = -1;
return NULL;
} }

View File

@ -191,7 +191,7 @@ import_ownertrust (ctrl_t ctrl, const char *fname )
while (fprlen < MAX_FINGERPRINT_LEN) while (fprlen < MAX_FINGERPRINT_LEN)
fpr[fprlen++] = 0; fpr[fprlen++] = 0;
rc = tdbio_search_trust_byfpr (fpr, &rec); rc = tdbio_search_trust_byfpr (ctrl, fpr, &rec);
if( !rc ) { /* found: update */ if( !rc ) { /* found: update */
if (rec.r.trust.ownertrust != otrust) if (rec.r.trust.ownertrust != otrust)
{ {

View File

@ -105,16 +105,17 @@ struct cmp_xdir_struct
/* The name of the trustdb file. */ /* The name of the trustdb file. */
static char *db_name; static char *db_name;
/* The handle for locking the trustdb file and a flag to record /* The handle for locking the trustdb file and a counter to record how
whether a lock has been taken. */ * often this lock has been taken. That counter is required becuase
* dotlock does not implemen recursive locks. */
static dotlock_t lockhandle; static dotlock_t lockhandle;
static int is_locked; static unsigned int is_locked;
/* The file descriptor of the trustdb. */ /* The file descriptor of the trustdb. */
static int db_fd = -1; static int db_fd = -1;
/* A flag indicating that a transaction is active. */ /* A flag indicating that a transaction is active. */
static int in_transaction; /* static int in_transaction; Not yet used. */
@ -125,7 +126,7 @@ static void create_hashtable (ctrl_t ctrl, TRUSTREC *vr, int type);
/* /*
* Take a lock on the trustdb file name. I a lock file can't be * Take a lock on the trustdb file name. I a lock file can't be
* created the function terminates the process. Excvept for a * created the function terminates the process. Except for a
* different return code the function does nothing if the lock has * different return code the function does nothing if the lock has
* already been taken. * already been taken.
* *
@ -135,6 +136,8 @@ static void create_hashtable (ctrl_t ctrl, TRUSTREC *vr, int type);
static int static int
take_write_lock (void) take_write_lock (void)
{ {
int rc;
if (!lockhandle) if (!lockhandle)
lockhandle = dotlock_create (db_name, 0); lockhandle = dotlock_create (db_name, 0);
if (!lockhandle) if (!lockhandle)
@ -144,12 +147,16 @@ take_write_lock (void)
{ {
if (dotlock_take (lockhandle, -1) ) if (dotlock_take (lockhandle, -1) )
log_fatal ( _("can't lock '%s'\n"), db_name ); log_fatal ( _("can't lock '%s'\n"), db_name );
else rc = 0;
is_locked = 1;
return 0;
} }
else else
return 1; rc = 1;
if (opt.lock_once)
is_locked = 1;
else
is_locked++;
return rc;
} }
@ -160,10 +167,22 @@ take_write_lock (void)
static void static void
release_write_lock (void) release_write_lock (void)
{ {
if (!opt.lock_once) if (opt.lock_once)
if (!dotlock_release (lockhandle)) return; /* Don't care; here IS_LOCKED is fixed to 1. */
is_locked = 0;
if (!is_locked)
{
log_error ("Ooops, tdbio:release_write_lock with no lock held\n");
return;
}
if (--is_locked)
return;
if (dotlock_release (lockhandle))
log_error ("Oops, tdbio:release_write_locked failed\n");
} }
/************************************* /*************************************
************* record cache ********** ************* record cache **********
@ -329,6 +348,7 @@ put_record_into_cache (ulong recno, const char *data)
} }
/* No clean entries: We have to flush some dirty entries. */ /* No clean entries: We have to flush some dirty entries. */
#if 0 /* Transactions are not yet used. */
if (in_transaction) if (in_transaction)
{ {
/* But we can't do this while in a transaction. Thus we /* But we can't do this while in a transaction. Thus we
@ -352,6 +372,7 @@ put_record_into_cache (ulong recno, const char *data)
log_info (_("trustdb transaction too large\n")); log_info (_("trustdb transaction too large\n"));
return GPG_ERR_RESOURCE_LIMIT; return GPG_ERR_RESOURCE_LIMIT;
} }
#endif
if (dirty_count) if (dirty_count)
{ {
@ -418,8 +439,10 @@ tdbio_sync()
if( db_fd == -1 ) if( db_fd == -1 )
open_db(); open_db();
#if 0 /* Transactions are not yet used. */
if( in_transaction ) if( in_transaction )
log_bug("tdbio: syncing while in transaction\n"); log_bug("tdbio: syncing while in transaction\n");
#endif
if( !cache_is_dirty ) if( !cache_is_dirty )
return 0; return 0;
@ -560,7 +583,7 @@ tdbio_update_version_record (ctrl_t ctrl)
/* /*
* Create and write the trustdb version record. * Create and write the trustdb version record.
* * This is called with the writelock activ.
* Returns: 0 on success or an error code. * Returns: 0 on success or an error code.
*/ */
static int static int
@ -951,10 +974,12 @@ tdbio_write_nextcheck (ctrl_t ctrl, ulong stamp)
* Return: record number * Return: record number
*/ */
static ulong static ulong
get_trusthashrec(void) get_trusthashrec (ctrl_t ctrl)
{ {
static ulong trusthashtbl; /* Record number of the trust hashtable. */ static ulong trusthashtbl; /* Record number of the trust hashtable. */
(void)ctrl;
if (!trusthashtbl) if (!trusthashtbl)
{ {
TRUSTREC vr; TRUSTREC vr;
@ -965,6 +990,20 @@ get_trusthashrec(void)
log_fatal (_("%s: error reading version record: %s\n"), log_fatal (_("%s: error reading version record: %s\n"),
db_name, gpg_strerror (rc) ); db_name, gpg_strerror (rc) );
if (!vr.r.ver.trusthashtbl)
{
/* Oops: the trustdb is corrupt because the hashtable is
* always created along with the version record. However,
* if something went initially wrong it may happen that
* there is just the version record. We try to fix it here.
* If we can't do that we return 0 - this is the version
* record and thus the actual read will detect the mismatch
* and bail out. Note that create_hashtable updates VR. */
take_write_lock ();
if (lseek (db_fd, 0, SEEK_END) == TRUST_RECORD_LEN)
create_hashtable (ctrl, &vr, 0);
release_write_lock ();
}
trusthashtbl = vr.r.ver.trusthashtbl; trusthashtbl = vr.r.ver.trusthashtbl;
} }
@ -1269,6 +1308,13 @@ lookup_hashtable (ulong table, const byte *key, size_t keylen,
int msb; int msb;
int level = 0; int level = 0;
if (!table)
{
rc = gpg_error (GPG_ERR_INV_RECORD);
log_error("lookup_hashtable failed: %s\n", "request for record 0");
return rc;
}
hashrec = table; hashrec = table;
next_level: next_level:
msb = key[level]; msb = key[level];
@ -1358,7 +1404,7 @@ lookup_hashtable (ulong table, const byte *key, size_t keylen,
static int static int
update_trusthashtbl (ctrl_t ctrl, TRUSTREC *tr) update_trusthashtbl (ctrl_t ctrl, TRUSTREC *tr)
{ {
return upd_hashtable (ctrl, get_trusthashrec (), return upd_hashtable (ctrl, get_trusthashrec (ctrl),
tr->r.trust.fingerprint, 20, tr->recnum); tr->r.trust.fingerprint, 20, tr->recnum);
} }
@ -1441,7 +1487,7 @@ tdbio_dump_record (TRUSTREC *rec, estream_t fp)
* EXPECTED is not 0 reading any other record type will return an * EXPECTED is not 0 reading any other record type will return an
* error. * error.
* *
* Return: 0 on success, -1 on EOF, or an error code. * Return: 0 on success or an error code.
*/ */
int int
tdbio_read_record (ulong recnum, TRUSTREC *rec, int expected) tdbio_read_record (ulong recnum, TRUSTREC *rec, int expected)
@ -1466,7 +1512,7 @@ tdbio_read_record (ulong recnum, TRUSTREC *rec, int expected)
n = read (db_fd, readbuf, TRUST_RECORD_LEN); n = read (db_fd, readbuf, TRUST_RECORD_LEN);
if (!n) if (!n)
{ {
return -1; /* eof */ return gpg_error (GPG_ERR_EOF);
} }
else if (n != TRUST_RECORD_LEN) else if (n != TRUST_RECORD_LEN)
{ {
@ -1700,7 +1746,7 @@ tdbio_delete_record (ctrl_t ctrl, ulong recnum)
; ;
else if (rec.rectype == RECTYPE_TRUST) else if (rec.rectype == RECTYPE_TRUST)
{ {
rc = drop_from_hashtable (ctrl, get_trusthashrec(), rc = drop_from_hashtable (ctrl, get_trusthashrec (ctrl),
rec.r.trust.fingerprint, 20, rec.recnum); rec.r.trust.fingerprint, 20, rec.recnum);
} }
@ -1746,20 +1792,14 @@ tdbio_new_recnum (ctrl_t ctrl)
recnum = vr.r.ver.firstfree; recnum = vr.r.ver.firstfree;
rc = tdbio_read_record (recnum, &rec, RECTYPE_FREE); rc = tdbio_read_record (recnum, &rec, RECTYPE_FREE);
if (rc) if (rc)
{ log_fatal (_("%s: error reading free record: %s\n"),
log_error (_("%s: error reading free record: %s\n"),
db_name, gpg_strerror (rc)); db_name, gpg_strerror (rc));
return rc;
}
/* Update dir record. */ /* Update dir record. */
vr.r.ver.firstfree = rec.r.free.next; vr.r.ver.firstfree = rec.r.free.next;
rc = tdbio_write_record (ctrl, &vr); rc = tdbio_write_record (ctrl, &vr);
if (rc) if (rc)
{ log_fatal (_("%s: error writing dir record: %s\n"),
log_error (_("%s: error writing dir record: %s\n"),
db_name, gpg_strerror (rc)); db_name, gpg_strerror (rc));
return rc;
}
/* Zero out the new record. */ /* Zero out the new record. */
memset (&rec, 0, sizeof rec); memset (&rec, 0, sizeof rec);
rec.rectype = 0; /* Mark as unused record (actually already done rec.rectype = 0; /* Mark as unused record (actually already done
@ -1776,7 +1816,7 @@ tdbio_new_recnum (ctrl_t ctrl)
if (offset == (off_t)(-1)) if (offset == (off_t)(-1))
log_fatal ("trustdb: lseek to end failed: %s\n", strerror (errno)); log_fatal ("trustdb: lseek to end failed: %s\n", strerror (errno));
recnum = offset / TRUST_RECORD_LEN; recnum = offset / TRUST_RECORD_LEN;
log_assert (recnum); /* this is will never be the first record */ log_assert (recnum); /* This will never be the first record */
/* We must write a record, so that the next call to this /* We must write a record, so that the next call to this
* function returns another recnum. */ * function returns another recnum. */
memset (&rec, 0, sizeof rec); memset (&rec, 0, sizeof rec);
@ -1798,7 +1838,7 @@ tdbio_new_recnum (ctrl_t ctrl)
{ {
rc = gpg_error_from_syserror (); rc = gpg_error_from_syserror ();
log_error (_("trustdb rec %lu: write failed (n=%d): %s\n"), log_error (_("trustdb rec %lu: write failed (n=%d): %s\n"),
recnum, n, strerror (errno)); recnum, n, gpg_strerror (rc));
} }
} }
@ -1828,12 +1868,12 @@ cmp_trec_fpr ( const void *fpr, const TRUSTREC *rec )
* Return: 0 if found, GPG_ERR_NOT_FOUND, or another error code. * Return: 0 if found, GPG_ERR_NOT_FOUND, or another error code.
*/ */
gpg_error_t gpg_error_t
tdbio_search_trust_byfpr (const byte *fingerprint, TRUSTREC *rec) tdbio_search_trust_byfpr (ctrl_t ctrl, const byte *fingerprint, TRUSTREC *rec)
{ {
int rc; int rc;
/* Locate the trust record using the hash table */ /* Locate the trust record using the hash table */
rc = lookup_hashtable (get_trusthashrec(), fingerprint, 20, rc = lookup_hashtable (get_trusthashrec (ctrl), fingerprint, 20,
cmp_trec_fpr, fingerprint, rec ); cmp_trec_fpr, fingerprint, rec );
return rc; return rc;
} }
@ -1846,7 +1886,7 @@ tdbio_search_trust_byfpr (const byte *fingerprint, TRUSTREC *rec)
* Return: 0 if found, GPG_ERR_NOT_FOUND, or another error code. * Return: 0 if found, GPG_ERR_NOT_FOUND, or another error code.
*/ */
gpg_error_t gpg_error_t
tdbio_search_trust_bypk (PKT_public_key *pk, TRUSTREC *rec) tdbio_search_trust_bypk (ctrl_t ctrl, PKT_public_key *pk, TRUSTREC *rec)
{ {
byte fingerprint[MAX_FINGERPRINT_LEN]; byte fingerprint[MAX_FINGERPRINT_LEN];
size_t fingerlen; size_t fingerlen;
@ -1854,7 +1894,7 @@ tdbio_search_trust_bypk (PKT_public_key *pk, TRUSTREC *rec)
fingerprint_from_pk( pk, fingerprint, &fingerlen ); fingerprint_from_pk( pk, fingerprint, &fingerlen );
for (; fingerlen < 20; fingerlen++) for (; fingerlen < 20; fingerlen++)
fingerprint[fingerlen] = 0; fingerprint[fingerlen] = 0;
return tdbio_search_trust_byfpr (fingerprint, rec); return tdbio_search_trust_byfpr (ctrl, fingerprint, rec);
} }

View File

@ -110,8 +110,10 @@ int tdbio_end_transaction(void);
int tdbio_cancel_transaction(void); int tdbio_cancel_transaction(void);
int tdbio_delete_record (ctrl_t ctrl, ulong recnum); int tdbio_delete_record (ctrl_t ctrl, ulong recnum);
ulong tdbio_new_recnum (ctrl_t ctrl); ulong tdbio_new_recnum (ctrl_t ctrl);
gpg_error_t tdbio_search_trust_byfpr (const byte *fingerprint, TRUSTREC *rec); gpg_error_t tdbio_search_trust_byfpr (ctrl_t ctrl, const byte *fingerprint,
gpg_error_t tdbio_search_trust_bypk (PKT_public_key *pk, TRUSTREC *rec); TRUSTREC *rec);
gpg_error_t tdbio_search_trust_bypk (ctrl_t ctrl, PKT_public_key *pk,
TRUSTREC *rec);
void tdbio_how_to_fix (void); void tdbio_how_to_fix (void);
void tdbio_invalid(void); void tdbio_invalid(void);

View File

@ -649,7 +649,7 @@ read_trust_record (ctrl_t ctrl, PKT_public_key *pk, TRUSTREC *rec)
int rc; int rc;
init_trustdb (ctrl, 0); init_trustdb (ctrl, 0);
rc = tdbio_search_trust_bypk (pk, rec); rc = tdbio_search_trust_bypk (ctrl, pk, rec);
if (rc) if (rc)
{ {
if (gpg_err_code (rc) != GPG_ERR_NOT_FOUND) if (gpg_err_code (rc) != GPG_ERR_NOT_FOUND)

View File

@ -119,6 +119,7 @@ struct reader_table_s {
pcsc_dword_t modify_ioctl; pcsc_dword_t modify_ioctl;
int pinmin; int pinmin;
int pinmax; int pinmax;
pcsc_dword_t current_state;
} pcsc; } pcsc;
#ifdef USE_G10CODE_RAPDU #ifdef USE_G10CODE_RAPDU
struct { struct {
@ -228,6 +229,7 @@ static npth_mutex_t reader_table_lock;
#define PCSC_E_READER_UNAVAILABLE 0x80100017 #define PCSC_E_READER_UNAVAILABLE 0x80100017
#define PCSC_E_NO_SERVICE 0x8010001D #define PCSC_E_NO_SERVICE 0x8010001D
#define PCSC_E_SERVICE_STOPPED 0x8010001E #define PCSC_E_SERVICE_STOPPED 0x8010001E
#define PCSC_W_RESET_CARD 0x80100068
#define PCSC_W_REMOVED_CARD 0x80100069 #define PCSC_W_REMOVED_CARD 0x80100069
/* Fix pcsc-lite ABI incompatibility. */ /* Fix pcsc-lite ABI incompatibility. */
@ -453,6 +455,7 @@ new_reader_slot (void)
reader_table[reader].pcsc.modify_ioctl = 0; reader_table[reader].pcsc.modify_ioctl = 0;
reader_table[reader].pcsc.pinmin = -1; reader_table[reader].pcsc.pinmin = -1;
reader_table[reader].pcsc.pinmax = -1; reader_table[reader].pcsc.pinmax = -1;
reader_table[reader].pcsc.current_state = PCSC_STATE_UNAWARE;
return reader; return reader;
} }
@ -653,12 +656,12 @@ pcsc_get_status (int slot, unsigned int *status, int on_wire)
(void)on_wire; (void)on_wire;
memset (rdrstates, 0, sizeof *rdrstates); memset (rdrstates, 0, sizeof *rdrstates);
rdrstates[0].reader = reader_table[slot].rdrname; rdrstates[0].reader = reader_table[slot].rdrname;
rdrstates[0].current_state = PCSC_STATE_UNAWARE; rdrstates[0].current_state = reader_table[slot].pcsc.current_state;
err = pcsc_get_status_change (reader_table[slot].pcsc.context, err = pcsc_get_status_change (reader_table[slot].pcsc.context,
0, 0,
rdrstates, 1); rdrstates, 1);
if (err == PCSC_E_TIMEOUT) if (err == PCSC_E_TIMEOUT)
err = 0; /* Timeout is no error error here. */ err = 0; /* Timeout is no error here. */
if (err) if (err)
{ {
log_error ("pcsc_get_status_change failed: %s (0x%lx)\n", log_error ("pcsc_get_status_change failed: %s (0x%lx)\n",
@ -666,24 +669,29 @@ pcsc_get_status (int slot, unsigned int *status, int on_wire)
return pcsc_error_to_sw (err); return pcsc_error_to_sw (err);
} }
/* log_debug */ if ((rdrstates[0].event_state & PCSC_STATE_CHANGED))
/* ("pcsc_get_status_change: %s%s%s%s%s%s%s%s%s%s\n", */ reader_table[slot].pcsc.current_state =
/* (rdrstates[0].event_state & PCSC_STATE_IGNORE)? " ignore":"", */ (rdrstates[0].event_state & ~PCSC_STATE_CHANGED);
/* (rdrstates[0].event_state & PCSC_STATE_CHANGED)? " changed":"", */
/* (rdrstates[0].event_state & PCSC_STATE_UNKNOWN)? " unknown":"", */ if (DBG_CARD_IO)
/* (rdrstates[0].event_state & PCSC_STATE_UNAVAILABLE)?" unavail":"", */ log_debug
/* (rdrstates[0].event_state & PCSC_STATE_EMPTY)? " empty":"", */ ("pcsc_get_status_change: %s%s%s%s%s%s%s%s%s%s\n",
/* (rdrstates[0].event_state & PCSC_STATE_PRESENT)? " present":"", */ (rdrstates[0].event_state & PCSC_STATE_IGNORE)? " ignore":"",
/* (rdrstates[0].event_state & PCSC_STATE_ATRMATCH)? " atr":"", */ (rdrstates[0].event_state & PCSC_STATE_CHANGED)? " changed":"",
/* (rdrstates[0].event_state & PCSC_STATE_EXCLUSIVE)? " excl":"", */ (rdrstates[0].event_state & PCSC_STATE_UNKNOWN)? " unknown":"",
/* (rdrstates[0].event_state & PCSC_STATE_INUSE)? " unuse":"", */ (rdrstates[0].event_state & PCSC_STATE_UNAVAILABLE)?" unavail":"",
/* (rdrstates[0].event_state & PCSC_STATE_MUTE)? " mute":"" ); */ (rdrstates[0].event_state & PCSC_STATE_EMPTY)? " empty":"",
(rdrstates[0].event_state & PCSC_STATE_PRESENT)? " present":"",
(rdrstates[0].event_state & PCSC_STATE_ATRMATCH)? " atr":"",
(rdrstates[0].event_state & PCSC_STATE_EXCLUSIVE)? " excl":"",
(rdrstates[0].event_state & PCSC_STATE_INUSE)? " inuse":"",
(rdrstates[0].event_state & PCSC_STATE_MUTE)? " mute":"" );
*status = 0; *status = 0;
if ( (rdrstates[0].event_state & PCSC_STATE_PRESENT) ) if ( (reader_table[slot].pcsc.current_state & PCSC_STATE_PRESENT) )
{ {
*status |= APDU_CARD_PRESENT; *status |= APDU_CARD_PRESENT;
if ( !(rdrstates[0].event_state & PCSC_STATE_MUTE) ) if ( !(reader_table[slot].pcsc.current_state & PCSC_STATE_MUTE) )
*status |= APDU_CARD_ACTIVE; *status |= APDU_CARD_ACTIVE;
} }
#ifndef HAVE_W32_SYSTEM #ifndef HAVE_W32_SYSTEM
@ -692,7 +700,7 @@ pcsc_get_status (int slot, unsigned int *status, int on_wire)
mode. */ mode. */
if ( (*status & (APDU_CARD_PRESENT|APDU_CARD_ACTIVE)) if ( (*status & (APDU_CARD_PRESENT|APDU_CARD_ACTIVE))
== (APDU_CARD_PRESENT|APDU_CARD_ACTIVE) == (APDU_CARD_PRESENT|APDU_CARD_ACTIVE)
&& !(rdrstates[0].event_state & PCSC_STATE_INUSE) ) && !(reader_table[slot].pcsc.current_state & PCSC_STATE_INUSE) )
*status |= APDU_CARD_USABLE; *status |= APDU_CARD_USABLE;
#else #else
/* Some winscard drivers may set EXCLUSIVE and INUSE at the same /* Some winscard drivers may set EXCLUSIVE and INUSE at the same
@ -702,6 +710,10 @@ pcsc_get_status (int slot, unsigned int *status, int on_wire)
*status |= APDU_CARD_USABLE; *status |= APDU_CARD_USABLE;
#endif #endif
if (!on_wire && (rdrstates[0].event_state & PCSC_STATE_CHANGED))
/* Event like sleep/resume occurs, which requires RESET. */
return SW_HOST_NO_READER;
else
return 0; return 0;
} }
@ -741,6 +753,14 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
log_error ("pcsc_transmit failed: %s (0x%lx)\n", log_error ("pcsc_transmit failed: %s (0x%lx)\n",
pcsc_error_string (err), err); pcsc_error_string (err), err);
/* Handle fatal errors which require shutdown of reader. */
if (err == PCSC_E_NOT_TRANSACTED || err == PCSC_W_RESET_CARD
|| err == PCSC_W_REMOVED_CARD)
{
reader_table[slot].pcsc.current_state = PCSC_STATE_UNAWARE;
scd_kick_the_loop ();
}
return pcsc_error_to_sw (err); return pcsc_error_to_sw (err);
} }

View File

@ -1018,7 +1018,7 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
snprintf (tmp, sizeof tmp, snprintf (tmp, sizeof tmp,
"gc=%d ki=%d fc=%d pd=%d mcl3=%u aac=%d " "gc=%d ki=%d fc=%d pd=%d mcl3=%u aac=%d "
"sm=%d si=%u dec=%d bt=%d", "sm=%d si=%u dec=%d bt=%d kdf=%d",
app->app_local->extcap.get_challenge, app->app_local->extcap.get_challenge,
app->app_local->extcap.key_import, app->app_local->extcap.key_import,
app->app_local->extcap.change_force_chv, app->app_local->extcap.change_force_chv,
@ -1032,7 +1032,8 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
: 0), : 0),
app->app_local->status_indicator, app->app_local->status_indicator,
app->app_local->extcap.has_decrypt, app->app_local->extcap.has_decrypt,
app->app_local->extcap.has_button); app->app_local->extcap.has_button,
app->app_local->extcap.kdf_do);
send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0); send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0);
return 0; return 0;
} }

View File

@ -1467,7 +1467,8 @@ intr_cb (struct libusb_transfer *transfer)
DEBUGOUT_1 ("CCID: interrupt callback %d\n", transfer->status); DEBUGOUT_1 ("CCID: interrupt callback %d\n", transfer->status);
if (transfer->status == LIBUSB_TRANSFER_TIMED_OUT) if (transfer->status == LIBUSB_TRANSFER_TIMED_OUT
|| transfer->status == LIBUSB_TRANSFER_NO_DEVICE)
{ {
int err; int err;

View File

@ -393,7 +393,21 @@ cleanup (void)
} }
} }
static void
setup_signal_mask (void)
{
#ifndef HAVE_W32_SYSTEM
npth_sigev_init ();
npth_sigev_add (SIGHUP);
npth_sigev_add (SIGUSR1);
npth_sigev_add (SIGUSR2);
npth_sigev_add (SIGINT);
npth_sigev_add (SIGCONT);
npth_sigev_add (SIGTERM);
npth_sigev_fini ();
main_thread_pid = getpid ();
#endif
}
int int
main (int argc, char **argv ) main (int argc, char **argv )
@ -744,6 +758,7 @@ main (int argc, char **argv )
#endif #endif
npth_init (); npth_init ();
setup_signal_mask ();
gpgrt_set_syscall_clamp (npth_unprotect, npth_protect); gpgrt_set_syscall_clamp (npth_unprotect, npth_protect);
/* If --debug-allow-core-dump has been given we also need to /* If --debug-allow-core-dump has been given we also need to
@ -884,6 +899,7 @@ main (int argc, char **argv )
/* This is the child. */ /* This is the child. */
npth_init (); npth_init ();
setup_signal_mask ();
gpgrt_set_syscall_clamp (npth_unprotect, npth_protect); gpgrt_set_syscall_clamp (npth_unprotect, npth_protect);
/* Detach from tty and put process into a new session. */ /* Detach from tty and put process into a new session. */
@ -1206,18 +1222,16 @@ start_connection_thread (void *arg)
void void
scd_kick_the_loop (void) scd_kick_the_loop (void)
{ {
int ret;
/* Kick the select loop. */ /* Kick the select loop. */
#ifdef HAVE_W32_SYSTEM #ifdef HAVE_W32_SYSTEM
ret = SetEvent (the_event); int ret = SetEvent (the_event);
if (ret == 0) if (ret == 0)
log_error ("SetEvent for scd_kick_the_loop failed: %s\n", log_error ("SetEvent for scd_kick_the_loop failed: %s\n",
w32_strerror (-1)); w32_strerror (-1));
#elif defined(HAVE_PSELECT_NO_EINTR) #elif defined(HAVE_PSELECT_NO_EINTR)
write (notify_fd, "", 1); write (notify_fd, "", 1);
#else #else
ret = kill (main_thread_pid, SIGCONT); int ret = kill (main_thread_pid, SIGCONT);
if (ret < 0) if (ret < 0)
log_error ("SetEvent for scd_kick_the_loop failed: %s\n", log_error ("SetEvent for scd_kick_the_loop failed: %s\n",
gpg_strerror (gpg_error_from_syserror ())); gpg_strerror (gpg_error_from_syserror ()));
@ -1292,16 +1306,6 @@ handle_connections (int listen_fd)
events[0] = the_event = h2; events[0] = the_event = h2;
} }
} }
#else
npth_sigev_init ();
npth_sigev_add (SIGHUP);
npth_sigev_add (SIGUSR1);
npth_sigev_add (SIGUSR2);
npth_sigev_add (SIGINT);
npth_sigev_add (SIGCONT);
npth_sigev_add (SIGTERM);
npth_sigev_fini ();
main_thread_pid = getpid ();
#endif #endif
FD_ZERO (&fdset); FD_ZERO (&fdset);
@ -1348,6 +1352,8 @@ handle_connections (int listen_fd)
FD_SET (pipe_fd[0], &read_fdset); FD_SET (pipe_fd[0], &read_fdset);
if (max_fd < pipe_fd[0]) if (max_fd < pipe_fd[0])
max_fd = pipe_fd[0]; max_fd = pipe_fd[0];
#else
(void)max_fd;
#endif #endif
#ifndef HAVE_W32_SYSTEM #ifndef HAVE_W32_SYSTEM

View File

@ -179,6 +179,20 @@ start_agent (ctrl_t ctrl)
gpg_strerror (rc)); 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 /* In DE_VS mode under Windows we require that the JENT RNG
* is active. */ * is active. */
#ifdef HAVE_W32_SYSTEM #ifdef HAVE_W32_SYSTEM

View File

@ -125,6 +125,7 @@ enum cmd_and_opt_values {
oPassphraseFD, oPassphraseFD,
oPinentryMode, oPinentryMode,
oRequestOrigin,
oAssumeArmor, oAssumeArmor,
oAssumeBase64, oAssumeBase64,
@ -255,6 +256,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_i (oPassphraseFD, "passphrase-fd", "@"), ARGPARSE_s_i (oPassphraseFD, "passphrase-fd", "@"),
ARGPARSE_s_s (oPinentryMode, "pinentry-mode", "@"), ARGPARSE_s_s (oPinentryMode, "pinentry-mode", "@"),
ARGPARSE_s_s (oRequestOrigin, "request-origin", "@"),
ARGPARSE_s_n (oAssumeArmor, "assume-armor", ARGPARSE_s_n (oAssumeArmor, "assume-armor",
N_("assume input is in PEM format")), N_("assume input is in PEM format")),
@ -1162,6 +1164,12 @@ main ( int argc, char **argv)
log_error (_("invalid pinentry mode '%s'\n"), pargs.r.ret_str); log_error (_("invalid pinentry mode '%s'\n"), pargs.r.ret_str);
break; break;
case oRequestOrigin:
opt.request_origin = parse_request_origin (pargs.r.ret_str);
if (opt.request_origin == -1)
log_error (_("invalid request origin '%s'\n"), pargs.r.ret_str);
break;
/* Input encoding selection. */ /* Input encoding selection. */
case oAssumeArmor: case oAssumeArmor:
ctrl.autodetect_encoding = 0; ctrl.autodetect_encoding = 0;

View File

@ -88,6 +88,7 @@ struct
int with_key_screening; /* Option --with-key-screening active. */ int with_key_screening; /* Option --with-key-screening active. */
int pinentry_mode; int pinentry_mode;
int request_origin;
int armor; /* force base64 armoring (see also ctrl.with_base64) */ int armor; /* force base64 armoring (see also ctrl.with_base64) */
int no_armor; /* don't try to figure out whether data is base64 armored*/ int no_armor; /* don't try to figure out whether data is base64 armored*/

View File

@ -32,6 +32,7 @@
#include "../common/sysutils.h" #include "../common/sysutils.h"
#include "../common/server-help.h" #include "../common/server-help.h"
#include "../common/asshelp.h" #include "../common/asshelp.h"
#include "../common/shareddefs.h"
#define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t)) #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
@ -289,6 +290,17 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
ctrl->offline = i; ctrl->offline = i;
} }
} }
else if (!strcmp (key, "request-origin"))
{
if (!opt.request_origin)
{
int i = parse_request_origin (value);
if (i == -1)
err = gpg_error (GPG_ERR_INV_VALUE);
else
opt.request_origin = i;
}
}
else else
err = gpg_error (GPG_ERR_UNKNOWN_OPTION); err = gpg_error (GPG_ERR_UNKNOWN_OPTION);