2003-01-09 14:29:36 +01:00
|
|
|
/* cache.c - keep a cache of passphrases
|
2010-09-01 11:48:35 +02:00
|
|
|
* Copyright (C) 2002, 2010 Free Software Foundation, Inc.
|
2003-01-09 14:29:36 +01:00
|
|
|
*
|
|
|
|
* This file is part of GnuPG.
|
|
|
|
*
|
|
|
|
* GnuPG is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
2007-07-04 21:49:40 +02:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2003-01-09 14:29:36 +01:00
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* GnuPG is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2016-11-05 12:02:19 +01:00
|
|
|
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
2003-01-09 14:29:36 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <time.h>
|
Port to npth.
* configure.ac: Don't check for PTH but for NPTH.
(AH_BOTTOM): Remove PTH_SYSCALL_SOFT.
(have_pth): Rename to ...
(have_npth): ... this.
(USE_GNU_NPTH): Rename to ...
(USE_GNU_PTH): ... this.
* m4/npth.m4: New file.
* agent/Makefile.am, agent/cache.c, agent/call-pinentry.c,
agent/call-scd.c, agent/findkey.c, agent/gpg-agent.c,
agent/trustlist.c, common/Makefile.am, common/estream.c,
common/exechelp-posix.c, common/exechelp-w32.c,
common/exechelp-w32ce.c, common/http.c, common/init.c,
common/sysutils.c, dirmngr/Makefile.am, dirmngr/crlfetch.c,
dirmngr/dirmngr.c, dirmngr/dirmngr_ldap.c, dirmngr/ldap-wrapper-ce.c,
dirmngr/ldap-wrapper.c, dirmngr/ldap.c, g13/Makefile.am,
g13/call-gpg.c, g13/g13.c, g13/runner.c, scd/Makefile.am,
scd/apdu.c, scd/app.c, scd/ccid-driver.c, scd/command.c,
scd/scdaemon.c, tools/Makefile.am: Port to npth.
2012-01-03 22:12:37 +01:00
|
|
|
#include <npth.h>
|
2003-01-09 14:29:36 +01:00
|
|
|
|
|
|
|
#include "agent.h"
|
|
|
|
|
2018-07-02 21:24:15 +02:00
|
|
|
/* The default TTL for DATA items. This has no configure
|
|
|
|
* option because it is expected that clients provide a TTL. */
|
|
|
|
#define DEF_CACHE_TTL_DATA (10 * 60) /* 10 minutes. */
|
|
|
|
|
2010-09-02 12:46:23 +02:00
|
|
|
/* The size of the encryption key in bytes. */
|
|
|
|
#define ENCRYPTION_KEYSIZE (128/8)
|
|
|
|
|
2017-04-07 01:39:26 +02:00
|
|
|
/* A mutex used to serialize access to the cache. */
|
|
|
|
static npth_mutex_t cache_lock;
|
2010-09-02 12:46:23 +02:00
|
|
|
/* The encryption context. This is the only place where the
|
2010-09-13 12:17:04 +02:00
|
|
|
encryption key for all cached entries is available. It would be nice
|
2010-09-02 12:46:23 +02:00
|
|
|
to keep this (or just the key) in some hardware device, for example
|
|
|
|
a TPM. Libgcrypt could be extended to provide such a service.
|
|
|
|
With the current scheme it is easy to retrieve the cached entries
|
|
|
|
if access to Libgcrypt's memory is available. The encryption
|
|
|
|
merely avoids grepping for clear texts in the memory. Nevertheless
|
|
|
|
the encryption provides the necessary infrastructure to make it
|
|
|
|
more secure. */
|
|
|
|
static gcry_cipher_hd_t encryption_handle;
|
|
|
|
|
|
|
|
|
2003-01-09 14:29:36 +01:00
|
|
|
struct secret_data_s {
|
2010-09-02 12:46:23 +02:00
|
|
|
int totallen; /* This includes the padding and space for AESWRAP. */
|
|
|
|
char data[1]; /* A string. */
|
2003-01-09 14:29:36 +01:00
|
|
|
};
|
|
|
|
|
2023-08-31 07:49:38 +02:00
|
|
|
/* The type of cache object. */
|
2003-01-09 14:29:36 +01:00
|
|
|
typedef struct cache_item_s *ITEM;
|
2023-08-31 07:49:38 +02:00
|
|
|
|
|
|
|
/* The timer entry in a linked list. */
|
|
|
|
struct timer_s {
|
|
|
|
ITEM next;
|
|
|
|
int tv_sec;
|
|
|
|
int reason;
|
|
|
|
};
|
|
|
|
#define CACHE_EXPIRE_UNUSED 0
|
|
|
|
#define CACHE_EXPIRE_LAST_ACCESS 1
|
|
|
|
#define CACHE_EXPIRE_CREATION 2
|
|
|
|
|
|
|
|
/* The cache object. */
|
2003-01-09 14:29:36 +01:00
|
|
|
struct cache_item_s {
|
|
|
|
ITEM next;
|
|
|
|
time_t created;
|
2018-07-02 21:24:15 +02:00
|
|
|
time_t accessed; /* Not updated for CACHE_MODE_DATA */
|
2005-01-04 09:33:20 +01:00
|
|
|
int ttl; /* max. lifetime given in seconds, -1 one means infinite */
|
2003-01-09 14:29:36 +01:00
|
|
|
struct secret_data_s *pw;
|
2005-06-07 21:09:18 +02:00
|
|
|
cache_mode_t cache_mode;
|
2018-03-27 08:40:58 +02:00
|
|
|
int restricted; /* The value of ctrl->restricted is part of the key. */
|
2023-08-31 07:49:38 +02:00
|
|
|
struct timer_s t;
|
2003-01-09 14:29:36 +01:00
|
|
|
char key[1];
|
|
|
|
};
|
|
|
|
|
2010-09-02 12:46:23 +02:00
|
|
|
/* The cache himself. */
|
2003-01-09 14:29:36 +01:00
|
|
|
static ITEM thecache;
|
|
|
|
|
2023-08-31 07:49:38 +02:00
|
|
|
/* The timer list of expiration, in active. */
|
|
|
|
static ITEM the_timer_list;
|
|
|
|
/* Newly created entries, to be inserted into the timer list. */
|
|
|
|
static ITEM the_timer_list_new;
|
|
|
|
|
2014-09-17 15:12:08 +02:00
|
|
|
/* NULL or the last cache key stored by agent_store_cache_hit. */
|
|
|
|
static char *last_stored_cache_key;
|
|
|
|
|
2003-01-09 14:29:36 +01:00
|
|
|
|
2010-09-02 12:46:23 +02:00
|
|
|
/* This function must be called once to initialize this module. It
|
|
|
|
has to be done before a second thread is spawned. */
|
|
|
|
void
|
|
|
|
initialize_module_cache (void)
|
|
|
|
{
|
Port to npth.
* configure.ac: Don't check for PTH but for NPTH.
(AH_BOTTOM): Remove PTH_SYSCALL_SOFT.
(have_pth): Rename to ...
(have_npth): ... this.
(USE_GNU_NPTH): Rename to ...
(USE_GNU_PTH): ... this.
* m4/npth.m4: New file.
* agent/Makefile.am, agent/cache.c, agent/call-pinentry.c,
agent/call-scd.c, agent/findkey.c, agent/gpg-agent.c,
agent/trustlist.c, common/Makefile.am, common/estream.c,
common/exechelp-posix.c, common/exechelp-w32.c,
common/exechelp-w32ce.c, common/http.c, common/init.c,
common/sysutils.c, dirmngr/Makefile.am, dirmngr/crlfetch.c,
dirmngr/dirmngr.c, dirmngr/dirmngr_ldap.c, dirmngr/ldap-wrapper-ce.c,
dirmngr/ldap-wrapper.c, dirmngr/ldap.c, g13/Makefile.am,
g13/call-gpg.c, g13/g13.c, g13/runner.c, scd/Makefile.am,
scd/apdu.c, scd/app.c, scd/ccid-driver.c, scd/command.c,
scd/scdaemon.c, tools/Makefile.am: Port to npth.
2012-01-03 22:12:37 +01:00
|
|
|
int err;
|
|
|
|
|
2017-04-07 01:39:26 +02:00
|
|
|
err = npth_mutex_init (&cache_lock, NULL);
|
Port to npth.
* configure.ac: Don't check for PTH but for NPTH.
(AH_BOTTOM): Remove PTH_SYSCALL_SOFT.
(have_pth): Rename to ...
(have_npth): ... this.
(USE_GNU_NPTH): Rename to ...
(USE_GNU_PTH): ... this.
* m4/npth.m4: New file.
* agent/Makefile.am, agent/cache.c, agent/call-pinentry.c,
agent/call-scd.c, agent/findkey.c, agent/gpg-agent.c,
agent/trustlist.c, common/Makefile.am, common/estream.c,
common/exechelp-posix.c, common/exechelp-w32.c,
common/exechelp-w32ce.c, common/http.c, common/init.c,
common/sysutils.c, dirmngr/Makefile.am, dirmngr/crlfetch.c,
dirmngr/dirmngr.c, dirmngr/dirmngr_ldap.c, dirmngr/ldap-wrapper-ce.c,
dirmngr/ldap-wrapper.c, dirmngr/ldap.c, g13/Makefile.am,
g13/call-gpg.c, g13/g13.c, g13/runner.c, scd/Makefile.am,
scd/apdu.c, scd/app.c, scd/ccid-driver.c, scd/command.c,
scd/scdaemon.c, tools/Makefile.am: Port to npth.
2012-01-03 22:12:37 +01:00
|
|
|
|
|
|
|
if (err)
|
|
|
|
log_fatal ("error initializing cache module: %s\n", strerror (err));
|
2010-11-29 07:49:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
deinitialize_module_cache (void)
|
|
|
|
{
|
|
|
|
gcry_cipher_close (encryption_handle);
|
|
|
|
encryption_handle = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* We do the encryption init on the fly. We can't do it in the module
|
|
|
|
init code because that is run before we listen for connections and
|
|
|
|
in case we are started on demand by gpg etc. it will only wait for
|
|
|
|
a few seconds to decide whether the agent may now accept
|
|
|
|
connections. Thus we should get into listen state as soon as
|
|
|
|
possible. */
|
|
|
|
static gpg_error_t
|
|
|
|
init_encryption (void)
|
|
|
|
{
|
2010-09-02 12:46:23 +02:00
|
|
|
gpg_error_t err;
|
|
|
|
void *key;
|
|
|
|
|
2010-11-29 07:49:44 +01:00
|
|
|
if (encryption_handle)
|
|
|
|
return 0; /* Shortcut - Already initialized. */
|
|
|
|
|
|
|
|
err = gcry_cipher_open (&encryption_handle, GCRY_CIPHER_AES128,
|
|
|
|
GCRY_CIPHER_MODE_AESWRAP, GCRY_CIPHER_SECURE);
|
2010-09-02 12:46:23 +02:00
|
|
|
if (!err)
|
|
|
|
{
|
|
|
|
key = gcry_random_bytes (ENCRYPTION_KEYSIZE, GCRY_STRONG_RANDOM);
|
|
|
|
if (!key)
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
else
|
|
|
|
{
|
|
|
|
err = gcry_cipher_setkey (encryption_handle, key, ENCRYPTION_KEYSIZE);
|
|
|
|
xfree (key);
|
|
|
|
}
|
2010-11-29 07:49:44 +01:00
|
|
|
if (err)
|
|
|
|
{
|
|
|
|
gcry_cipher_close (encryption_handle);
|
|
|
|
encryption_handle = NULL;
|
|
|
|
}
|
2010-09-02 12:46:23 +02:00
|
|
|
}
|
|
|
|
if (err)
|
2010-11-29 07:49:44 +01:00
|
|
|
log_error ("error initializing cache encryption context: %s\n",
|
|
|
|
gpg_strerror (err));
|
2011-02-04 12:57:53 +01:00
|
|
|
|
2010-11-29 07:49:44 +01:00
|
|
|
return err? gpg_error (GPG_ERR_NOT_INITIALIZED) : 0;
|
2010-09-02 12:46:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-11-29 07:49:44 +01:00
|
|
|
|
2003-01-09 14:29:36 +01:00
|
|
|
static void
|
|
|
|
release_data (struct secret_data_s *data)
|
|
|
|
{
|
|
|
|
xfree (data);
|
|
|
|
}
|
|
|
|
|
2010-09-02 12:46:23 +02:00
|
|
|
static gpg_error_t
|
|
|
|
new_data (const char *string, struct secret_data_s **r_data)
|
2003-01-09 14:29:36 +01:00
|
|
|
{
|
2010-09-02 12:46:23 +02:00
|
|
|
gpg_error_t err;
|
|
|
|
struct secret_data_s *d, *d_enc;
|
|
|
|
size_t length;
|
2003-01-09 14:29:36 +01:00
|
|
|
int total;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
2010-09-02 12:46:23 +02:00
|
|
|
*r_data = NULL;
|
|
|
|
|
2010-11-29 07:49:44 +01:00
|
|
|
err = init_encryption ();
|
|
|
|
if (err)
|
|
|
|
return err;
|
2010-09-02 12:46:23 +02:00
|
|
|
|
|
|
|
length = strlen (string) + 1;
|
2003-01-09 14:29:36 +01:00
|
|
|
|
2010-09-02 12:46:23 +02:00
|
|
|
/* We pad the data to 32 bytes so that it get more complicated
|
2003-01-09 14:29:36 +01:00
|
|
|
finding something out by watching allocation patterns. This is
|
2015-11-16 12:41:46 +01:00
|
|
|
usually not possible but we better assume nothing about our secure
|
2010-09-02 12:46:23 +02:00
|
|
|
storage provider. To support the AESWRAP mode we need to add 8
|
|
|
|
extra bytes as well. */
|
|
|
|
total = (length + 8) + 32 - ((length+8) % 32);
|
|
|
|
|
|
|
|
d = xtrymalloc_secure (sizeof *d + total - 1);
|
|
|
|
if (!d)
|
|
|
|
return gpg_error_from_syserror ();
|
|
|
|
memcpy (d->data, string, length);
|
|
|
|
|
|
|
|
d_enc = xtrymalloc (sizeof *d_enc + total - 1);
|
|
|
|
if (!d_enc)
|
|
|
|
{
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
xfree (d);
|
|
|
|
return err;
|
|
|
|
}
|
2003-01-09 14:29:36 +01:00
|
|
|
|
2010-09-02 12:46:23 +02:00
|
|
|
d_enc->totallen = total;
|
|
|
|
err = gcry_cipher_encrypt (encryption_handle, d_enc->data, total,
|
|
|
|
d->data, total - 8);
|
|
|
|
xfree (d);
|
|
|
|
if (err)
|
2003-01-09 14:29:36 +01:00
|
|
|
{
|
2010-09-02 12:46:23 +02:00
|
|
|
xfree (d_enc);
|
|
|
|
return err;
|
2003-01-09 14:29:36 +01:00
|
|
|
}
|
2010-09-02 12:46:23 +02:00
|
|
|
*r_data = d_enc;
|
|
|
|
return 0;
|
2003-01-09 14:29:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-08-31 07:49:38 +02:00
|
|
|
static void
|
|
|
|
insert_to_timer_list_new (ITEM entry)
|
|
|
|
{
|
|
|
|
entry->t.next = the_timer_list_new;
|
|
|
|
the_timer_list_new = entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Insert to the active timer list. */
|
|
|
|
static void
|
|
|
|
insert_to_timer_list (struct timespec *ts, ITEM entry)
|
|
|
|
{
|
|
|
|
ITEM e, eprev;
|
|
|
|
|
|
|
|
if (!the_timer_list || ts->tv_sec >= entry->t.tv_sec)
|
|
|
|
{
|
2023-09-01 04:28:44 +02:00
|
|
|
if (the_timer_list)
|
|
|
|
{
|
|
|
|
the_timer_list->t.tv_sec += ts->tv_sec - entry->t.tv_sec;
|
2023-09-04 05:00:29 +02:00
|
|
|
if (ts->tv_nsec >= 500000000)
|
2023-09-01 04:28:44 +02:00
|
|
|
the_timer_list->t.tv_sec++;
|
|
|
|
}
|
2023-08-31 07:49:38 +02:00
|
|
|
|
|
|
|
ts->tv_sec = entry->t.tv_sec;
|
|
|
|
ts->tv_nsec = 0;
|
|
|
|
|
|
|
|
entry->t.tv_sec = 0;
|
|
|
|
entry->t.next = the_timer_list;
|
|
|
|
the_timer_list = entry;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
entry->t.tv_sec -= ts->tv_sec;
|
|
|
|
eprev = NULL;
|
|
|
|
for (e = the_timer_list; e; e = e->t.next)
|
|
|
|
{
|
|
|
|
if (e->t.tv_sec > entry->t.tv_sec)
|
|
|
|
break;
|
|
|
|
|
|
|
|
eprev = e;
|
|
|
|
entry->t.tv_sec -= e->t.tv_sec;
|
|
|
|
}
|
|
|
|
|
|
|
|
entry->t.next = e;
|
|
|
|
if (e)
|
|
|
|
e->t.tv_sec -= entry->t.tv_sec;
|
|
|
|
|
|
|
|
if (eprev)
|
|
|
|
eprev->t.next = entry;
|
|
|
|
else
|
|
|
|
the_timer_list = entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
remove_from_timer_list (ITEM entry)
|
|
|
|
{
|
|
|
|
ITEM e, eprev;
|
|
|
|
|
|
|
|
eprev = NULL;
|
|
|
|
for (e = the_timer_list; e; e = e->t.next)
|
|
|
|
if (e != entry)
|
|
|
|
eprev = e;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (e->t.next)
|
|
|
|
e->t.next->t.tv_sec += e->t.tv_sec;
|
|
|
|
|
|
|
|
if (eprev)
|
|
|
|
eprev->t.next = e->t.next;
|
|
|
|
else
|
|
|
|
the_timer_list = e->t.next;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
entry->t.next = NULL;
|
|
|
|
entry->t.tv_sec = 0;
|
|
|
|
}
|
2005-06-07 21:09:18 +02:00
|
|
|
|
2003-01-09 14:29:36 +01:00
|
|
|
static void
|
2023-08-31 07:49:38 +02:00
|
|
|
remove_from_timer_list_new (ITEM entry)
|
2003-01-09 14:29:36 +01:00
|
|
|
{
|
2023-08-31 07:49:38 +02:00
|
|
|
ITEM e, eprev;
|
|
|
|
|
|
|
|
eprev = NULL;
|
|
|
|
for (e = the_timer_list_new; e; e = e->t.next)
|
|
|
|
if (e != entry)
|
|
|
|
eprev = e;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (eprev)
|
|
|
|
eprev->t.next = e->t.next;
|
|
|
|
else
|
|
|
|
the_timer_list_new = e->t.next;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
entry->t.next = NULL;
|
|
|
|
entry->t.tv_sec = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
compute_expiration (ITEM r)
|
|
|
|
{
|
|
|
|
unsigned long maxttl;
|
2003-01-09 14:29:36 +01:00
|
|
|
time_t current = gnupg_get_time ();
|
2023-08-31 07:49:38 +02:00
|
|
|
time_t next;
|
2003-01-09 14:29:36 +01:00
|
|
|
|
2023-08-31 07:49:38 +02:00
|
|
|
if (r->cache_mode == CACHE_MODE_PIN)
|
|
|
|
return 0; /* Don't let it expire - scdaemon explicitly flushes them. */
|
|
|
|
|
|
|
|
if (!r->pw)
|
2003-01-09 14:29:36 +01:00
|
|
|
{
|
2023-08-31 07:49:38 +02:00
|
|
|
/* Expire an old and unused entry after 30 minutes. */
|
|
|
|
r->t.tv_sec = 60*30;
|
|
|
|
r->t.reason = CACHE_EXPIRE_UNUSED;
|
|
|
|
return 1;
|
2003-01-09 14:29:36 +01:00
|
|
|
}
|
|
|
|
|
2023-08-31 07:49:38 +02:00
|
|
|
switch (r->cache_mode)
|
2003-01-09 14:29:36 +01:00
|
|
|
{
|
2023-08-31 07:49:38 +02:00
|
|
|
case CACHE_MODE_DATA:
|
|
|
|
case CACHE_MODE_PIN:
|
|
|
|
maxttl = 0; /* No MAX TTL here. */
|
|
|
|
break;
|
|
|
|
case CACHE_MODE_SSH: maxttl = opt.max_cache_ttl_ssh; break;
|
|
|
|
default: maxttl = opt.max_cache_ttl; break;
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
2023-08-31 07:49:38 +02:00
|
|
|
if (maxttl)
|
|
|
|
{
|
|
|
|
if (r->created + maxttl < current)
|
2005-06-16 10:12:03 +02:00
|
|
|
{
|
2023-08-31 07:49:38 +02:00
|
|
|
r->t.tv_sec = 0;
|
|
|
|
r->t.reason = CACHE_EXPIRE_CREATION;
|
|
|
|
return 1;
|
2003-01-09 14:29:36 +01:00
|
|
|
}
|
2023-08-31 07:49:38 +02:00
|
|
|
|
|
|
|
next = r->created + maxttl - current;
|
2003-01-09 14:29:36 +01:00
|
|
|
}
|
2023-08-31 07:49:38 +02:00
|
|
|
else
|
|
|
|
next = 0;
|
2003-01-09 14:29:36 +01:00
|
|
|
|
2023-08-31 07:49:38 +02:00
|
|
|
if (r->ttl >= 0 && (next == 0 || r->ttl < next))
|
2003-01-09 14:29:36 +01:00
|
|
|
{
|
2023-08-31 07:49:38 +02:00
|
|
|
r->t.tv_sec = r->ttl;
|
|
|
|
r->t.reason = CACHE_EXPIRE_LAST_ACCESS;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (next)
|
|
|
|
{
|
|
|
|
r->t.tv_sec = next;
|
|
|
|
r->t.reason = CACHE_EXPIRE_CREATION;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
update_expiration (ITEM entry, int is_new_entry)
|
|
|
|
{
|
|
|
|
if (!is_new_entry)
|
|
|
|
{
|
|
|
|
remove_from_timer_list (entry);
|
|
|
|
remove_from_timer_list_new (entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (compute_expiration (entry))
|
|
|
|
{
|
|
|
|
insert_to_timer_list_new (entry);
|
|
|
|
agent_kick_the_loop ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Expire the cache entry. Returns 1 when the entry should be removed
|
|
|
|
* from the cache. */
|
|
|
|
static int
|
|
|
|
do_expire (ITEM e)
|
|
|
|
{
|
|
|
|
if (!e->pw)
|
|
|
|
/* Unused entry after 30 minutes. */
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (e->t.reason == CACHE_EXPIRE_LAST_ACCESS)
|
|
|
|
{
|
|
|
|
if (DBG_CACHE)
|
|
|
|
log_debug (" expired '%s'.%d (%ds after last access)\n",
|
|
|
|
e->key, e->restricted, e->ttl);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (DBG_CACHE)
|
|
|
|
log_debug (" expired '%s'.%d (%lus after creation)\n",
|
|
|
|
e->key, e->restricted, opt.max_cache_ttl);
|
2003-01-09 14:29:36 +01:00
|
|
|
}
|
2023-08-31 07:49:38 +02:00
|
|
|
|
|
|
|
release_data (e->pw);
|
|
|
|
e->pw = NULL;
|
|
|
|
e->accessed = 0;
|
|
|
|
|
|
|
|
if (compute_expiration (e))
|
|
|
|
insert_to_timer_list_new (e);
|
|
|
|
|
|
|
|
return 0;
|
2003-01-09 14:29:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-08-30 07:48:56 +02:00
|
|
|
struct timespec *
|
|
|
|
agent_cache_expiration (void)
|
2018-03-06 16:22:42 +01:00
|
|
|
{
|
2023-08-30 07:48:56 +02:00
|
|
|
static struct timespec abstime;
|
|
|
|
static struct timespec timeout;
|
2023-08-31 07:49:38 +02:00
|
|
|
struct timespec *tp;
|
2023-08-30 07:48:56 +02:00
|
|
|
struct timespec curtime;
|
2018-03-06 16:22:42 +01:00
|
|
|
int res;
|
2023-08-31 07:49:38 +02:00
|
|
|
int expired = 0;
|
|
|
|
ITEM e, enext;
|
|
|
|
|
|
|
|
res = npth_mutex_lock (&cache_lock);
|
|
|
|
if (res)
|
|
|
|
log_fatal ("failed to acquire cache mutex: %s\n", strerror (res));
|
2018-03-06 16:22:42 +01:00
|
|
|
|
2023-08-31 07:49:38 +02:00
|
|
|
npth_clock_gettime (&curtime);
|
|
|
|
if (the_timer_list)
|
2023-08-30 07:48:56 +02:00
|
|
|
{
|
2023-08-31 07:49:38 +02:00
|
|
|
if (npth_timercmp (&abstime, &curtime, <))
|
|
|
|
expired = 1;
|
|
|
|
else
|
|
|
|
npth_timersub (&abstime, &curtime, &timeout);
|
2023-08-30 07:48:56 +02:00
|
|
|
}
|
2018-03-06 16:22:42 +01:00
|
|
|
|
2023-08-31 07:49:38 +02:00
|
|
|
if (expired && (e = the_timer_list) && e->t.tv_sec == 0)
|
2023-08-30 07:48:56 +02:00
|
|
|
{
|
2023-08-31 07:49:38 +02:00
|
|
|
the_timer_list = e->t.next;
|
|
|
|
e->t.next = NULL;
|
2018-03-06 16:22:42 +01:00
|
|
|
|
2023-08-31 07:49:38 +02:00
|
|
|
if (do_expire (e))
|
|
|
|
{
|
|
|
|
ITEM r, rprev;
|
|
|
|
|
|
|
|
if (DBG_CACHE)
|
|
|
|
log_debug (" removed '%s'.%d (mode %d) (slot not used for 30m)\n",
|
|
|
|
e->key, e->restricted, e->cache_mode);
|
|
|
|
|
|
|
|
rprev = NULL;
|
|
|
|
for (r = thecache; r; r = r->next)
|
|
|
|
if (r == e)
|
|
|
|
{
|
|
|
|
if (!rprev)
|
|
|
|
thecache = r->next;
|
|
|
|
else
|
|
|
|
rprev->next = r->next;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
rprev = r;
|
|
|
|
|
|
|
|
remove_from_timer_list_new (e);
|
|
|
|
|
|
|
|
xfree (e);
|
|
|
|
}
|
|
|
|
}
|
2018-03-06 16:22:42 +01:00
|
|
|
|
2023-08-31 07:49:38 +02:00
|
|
|
if (expired || !the_timer_list)
|
|
|
|
timeout.tv_sec = timeout.tv_nsec = 0;
|
2023-08-30 07:48:56 +02:00
|
|
|
|
2023-08-31 07:49:38 +02:00
|
|
|
for (e = the_timer_list_new; e; e = enext)
|
|
|
|
{
|
|
|
|
enext = e->t.next;
|
|
|
|
e->t.next = NULL;
|
|
|
|
insert_to_timer_list (&timeout, e);
|
|
|
|
}
|
|
|
|
the_timer_list_new = NULL;
|
2023-08-30 07:48:56 +02:00
|
|
|
|
2023-08-31 07:49:38 +02:00
|
|
|
if (!the_timer_list)
|
|
|
|
tp = NULL;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (the_timer_list->t.tv_sec != 0)
|
|
|
|
{
|
|
|
|
timeout.tv_sec += the_timer_list->t.tv_sec;
|
|
|
|
the_timer_list->t.tv_sec = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
npth_timeradd (&timeout, &curtime, &abstime);
|
|
|
|
tp = &timeout;
|
2023-08-30 07:48:56 +02:00
|
|
|
}
|
|
|
|
|
2023-08-31 07:49:38 +02:00
|
|
|
res = npth_mutex_unlock (&cache_lock);
|
|
|
|
if (res)
|
|
|
|
log_fatal ("failed to release cache mutex: %s\n", strerror (res));
|
|
|
|
|
|
|
|
return tp;
|
2018-03-06 16:22:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-01-09 14:29:36 +01:00
|
|
|
void
|
2020-01-07 18:36:18 +01:00
|
|
|
agent_flush_cache (int pincache_only)
|
2003-01-09 14:29:36 +01:00
|
|
|
{
|
|
|
|
ITEM r;
|
2017-04-07 01:39:26 +02:00
|
|
|
int res;
|
2003-01-09 14:29:36 +01:00
|
|
|
|
|
|
|
if (DBG_CACHE)
|
2020-01-07 18:36:18 +01:00
|
|
|
log_debug ("agent_flush_cache%s\n", pincache_only?" (pincache only)":"");
|
2003-01-09 14:29:36 +01:00
|
|
|
|
2017-04-07 01:39:26 +02:00
|
|
|
res = npth_mutex_lock (&cache_lock);
|
|
|
|
if (res)
|
|
|
|
log_fatal ("failed to acquire cache mutex: %s\n", strerror (res));
|
|
|
|
|
2003-01-09 14:29:36 +01:00
|
|
|
for (r=thecache; r; r = r->next)
|
|
|
|
{
|
2020-01-07 18:36:18 +01:00
|
|
|
if (pincache_only && r->cache_mode != CACHE_MODE_PIN)
|
|
|
|
continue;
|
2010-09-02 12:46:23 +02:00
|
|
|
if (r->pw)
|
2003-01-09 14:29:36 +01:00
|
|
|
{
|
|
|
|
if (DBG_CACHE)
|
2018-03-27 08:40:58 +02:00
|
|
|
log_debug (" flushing '%s'.%d\n", r->key, r->restricted);
|
2003-01-09 14:29:36 +01:00
|
|
|
release_data (r->pw);
|
|
|
|
r->pw = NULL;
|
|
|
|
r->accessed = 0;
|
2023-08-31 07:49:38 +02:00
|
|
|
update_expiration (r, 0);
|
2003-01-09 14:29:36 +01:00
|
|
|
}
|
|
|
|
}
|
2017-04-07 01:39:26 +02:00
|
|
|
|
|
|
|
res = npth_mutex_unlock (&cache_lock);
|
|
|
|
if (res)
|
|
|
|
log_fatal ("failed to release cache mutex: %s\n", strerror (res));
|
2003-01-09 14:29:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-07-18 12:51:38 +02:00
|
|
|
/* Compare two cache modes. */
|
|
|
|
static int
|
|
|
|
cache_mode_equal (cache_mode_t a, cache_mode_t b)
|
|
|
|
{
|
|
|
|
/* CACHE_MODE_ANY matches any mode other than CACHE_MODE_IGNORE. */
|
2018-07-02 21:24:15 +02:00
|
|
|
return ((a == CACHE_MODE_ANY
|
|
|
|
&& !(b == CACHE_MODE_IGNORE || b == CACHE_MODE_DATA))
|
|
|
|
|| (b == CACHE_MODE_ANY
|
|
|
|
&& !(a == CACHE_MODE_IGNORE || a == CACHE_MODE_DATA))
|
|
|
|
|| a == b);
|
2016-07-18 12:51:38 +02:00
|
|
|
}
|
|
|
|
|
2003-01-09 14:29:36 +01:00
|
|
|
|
2010-09-02 12:46:23 +02:00
|
|
|
/* Store the string DATA in the cache under KEY and mark it with a
|
|
|
|
maximum lifetime of TTL seconds. If there is already data under
|
|
|
|
this key, it will be replaced. Using a DATA of NULL deletes the
|
|
|
|
entry. A TTL of 0 is replaced by the default TTL and a TTL of -1
|
|
|
|
set infinite timeout. CACHE_MODE is stored with the cache entry
|
2009-05-15 13:16:28 +02:00
|
|
|
and used to select different timeouts. */
|
2003-01-09 14:29:36 +01:00
|
|
|
int
|
2018-03-27 08:40:58 +02:00
|
|
|
agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode,
|
2005-06-07 21:09:18 +02:00
|
|
|
const char *data, int ttl)
|
2003-01-09 14:29:36 +01:00
|
|
|
{
|
2010-09-02 12:46:23 +02:00
|
|
|
gpg_error_t err = 0;
|
2003-01-09 14:29:36 +01:00
|
|
|
ITEM r;
|
2017-04-07 01:39:26 +02:00
|
|
|
int res;
|
2018-03-27 08:40:58 +02:00
|
|
|
int restricted = ctrl? ctrl->restricted : -1;
|
2017-04-07 01:39:26 +02:00
|
|
|
|
|
|
|
res = npth_mutex_lock (&cache_lock);
|
|
|
|
if (res)
|
|
|
|
log_fatal ("failed to acquire cache mutex: %s\n", strerror (res));
|
2003-01-09 14:29:36 +01:00
|
|
|
|
|
|
|
if (DBG_CACHE)
|
2018-03-27 08:40:58 +02:00
|
|
|
log_debug ("agent_put_cache '%s'.%d (mode %d) requested ttl=%d\n",
|
|
|
|
key, restricted, cache_mode, ttl);
|
2003-01-09 14:29:36 +01:00
|
|
|
|
2005-01-04 09:33:20 +01:00
|
|
|
if (!ttl)
|
2005-06-07 21:09:18 +02:00
|
|
|
{
|
2005-06-16 10:12:03 +02:00
|
|
|
switch(cache_mode)
|
|
|
|
{
|
|
|
|
case CACHE_MODE_SSH: ttl = opt.def_cache_ttl_ssh; break;
|
2018-07-02 21:24:15 +02:00
|
|
|
case CACHE_MODE_DATA: ttl = DEF_CACHE_TTL_DATA; break;
|
2020-01-07 18:36:18 +01:00
|
|
|
case CACHE_MODE_PIN: ttl = -1; break;
|
2005-06-16 10:12:03 +02:00
|
|
|
default: ttl = opt.def_cache_ttl; break;
|
|
|
|
}
|
2005-06-07 21:09:18 +02:00
|
|
|
}
|
2010-10-26 11:10:29 +02:00
|
|
|
if ((!ttl && data) || cache_mode == CACHE_MODE_IGNORE)
|
2017-04-07 01:39:26 +02:00
|
|
|
goto out;
|
2003-01-09 14:29:36 +01:00
|
|
|
|
|
|
|
for (r=thecache; r; r = r->next)
|
|
|
|
{
|
2020-01-07 18:36:18 +01:00
|
|
|
if (cache_mode == CACHE_MODE_PIN && data)
|
|
|
|
{
|
|
|
|
/* PIN mode is special because it is only used by scdaemon. */
|
|
|
|
if (!strcmp (r->key, key))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (cache_mode == CACHE_MODE_PIN)
|
|
|
|
{
|
|
|
|
/* FIXME: Parse the structure of the key and delete several
|
|
|
|
* cached PINS. */
|
|
|
|
if (!strcmp (r->key, key))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (((cache_mode != CACHE_MODE_USER
|
|
|
|
&& cache_mode != CACHE_MODE_NONCE)
|
|
|
|
|| cache_mode_equal (r->cache_mode, cache_mode))
|
|
|
|
&& r->restricted == restricted
|
|
|
|
&& !strcmp (r->key, key))
|
2003-01-09 14:29:36 +01:00
|
|
|
break;
|
|
|
|
}
|
2010-09-02 12:46:23 +02:00
|
|
|
if (r) /* Replace. */
|
|
|
|
{
|
2003-01-09 14:29:36 +01:00
|
|
|
if (r->pw)
|
|
|
|
{
|
|
|
|
release_data (r->pw);
|
|
|
|
r->pw = NULL;
|
|
|
|
}
|
|
|
|
if (data)
|
|
|
|
{
|
2011-02-04 12:57:53 +01:00
|
|
|
r->created = r->accessed = gnupg_get_time ();
|
2003-01-09 14:29:36 +01:00
|
|
|
r->ttl = ttl;
|
2005-06-07 21:09:18 +02:00
|
|
|
r->cache_mode = cache_mode;
|
2010-09-02 12:46:23 +02:00
|
|
|
err = new_data (data, &r->pw);
|
|
|
|
if (err)
|
|
|
|
log_error ("error replacing cache item: %s\n", gpg_strerror (err));
|
2023-08-31 07:49:38 +02:00
|
|
|
update_expiration (r, 0);
|
2003-01-09 14:29:36 +01:00
|
|
|
}
|
|
|
|
}
|
2010-09-02 12:46:23 +02:00
|
|
|
else if (data) /* Insert. */
|
|
|
|
{
|
2003-01-09 14:29:36 +01:00
|
|
|
r = xtrycalloc (1, sizeof *r + strlen (key));
|
|
|
|
if (!r)
|
2010-09-02 12:46:23 +02:00
|
|
|
err = gpg_error_from_syserror ();
|
2003-01-09 14:29:36 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
strcpy (r->key, key);
|
2018-03-27 08:40:58 +02:00
|
|
|
r->restricted = restricted;
|
2011-02-04 12:57:53 +01:00
|
|
|
r->created = r->accessed = gnupg_get_time ();
|
2003-01-09 14:29:36 +01:00
|
|
|
r->ttl = ttl;
|
2005-06-07 21:09:18 +02:00
|
|
|
r->cache_mode = cache_mode;
|
2010-09-02 12:46:23 +02:00
|
|
|
err = new_data (data, &r->pw);
|
|
|
|
if (err)
|
|
|
|
xfree (r);
|
2003-01-09 14:29:36 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
r->next = thecache;
|
|
|
|
thecache = r;
|
2023-08-31 07:49:38 +02:00
|
|
|
update_expiration (r, 1);
|
2003-01-09 14:29:36 +01:00
|
|
|
}
|
|
|
|
}
|
2010-09-02 12:46:23 +02:00
|
|
|
if (err)
|
|
|
|
log_error ("error inserting cache item: %s\n", gpg_strerror (err));
|
2003-01-09 14:29:36 +01:00
|
|
|
}
|
2017-04-07 01:39:26 +02:00
|
|
|
|
|
|
|
out:
|
|
|
|
res = npth_mutex_unlock (&cache_lock);
|
|
|
|
if (res)
|
|
|
|
log_fatal ("failed to release cache mutex: %s\n", strerror (res));
|
|
|
|
|
2010-09-02 12:46:23 +02:00
|
|
|
return err;
|
2003-01-09 14:29:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-01-09 12:00:50 +01:00
|
|
|
/* Try to find an item in the cache. Returns NULL if not found or an
|
|
|
|
* malloced string with the value. */
|
2010-09-02 12:46:23 +02:00
|
|
|
char *
|
2018-03-27 08:40:58 +02:00
|
|
|
agent_get_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode)
|
2003-01-09 14:29:36 +01:00
|
|
|
{
|
2010-09-02 12:46:23 +02:00
|
|
|
gpg_error_t err;
|
2003-01-09 14:29:36 +01:00
|
|
|
ITEM r;
|
2010-09-02 12:46:23 +02:00
|
|
|
char *value = NULL;
|
Port to npth.
* configure.ac: Don't check for PTH but for NPTH.
(AH_BOTTOM): Remove PTH_SYSCALL_SOFT.
(have_pth): Rename to ...
(have_npth): ... this.
(USE_GNU_NPTH): Rename to ...
(USE_GNU_PTH): ... this.
* m4/npth.m4: New file.
* agent/Makefile.am, agent/cache.c, agent/call-pinentry.c,
agent/call-scd.c, agent/findkey.c, agent/gpg-agent.c,
agent/trustlist.c, common/Makefile.am, common/estream.c,
common/exechelp-posix.c, common/exechelp-w32.c,
common/exechelp-w32ce.c, common/http.c, common/init.c,
common/sysutils.c, dirmngr/Makefile.am, dirmngr/crlfetch.c,
dirmngr/dirmngr.c, dirmngr/dirmngr_ldap.c, dirmngr/ldap-wrapper-ce.c,
dirmngr/ldap-wrapper.c, dirmngr/ldap.c, g13/Makefile.am,
g13/call-gpg.c, g13/g13.c, g13/runner.c, scd/Makefile.am,
scd/apdu.c, scd/app.c, scd/ccid-driver.c, scd/command.c,
scd/scdaemon.c, tools/Makefile.am: Port to npth.
2012-01-03 22:12:37 +01:00
|
|
|
int res;
|
2014-09-17 15:12:08 +02:00
|
|
|
int last_stored = 0;
|
2018-03-27 08:40:58 +02:00
|
|
|
int restricted = ctrl? ctrl->restricted : -1;
|
2020-01-07 18:36:18 +01:00
|
|
|
int yes;
|
2003-01-09 14:29:36 +01:00
|
|
|
|
2005-06-07 21:09:18 +02:00
|
|
|
if (cache_mode == CACHE_MODE_IGNORE)
|
|
|
|
return NULL;
|
|
|
|
|
2017-04-07 01:39:26 +02:00
|
|
|
res = npth_mutex_lock (&cache_lock);
|
|
|
|
if (res)
|
|
|
|
log_fatal ("failed to acquire cache mutex: %s\n", strerror (res));
|
|
|
|
|
2014-09-17 15:12:08 +02:00
|
|
|
if (!key)
|
|
|
|
{
|
|
|
|
key = last_stored_cache_key;
|
|
|
|
if (!key)
|
2017-04-07 01:39:26 +02:00
|
|
|
goto out;
|
2014-09-17 15:12:08 +02:00
|
|
|
last_stored = 1;
|
|
|
|
}
|
|
|
|
|
2003-01-09 14:29:36 +01:00
|
|
|
if (DBG_CACHE)
|
2018-03-27 08:40:58 +02:00
|
|
|
log_debug ("agent_get_cache '%s'.%d (mode %d)%s ...\n",
|
2020-10-09 05:02:07 +02:00
|
|
|
key, restricted, cache_mode,
|
2014-09-17 15:12:08 +02:00
|
|
|
last_stored? " (stored cache key)":"");
|
2003-01-09 14:29:36 +01:00
|
|
|
|
|
|
|
for (r=thecache; r; r = r->next)
|
|
|
|
{
|
2020-01-07 18:36:18 +01:00
|
|
|
if (cache_mode == CACHE_MODE_PIN)
|
|
|
|
yes = (r->pw && !strcmp (r->key, key));
|
|
|
|
else if (r->pw
|
|
|
|
&& ((cache_mode != CACHE_MODE_USER
|
|
|
|
&& cache_mode != CACHE_MODE_NONCE)
|
|
|
|
|| cache_mode_equal (r->cache_mode, cache_mode))
|
|
|
|
&& r->restricted == restricted
|
|
|
|
&& !strcmp (r->key, key))
|
|
|
|
yes = 1;
|
|
|
|
else
|
|
|
|
yes = 0;
|
|
|
|
|
|
|
|
if (yes)
|
2003-01-09 14:29:36 +01:00
|
|
|
{
|
2018-07-02 21:24:15 +02:00
|
|
|
/* Note: To avoid races KEY may not be accessed anymore
|
|
|
|
* below. Note also that we don't update the accessed time
|
|
|
|
* for data items. */
|
|
|
|
if (r->cache_mode != CACHE_MODE_DATA)
|
2023-08-31 07:49:38 +02:00
|
|
|
{
|
|
|
|
r->accessed = gnupg_get_time ();
|
|
|
|
update_expiration (r, 0);
|
|
|
|
}
|
2003-01-09 14:29:36 +01:00
|
|
|
if (DBG_CACHE)
|
|
|
|
log_debug ("... hit\n");
|
2010-09-02 12:46:23 +02:00
|
|
|
if (r->pw->totallen < 32)
|
|
|
|
err = gpg_error (GPG_ERR_INV_LENGTH);
|
2010-11-29 07:49:44 +01:00
|
|
|
else if ((err = init_encryption ()))
|
|
|
|
;
|
2010-09-02 12:46:23 +02:00
|
|
|
else if (!(value = xtrymalloc_secure (r->pw->totallen - 8)))
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
else
|
|
|
|
{
|
|
|
|
err = gcry_cipher_decrypt (encryption_handle,
|
|
|
|
value, r->pw->totallen - 8,
|
|
|
|
r->pw->data, r->pw->totallen);
|
|
|
|
}
|
|
|
|
if (err)
|
|
|
|
{
|
|
|
|
xfree (value);
|
|
|
|
value = NULL;
|
2018-03-27 08:40:58 +02:00
|
|
|
log_error ("retrieving cache entry '%s'.%d failed: %s\n",
|
|
|
|
key, restricted, gpg_strerror (err));
|
2010-09-02 12:46:23 +02:00
|
|
|
}
|
2017-04-07 01:39:26 +02:00
|
|
|
break;
|
2003-01-09 14:29:36 +01:00
|
|
|
}
|
|
|
|
}
|
2017-04-07 01:39:26 +02:00
|
|
|
if (DBG_CACHE && value == NULL)
|
2003-01-09 14:29:36 +01:00
|
|
|
log_debug ("... miss\n");
|
|
|
|
|
2017-04-07 01:39:26 +02:00
|
|
|
out:
|
|
|
|
res = npth_mutex_unlock (&cache_lock);
|
|
|
|
if (res)
|
|
|
|
log_fatal ("failed to release cache mutex: %s\n", strerror (res));
|
|
|
|
|
|
|
|
return value;
|
2003-01-09 14:29:36 +01:00
|
|
|
}
|
2014-09-17 15:12:08 +02:00
|
|
|
|
|
|
|
|
|
|
|
/* Store the key for the last successful cache hit. That value is
|
|
|
|
used by agent_get_cache if the requested KEY is given as NULL.
|
|
|
|
NULL may be used to remove that key. */
|
|
|
|
void
|
|
|
|
agent_store_cache_hit (const char *key)
|
|
|
|
{
|
2017-01-25 13:51:57 +01:00
|
|
|
char *new;
|
|
|
|
char *old;
|
|
|
|
|
|
|
|
/* To make sure the update is atomic under the non-preemptive thread
|
|
|
|
* model, we must make sure not to surrender control to a different
|
|
|
|
* thread. Therefore, we avoid calling the allocator during the
|
2017-01-30 12:07:46 +01:00
|
|
|
* update.
|
|
|
|
*
|
|
|
|
* Background: xtrystrdup uses gcry_strdup which may use the secure
|
|
|
|
* memory allocator of Libgcrypt. That allocator takes locks and
|
2017-02-01 08:18:44 +01:00
|
|
|
* since version 1.14 libgpg-error is nPth aware and thus taking a
|
2017-01-30 12:07:46 +01:00
|
|
|
* lock may now lead to thread switch. Note that this only happens
|
2017-02-01 08:18:44 +01:00
|
|
|
* when secure memory is _allocated_ (the standard allocator uses
|
|
|
|
* malloc which is not nPth aware) but not when calling _xfree_
|
|
|
|
* because gcry_free needs to check whether the pointer is in secure
|
|
|
|
* memory and thus needs to take a lock.
|
2017-01-30 12:07:46 +01:00
|
|
|
*/
|
2017-01-25 13:51:57 +01:00
|
|
|
new = key ? xtrystrdup (key) : NULL;
|
|
|
|
|
|
|
|
/* Atomic update. */
|
|
|
|
old = last_stored_cache_key;
|
|
|
|
last_stored_cache_key = new;
|
|
|
|
/* Done. */
|
|
|
|
|
|
|
|
xfree (old);
|
2014-09-17 15:12:08 +02:00
|
|
|
}
|