aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2023-12-22 12:45:02 +0000
committerWerner Koch <[email protected]>2023-12-22 12:45:02 +0000
commit2764ee309a2e0c10cef606345f06dd37c637fc41 (patch)
tree4238a756e7624b31ade6e558a1c0794af691412d
parentRegister DCO for Mario Haustein (diff)
parentdoc: Explain why socket activation is a problem (diff)
downloadgnupg-2764ee309a2e0c10cef606345f06dd37c637fc41.tar.gz
gnupg-2764ee309a2e0c10cef606345f06dd37c637fc41.zip
Merge branch 'STABLE-BRANCH-2-4'
-- Fixed conflicts in NEWS g10/encrypt.c sm/encrypt.c sm/sign.c
-rw-r--r--AUTHORS2
-rw-r--r--NEWS4
-rw-r--r--README30
-rw-r--r--agent/findkey.c75
-rw-r--r--common/compliance.c13
-rw-r--r--common/compliance.h1
-rw-r--r--common/dotlock.c322
-rw-r--r--common/dotlock.h23
-rw-r--r--common/homedir.c192
-rw-r--r--common/name-value.c61
-rw-r--r--common/name-value.h7
-rw-r--r--common/openpgpdefs.h3
-rw-r--r--common/t-dotlock.c36
-rw-r--r--doc/opt-homedir.texi10
-rw-r--r--doc/tools.texi28
-rw-r--r--doc/wks.texi15
-rw-r--r--g10/call-agent.c6
-rw-r--r--g10/call-keyboxd.c26
-rw-r--r--g10/keyedit.c2
-rw-r--r--kbx/backend-sqlite.c68
-rw-r--r--kbx/kbx-client-util.c8
-rw-r--r--kbx/keyboxd.c1
-rw-r--r--po/ja.po16
-rw-r--r--scd/apdu.c12
-rw-r--r--scd/app-openpgp.c56
-rw-r--r--scd/app-p15.c176
-rw-r--r--scd/iso7816.c2
-rw-r--r--scd/scdaemon.c5
-rw-r--r--scd/scdaemon.h1
-rw-r--r--sm/call-agent.c5
-rw-r--r--sm/decrypt.c3
-rw-r--r--sm/encrypt.c74
-rw-r--r--sm/keydb.c23
-rw-r--r--sm/keylist.c2
-rw-r--r--sm/minip12.c2
-rw-r--r--sm/sign.c132
-rw-r--r--sm/verify.c1
-rw-r--r--tools/gpgconf.c70
38 files changed, 1146 insertions, 367 deletions
diff --git a/AUTHORS b/AUTHORS
index df4e1ec39..65522a1cc 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -221,7 +221,7 @@ Kyle Butt <[email protected]>
2013-05-29:CAAODAYLbCtqOG6msLLL0UTdASKWT6u2ptxsgUQ1JpusBESBoNQ@mail.gmail.com:
Mario Haustein <[email protected]>
-2022-09026:8149069.T7Z3S40VBb@localdomain:
+2022-09-26:8149069.T7Z3S40VBb@localdomain:
Michael Haubenwallner <[email protected]>
2018-07-13:[email protected]:
diff --git a/NEWS b/NEWS
index f38cf9f0d..b9bff6232 100644
--- a/NEWS
+++ b/NEWS
@@ -1,7 +1,9 @@
Noteworthy changes in version 2.5.0 (unreleased)
------------------------------------------------
- Changes also found in 2.4.3:
+ Changes also found in 2.4.4:
+
+ * gpgsm: Support ECDSA in de-vs compliance mode. [T6802]
* Fix garbled time output in non-English Windows. [T6741]
diff --git a/README b/README
index aa8b3e12b..6905daafb 100644
--- a/README
+++ b/README
@@ -144,6 +144,13 @@
gpg --import --import-options restore < allkeys.gpg
gpgsm --import < allcerts.crt
+ In case the keyboxd is not able to startup due to a stale lockfile
+ created by another host, the command
+
+ gpgconf --unlock pubring.db
+
+ can be used to remove the lock file.
+
** Socket directory
GnuPG uses Unix domain sockets to connect its components (on Windows
@@ -166,6 +173,29 @@
fi
done )
+** Conflicts with systemd socket activation
+
+ Some Linux distribution use the meanwhile deprecated --supervised
+ option with gpg-agent, dirmngr, and keyboxd. The idea is that the
+ systemd process launches the daemons as soon as gpg or gpgsm try to
+ access them. However, this creates a race condition with GnuPG's
+ own on-demand launching of these daemon. It also conflicts with the
+ remote use gpg-agent because the no-autostart feature on the remote
+ site will not work as expected.
+
+ Thus the recommendation is not to use the --supervised option. All
+ GnuPG components handle the startup of their daemons on their own.
+
+ The only problem is that for using GnuPG's ssh-agent protocol
+ support, the gpg-agent must have been started before ssh. This can
+ either be done with an ssh wrapper running
+
+ gpg-connect-agent updatestartuptty /bye
+
+ for each new tty or by using that command directly after login when
+ the anyway required SSH_AUTH_SOCK envvar is set (see the example in
+ the gpg-agent man page).
+
* DOCUMENTATION
diff --git a/agent/findkey.c b/agent/findkey.c
index a5f022574..4e55119e3 100644
--- a/agent/findkey.c
+++ b/agent/findkey.c
@@ -41,7 +41,8 @@
static gpg_error_t read_key_file (const unsigned char *grip,
- gcry_sexp_t *result, nvc_t *r_keymeta);
+ gcry_sexp_t *result, nvc_t *r_keymeta,
+ char **r_orig_key_value);
static gpg_error_t is_shadowed_key (gcry_sexp_t s_skey);
@@ -129,12 +130,15 @@ agent_write_private_key (const unsigned char *grip,
char **tokenfields = NULL;
int is_regular;
int blocksigs = 0;
+ char *orig_key_value = NULL;
+ const char *s;
+ int force_modify = 0;
fname = fname_from_keygrip (grip, 0);
if (!fname)
return gpg_error_from_syserror ();
- err = read_key_file (grip, &key, &pk);
+ err = read_key_file (grip, &key, &pk, &orig_key_value);
if (err)
{
if (gpg_err_code (err) == GPG_ERR_ENOENT)
@@ -146,6 +150,8 @@ agent_write_private_key (const unsigned char *grip,
}
}
+ nvc_modified (pk, 1); /* Clear that flag after a read. */
+
if (!pk)
{
/* Key is still in the old format or does not exist - create a
@@ -156,6 +162,7 @@ agent_write_private_key (const unsigned char *grip,
err = gpg_error_from_syserror ();
goto leave;
}
+ force_modify = 1;
}
/* Check whether we already have a regular key. */
@@ -171,6 +178,19 @@ agent_write_private_key (const unsigned char *grip,
if (err)
goto leave;
+ /* Detect whether the key value actually changed and if not clear
+ * the modified flag. This extra check is required because
+ * read_key_file removes the Key entry from the container and we
+ * then create a new Key entry which might be the same, though. */
+ if (!force_modify
+ && orig_key_value && (s = nvc_get_string (pk, "Key:"))
+ && !strcmp (orig_key_value, s))
+ {
+ nvc_modified (pk, 1); /* Clear that flag. */
+ }
+ xfree (orig_key_value);
+ orig_key_value = NULL;
+
/* Check that we do not update a regular key with a shadow key. */
if (is_regular && gpg_err_code (is_shadowed_key (key)) == GPG_ERR_TRUE)
{
@@ -192,7 +212,6 @@ agent_write_private_key (const unsigned char *grip,
if (serialno && keyref)
{
nve_t item;
- const char *s;
size_t token0len;
if (dispserialno)
@@ -242,7 +261,7 @@ agent_write_private_key (const unsigned char *grip,
; /* No need to update Token entry. */
else
{
- err = nve_set (item, token);
+ err = nve_set (pk, item, token);
if (err)
goto leave;
}
@@ -263,6 +282,13 @@ agent_write_private_key (const unsigned char *grip,
goto leave;
}
+ /* Check whether we need to write the file at all. */
+ if (!nvc_modified (pk, 0))
+ {
+ err = 0;
+ goto leave;
+ }
+
/* Create a temporary file for writing. */
tmpfname = fname_from_keygrip (grip, 1);
fp = tmpfname ? es_fopen (tmpfname, "wbx,mode=-rw") : NULL;
@@ -310,6 +336,7 @@ agent_write_private_key (const unsigned char *grip,
es_fclose (fp);
if (removetmp && tmpfname)
gnupg_remove (tmpfname);
+ xfree (orig_key_value);
xfree (fname);
xfree (tmpfname);
xfree (token);
@@ -856,10 +883,13 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
* return it as an gcrypt S-expression object in RESULT. If R_KEYMETA
* is not NULL and the extended key format is used, the meta data
* items are stored there. However the "Key:" item is removed from
- * it. On failure returns an error code and stores NULL at RESULT and
- * R_KEYMETA. */
+ * it. If R_ORIG_KEY_VALUE is non-NULL and the Key item was removed,
+ * its original value is stored at that R_ORIG_KEY_VALUE and the
+ * caller must free it. On failure returns an error code and stores
+ * NULL at RESULT and R_KEYMETA. */
static gpg_error_t
-read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta)
+read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta,
+ char **r_orig_key_value)
{
gpg_error_t err;
char *fname;
@@ -873,6 +903,8 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta)
*result = NULL;
if (r_keymeta)
*r_keymeta = NULL;
+ if (r_orig_key_value)
+ *r_orig_key_value = NULL;
fname = fname_from_keygrip (grip, 0);
if (!fname)
@@ -927,7 +959,24 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta)
log_error ("error getting private key from '%s': %s\n",
fname, gpg_strerror (err));
else
- nvc_delete_named (pk, "Key:");
+ {
+ if (r_orig_key_value)
+ {
+ const char *s = nvc_get_string (pk, "Key:");
+ if (s)
+ {
+ *r_orig_key_value = xtrystrdup (s);
+ if (!*r_orig_key_value)
+ {
+ err = gpg_error_from_syserror ();
+ nvc_release (pk);
+ xfree (fname);
+ return err;
+ }
+ }
+ }
+ nvc_delete_named (pk, "Key:");
+ }
}
if (!err && r_keymeta)
@@ -1177,7 +1226,7 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce,
if (!grip && !ctrl->have_keygrip)
return gpg_error (GPG_ERR_NO_SECKEY);
- err = read_key_file (grip? grip : ctrl->keygrip, &s_skey, &keymeta);
+ err = read_key_file (grip? grip : ctrl->keygrip, &s_skey, &keymeta, NULL);
if (err)
{
if (gpg_err_code (err) == GPG_ERR_ENOENT)
@@ -1436,7 +1485,7 @@ agent_raw_key_from_file (ctrl_t ctrl, const unsigned char *grip,
*result = NULL;
- err = read_key_file (grip, &s_skey, r_keymeta);
+ err = read_key_file (grip, &s_skey, r_keymeta, NULL);
if (!err)
*result = s_skey;
return err;
@@ -1479,7 +1528,7 @@ public_key_from_file (ctrl_t ctrl, const unsigned char *grip,
if (r_sshorder)
*r_sshorder = 0;
- err = read_key_file (grip, &s_skey, for_ssh? &keymeta : NULL);
+ err = read_key_file (grip, &s_skey, for_ssh? &keymeta : NULL, NULL);
if (err)
return err;
@@ -1651,7 +1700,7 @@ agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
{
gcry_sexp_t sexp;
- err = read_key_file (grip, &sexp, NULL);
+ err = read_key_file (grip, &sexp, NULL, NULL);
if (err)
{
if (gpg_err_code (err) == GPG_ERR_ENOENT)
@@ -1735,7 +1784,7 @@ agent_delete_key (ctrl_t ctrl, const char *desc_text,
char *default_desc = NULL;
int key_type;
- err = read_key_file (grip, &s_skey, NULL);
+ err = read_key_file (grip, &s_skey, NULL, NULL);
if (gpg_err_code (err) == GPG_ERR_ENOENT)
err = gpg_error (GPG_ERR_NO_SECKEY);
if (err)
diff --git a/common/compliance.c b/common/compliance.c
index 59d94038d..04978ed1b 100644
--- a/common/compliance.c
+++ b/common/compliance.c
@@ -256,6 +256,13 @@ gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
if (! initialized)
return 1;
+ /* Map the the generic ECC algo to ECDSA if requested. */
+ if ((algo_flags & PK_ALGO_FLAG_ECC18)
+ && algo == GCRY_PK_ECC
+ && (use == PK_USE_VERIFICATION
+ || use == PK_USE_SIGNING))
+ algo = GCRY_PK_ECDSA;
+
switch (compliance)
{
case CO_DE_VS:
@@ -280,7 +287,6 @@ gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
default:
log_assert (!"reached");
}
- (void)algo_flags;
break;
case PUBKEY_ALGO_DSA:
@@ -301,7 +307,7 @@ gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
result = (use == PK_USE_DECRYPTION);
break;
- case PUBKEY_ALGO_ECDH:
+ case PUBKEY_ALGO_ECDH: /* Same value as GCRY_PK_ECC, i.e. 18 */
case GCRY_PK_ECDH:
if (use == PK_USE_DECRYPTION)
result = 1;
@@ -549,6 +555,9 @@ gnupg_rng_is_compliant (enum gnupg_compliance_mode compliance)
int *result;
int res;
+ /* #warning debug code ahead */
+ /* return 1; */
+
result = get_compliance_cache (compliance, 1);
if (result && *result != -1)
diff --git a/common/compliance.h b/common/compliance.h
index ead11472c..111fdc74b 100644
--- a/common/compliance.h
+++ b/common/compliance.h
@@ -50,6 +50,7 @@ enum pk_use_case
/* Flags to distinguish public key algorithm variants. */
#define PK_ALGO_FLAG_RSAPSS 1 /* Use rsaPSS padding. */
+#define PK_ALGO_FLAG_ECC18 256 /* GCRY_PK_ECC is used in a generic way. */
int gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
diff --git a/common/dotlock.c b/common/dotlock.c
index 74186b776..fe6d7fe71 100644
--- a/common/dotlock.c
+++ b/common/dotlock.c
@@ -291,6 +291,7 @@
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/utsname.h>
+# include <dirent.h>
#endif
#include <sys/types.h>
#include <sys/time.h>
@@ -393,9 +394,18 @@ struct dotlock_handle
unsigned int locked:1; /* Lock status. */
unsigned int disable:1; /* If true, locking is disabled. */
unsigned int use_o_excl:1; /* Use open (O_EXCL) for locking. */
+ unsigned int by_parent:1; /* Parent does the locking. */
+ unsigned int no_write:1; /* No write to the lockfile. */
int extra_fd; /* A place for the caller to store an FD. */
+ /* An optional info callback - see dotlock_set_info_cb. */
+ int (*info_cb)(dotlock_t, void *,
+ enum dotlock_reasons reason,
+ const char *,...);
+ void *info_cb_value;
+
+
#ifdef HAVE_DOSISH_SYSTEM
HANDLE lockhd; /* The W32 handle of the lock file. */
#else /*!HAVE_DOSISH_SYSTEM */
@@ -545,8 +555,15 @@ read_lockfile (dotlock_t h, int *same_node, int *r_fd)
if ( (fd = open (h->lockname, O_RDONLY)) == -1 )
{
int e = errno;
- my_info_2 ("error opening lockfile '%s': %s\n",
- h->lockname, strerror(errno) );
+ if (errno != ENOENT)
+ {
+ my_info_2 ("error opening lockfile '%s': %s\n",
+ h->lockname, strerror(errno) );
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
+ "error opening lockfile '%s': %s\n",
+ h->lockname, strerror (errno) );
+ }
if (buffer != buffer_space)
xfree (buffer);
my_set_errno (e); /* Need to return ERRNO here. */
@@ -564,6 +581,10 @@ read_lockfile (dotlock_t h, int *same_node, int *r_fd)
{
int e = errno;
my_info_1 ("error reading lockfile '%s'\n", h->lockname );
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
+ "error reading lockfile '%s': %s\n",
+ h->lockname, strerror (errno) );
close (fd);
if (buffer != buffer_space)
xfree (buffer);
@@ -583,6 +604,9 @@ read_lockfile (dotlock_t h, int *same_node, int *r_fd)
if (nread < 11)
{
my_info_1 ("invalid size of lockfile '%s'\n", h->lockname);
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_INV_FILE,
+ "invalid size of lockfile '%s'\n", h->lockname);
if (buffer != buffer_space)
xfree (buffer);
my_set_errno (EINVAL);
@@ -594,6 +618,9 @@ read_lockfile (dotlock_t h, int *same_node, int *r_fd)
|| !pid )
{
my_error_2 ("invalid pid %d in lockfile '%s'\n", pid, h->lockname);
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_INV_FILE,
+ "invalid pid %d in lockfile '%s'\n", pid, h->lockname);
if (buffer != buffer_space)
xfree (buffer);
my_set_errno (EINVAL);
@@ -655,6 +682,80 @@ use_hardlinks_p (const char *tname)
#ifdef HAVE_POSIX_SYSTEM
+static int
+dotlock_get_process_id (dotlock_t h)
+{
+ return h->by_parent? (int)getppid(): (int)getpid();
+}
+
+static int
+dotlock_detect_tname (dotlock_t h)
+{
+ struct stat sb;
+ DIR *dir;
+ char *dirname;
+ char *basename;
+ struct dirent *d;
+ int r;
+
+ if (stat (h->lockname, &sb))
+ return -1;
+
+ basename = make_basename (h->lockname, NULL);
+ dirname = make_dirname (h->lockname);
+
+ dir = opendir (dirname);
+ if (dir == NULL)
+ {
+ xfree (basename);
+ xfree (dirname);
+ return -1;
+ }
+
+ while ((d = readdir (dir)))
+ if (sb.st_ino == d->d_ino && strcmp (d->d_name, basename))
+ break;
+
+ if (d)
+ {
+ int len = strlen (h->tname);
+ int dlen = strlen (d->d_name);
+ const char *tname_path;
+
+ if (dlen > len)
+ {
+ xfree (basename);
+ xfree (dirname);
+ return -1;
+ }
+
+ strcpy (stpcpy (stpcpy (h->tname, dirname), DIRSEP_S), d->d_name);
+ h->use_o_excl = 0;
+ tname_path = strchr (h->tname + strlen (dirname) + 2, '.');
+ if (!tname_path)
+ {
+ xfree (basename);
+ xfree (dirname);
+ return -1;
+ }
+ h->nodename_off = tname_path - h->tname + 1;
+ }
+ else
+ h->use_o_excl = 1;
+
+ r = closedir (dir);
+ if (r)
+ {
+ xfree (basename);
+ xfree (dirname);
+ return r;
+ }
+
+ xfree (basename);
+ xfree (dirname);
+ return 0;
+}
+
/* Locking core for Unix. It used a temporary file and the link
system call to make locking an atomic operation. */
static dotlock_t
@@ -667,8 +768,10 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
int dirpartlen;
struct utsname utsbuf;
size_t tnamelen;
+ int pid;
- snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid() );
+ pid = dotlock_get_process_id (h);
+ snprintf (pidstr, sizeof pidstr, "%10d\n", pid);
/* Create a temporary file. */
if ( uname ( &utsbuf ) )
@@ -702,10 +805,17 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
}
h->nodename_len = strlen (nodename);
+ if (h->no_write)
+ {
+ memset (h->tname, '_', tnamelen);
+ h->tname[tnamelen] = 0;
+ goto skip_write;
+ }
+
snprintf (h->tname, tnamelen, "%.*s/.#lk%p.", dirpartlen, dirpart, h );
h->nodename_off = strlen (h->tname);
snprintf (h->tname+h->nodename_off, tnamelen - h->nodename_off,
- "%s.%d", nodename, (int)getpid ());
+ "%s.%d", nodename, pid);
do
{
@@ -722,6 +832,10 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
UNLOCK_all_lockfiles ();
my_error_2 (_("failed to create temporary file '%s': %s\n"),
h->tname, strerror (errno));
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_WAITING,
+ _("failed to create temporary file '%s': %s\n"),
+ h->tname, strerror (errno));
xfree (h->tname);
xfree (h);
my_set_errno (saveerrno);
@@ -755,11 +869,16 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
int saveerrno = errno;
my_error_2 ("can't check whether hardlinks are supported for '%s': %s\n"
, h->tname, strerror (saveerrno));
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_CONFIG_TEST,
+ "can't check whether hardlinks are supported for '%s': %s\n"
+ , h->tname, strerror (saveerrno));
my_set_errno (saveerrno);
}
goto write_failed;
}
+ skip_write:
h->lockname = xtrymalloc (strlen (file_to_lock) + 6 );
if (!h->lockname)
{
@@ -775,6 +894,20 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
strcpy (stpcpy (h->lockname, file_to_lock), EXTSEP_S "lock");
UNLOCK_all_lockfiles ();
+ if (h->no_write)
+ {
+ if (dotlock_detect_tname (h) < 0)
+ {
+ xfree (h->lockname);
+ xfree (h->tname);
+ xfree (h);
+ my_set_errno (EACCES);
+ return NULL;
+ }
+
+ h->locked = 1;
+ }
+
return h;
write_failed:
@@ -783,6 +916,11 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
all_lockfiles = h->next;
UNLOCK_all_lockfiles ();
my_error_2 (_("error writing to '%s': %s\n"), h->tname, strerror (errno));
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
+ _("error writing to '%s': %s\n"),
+ h->tname, strerror (errno));
+
if ( fd != -1 )
close (fd);
unlink (h->tname);
@@ -849,6 +987,10 @@ dotlock_create_w32 (dotlock_t h, const char *file_to_lock)
all_lockfiles = h->next;
UNLOCK_all_lockfiles ();
my_error_2 (_("can't create '%s': %s\n"), h->lockname, w32_strerror (-1));
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
+ _("can't create '%s': %s\n"),
+ h->lockname, w32_strerror (-1));
xfree (h->lockname);
xfree (h);
my_set_errno (saveerrno);
@@ -873,7 +1015,15 @@ dotlock_create_w32 (dotlock_t h, const char *file_to_lock)
POSIX systems a temporary file ".#lk.<hostname>.pid[.threadid] is
used.
- FLAGS must be 0.
+ FLAGS may include DOTLOCK_PREPARE_CREATE bit, which only allocates
+ the handle and requires a further call to dotlock_finish_create.
+ This can be used to set a callback between these calls.
+
+ FLAGS may include DOTLOCK_LOCK_BY_PARENT bit, when it's the parent
+ process controlling the lock. This is used by dotlock util.
+
+ FLAGS may include DOTLOCK_LOCKED bit, when it should not create the
+ lockfile, but to unlock. This is used by dotlock util.
The function returns an new handle which needs to be released using
destroy_dotlock but gets also released at the termination of the
@@ -885,8 +1035,13 @@ dotlock_create (const char *file_to_lock, unsigned int flags)
{
static int initialized;
dotlock_t h;
+#ifndef HAVE_DOSISH_SYSTEM
+ int by_parent = 0;
+ int no_write = 0;
+#endif
- if ( !initialized )
+ if ( !(flags & DOTLOCK_LOCK_BY_PARENT)
+ && !initialized )
{
atexit (dotlock_remove_lockfiles);
initialized = 1;
@@ -895,7 +1050,15 @@ dotlock_create (const char *file_to_lock, unsigned int flags)
if ( !file_to_lock )
return NULL; /* Only initialization was requested. */
- if (flags)
+#ifndef HAVE_DOSISH_SYSTEM
+ if ((flags & DOTLOCK_LOCK_BY_PARENT) || (flags & DOTLOCK_LOCKED))
+ {
+ by_parent = !!(flags & DOTLOCK_LOCK_BY_PARENT);
+ no_write = !!(flags & DOTLOCK_LOCKED);
+ flags &= ~(DOTLOCK_LOCK_BY_PARENT | DOTLOCK_LOCKED);
+ }
+#endif
+ if ((flags & ~DOTLOCK_PREPARE_CREATE))
{
my_set_errno (EINVAL);
return NULL;
@@ -905,6 +1068,10 @@ dotlock_create (const char *file_to_lock, unsigned int flags)
if (!h)
return NULL;
h->extra_fd = -1;
+#ifndef HAVE_DOSISH_SYSTEM
+ h->by_parent = by_parent;
+ h->no_write = no_write;
+#endif
if (never_lock)
{
@@ -916,6 +1083,24 @@ dotlock_create (const char *file_to_lock, unsigned int flags)
return h;
}
+ if ((flags & DOTLOCK_PREPARE_CREATE))
+ return h;
+ else
+ return dotlock_finish_create (h, file_to_lock);
+}
+
+
+/* This function may be used along with dotlock_create (file_name,
+ * DOTLOCK_PREPARE_CREATE) to finish the creation call. The given
+ * filename shall be the same as passed to dotlock_create. On success
+ * the same handle H is returned, on error NULL is returned and H is
+ * released. */
+dotlock_t
+dotlock_finish_create (dotlock_t h, const char *file_to_lock)
+{
+ if (!h || !file_to_lock)
+ return NULL;
+
#ifdef HAVE_DOSISH_SYSTEM
return dotlock_create_w32 (h, file_to_lock);
#else /*!HAVE_DOSISH_SYSTEM */
@@ -942,6 +1127,24 @@ dotlock_get_fd (dotlock_t h)
}
+/* Set a callback function for info diagnostics. The callback
+ * function CB is called with the handle, the opaque value OPAQUE, a
+ * reason code, and a format string with its arguments. The callback
+ * shall return 0 to continue operation or true in which case the
+ * current function will be terminated with an error. */
+void
+dotlock_set_info_cb (dotlock_t h,
+ int (*cb)(dotlock_t, void *,
+ enum dotlock_reasons reason,
+ const char *,...),
+ void *opaque)
+{
+ h->info_cb = cb;
+ h->info_cb_value = opaque;
+}
+
+
+
#ifdef HAVE_POSIX_SYSTEM
/* Unix specific code of destroy_dotlock. */
@@ -952,7 +1155,6 @@ dotlock_destroy_unix (dotlock_t h)
unlink (h->lockname);
if (h->tname && !h->use_o_excl)
unlink (h->tname);
- xfree (h->tname);
}
#endif /*HAVE_POSIX_SYSTEM*/
@@ -998,15 +1200,28 @@ dotlock_destroy (dotlock_t h)
UNLOCK_all_lockfiles ();
/* Then destroy the lock. */
- if (!h->disable)
+ if (!h->disable
+ && (!h->by_parent || h->no_write))
{
+ /* NOTE: under the condition of (by_parent && !no_write),
+ it doesn't come here. So, the lock file remains. */
#ifdef HAVE_DOSISH_SYSTEM
dotlock_destroy_w32 (h);
#else /* !HAVE_DOSISH_SYSTEM */
dotlock_destroy_unix (h);
#endif /* HAVE_DOSISH_SYSTEM */
- xfree (h->lockname);
}
+
+#ifdef HAVE_POSIX_SYSTEM
+ /* When DOTLOCK_LOCK_BY_PARENT and lock fails,
+ the temporary file created should be removed. */
+ if (h->by_parent && !h->no_write && !h->locked)
+ if (h->tname && !h->use_o_excl)
+ unlink (h->tname);
+
+ xfree (h->tname);
+#endif
+ xfree (h->lockname);
xfree(h);
}
@@ -1061,6 +1276,7 @@ static int
dotlock_take_unix (dotlock_t h, long timeout)
{
int wtime = 0;
+ int timedout = 0;
int sumtime = 0;
int pid;
int lastpid = -1;
@@ -1089,6 +1305,10 @@ dotlock_take_unix (dotlock_t h, long timeout)
saveerrno = errno;
my_error_2 ("lock not made: open(O_EXCL) of '%s' failed: %s\n",
h->lockname, strerror (saveerrno));
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
+ "lock not made: open(O_EXCL) of '%s' failed: %s\n",
+ h->lockname, strerror (saveerrno));
my_set_errno (saveerrno);
return -1;
}
@@ -1096,7 +1316,8 @@ dotlock_take_unix (dotlock_t h, long timeout)
{
char pidstr[16];
- snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid());
+ snprintf (pidstr, sizeof pidstr, "%10d\n",
+ dotlock_get_process_id (h));
if (write (fd, pidstr, 11 ) == 11
&& write (fd, h->tname + h->nodename_off,h->nodename_len)
== h->nodename_len
@@ -1110,6 +1331,10 @@ dotlock_take_unix (dotlock_t h, long timeout)
saveerrno = errno;
my_error_2 ("lock not made: writing to '%s' failed: %s\n",
h->lockname, strerror (errno));
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
+ "lock not made: writing to '%s' failed: %s\n",
+ h->lockname, strerror (errno));
close (fd);
unlink (h->lockname);
my_set_errno (saveerrno);
@@ -1128,6 +1353,10 @@ dotlock_take_unix (dotlock_t h, long timeout)
saveerrno = errno;
my_error_1 ("lock not made: Oops: stat of tmp file failed: %s\n",
strerror (errno));
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
+ "lock not made: Oops: stat of tmp file failed: %s\n",
+ strerror (errno));
/* In theory this might be a severe error: It is possible
that link succeeded but stat failed due to changed
permissions. We can't do anything about it, though. */
@@ -1149,16 +1378,19 @@ dotlock_take_unix (dotlock_t h, long timeout)
{
saveerrno = errno;
my_info_0 ("cannot read lockfile\n");
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
+ "cannot read lockfile\n");
my_set_errno (saveerrno);
return -1;
}
my_info_0 ("lockfile disappeared\n");
goto again;
}
- else if ( (pid == getpid() && same_node)
+ else if ( (pid == dotlock_get_process_id (h) && same_node && !h->by_parent)
|| (same_node && kill (pid, 0) && errno == ESRCH) )
- /* Stale lockfile is detected. */
{
+ /* Stale lockfile is detected. */
struct stat sb;
/* Check if it's unlocked during examining the lockfile. */
@@ -1201,6 +1433,9 @@ dotlock_take_unix (dotlock_t h, long timeout)
unlink (h->lockname);
my_info_1 (_("removing stale lockfile (created by %d)\n"), pid);
close (fd);
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_STALE_REMOVED,
+ _("removing stale lockfile (created by %d)\n"), pid);
goto again;
}
@@ -1218,6 +1453,8 @@ dotlock_take_unix (dotlock_t h, long timeout)
wtime = 0; /* Reset because owner chnaged. */
wtimereal = next_wait_interval (&wtime, &timeout);
+ if (!timeout)
+ timedout = 1; /* remember. */
sumtime += wtimereal;
if (sumtime >= 1500)
@@ -1225,6 +1462,15 @@ dotlock_take_unix (dotlock_t h, long timeout)
sumtime = 0;
my_info_3 (_("waiting for lock (held by %d%s) %s...\n"),
pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):"");
+ if (h->info_cb
+ && h->info_cb (h, h->info_cb_value, DOTLOCK_WAITING,
+ _("waiting for lock (held by %d%s) %s...\n"),
+ pid, maybe_dead,
+ maybe_deadlock(h)? _("(deadlock?) "):""))
+ {
+ my_set_errno (ECANCELED);
+ return -1;
+ }
}
tv.tv_sec = wtimereal / 1000;
@@ -1233,7 +1479,7 @@ dotlock_take_unix (dotlock_t h, long timeout)
goto again;
}
- my_set_errno (EACCES);
+ my_set_errno (timedout? ETIMEDOUT : EACCES);
return -1;
}
#endif /*HAVE_POSIX_SYSTEM*/
@@ -1246,6 +1492,7 @@ static int
dotlock_take_w32 (dotlock_t h, long timeout)
{
int wtime = 0;
+ int timedout = 0;
int w32err;
OVERLAPPED ovl;
@@ -1264,7 +1511,11 @@ dotlock_take_w32 (dotlock_t h, long timeout)
{
my_error_2 (_("lock '%s' not made: %s\n"),
h->lockname, w32_strerror (w32err));
- my_set_errno (map_w32_to_errno (w32err));
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
+ _("lock '%s' not made: %s\n"),
+ h->lockname, w32_strerror (w32err));
+ _set_errno (map_w32_to_errno (w32err));
return -1;
}
@@ -1273,15 +1524,26 @@ dotlock_take_w32 (dotlock_t h, long timeout)
int wtimereal;
wtimereal = next_wait_interval (&wtime, &timeout);
+ if (!timeout)
+ timedout = 1; /* remember. */
if (wtime >= 800)
- my_info_1 (_("waiting for lock %s...\n"), h->lockname);
+ {
+ my_info_1 (_("waiting for lock %s...\n"), h->lockname);
+ if (h->info_cb
+ && h->info_cb (h, h->info_cb_value, DOTLOCK_WAITING,
+ _("waiting for lock %s...\n"), h->lockname))
+ {
+ my_set_errno (ECANCELED);
+ return -1;
+ }
+ }
Sleep (wtimereal);
goto again;
}
- my_set_errno (EACCES);
+ my_set_errno (timedout? ETIMEDOUT : EACCES);
return -1;
}
#endif /*HAVE_DOSISH_SYSTEM*/
@@ -1328,12 +1590,18 @@ dotlock_release_unix (dotlock_t h)
{
saveerrno = errno;
my_error_0 ("release_dotlock: lockfile error\n");
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
+ "release_dotlock: lockfile error\n");
my_set_errno (saveerrno);
return -1;
}
- if ( pid != getpid() || !same_node )
+ if ( pid != dotlock_get_process_id (h) || !same_node )
{
my_error_1 ("release_dotlock: not our lock (pid=%d)\n", pid);
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_CONFLICT,
+ "release_dotlock: not our lock (pid=%d)\n", pid);
my_set_errno (EACCES);
return -1;
}
@@ -1343,6 +1611,10 @@ dotlock_release_unix (dotlock_t h)
saveerrno = errno;
my_error_1 ("release_dotlock: error removing lockfile '%s'\n",
h->lockname);
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
+ "release_dotlock: error removing lockfile '%s'\n",
+ h->lockname);
my_set_errno (saveerrno);
return -1;
}
@@ -1363,10 +1635,15 @@ dotlock_release_w32 (dotlock_t h)
memset (&ovl, 0, sizeof ovl);
if (!UnlockFileEx (h->lockhd, 0, 1, 0, &ovl))
{
- int saveerrno = map_w32_to_errno (GetLastError ());
+ int ec = (int)GetLastError ();
+
my_error_2 ("release_dotlock: error removing lockfile '%s': %s\n",
- h->lockname, w32_strerror (-1));
- my_set_errno (saveerrno);
+ h->lockname, w32_strerror (ec));
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
+ "release_dotlock: error removing lockfile '%s': %s\n",
+ h->lockname, w32_strerror (ec));
+ my_set_errno (map_w32_to_errno (ec));
return -1;
}
@@ -1397,6 +1674,9 @@ dotlock_release (dotlock_t h)
if ( !h->locked )
{
my_debug_1 ("Oops, '%s' is not locked\n", h->lockname);
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_NOT_LOCKED,
+ "Oops, '%s' is not locked\n", h->lockname);
return 0;
}
diff --git a/common/dotlock.h b/common/dotlock.h
index 03131bb0c..0f52d4037 100644
--- a/common/dotlock.h
+++ b/common/dotlock.h
@@ -97,12 +97,35 @@ extern "C"
struct dotlock_handle;
typedef struct dotlock_handle *dotlock_t;
+enum dotlock_reasons
+ {
+ DOTLOCK_CONFIG_TEST, /* Can't check system - function terminates. */
+ DOTLOCK_FILE_ERROR, /* General file error - function terminates. */
+ DOTLOCK_INV_FILE, /* Invalid file - function terminates. */
+ DOTLOCK_CONFLICT, /* Something is wrong - function terminates. */
+ DOTLOCK_NOT_LOCKED, /* Not locked - No action required. */
+ DOTLOCK_STALE_REMOVED, /* Stale lock file was removed - retrying. */
+ DOTLOCK_WAITING /* Waiting for the lock - may be terminated. */
+ };
+
+/* Flags for dotlock_create. */
+#define DOTLOCK_PREPARE_CREATE (1U << 5) /* Require dotlock_finish_create. */
+#define DOTLOCK_LOCK_BY_PARENT (1U << 6) /* Used by dotlock util. */
+#define DOTLOCK_LOCKED (1U << 7) /* Used by dotlock util. */
+
void dotlock_disable (void);
dotlock_t dotlock_create (const char *file_to_lock, unsigned int flags);
+dotlock_t dotlock_finish_create (dotlock_t h, const char *file_to_lock);
void dotlock_set_fd (dotlock_t h, int fd);
int dotlock_get_fd (dotlock_t h);
+void dotlock_set_info_cb (dotlock_t h,
+ int (*cb)(dotlock_t, void *,
+ enum dotlock_reasons reason,
+ const char *,...),
+ void *opaque);
void dotlock_destroy (dotlock_t h);
int dotlock_take (dotlock_t h, long timeout);
+int dotlock_is_locked (dotlock_t h);
int dotlock_release (dotlock_t h);
void dotlock_remove_lockfiles (void);
diff --git a/common/homedir.c b/common/homedir.c
index 286685feb..2b99c9bdc 100644
--- a/common/homedir.c
+++ b/common/homedir.c
@@ -77,6 +77,14 @@
#endif
+/* Mode flags for unix_rootdir. */
+enum wantdir_values {
+ WANTDIR_ROOT = 0,
+ WANTDIR_SYSCONF,
+ WANTDIR_SOCKET
+};
+
+
/* The GnuPG homedir. This is only accessed by the functions
* gnupg_homedir and gnupg_set_homedir. Malloced. */
static char *the_gnupg_homedir;
@@ -491,11 +499,12 @@ w32_rootdir (void)
* file system. If WANT_SYSCONFDIR is true the optional sysconfdir
* entry is returned. */
static const char *
-unix_rootdir (int want_sysconfdir)
+unix_rootdir (enum wantdir_values wantdir)
{
static int checked;
static char *dir; /* for the rootdir */
static char *sdir; /* for the sysconfdir */
+ static char *s2dir; /* for the socketdir */
if (!checked)
{
@@ -510,8 +519,10 @@ unix_rootdir (int want_sysconfdir)
estream_t fp;
char *rootdir;
char *sysconfdir;
+ char *socketdir;
const char *name;
int ignoreall = 0;
+ int okay;
for (;;)
{
@@ -602,45 +613,44 @@ unix_rootdir (int want_sysconfdir)
linelen = 0;
rootdir = NULL;
sysconfdir = NULL;
+ socketdir = NULL;
while ((length = es_read_line (fp, &line, &linelen, NULL)) > 0)
{
+ static const char *names[] =
+ {
+ "rootdir",
+ "sysconfdir",
+ "socketdir",
+ ".enable"
+ };
+ int i;
+ size_t n;
+
/* Strip NL and CR, if present. */
while (length > 0
&& (line[length - 1] == '\n' || line[length - 1] == '\r'))
line[--length] = 0;
trim_spaces (line);
- if (!strncmp (line, "rootdir=", 8))
- {
- name = "rootdir";
- p = line + 8;
- }
- else if (!strncmp (line, "rootdir =", 9)) /* (What a kludge) */
- {
- name = "rootdir";
- p = line + 9;
- }
- else if (!strncmp (line, "sysconfdir=", 11))
+ /* Find the stamement. */
+ name = NULL;
+ for (i=0; i < DIM (names); i++)
{
- name = "sysconfdir";
- p = line + 11;
- }
- else if (!strncmp (line, "sysconfdir =", 12)) /* (What a kludge) */
- {
- name = "sysconfdir";
- p = line + 12;
- }
- else if (!strncmp (line, ".enable=", 8))
- {
- name = ".enable";
- p = line + 8;
- }
- else if (!strncmp (line, ".enable =", 9))
- {
- name = ".enable";
- p = line + 9;
+ n = strlen (names[i]);
+ if (!strncmp (line, names[i], n))
+ {
+ while (line[n] == ' ' || line[n] == '\t')
+ n++;
+ if (line[n] == '=')
+ {
+ name = names[i];
+ p = line + n + 1;
+ break;
+ }
+ }
}
- else
- continue;
+ if (!name)
+ continue; /* Statement not known. */
+
trim_spaces (p);
p = substitute_envvars (p);
if (!p)
@@ -665,6 +675,11 @@ unix_rootdir (int want_sysconfdir)
xfree (sysconfdir);
sysconfdir = p;
}
+ else if (!strcmp (name, "socketdir"))
+ {
+ xfree (socketdir);
+ socketdir = p;
+ }
else
{
xfree (rootdir);
@@ -680,6 +695,7 @@ unix_rootdir (int want_sysconfdir)
xfree (line);
xfree (rootdir);
xfree (sysconfdir);
+ xfree (socketdir);
checked = 1;
return NULL;
}
@@ -687,29 +703,26 @@ unix_rootdir (int want_sysconfdir)
xfree (buffer);
xfree (line);
+ okay = 0;
if (ignoreall)
- {
- xfree (rootdir);
- xfree (sysconfdir);
- sdir = dir = NULL;
- }
+ ;
else if (!rootdir || !*rootdir || *rootdir != '/')
{
log_info ("invalid rootdir '%s' specified in gpgconf.ctl\n", rootdir);
- xfree (rootdir);
- xfree (sysconfdir);
- dir = NULL;
}
else if (sysconfdir && (!*sysconfdir || *sysconfdir != '/'))
{
log_info ("invalid sysconfdir '%s' specified in gpgconf.ctl\n",
sysconfdir);
- xfree (rootdir);
- xfree (sysconfdir);
- dir = NULL;
+ }
+ else if (socketdir && (!*socketdir || *socketdir != '/'))
+ {
+ log_info ("invalid socketdir '%s' specified in gpgconf.ctl\n",
+ socketdir);
}
else
{
+ okay = 1;
while (*rootdir && rootdir[strlen (rootdir)-1] == '/')
rootdir[strlen (rootdir)-1] = 0;
dir = rootdir;
@@ -723,11 +736,34 @@ unix_rootdir (int want_sysconfdir)
gpgrt_annotate_leaked_object (sdir);
/* log_info ("want sysconfdir '%s'\n", sdir); */
}
+ if (socketdir)
+ {
+ while (*socketdir && socketdir[strlen (socketdir)-1] == '/')
+ socketdir[strlen (socketdir)-1] = 0;
+ s2dir = socketdir;
+ gpgrt_annotate_leaked_object (s2dir);
+ /* log_info ("want socketdir '%s'\n", s2dir); */
+ }
+ }
+
+ if (!okay)
+ {
+ xfree (rootdir);
+ xfree (sysconfdir);
+ xfree (socketdir);
+ dir = sdir = s2dir = NULL;
}
checked = 1;
}
- return want_sysconfdir? sdir : dir;
+ switch (wantdir)
+ {
+ case WANTDIR_ROOT: return dir;
+ case WANTDIR_SYSCONF: return sdir;
+ case WANTDIR_SOCKET: return s2dir;
+ }
+
+ return NULL; /* Not reached. */
}
#endif /* Unix */
@@ -1038,7 +1074,8 @@ _gnupg_socketdir_internal (int skip_checks, unsigned *r_info)
};
int i;
struct stat sb;
- char prefix[19 + 1 + 20 + 6 + 1];
+ char prefixbuffer[19 + 1 + 20 + 6 + 1];
+ const char *prefix;
const char *s;
char *name = NULL;
@@ -1053,35 +1090,42 @@ _gnupg_socketdir_internal (int skip_checks, unsigned *r_info)
* as a background process with no (desktop) user logged in. Thus
* we better don't do that. */
- /* Check whether we have a /run/[gnupg/]user dir. */
- for (i=0; bases[i]; i++)
- {
- snprintf (prefix, sizeof prefix, "%s/user/%u",
- bases[i], (unsigned int)getuid ());
- if (!stat (prefix, &sb) && S_ISDIR(sb.st_mode))
- break;
- }
- if (!bases[i])
+ prefix = unix_rootdir (WANTDIR_SOCKET);
+ if (!prefix)
{
- *r_info |= 2; /* No /run/user directory. */
- goto leave;
- }
+ /* gpgconf.ctl does not specify a directory. Check whether we
+ * have the usual /run/[gnupg/]user dir. */
+ for (i=0; bases[i]; i++)
+ {
+ snprintf (prefixbuffer, sizeof prefixbuffer, "%s/user/%u",
+ bases[i], (unsigned int)getuid ());
+ prefix = prefixbuffer;
+ if (!stat (prefix, &sb) && S_ISDIR(sb.st_mode))
+ break;
+ }
+ if (!bases[i])
+ {
+ *r_info |= 2; /* No /run/user directory. */
+ goto leave;
+ }
- if (sb.st_uid != getuid ())
- {
- *r_info |= 4; /* Not owned by the user. */
- if (!skip_checks)
- goto leave;
- }
+ if (sb.st_uid != getuid ())
+ {
+ *r_info |= 4; /* Not owned by the user. */
+ if (!skip_checks)
+ goto leave;
+ }
- if (strlen (prefix) + 7 >= sizeof prefix)
- {
- *r_info |= 1; /* Ooops: Buffer too short to append "/gnupg". */
- goto leave;
+ if (strlen (prefix) + 7 >= sizeof prefixbuffer)
+ {
+ *r_info |= 1; /* Ooops: Buffer too short to append "/gnupg". */
+ goto leave;
+ }
+ strcat (prefixbuffer, "/gnupg");
}
- strcat (prefix, "/gnupg");
- /* Check whether the gnupg sub directory has proper permissions. */
+ /* Check whether the gnupg sub directory (or the specified diretory)
+ * has proper permissions. */
if (stat (prefix, &sb))
{
if (errno != ENOENT)
@@ -1241,7 +1285,7 @@ gnupg_sysconfdir (void)
}
return name;
#else /*!HAVE_W32_SYSTEM*/
- const char *dir = unix_rootdir (1);
+ const char *dir = unix_rootdir (WANTDIR_SYSCONF);
if (dir)
return dir;
else
@@ -1270,7 +1314,7 @@ gnupg_bindir (void)
else
return rdir;
#else /*!HAVE_W32_SYSTEM*/
- rdir = unix_rootdir (0);
+ rdir = unix_rootdir (WANTDIR_ROOT);
if (rdir)
{
if (!name)
@@ -1297,7 +1341,7 @@ gnupg_libexecdir (void)
static char *name;
const char *rdir;
- rdir = unix_rootdir (0);
+ rdir = unix_rootdir (WANTDIR_ROOT);
if (rdir)
{
if (!name)
@@ -1327,7 +1371,7 @@ gnupg_libdir (void)
#else /*!HAVE_W32_SYSTEM*/
const char *rdir;
- rdir = unix_rootdir (0);
+ rdir = unix_rootdir (WANTDIR_ROOT);
if (rdir)
{
if (!name)
@@ -1358,7 +1402,7 @@ gnupg_datadir (void)
#else /*!HAVE_W32_SYSTEM*/
const char *rdir;
- rdir = unix_rootdir (0);
+ rdir = unix_rootdir (WANTDIR_ROOT);
if (rdir)
{
if (!name)
@@ -1390,7 +1434,7 @@ gnupg_localedir (void)
#else /*!HAVE_W32_SYSTEM*/
const char *rdir;
- rdir = unix_rootdir (0);
+ rdir = unix_rootdir (WANTDIR_ROOT);
if (rdir)
{
if (!name)
diff --git a/common/name-value.c b/common/name-value.c
index 0dffc63b4..ea6a84f56 100644
--- a/common/name-value.c
+++ b/common/name-value.c
@@ -48,6 +48,7 @@ struct name_value_container
struct name_value_entry *first;
struct name_value_entry *last;
unsigned int private_key_mode:1;
+ unsigned int modified:1;
};
@@ -87,11 +88,15 @@ my_error (gpg_err_code_t ec)
/* Allocation and deallocation. */
-/* Allocate a private key container structure. */
+/* Allocate a name value container structure. */
nvc_t
nvc_new (void)
{
- return xtrycalloc (1, sizeof (struct name_value_container));
+ nvc_t nvc;
+ nvc = xtrycalloc (1, sizeof (struct name_value_container));
+ if (nvc)
+ nvc->modified = 1;
+ return nvc;
}
@@ -142,6 +147,24 @@ nvc_release (nvc_t pk)
xfree (pk);
}
+
+/* Return the modified-flag of the container and clear it if CLEAR is
+ * set. That flag is set for a new container and set with each
+ * update. */
+int
+nvc_modified (nvc_t pk, int clear)
+{
+ int modified;
+
+ if (!pk)
+ return 0;
+ modified = pk->modified;
+ if (clear)
+ pk->modified = 0;
+ return modified;
+}
+
+
/* Dealing with names and values. */
@@ -427,6 +450,8 @@ _nvc_add (nvc_t pk, char *name, char *value, strlist_t raw_value,
else
pk->first = pk->last = e;
+ pk->modified = 1;
+
leave:
if (err)
{
@@ -476,36 +501,29 @@ nvc_set (nvc_t pk, const char *name, const char *value)
e = nvc_lookup (pk, name);
if (e)
- {
- char *v;
-
- v = xtrystrdup (value);
- if (v == NULL)
- return my_error_from_syserror ();
-
- free_strlist_wipe (e->raw_value);
- e->raw_value = NULL;
- if (e->value)
- wipememory (e->value, strlen (e->value));
- xfree (e->value);
- e->value = v;
-
- return 0;
- }
+ return nve_set (pk, e, value);
else
return nvc_add (pk, name, value);
}
-/* Update entry E to VALUE. */
+/* Update entry E to VALUE. PK is optional; if given its modified
+ * flag will be updated. */
gpg_error_t
-nve_set (nve_t e, const char *value)
+nve_set (nvc_t pk, nve_t e, const char *value)
{
char *v;
if (!e)
return GPG_ERR_INV_ARG;
+ if (e->value && value && !strcmp (e->value, value))
+ {
+ /* Setting same value - ignore this call and don't set the
+ * modified flag (if PK is given). */
+ return 0;
+ }
+
v = xtrystrdup (value? value:"");
if (!v)
return my_error_from_syserror ();
@@ -516,6 +534,8 @@ nve_set (nve_t e, const char *value)
wipememory (e->value, strlen (e->value));
xfree (e->value);
e->value = v;
+ if (pk)
+ pk->modified = 1;
return 0;
}
@@ -536,6 +556,7 @@ nvc_delete (nvc_t pk, nve_t entry)
pk->last = entry->prev;
nve_release (entry, pk->private_key_mode);
+ pk->modified = 1;
}
diff --git a/common/name-value.h b/common/name-value.h
index b3fc2f63c..dfded6678 100644
--- a/common/name-value.h
+++ b/common/name-value.h
@@ -50,6 +50,9 @@ nvc_t nvc_new_private_key (void);
/* Release a name value container structure. */
void nvc_release (nvc_t pk);
+/* Return the modified flag and optionally clear it. */
+int nvc_modified (nvc_t pk, int clear);
+
/* Get the name. */
char *nve_name (nve_t pke);
@@ -92,8 +95,8 @@ gpg_error_t nvc_add (nvc_t pk, const char *name, const char *value);
first entry is updated. */
gpg_error_t nvc_set (nvc_t pk, const char *name, const char *value);
-/* Update entry E to VALUE. */
-gpg_error_t nve_set (nve_t e, const char *value);
+/* Update entry E to VALUE. PK is optional. */
+gpg_error_t nve_set (nvc_t pk, nve_t e, const char *value);
/* Delete the given entry from PK. */
void nvc_delete (nvc_t pk, nve_t pke);
diff --git a/common/openpgpdefs.h b/common/openpgpdefs.h
index c97995568..d8672ac47 100644
--- a/common/openpgpdefs.h
+++ b/common/openpgpdefs.h
@@ -122,6 +122,9 @@ typedef enum
SIGSUBPKT_ATTST_SIGS = 37, /* Attested Certifications. */
SIGSUBPKT_KEY_BLOCK = 38, /* Entire key used. */
+ SIGSUBPKT_META_HASH = 40, /* Literal Data Meta Hash. */
+ SIGSUBPKT_TRUST_ALIAS = 41, /* Trust Alias. */
+
SIGSUBPKT_FLAG_CRITICAL = 128
}
sigsubpkttype_t;
diff --git a/common/t-dotlock.c b/common/t-dotlock.c
index 994ef1be3..87e62bb33 100644
--- a/common/t-dotlock.c
+++ b/common/t-dotlock.c
@@ -52,6 +52,7 @@
#ifdef HAVE_W32_SYSTEM
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
+
const char *
w32_strerror (int ec)
{
@@ -174,6 +175,11 @@ strconcat (const char *s1, ...)
#define PGM "t-dotlock"
+static int opt_silent;
+
+
+
+
#ifndef HAVE_W32_SYSTEM
static volatile int ctrl_c_pending_flag;
static void
@@ -217,6 +223,9 @@ inf (const char *format, ...)
{
va_list arg_ptr;
+ if (opt_silent)
+ return;
+
va_start (arg_ptr, format);
fprintf (stderr, PGM "[%lu]: ", (unsigned long)getpid ());
vfprintf (stderr, format, arg_ptr);
@@ -225,15 +234,35 @@ inf (const char *format, ...)
}
+static int
+lock_info_cb (dotlock_t h, void *opaque, enum dotlock_reasons reason,
+ const char *format, ...)
+{
+ va_list arg_ptr;
+
+ va_start (arg_ptr, format);
+ fprintf (stderr, PGM "[%lu]: info_cb: reason %d, ",
+ (unsigned long)getpid (), (int)reason);
+ vfprintf (stderr, format, arg_ptr);
+ va_end (arg_ptr);
+ return 0;
+}
+
+
static void
lock_and_unlock (const char *fname)
{
dotlock_t h;
unsigned long usec;
- h = dotlock_create (fname, 0);
+ h = dotlock_create (fname, DOTLOCK_PREPARE_CREATE);
if (!h)
die ("error creating lock file for '%s': %s", fname, strerror (errno));
+ dotlock_set_info_cb (h, lock_info_cb, NULL);
+ h = dotlock_finish_create (h, fname);
+ if (!h)
+ die ("error finishing lock file creation for '%s': %s",
+ fname, strerror (errno));
inf ("lock created");
do
@@ -270,6 +299,11 @@ main (int argc, char **argv)
ctrl_c_pending_flag = 1;
argc--;
}
+ if (argc > 1 && !strcmp (argv[1], "--silent"))
+ {
+ opt_silent = 1;
+ argc--;
+ }
if (argc > 1)
fname = argv[argc-1];
diff --git a/doc/opt-homedir.texi b/doc/opt-homedir.texi
index 07993d29d..15ae1970d 100644
--- a/doc/opt-homedir.texi
+++ b/doc/opt-homedir.texi
@@ -13,13 +13,3 @@ directory stated through the environment variable @env{GNUPGHOME} or
On Windows systems it is possible to install GnuPG as a portable
application. In this case only this command line option is
considered, all other ways to set a home directory are ignored.
-
-@efindex gpgconf.ctl
-To install GnuPG as a portable application under Windows, create an
-empty file named @file{gpgconf.ctl} in the same directory as the tool
-@file{gpgconf.exe}. The root of the installation is then that
-directory; or, if @file{gpgconf.exe} has been installed directly below
-a directory named @file{bin}, its parent directory. You also need to
-make sure that the following directories exist and are writable:
-@file{ROOT/home} for the GnuPG home and @file{ROOT@value{LOCALCACHEDIR}}
-for internal cache files.
diff --git a/doc/tools.texi b/doc/tools.texi
index a7c141cfc..07a50820b 100644
--- a/doc/tools.texi
+++ b/doc/tools.texi
@@ -1122,10 +1122,36 @@ More fields may be added in future to the output.
@table @file
+@item gpgconf.ctl
+@cindex gpgconf.ctl
+ Under Unix @file{gpgconf.ctl} may be used to change some of the
+ compiled in directories where the GnuPG components are expected. This
+ file is expected in the same directory as @file{gpgconf}. The
+ physical installation directories are evaluated and no symlinks.
+ Blank lines and lines starting with pound sign are ignored in the
+ file. The keywords must be followed by optional white space, an equal
+ sign, optional white space, and the value. Environment variables are
+ substituted in standard shell manner, the final value must start with
+ a slash, trailing slashes are stripped. Valid keywords are
+ @code{rootdir}, @code{sysconfdir}, @code{socketdir}, and
+ @code{.enable}. No errors are printed for unknown keywords. The
+ @code{.enable} keyword is special: if the keyword is used and its
+ value evaluates to true the entire file is ignored.
+
+ Under Windows this file is used to install GnuPG as a portable
+ application. An empty file named @file{gpgconf.ctl} is expected in
+ the same directory as the tool @file{gpgconf.exe}. The root of the
+ installation is then that directory; or, if @file{gpgconf.exe} has
+ been installed directly below a directory named @file{bin}, its parent
+ directory. You also need to make sure that the following directories
+ exist and are writable: @file{ROOT/home} for the GnuPG home and
+ @file{ROOT@value{LOCALCACHEDIR}} for internal cache files.
+
+
@item /etc/gnupg/gpgconf.conf
@cindex gpgconf.conf
If this file exists, it is processed as a global configuration file.
- This is a legacy mechanism which should not be used tigether with
+ This is a legacy mechanism which should not be used together with
the modern global per component configuration files. A commented
example can be found in the @file{examples} directory of the
distribution.
diff --git a/doc/wks.texi b/doc/wks.texi
index 1959151a1..8c5fc557c 100644
--- a/doc/wks.texi
+++ b/doc/wks.texi
@@ -243,6 +243,21 @@ Display a brief help page and exit.
@end table
+@noindent
+@mansect examples
+@chapheading Examples
+
+To use the services with clients lacking integrated support, the
+mailcap mechanism can be used. Simply put:
+@example
+application/vnd.gnupg.wks; \
+ @value{BINDIR}/gpg-wks-client -v --read --send; \
+ needsterminal; \
+ description=WKS message
+@end example
+into the @file{/etc/mailcap}. This assumes that a /usr/lib/sendmail
+is installed. With this configuration any real mail programs will run
+gpg-wks-client for messages received from a Web Key Service.
@mansect see also
@ifset isman
diff --git a/g10/call-agent.c b/g10/call-agent.c
index c44c1cddb..f545b6690 100644
--- a/g10/call-agent.c
+++ b/g10/call-agent.c
@@ -1996,7 +1996,7 @@ agent_get_passphrase (const char *cache_id,
char *arg4 = NULL;
membuf_t data;
struct default_inq_parm_s dfltparm;
- int have_newsymkey;
+ int have_newsymkey, wasconf;
memset (&dfltparm, 0, sizeof dfltparm);
@@ -2048,10 +2048,14 @@ agent_get_passphrase (const char *cache_id,
xfree (arg4);
init_membuf_secure (&data, 64);
+ wasconf = assuan_get_flag (agent_ctx, ASSUAN_CONFIDENTIAL);
+ assuan_begin_confidential (agent_ctx);
rc = assuan_transact (agent_ctx, line,
put_membuf_cb, &data,
default_inq_cb, &dfltparm,
NULL, NULL);
+ if (!wasconf)
+ assuan_end_confidential (agent_ctx);
if (rc)
xfree (get_membuf (&data, NULL));
diff --git a/g10/call-keyboxd.c b/g10/call-keyboxd.c
index 960979aae..bc3806f0b 100644
--- a/g10/call-keyboxd.c
+++ b/g10/call-keyboxd.c
@@ -393,6 +393,23 @@ keydb_get_keyblock (KEYDB_HANDLE hd, kbnode_t *ret_kb)
}
+/* Default status callback used to show diagnostics from the keyboxd */
+static gpg_error_t
+keydb_default_status_cb (void *opaque, const char *line)
+{
+ const char *s;
+
+ (void)opaque;
+
+ if ((s = has_leading_keyword (line, "NOTE")))
+ log_info (_("Note: %s\n"), s);
+ else if ((s = has_leading_keyword (line, "WARNING")))
+ log_info (_("WARNING: %s\n"), s);
+
+ return 0;
+}
+
+
/* Communication object for STORE commands. */
struct store_parm_s
@@ -472,7 +489,8 @@ keydb_update_keyblock (ctrl_t ctrl, KEYDB_HANDLE hd, kbnode_t kb)
err = assuan_transact (hd->kbl->ctx, "STORE --update",
NULL, NULL,
store_inq_cb, &parm,
- NULL, NULL);
+ keydb_default_status_cb, hd);
+
leave:
iobuf_close (iobuf);
@@ -523,7 +541,7 @@ keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
err = assuan_transact (hd->kbl->ctx, "STORE --insert",
NULL, NULL,
store_inq_cb, &parm,
- NULL, NULL);
+ keydb_default_status_cb, hd);
leave:
iobuf_close (iobuf);
@@ -569,7 +587,7 @@ keydb_delete_keyblock (KEYDB_HANDLE hd)
err = assuan_transact (hd->kbl->ctx, line,
NULL, NULL,
NULL, NULL,
- NULL, NULL);
+ keydb_default_status_cb, hd);
leave:
return err;
@@ -656,6 +674,8 @@ search_status_cb (void *opaque, const char *line)
}
}
}
+ else
+ err = keydb_default_status_cb (opaque, line);
return err;
}
diff --git a/g10/keyedit.c b/g10/keyedit.c
index 21c1ee8d8..1f614fb7e 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -4794,7 +4794,7 @@ fail:
/*
* Ask for a new additional decryption subkey and add it to the key
* block. Returns true if the keyblock was changed and false
- * otherwise. If ADSKFPR is not NULL, this fucntion has been called
+ * otherwise. If ADSKFPR is not NULL, this function has been called
* by quick_addadsk and gives the fingerprint of the to be added key.
*/
static int
diff --git a/kbx/backend-sqlite.c b/kbx/backend-sqlite.c
index 202897e91..ec891da6d 100644
--- a/kbx/backend-sqlite.c
+++ b/kbx/backend-sqlite.c
@@ -521,11 +521,45 @@ run_sql_statement (const char *sqlstr)
}
+static int
+dblock_info_cb (dotlock_t h, void *opaque, enum dotlock_reasons reason,
+ const char *format, ...)
+{
+ ctrl_t ctrl = opaque;
+ va_list arg_ptr;
+ gpg_error_t err;
+ int rc = 0;
+ char tmpbuf[200];
+
+ (void)h;
+
+ if (reason == DOTLOCK_WAITING)
+ {
+ if (format)
+ {
+ va_start (arg_ptr, format);
+ gpgrt_vsnprintf (tmpbuf, sizeof tmpbuf, format, arg_ptr);
+ va_end (arg_ptr);
+ }
+ else
+ *tmpbuf = 0;
+ err = kbxd_status_printf (ctrl, "NOTE", "database_open %u %s",
+ gpg_error (GPG_ERR_LOCKED), tmpbuf);
+ if (err)
+ {
+ log_error ("sending status line failed: %s\n", gpg_strerror (err));
+ rc = 1; /* snprintf failed. */
+ }
+
+ }
+ return rc;
+}
+
/* Create and initialize a new SQL database file if it does not
* exists; else open it and check that all required objects are
* available. */
static gpg_error_t
-create_or_open_database (const char *filename)
+create_or_open_database (ctrl_t ctrl, const char *filename)
{
gpg_error_t err;
int res;
@@ -542,7 +576,16 @@ create_or_open_database (const char *filename)
/* To avoid races with other temporary instances of keyboxd trying
* to create or update the database, we run the database with a lock
* file held. */
- database_lock = dotlock_create (filename, 0);
+ database_lock = dotlock_create (filename, DOTLOCK_PREPARE_CREATE);
+ if (!database_lock)
+ {
+ err = gpg_error_from_syserror ();
+ if (opt.verbose)
+ log_info ("can't allocate dotlock handle: %s\n", gpg_strerror (err));
+ goto leave;
+ }
+ dotlock_set_info_cb (database_lock, dblock_info_cb, ctrl);
+ database_lock = dotlock_finish_create (database_lock, filename);
if (!database_lock)
{
err = gpg_error_from_syserror ();
@@ -556,7 +599,7 @@ create_or_open_database (const char *filename)
goto leave;
}
- if (dotlock_take (database_lock, -1))
+ if (dotlock_take (database_lock, 10000))
{
err = gpg_error_from_syserror ();
/* This is something bad. Probably a stale lockfile. */
@@ -646,7 +689,8 @@ create_or_open_database (const char *filename)
{
log_error (_("error creating database '%s': %s\n"),
filename, gpg_strerror (err));
- dotlock_release (database_lock);
+ if (dotlock_is_locked (database_lock))
+ dotlock_release (database_lock);
dotlock_destroy (database_lock);
database_lock = NULL;
}
@@ -660,7 +704,6 @@ gpg_error_t
be_sqlite_add_resource (ctrl_t ctrl, backend_handle_t *r_hd,
const char *filename, int readonly)
{
- gpg_error_t err;
backend_handle_t hd;
(void)ctrl;
@@ -672,19 +715,10 @@ be_sqlite_add_resource (ctrl_t ctrl, backend_handle_t *r_hd,
return gpg_error_from_syserror ();
hd->db_type = DB_TYPE_SQLITE;
strcpy (hd->filename, filename);
-
- err = create_or_open_database (filename);
- if (err)
- goto leave;
-
hd->backend_id = be_new_backend_id ();
*r_hd = hd;
- hd = NULL;
-
- leave:
- xfree (hd);
- return err;
+ return 0;
}
@@ -1139,6 +1173,10 @@ be_sqlite_search (ctrl_t ctrl,
log_assert (backend_hd && backend_hd->db_type == DB_TYPE_SQLITE);
log_assert (request);
+ err = create_or_open_database (ctrl, backend_hd->filename);
+ if (err)
+ return err;
+
acquire_mutex ();
/* Find the specific request part or allocate it. */
diff --git a/kbx/kbx-client-util.c b/kbx/kbx-client-util.c
index 2ea3f5ef7..b900586c8 100644
--- a/kbx/kbx-client-util.c
+++ b/kbx/kbx-client-util.c
@@ -405,10 +405,10 @@ kbx_client_data_cmd (kbx_client_data_t kcd, const char *command,
status_cb, status_cb_value);
if (err)
{
- if (gpg_err_code (err) != GPG_ERR_NOT_FOUND
- && gpg_err_code (err) != GPG_ERR_NOTHING_FOUND)
- log_debug ("%s: finished command with error: %s\n",
- __func__, gpg_strerror (err));
+ /* if (gpg_err_code (err) != GPG_ERR_NOT_FOUND */
+ /* && gpg_err_code (err) != GPG_ERR_NOTHING_FOUND) */
+ /* log_debug ("%s: finished command with error: %s\n", */
+ /* __func__, gpg_strerror (err)); */
xfree (get_membuf (&mb, &len));
kcd->dlineerr = err;
goto leave;
diff --git a/kbx/keyboxd.c b/kbx/keyboxd.c
index e8e41486c..f9792789d 100644
--- a/kbx/keyboxd.c
+++ b/kbx/keyboxd.c
@@ -1257,6 +1257,7 @@ create_directories (void)
{
if (!opt.quiet)
log_info (_("directory '%s' created\n"), home);
+ create_public_keys_directory (home);
}
}
}
diff --git a/po/ja.po b/po/ja.po
index 73d141545..d067bf202 100644
--- a/po/ja.po
+++ b/po/ja.po
@@ -9,9 +9,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: gnupg 2.4.1\n"
+"Project-Id-Version: gnupg 2.4.3\n"
"Report-Msgid-Bugs-To: [email protected]\n"
-"PO-Revision-Date: 2023-05-25 11:12+0900\n"
+"PO-Revision-Date: 2023-11-20 10:50+0900\n"
"Last-Translator: NIIBE Yutaka <[email protected]>\n"
"Language-Team: none\n"
"Language: ja\n"
@@ -1789,14 +1789,14 @@ msgid "using cipher %s.%s\n"
msgstr "暗号方式 %s.%s を使います\n"
#, c-format
-msgid "'%s' already compressed\n"
-msgstr "'%s'はもう圧縮済みです\n"
-
-#, c-format
msgid "WARNING: '%s' is an empty file\n"
msgstr "*警告*: '%s'は空のファイルです\n"
#, c-format
+msgid "'%s' already compressed\n"
+msgstr "'%s'はもう圧縮済みです\n"
+
+#, c-format
msgid "digest algorithm '%s' may not be used in %s mode\n"
msgstr "ダイジェスト・アルゴリズム'%s'を%sモードで使うことはできません\n"
@@ -1869,7 +1869,7 @@ msgstr "'%s'への書き込み\n"
#, c-format
msgid "key %s: key material on-card - skipped\n"
-msgstr "鍵%s: 鍵マテリアルはカード上にあります - スキップします\n"
+msgstr "鍵%s: 鍵の実体はカード上にあります - スキップします\n"
#, c-format
msgid "exporting secret keys not allowed\n"
@@ -2893,7 +2893,7 @@ msgstr "鍵 %s: エージェントへの送信エラー: %s\n"
#, c-format
msgid "key %s: card reference is overridden by key material\n"
-msgstr "鍵 %s: カード参照が鍵マテリアルで上書きされます\n"
+msgstr "鍵 %s: カード参照が鍵の実体で上書きされます\n"
#. TRANSLATORS: For a smartcard, each private key on host has a
#. * reference (stub) to a smartcard and actual private key data
diff --git a/scd/apdu.c b/scd/apdu.c
index deb1134e6..98158648b 100644
--- a/scd/apdu.c
+++ b/scd/apdu.c
@@ -775,8 +775,8 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
if (DBG_CARD_IO)
{
/* Do not dump the PIN in a VERIFY command. */
- if (apdulen > 5 && apdu[1] == 0x20)
- log_debug ("PCSC_data: %02X %02X %02X %02X %02X [redacted]\n",
+ if (apdulen > 5 && apdu[1] == 0x20 && !opt.debug_allow_pin_logging)
+ log_debug ("PCSC_data: %02X %02X %02X %02X %02X [hidden]\n",
apdu[0], apdu[1], apdu[2], apdu[3], apdu[4]);
else
log_printhex (apdu, apdulen, "PCSC_data:");
@@ -1564,8 +1564,8 @@ send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen,
if (DBG_CARD_IO)
{
/* Do not dump the PIN in a VERIFY command. */
- if (apdulen > 5 && apdu[1] == 0x20)
- log_debug (" raw apdu: %02x%02x%02x%02x%02x [redacted]\n",
+ if (apdulen > 5 && apdu[1] == 0x20 && !opt.debug_allow_pin_logging)
+ log_debug (" raw apdu: %02x%02x%02x%02x%02x [hidden]\n",
apdu[0], apdu[1], apdu[2], apdu[3], apdu[4]);
else
log_printhex (apdu, apdulen, " raw apdu:");
@@ -3049,7 +3049,9 @@ send_le (int slot, int class, int ins, int p0, int p1,
sw, (unsigned int)resultlen);
if ( !retbuf && (sw == SW_SUCCESS || (sw & 0xff00) == SW_MORE_DATA))
{
- if (all_zero_p (result, resultlen))
+ if (!resultlen)
+ ;
+ else if (all_zero_p (result, resultlen))
log_debug (" dump: [all zero]\n");
else
log_printhex (result, resultlen, " dump:");
diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index 014cd9395..3bc709602 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -3499,6 +3499,31 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
log_error (_("error getting new PIN: %s\n"), gpg_strerror (rc));
goto leave;
}
+
+ if (set_resetcode)
+ {
+ size_t bufferlen = strlen (pinvalue);
+
+ if (bufferlen != 0 && bufferlen < 8)
+ {
+ log_error (_("Reset Code is too short; minimum length is %d\n"), 8);
+ rc = gpg_error (GPG_ERR_BAD_RESET_CODE);
+ goto leave;
+ }
+ }
+ else
+ {
+ if (chvno == 3)
+ minlen = 8;
+
+ if (strlen (pinvalue) < minlen)
+ {
+ log_info (_("PIN for CHV%d is too short;"
+ " minimum length is %d\n"), chvno, minlen);
+ rc = gpg_error (GPG_ERR_BAD_PIN);
+ goto leave;
+ }
+ }
}
@@ -3533,24 +3558,15 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
}
else if (set_resetcode)
{
- size_t bufferlen = strlen (pinvalue);
-
- if (bufferlen != 0 && bufferlen < 8)
- {
- log_error (_("Reset Code is too short; minimum length is %d\n"), 8);
- rc = gpg_error (GPG_ERR_BAD_RESET_CODE);
- }
- else
- {
- char *buffer = NULL;
+ size_t bufferlen;
+ char *buffer = NULL;
- rc = pin2hash_if_kdf (app, 0, pinvalue, &buffer, &bufferlen);
- if (!rc)
- rc = iso7816_put_data (app_get_slot (app),
- 0, 0xD3, buffer, bufferlen);
+ rc = pin2hash_if_kdf (app, 0, pinvalue, &buffer, &bufferlen);
+ if (!rc)
+ rc = iso7816_put_data (app_get_slot (app),
+ 0, 0xD3, buffer, bufferlen);
- wipe_and_free (buffer, bufferlen);
- }
+ wipe_and_free (buffer, bufferlen);
}
else if (reset_mode)
{
@@ -4733,9 +4749,11 @@ ecc_writekey (app_t app, ctrl_t ctrl,
if (algo == PUBKEY_ALGO_ECDH && !ecdh_param)
{
- log_error ("opgp: ecdh parameters missing\n");
- err = gpg_error (GPG_ERR_INV_VALUE);
- goto leave;
+ /* In case this is used by older clients we fallback to our
+ * default ecc parameters. */
+ log_info ("opgp: using default ecdh parameters\n");
+ ecdh_param = ecdh_params (curve);
+ ecdh_param_len = 4;
}
oidstr = openpgp_curve_to_oid (curve, &n, NULL);
diff --git a/scd/app-p15.c b/scd/app-p15.c
index 4338a623e..8edd737a6 100644
--- a/scd/app-p15.c
+++ b/scd/app-p15.c
@@ -74,8 +74,10 @@ typedef enum
CARD_TYPE_MICARDO,
CARD_TYPE_CARDOS_50,
CARD_TYPE_CARDOS_53,
+ CARD_TYPE_CARDOS_54,
CARD_TYPE_AET, /* A.E.T. Europe JCOP card. */
- CARD_TYPE_BELPIC /* Belgian eID card specs. */
+ CARD_TYPE_BELPIC, /* Belgian eID card specs. */
+ CARD_TYPE_STARCOS_32
}
card_type_t;
@@ -86,7 +88,8 @@ typedef enum
{
CARD_PRODUCT_UNKNOWN,
CARD_PRODUCT_RSCS, /* Rohde&Schwarz Cybersecurity */
- CARD_PRODUCT_DTRUST, /* D-Trust GmbH (bundesdruckerei.de) */
+ CARD_PRODUCT_DTRUST3, /* D-Trust GmbH (bundesdruckerei.de) */
+ CARD_PRODUCT_DTRUST4,
CARD_PRODUCT_GENUA, /* GeNUA mbH */
CARD_PRODUCT_NEXUS /* Technology Nexus */
}
@@ -123,17 +126,23 @@ static struct
CARD_TYPE_CARDOS_50 }, /* CardOS 5.0 */
{ 11, X("\x3b\xd2\x18\x00\x81\x31\xfe\x58\xc9\x03\x16"),
CARD_TYPE_CARDOS_53 }, /* CardOS 5.3 */
+ { 11, X("\x3b\xd2\x18\x00\x81\x31\xfe\x58\xc9\x04\x11"),
+ CARD_TYPE_CARDOS_54 }, /* CardOS 5.4 */
{ 24, X("\x3b\xfe\x18\x00\x00\x80\x31\xfe\x45\x53\x43\x45"
"\x36\x30\x2d\x43\x44\x30\x38\x31\x2d\x6e\x46\xa9"),
CARD_TYPE_AET },
+ { 25, X("\x3b\x9f\x96\x81\xb1\xfe\x45\x1f\x07\x00\x64\x05"
+ "\x1e\xb2\x00\x31\xb0\x73\x96\x21\xdb\x05\x90\x00\x5c"),
+ CARD_TYPE_STARCOS_32 },
{ 0 }
};
#undef X
-/* Macro to test for CardOS 5.0 and 5.3. */
+/* Macro to test for CardOS 5.0, 5.3 and 5.4. */
#define IS_CARDOS_5(a) ((a)->app_local->card_type == CARD_TYPE_CARDOS_50 \
- || (a)->app_local->card_type == CARD_TYPE_CARDOS_53)
+ || (a)->app_local->card_type == CARD_TYPE_CARDOS_53 \
+ || (a)->app_local->card_type == CARD_TYPE_CARDOS_54)
/* The default PKCS-15 home DF */
#define DEFAULT_HOME_DF 0x5015
@@ -147,6 +156,11 @@ static char const pkcs15_aid[] = { 0xA0, 0, 0, 0, 0x63,
static char const pkcs15be_aid[] = { 0xA0, 0, 0, 0x01, 0x77,
0x50, 0x4B, 0x43, 0x53, 0x2D, 0x31, 0x35 };
+/* The D-TRUST Card 4.x variant - dito */
+static char const pkcs15dtrust4_aid[] = { 0xE8, 0x28, 0xBD, 0x08, 0x0F, 0xA0,
+ 0x00, 0x00, 0x01, 0x67, 0x45, 0x53,
+ 0x49, 0x47, 0x4E };
+
/* The PIN types as defined in pkcs#15 v1.1 */
typedef enum
@@ -518,6 +532,8 @@ struct app_local_s
/*** Local prototypes. ***/
static gpg_error_t select_ef_by_path (app_t app, const unsigned short *path,
size_t pathlen);
+static gpg_error_t select_df_by_path (app_t app, const unsigned short *path,
+ size_t pathlen);
static gpg_error_t keygrip_from_prkdf (app_t app, prkdf_object_t prkdf);
static gpg_error_t readcert_by_cdf (app_t app, cdf_object_t cdf,
unsigned char **r_cert, size_t *r_certlen);
@@ -536,8 +552,10 @@ cardtype2str (card_type_t cardtype)
case CARD_TYPE_MICARDO: return "Micardo";
case CARD_TYPE_CARDOS_50: return "CardOS 5.0";
case CARD_TYPE_CARDOS_53: return "CardOS 5.3";
+ case CARD_TYPE_CARDOS_54: return "CardOS 5.4";
case CARD_TYPE_BELPIC: return "Belgian eID";
case CARD_TYPE_AET: return "AET";
+ case CARD_TYPE_STARCOS_32:return "STARCOS 3.2";
}
return "";
}
@@ -549,7 +567,8 @@ cardproduct2str (card_product_t cardproduct)
{
case CARD_PRODUCT_UNKNOWN: return "";
case CARD_PRODUCT_RSCS: return "R&S";
- case CARD_PRODUCT_DTRUST: return "D-Trust";
+ case CARD_PRODUCT_DTRUST3: return "D-Trust 3";
+ case CARD_PRODUCT_DTRUST4: return "D-Trust 4.1/4.4";
case CARD_PRODUCT_GENUA: return "GeNUA";
case CARD_PRODUCT_NEXUS: return "Nexus";
}
@@ -765,20 +784,28 @@ select_and_read_record (app_t app, unsigned short efid, int recno,
/* This function calls select file to read a file using a complete
- path which may or may not start at the master file (MF). */
+ * path which may or may not start at the master file (MF). If
+ * EXPECT_DF is set a directory or file is expected - otherwise an
+ * elementary file expected. */
static gpg_error_t
-select_ef_by_path (app_t app, const unsigned short *path, size_t pathlen)
+select_by_path (app_t app, const unsigned short *path, size_t pathlen,
+ int expect_df)
{
gpg_error_t err;
int i, j;
+ int home_df_used = 0;
if (!pathlen)
return gpg_error (GPG_ERR_INV_VALUE);
- /* log_debug ("%s: path=", __func__); */
- /* for (j=0; j < pathlen; j++) */
- /* log_printf ("%s%04hX", j? "/":"", path[j]); */
- /* log_printf ("%s\n",app->app_local->direct_path_selection?" (direct)":"");*/
+ if (opt.debug)
+ {
+ log_debug ("%s: path=", __func__);
+ for (j=0; j < pathlen; j++)
+ log_printf ("%s%04hX", j? "/":"", path[j]);
+ log_printf ("%s\n",expect_df?" (DF requested)":"");
+ log_printf ("%s\n",app->app_local->direct_path_selection?" (direct)":"");
+ }
if (app->app_local->direct_path_selection)
{
@@ -791,34 +818,16 @@ select_ef_by_path (app_t app, const unsigned short *path, size_t pathlen)
0);
}
else
- err = iso7816_select_path (app_get_slot (app), path, pathlen,
- app->app_local->home_df);
- if (err)
{
- log_error ("p15: error selecting path ");
- goto err_print_path;
+ home_df_used = 1;
+ err = iso7816_select_path (app_get_slot (app), path, pathlen,
+ app->app_local->home_df);
}
- }
- else if (pathlen > 1 && path[0] == 0x3fff)
- {
- err = iso7816_select_file (app_get_slot (app), 0x3f00, 0);
if (err)
{
- log_error ("p15: error selecting part %d from path ", 0);
+ log_error ("p15: error selecting path ");
goto err_print_path;
}
- path++;
- pathlen--;
- for (i=0; i < pathlen; i++)
- {
- err = iso7816_select_file (app_get_slot (app),
- path[i], (i+1 == pathlen)? 2 : 1);
- if (err)
- {
- log_error ("p15: error selecting part %d from path ", i);
- goto err_print_path;
- }
- }
}
else
{
@@ -829,7 +838,7 @@ select_ef_by_path (app_t app, const unsigned short *path, size_t pathlen)
for (i=0; i < pathlen; i++)
{
err = iso7816_select_file (app_get_slot (app),
- path[i], !(i+1 == pathlen));
+ path[i], (expect_df || (i+1 < pathlen)));
if (err)
{
log_error ("p15: error selecting part %d from path ", i);
@@ -842,7 +851,7 @@ select_ef_by_path (app_t app, const unsigned short *path, size_t pathlen)
err_print_path:
if (pathlen && *path != 0x3f00 )
log_printf ("3F00/");
- else
+ else if (home_df_used)
log_printf ("%04hX/", app->app_local->home_df);
for (j=0; j < pathlen; j++)
log_printf ("%s%04hX", j? "/":"", path[j]);
@@ -851,6 +860,20 @@ select_ef_by_path (app_t app, const unsigned short *path, size_t pathlen)
}
+static gpg_error_t
+select_ef_by_path (app_t app, const unsigned short *path, size_t pathlen)
+{
+ return select_by_path (app, path, pathlen, 0);
+}
+
+
+static gpg_error_t
+select_df_by_path (app_t app, const unsigned short *path, size_t pathlen)
+{
+ return select_by_path (app, path, pathlen, 1);
+}
+
+
/* Parse a cert Id string (or a key Id string) and return the binary
object Id string in a newly allocated buffer stored at R_OBJID and
R_OBJIDLEN. On Error NULL will be stored there and an error code
@@ -3245,7 +3268,7 @@ read_ef_aodf (app_t app, unsigned short fid, aodf_object_t *result)
if (aodf->max_length_valid)
log_printf (" max=%lu", aodf->max_length);
if (aodf->pad_char_valid)
- log_printf (" pad=0x%02x", aodf->pad_char);
+ log_printf (" pad=0x%02x", (unsigned char)aodf->pad_char);
log_info ("p15: flags=");
s = "";
@@ -3495,7 +3518,7 @@ read_ef_tokeninfo (app_t app)
ul |= (*p++) & 0xff;
n--;
}
- if (ul)
+ if (ul > 1)
{
log_error ("p15: invalid version %lu in TokenInfo\n", ul);
err = gpg_error (GPG_ERR_INV_OBJ);
@@ -3829,7 +3852,14 @@ read_p15_info (app_t app)
&& !strncmp (app->app_local->token_label, "D-TRUST Card V3", 15)
&& app->app_local->card_type == CARD_TYPE_CARDOS_50)
{
- app->app_local->card_product = CARD_PRODUCT_DTRUST;
+ app->app_local->card_product = CARD_PRODUCT_DTRUST3;
+ }
+ if (!app->app_local->card_product
+ && app->app_local->token_label
+ && !strncmp (app->app_local->token_label, "D-TRUST Card 4.", 15)
+ && app->app_local->card_type == CARD_TYPE_CARDOS_54)
+ {
+ app->app_local->card_product = CARD_PRODUCT_DTRUST4;
}
@@ -5007,7 +5037,7 @@ prepare_verify_pin (app_t app, const char *keyref,
}
- if (app->app_local->card_product == CARD_PRODUCT_DTRUST)
+ if (app->app_local->card_product == CARD_PRODUCT_DTRUST3)
{
/* According to our protocol analysis we need to select a
* special AID here. Before that the master file needs to be
@@ -5023,6 +5053,13 @@ prepare_verify_pin (app_t app, const char *keyref,
log_error ("p15: error selecting D-TRUST's AID for key %s: %s\n",
keyref, gpg_strerror (err));
}
+ else if (prkdf && app->app_local->card_type == CARD_TYPE_STARCOS_32)
+ {
+ err = select_df_by_path (app, prkdf->path, prkdf->pathlen);
+ if (err)
+ log_error ("p15: error selecting file for key %s: %s\n",
+ keyref, gpg_strerror (err));
+ }
else if (prkdf)
{
/* Standard case: Select the key file. Note that this may
@@ -5258,7 +5295,8 @@ verify_pin (app_t app,
if (prkdf
&& prkdf->usageflags.non_repudiation
&& (app->app_local->card_type == CARD_TYPE_BELPIC
- || app->app_local->card_product == CARD_PRODUCT_DTRUST))
+ || app->app_local->card_product == CARD_PRODUCT_DTRUST3
+ || app->app_local->card_product == CARD_PRODUCT_DTRUST4))
label = _("||Please enter the PIN for the key to create "
"qualified signatures.");
else if (aodf->pinflags.so_pin)
@@ -5622,7 +5660,8 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
goto leave;
}
if (app->app_local->card_type == CARD_TYPE_BELPIC
- || app->app_local->card_product == CARD_PRODUCT_NEXUS)
+ || app->app_local->card_product == CARD_PRODUCT_NEXUS
+ || app->app_local->card_product == CARD_PRODUCT_DTRUST4)
{
/* The default for these cards is to use a plain hash. We
* assume that due to the used certificate the correct hash
@@ -5708,6 +5747,31 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
else
err = micardo_mse (app, prkdf->path[prkdf->pathlen-1]);
}
+ else if (app->app_local->card_product == CARD_PRODUCT_DTRUST4)
+ {
+ if (prkdf->is_ecc)
+ {
+ /* Not implemented due to lacking test hardware. */
+ log_info ("Note: ECC is not yet implemented for DTRUST 4 cards\n");
+ err = gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
+ }
+ else
+ {
+ /* The D-TRUST Card 4.x doesn't support setting a security
+ * environment, at least as specified in the specs. Insted a
+ * predefined security environment has to be loaded depending on the
+ * cipher and message digest used. The spec states SE-ID 0x25 for
+ * SHA256, 0x26 for SHA384 and 0x27 for SHA512, when using PKCS#1
+ * padding. But this matters only if the message digest is computed
+ * on the card. When providing the digest info and a pre-calculated
+ * hash, all security environments yield the same result. Thus we
+ * choose 0x25.
+ *
+ * Note: For PSS signatures, different values apply. */
+ err = iso7816_manage_security_env (app_get_slot (app),
+ 0xf3, 0x25, NULL, 0);
+ }
+ }
else if (prkdf->key_reference_valid)
{
unsigned char mse[3];
@@ -5863,7 +5927,7 @@ do_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
/* The next is guess work for CardOS. */
- if (app->app_local->card_product == CARD_PRODUCT_DTRUST)
+ if (app->app_local->card_product == CARD_PRODUCT_DTRUST3)
{
/* From analyzing an USB trace of a Windows signing application
* we see that the SE is simply reset to 0x14. It seems to be
@@ -5880,6 +5944,22 @@ do_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
0xF3, 0x14, NULL, 0);
}
+ else if (app->app_local->card_product == CARD_PRODUCT_DTRUST4)
+ {
+ if (prkdf->is_ecc)
+ {
+ /* Not implemented due to lacking test hardware. */
+ log_info ("Note: ECC is not yet implemented for DTRUST 4 cards\n");
+ err = gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
+ }
+ else
+ {
+ /* SE-ID 0x31 is for PKCS#1 padded cryptograms. For OAEP encryption
+ * schemes, different values apply. */
+ err = iso7816_manage_security_env (app_get_slot (app),
+ 0xF3, 0x31, NULL, 0);
+ }
+ }
else if (prkdf->key_reference_valid)
{
unsigned char mse[9];
@@ -5923,7 +6003,8 @@ do_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
le_value = prkdf->keynbits / 8;
}
- if (app->app_local->card_product == CARD_PRODUCT_DTRUST)
+ if (app->app_local->card_product == CARD_PRODUCT_DTRUST3
+ || app->app_local->card_product == CARD_PRODUCT_DTRUST4)
padind = 0x81;
if (prkdf->is_ecc && IS_CARDOS_5(app))
@@ -6186,6 +6267,13 @@ app_select_p15 (app_t app)
rc = iso7816_select_application_ext (slot, pkcs15_aid, sizeof pkcs15_aid, 1,
&fci, &fcilen);
if (rc)
+ {
+ /* D-TRUST Card 4.x uses a different AID. */
+ rc = iso7816_select_application_ext (slot, pkcs15dtrust4_aid,
+ sizeof pkcs15dtrust4_aid, 1,
+ &fci, &fcilen);
+ }
+ if (rc)
{ /* Not found: Try to locate it from 2F00. We use direct path
selection here because it seems that the Belgian eID card
does only allow for that. Many other cards supports this
@@ -6284,9 +6372,11 @@ app_select_p15 (app_t app)
{
case CARD_TYPE_CARDOS_50:
case CARD_TYPE_CARDOS_53:
+ case CARD_TYPE_CARDOS_54:
direct = 1;
break;
case CARD_TYPE_AET:
+ case CARD_TYPE_STARCOS_32:
app->app_local->no_extended_mode = 1;
break;
default:
diff --git a/scd/iso7816.c b/scd/iso7816.c
index 47e16056c..703f1fdab 100644
--- a/scd/iso7816.c
+++ b/scd/iso7816.c
@@ -166,7 +166,7 @@ iso7816_select_mf (int slot)
{
int sw;
- sw = apdu_send_simple (slot, 0, 0x00, CMD_SELECT_FILE, 0x000, 0x0c, -1, NULL);
+ sw = apdu_send_simple (slot, 0, 0x00, CMD_SELECT_FILE, 0x00, 0x0c, -1, NULL);
return map_sw (sw);
}
diff --git a/scd/scdaemon.c b/scd/scdaemon.c
index 0376cbfba..e49b2ce42 100644
--- a/scd/scdaemon.c
+++ b/scd/scdaemon.c
@@ -79,6 +79,7 @@ enum cmd_and_opt_values
oDebugAllowCoreDump,
oDebugCCIDDriver,
oDebugLogTid,
+ oDebugAllowPINLogging,
oDebugAssuanLogCats,
oNoGreeting,
oNoOptions,
@@ -138,6 +139,7 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_s_n (oDebugAllowCoreDump, "debug-allow-core-dump", "@"),
ARGPARSE_s_n (oDebugCCIDDriver, "debug-ccid-driver", "@"),
ARGPARSE_s_n (oDebugLogTid, "debug-log-tid", "@"),
+ ARGPARSE_s_n (oDebugAllowPINLogging, "debug-allow-pin-logging", "@"),
ARGPARSE_p_u (oDebugAssuanLogCats, "debug-assuan-log-cats", "@"),
ARGPARSE_s_s (oLogFile, "log-file", N_("|FILE|write a log to FILE")),
@@ -583,6 +585,9 @@ main (int argc, char **argv )
case oDebugLogTid:
log_set_pid_suffix_cb (tid_log_callback);
break;
+ case oDebugAllowPINLogging:
+ opt.debug_allow_pin_logging = 1;
+ break;
case oDebugAssuanLogCats:
set_libassuan_log_cats (pargs.r.ret_ulong);
break;
diff --git a/scd/scdaemon.h b/scd/scdaemon.h
index 68136b886..7b82d1b21 100644
--- a/scd/scdaemon.h
+++ b/scd/scdaemon.h
@@ -66,6 +66,7 @@ struct
strlist_t disabled_applications; /* Card applications we do not
want to use. */
unsigned long card_timeout; /* Disconnect after N seconds of inactivity. */
+ int debug_allow_pin_logging; /* Allow PINs in debug output. */
} opt;
diff --git a/sm/call-agent.c b/sm/call-agent.c
index 7f7205f26..acce19058 100644
--- a/sm/call-agent.c
+++ b/sm/call-agent.c
@@ -1323,6 +1323,7 @@ gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg, int repeat,
char *arg4 = NULL;
membuf_t data;
struct default_inq_parm_s inq_parm;
+ int wasconf;
*r_passphrase = NULL;
@@ -1341,9 +1342,13 @@ gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg, int repeat,
xfree (arg4);
init_membuf_secure (&data, 64);
+ wasconf = assuan_get_flag (agent_ctx, ASSUAN_CONFIDENTIAL);
+ assuan_begin_confidential (agent_ctx);
err = assuan_transact (agent_ctx, line,
put_membuf_cb, &data,
default_inq_cb, &inq_parm, NULL, NULL);
+ if (!wasconf)
+ assuan_end_confidential (agent_ctx);
if (err)
xfree (get_membuf (&data, NULL));
diff --git a/sm/decrypt.c b/sm/decrypt.c
index 6121fd278..5a947779f 100644
--- a/sm/decrypt.c
+++ b/sm/decrypt.c
@@ -1309,7 +1309,8 @@ gpgsm_decrypt (ctrl_t ctrl, estream_t in_fp, estream_t out_fp)
/* Check compliance. */
if (!gnupg_pk_is_allowed (opt.compliance,
PK_USE_DECRYPTION,
- pk_algo, 0, NULL, nbits, curve))
+ pk_algo, PK_ALGO_FLAG_ECC18,
+ NULL, nbits, curve))
{
char kidstr[10+1];
diff --git a/sm/encrypt.c b/sm/encrypt.c
index 9113028db..16c48c8d5 100644
--- a/sm/encrypt.c
+++ b/sm/encrypt.c
@@ -577,9 +577,8 @@ int
gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
estream_t out_fp)
{
- int rc = 0;
+ gpg_error_t err = 0;
gnupg_ksba_io_t b64writer = NULL;
- gpg_error_t err;
ksba_writer_t writer;
ksba_reader_t reader = NULL;
ksba_cms_t cms = NULL;
@@ -607,7 +606,7 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
log_error(_("no valid recipients given\n"));
gpgsm_status (ctrl, STATUS_NO_RECP, "0");
audit_log_i (ctrl->audit, AUDIT_GOT_RECIPIENTS, 0);
- rc = gpg_error (GPG_ERR_NO_PUBKEY);
+ err = gpg_error (GPG_ERR_NO_PUBKEY);
goto leave;
}
@@ -619,28 +618,26 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
if (!kh)
{
log_error (_("failed to allocate keyDB handle\n"));
- rc = gpg_error (GPG_ERR_GENERAL);
+ err = gpg_error (GPG_ERR_GENERAL);
goto leave;
}
err = ksba_reader_new (&reader);
+ if (!err)
+ err = ksba_reader_set_cb (reader, encrypt_cb, &encparm);
if (err)
- rc = err;
- if (!rc)
- rc = ksba_reader_set_cb (reader, encrypt_cb, &encparm);
- if (rc)
- goto leave;
+ goto leave;
encparm.fp = data_fp;
ctrl->pem_name = "ENCRYPTED MESSAGE";
- rc = gnupg_ksba_create_writer
+ err = gnupg_ksba_create_writer
(&b64writer, ((ctrl->create_pem? GNUPG_KSBA_IO_PEM : 0)
| (ctrl->create_base64? GNUPG_KSBA_IO_BASE64 : 0)),
ctrl->pem_name, out_fp, &writer);
- if (rc)
+ if (err)
{
- log_error ("can't create writer: %s\n", gpg_strerror (rc));
+ log_error ("can't create writer: %s\n", gpg_strerror (err));
goto leave;
}
@@ -650,17 +647,13 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
err = ksba_cms_new (&cms);
if (err)
- {
- rc = err;
- goto leave;
- }
+ goto leave;
err = ksba_cms_set_reader_writer (cms, reader, writer);
if (err)
{
log_error ("ksba_cms_set_reader_writer failed: %s\n",
gpg_strerror (err));
- rc = err;
goto leave;
}
@@ -675,7 +668,6 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
{
log_error ("ksba_cms_set_content_type failed: %s\n",
gpg_strerror (err));
- rc = err;
goto leave;
}
@@ -687,34 +679,34 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
log_error (_("cipher algorithm '%s' may not be used in %s mode\n"),
opt.def_cipher_algoid,
gnupg_compliance_option_string (opt.compliance));
- rc = gpg_error (GPG_ERR_CIPHER_ALGO);
+ err = gpg_error (GPG_ERR_CIPHER_ALGO);
goto leave;
}
if (!gnupg_rng_is_compliant (opt.compliance))
{
- rc = gpg_error (GPG_ERR_FORBIDDEN);
+ err = gpg_error (GPG_ERR_FORBIDDEN);
log_error (_("%s is not compliant with %s mode\n"),
"RNG",
gnupg_compliance_option_string (opt.compliance));
gpgsm_status_with_error (ctrl, STATUS_ERROR,
- "random-compliance", rc);
+ "random-compliance", err);
goto leave;
}
/* Create a session key */
dek = xtrycalloc_secure (1, sizeof *dek);
if (!dek)
- rc = out_of_core ();
+ err = gpg_error_from_syserror ();
else
- {
- dek->algoid = opt.def_cipher_algoid;
- rc = init_dek (dek);
- }
- if (rc)
+ {
+ dek->algoid = opt.def_cipher_algoid;
+ err = init_dek (dek);
+ }
+ if (err)
{
log_error ("failed to create the session key: %s\n",
- gpg_strerror (rc));
+ gpg_strerror (err));
goto leave;
}
@@ -723,7 +715,6 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
{
log_error ("ksba_cms_set_content_enc_algo failed: %s\n",
gpg_strerror (err));
- rc = err;
goto leave;
}
@@ -733,7 +724,7 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
encparm.buffer = xtrymalloc (encparm.bufsize);
if (!encparm.buffer)
{
- rc = out_of_core ();
+ err = gpg_error_from_syserror ();
goto leave;
}
@@ -775,12 +766,12 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
xfree (curve);
curve = NULL;
- rc = encrypt_dek (dek, cl->cert, pk_algo, &encval);
- if (rc)
+ err = encrypt_dek (dek, cl->cert, pk_algo, &encval);
+ if (err)
{
- audit_log_cert (ctrl->audit, AUDIT_ENCRYPTED_TO, cl->cert, rc);
+ audit_log_cert (ctrl->audit, AUDIT_ENCRYPTED_TO, cl->cert, err);
log_error ("encryption failed for recipient no. %d: %s\n",
- recpno, gpg_strerror (rc));
+ recpno, gpg_strerror (err));
goto leave;
}
@@ -790,7 +781,6 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
audit_log_cert (ctrl->audit, AUDIT_ENCRYPTED_TO, cl->cert, err);
log_error ("ksba_cms_add_recipient failed: %s\n",
gpg_strerror (err));
- rc = err;
xfree (encval);
goto leave;
}
@@ -802,7 +792,6 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
{
log_error ("ksba_cms_set_enc_val failed: %s\n",
gpg_strerror (err));
- rc = err;
goto leave;
}
}
@@ -816,7 +805,7 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
log_error (_("operation forced to fail due to"
" unfulfilled compliance rules\n"));
gpgsm_errors_seen = 1;
- rc = gpg_error (GPG_ERR_FORBIDDEN);
+ err = gpg_error (GPG_ERR_FORBIDDEN);
goto leave;
}
@@ -828,7 +817,6 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
if (err)
{
log_error ("creating CMS object failed: %s\n", gpg_strerror (err));
- rc = err;
goto leave;
}
}
@@ -837,15 +825,15 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
if (encparm.readerror)
{
log_error ("error reading input: %s\n", strerror (encparm.readerror));
- rc = gpg_error (gpg_err_code_from_errno (encparm.readerror));
+ err = gpg_error (gpg_err_code_from_errno (encparm.readerror));
goto leave;
}
- rc = gnupg_ksba_finish_writer (b64writer);
- if (rc)
+ err = gnupg_ksba_finish_writer (b64writer);
+ if (err)
{
- log_error ("write failed: %s\n", gpg_strerror (rc));
+ log_error ("write failed: %s\n", gpg_strerror (err));
goto leave;
}
audit_log (ctrl->audit, AUDIT_ENCRYPTION_DONE);
@@ -859,5 +847,5 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
keydb_release (kh);
xfree (dek);
xfree (encparm.buffer);
- return rc;
+ return err;
}
diff --git a/sm/keydb.c b/sm/keydb.c
index 512ab1af8..151ae8103 100644
--- a/sm/keydb.c
+++ b/sm/keydb.c
@@ -1137,6 +1137,23 @@ keydb_set_flags (KEYDB_HANDLE hd, int which, int idx, unsigned int value)
}
+/* Default status callback used to show diagnostics from the keyboxd */
+static gpg_error_t
+keydb_default_status_cb (void *opaque, const char *line)
+{
+ const char *s;
+
+ (void)opaque;
+
+ if ((s = has_leading_keyword (line, "NOTE")))
+ log_info (_("Note: %s\n"), s);
+ else if ((s = has_leading_keyword (line, "WARNING")))
+ log_info (_("WARNING: %s\n"), s);
+
+ return 0;
+}
+
+
/* Communication object for Keyboxd STORE commands. */
struct store_parm_s
@@ -1200,7 +1217,7 @@ keydb_insert_cert (KEYDB_HANDLE hd, ksba_cert_t cert)
err = assuan_transact (hd->kbl->ctx, "STORE --insert",
NULL, NULL,
store_inq_cb, &parm,
- NULL, NULL);
+ keydb_default_status_cb, hd);
goto leave;
}
@@ -1335,7 +1352,7 @@ keydb_delete (KEYDB_HANDLE hd)
err = assuan_transact (hd->kbl->ctx, line,
NULL, NULL,
NULL, NULL,
- NULL, NULL);
+ keydb_default_status_cb, hd);
goto leave;
}
@@ -1563,6 +1580,8 @@ search_status_cb (void *opaque, const char *line)
}
}
}
+ else
+ err = keydb_default_status_cb (opaque, line);
return err;
}
diff --git a/sm/keylist.c b/sm/keylist.c
index ed1b74729..47fe69f30 100644
--- a/sm/keylist.c
+++ b/sm/keylist.c
@@ -532,6 +532,8 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
{
if (gpgsm_cert_has_well_known_private_key (cert))
*truststring = 'w'; /* Well, this is dummy CA. */
+ else if (gpg_err_code (valerr) == GPG_ERR_NOT_TRUSTED)
+ *truststring = 'n'; /* Likely the root cert is not trusted. */
else
*truststring = 'i';
}
diff --git a/sm/minip12.c b/sm/minip12.c
index ae81d821b..1bbe126ae 100644
--- a/sm/minip12.c
+++ b/sm/minip12.c
@@ -936,6 +936,7 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, tlv_parser_t tlv)
if (!datalen)
{
err = gpg_error (GPG_ERR_DECRYPT_FAILED);
+ ctx->badpass = 1; /* This is the most likley reason. */
goto bailout;
}
@@ -1461,6 +1462,7 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, tlv_parser_t tlv)
if (!datalen)
{
err = gpg_error (GPG_ERR_DECRYPT_FAILED);
+ ctx->badpass = 1;
goto bailout;
}
diff --git a/sm/sign.c b/sm/sign.c
index 8fd111a7d..ec0172b4b 100644
--- a/sm/sign.c
+++ b/sm/sign.c
@@ -606,8 +606,8 @@ int
gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
estream_t data_fp, int detached, estream_t out_fp)
{
- int i, rc;
gpg_error_t err;
+ int i;
gnupg_ksba_io_t b64writer = NULL;
ksba_writer_t writer;
estream_t sig_fp = NULL; /* Used for detached signatures. */
@@ -630,18 +630,18 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
if (!kh)
{
log_error (_("failed to allocate keyDB handle\n"));
- rc = gpg_error (GPG_ERR_GENERAL);
+ err = gpg_error (GPG_ERR_GENERAL);
goto leave;
}
if (!gnupg_rng_is_compliant (opt.compliance))
{
- rc = gpg_error (GPG_ERR_FORBIDDEN);
+ err = gpg_error (GPG_ERR_FORBIDDEN);
log_error (_("%s is not compliant with %s mode\n"),
"RNG",
gnupg_compliance_option_string (opt.compliance));
gpgsm_status_with_error (ctrl, STATUS_ERROR,
- "random-compliance", rc);
+ "random-compliance", err);
goto leave;
}
@@ -653,20 +653,20 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
if (binary_detached)
{
sig_fp = es_fopenmem (0, "w+");
- rc = sig_fp? 0 : gpg_error_from_syserror ();
- if (!rc)
- rc = gnupg_ksba_create_writer (&b64writer, 0, NULL, sig_fp, &writer);
+ err = sig_fp? 0 : gpg_error_from_syserror ();
+ if (!err)
+ err = gnupg_ksba_create_writer (&b64writer, 0, NULL, sig_fp, &writer);
}
else
{
- rc = gnupg_ksba_create_writer
+ err = gnupg_ksba_create_writer
(&b64writer, ((ctrl->create_pem? GNUPG_KSBA_IO_PEM : 0)
| (ctrl->create_base64? GNUPG_KSBA_IO_BASE64 : 0)),
ctrl->pem_name, out_fp, &writer);
}
- if (rc)
+ if (err)
{
- log_error ("can't create writer: %s\n", gpg_strerror (rc));
+ log_error ("can't create writer: %s\n", gpg_strerror (err));
goto leave;
}
@@ -676,17 +676,13 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
err = ksba_cms_new (&cms);
if (err)
- {
- rc = err;
- goto leave;
- }
+ goto leave;
err = ksba_cms_set_reader_writer (cms, NULL, writer);
if (err)
{
log_debug ("ksba_cms_set_reader_writer failed: %s\n",
gpg_strerror (err));
- rc = err;
goto leave;
}
@@ -703,7 +699,6 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
{
log_debug ("ksba_cms_set_content_type failed: %s\n",
gpg_strerror (err));
- rc = err;
goto leave;
}
@@ -716,23 +711,23 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
log_error ("no default signer found\n");
gpgsm_status2 (ctrl, STATUS_INV_SGNR,
get_inv_recpsgnr_code (GPG_ERR_NO_SECKEY), NULL);
- rc = gpg_error (GPG_ERR_GENERAL);
+ err = gpg_error (GPG_ERR_GENERAL);
goto leave;
}
/* Although we don't check for ambiguous specification we will
check that the signer's certificate is usable and valid. */
- rc = gpgsm_cert_use_sign_p (cert, 0);
- if (!rc)
- rc = gpgsm_validate_chain (ctrl, cert,
+ err = gpgsm_cert_use_sign_p (cert, 0);
+ if (!err)
+ err = gpgsm_validate_chain (ctrl, cert,
GNUPG_ISOTIME_NONE, NULL, 0, NULL, 0, NULL);
- if (rc)
+ if (err)
{
char *tmpfpr;
tmpfpr = gpgsm_get_fingerprint_hexstring (cert, 0);
gpgsm_status2 (ctrl, STATUS_INV_SGNR,
- get_inv_recpsgnr_code (rc), tmpfpr, NULL);
+ get_inv_recpsgnr_code (err), tmpfpr, NULL);
xfree (tmpfpr);
goto leave;
}
@@ -741,7 +736,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
signerlist = xtrycalloc (1, sizeof *signerlist);
if (!signerlist)
{
- rc = out_of_core ();
+ err = gpg_error_from_syserror ();
ksba_cert_release (cert);
goto leave;
}
@@ -822,8 +817,8 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
goto leave;
}
- if (!gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pk_algo, 0,
- NULL, nbits, curve))
+ if (!gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pk_algo,
+ PK_ALGO_FLAG_ECC18, NULL, nbits, curve))
{
char kidstr[10+1];
@@ -849,22 +844,21 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
/* Gather certificates of signers and store them in the CMS object. */
for (cl=signerlist; cl; cl = cl->next)
{
- rc = gpgsm_cert_use_sign_p (cl->cert, 0);
- if (rc)
+ err = gpgsm_cert_use_sign_p (cl->cert, 0);
+ if (err)
goto leave;
err = ksba_cms_add_signer (cms, cl->cert);
if (err)
{
log_error ("ksba_cms_add_signer failed: %s\n", gpg_strerror (err));
- rc = err;
goto leave;
}
- rc = add_certificate_list (ctrl, cms, cl->cert);
- if (rc)
+ err = add_certificate_list (ctrl, cms, cl->cert);
+ if (err)
{
log_error ("failed to store list of certificates: %s\n",
- gpg_strerror(rc));
+ gpg_strerror (err));
goto leave;
}
/* Set the hash algorithm we are going to use */
@@ -873,7 +867,6 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
{
log_debug ("ksba_cms_add_digest_algo failed: %s\n",
gpg_strerror (err));
- rc = err;
goto leave;
}
}
@@ -895,7 +888,6 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
{
log_error (_("checking for qualified certificate failed: %s\n"),
gpg_strerror (err));
- rc = err;
goto leave;
}
if (*buffer)
@@ -903,19 +895,16 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
else
err = gpgsm_not_qualified_warning (ctrl, cl->cert);
if (err)
- {
- rc = err;
- goto leave;
- }
+ goto leave;
}
}
/* Prepare hashing (actually we are figuring out what we have set
above). */
- rc = gcry_md_open (&data_md, 0, 0);
- if (rc)
+ err = gcry_md_open (&data_md, 0, 0);
+ if (err)
{
- log_error ("md_open failed: %s\n", gpg_strerror (rc));
+ log_error ("md_open failed: %s\n", gpg_strerror (err));
goto leave;
}
if (DBG_HASHING)
@@ -927,7 +916,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
if (!algo)
{
log_error ("unknown hash algorithm '%s'\n", algoid? algoid:"?");
- rc = gpg_error (GPG_ERR_BUG);
+ err = gpg_error (GPG_ERR_BUG);
goto leave;
}
gcry_md_enable (data_md, algo);
@@ -952,7 +941,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
if ( !digest || !digest_len )
{
log_error ("problem getting the hash of the data\n");
- rc = gpg_error (GPG_ERR_BUG);
+ err = gpg_error (GPG_ERR_BUG);
goto leave;
}
err = ksba_cms_set_message_digest (cms, signer, digest, digest_len);
@@ -960,7 +949,6 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
{
log_error ("ksba_cms_set_message_digest failed: %s\n",
gpg_strerror (err));
- rc = err;
goto leave;
}
}
@@ -974,7 +962,6 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
{
log_error ("ksba_cms_set_signing_time failed: %s\n",
gpg_strerror (err));
- rc = err;
goto leave;
}
}
@@ -1016,7 +1003,6 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
if (err)
{
log_error ("creating CMS object failed: %s\n", gpg_strerror (err));
- rc = err;
goto leave;
}
@@ -1028,8 +1014,8 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
log_assert (!detached);
- rc = hash_and_copy_data (data_fp, data_md, writer);
- if (rc)
+ err = hash_and_copy_data (data_fp, data_md, writer);
+ if (err)
goto leave;
audit_log (ctrl->audit, AUDIT_GOT_DATA);
for (cl=signerlist,signer=0; cl; cl = cl->next, signer++)
@@ -1039,7 +1025,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
if ( !digest || !digest_len )
{
log_error ("problem getting the hash of the data\n");
- rc = gpg_error (GPG_ERR_BUG);
+ err = gpg_error (GPG_ERR_BUG);
goto leave;
}
err = ksba_cms_set_message_digest (cms, signer,
@@ -1048,7 +1034,6 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
{
log_error ("ksba_cms_set_message_digest failed: %s\n",
gpg_strerror (err));
- rc = err;
goto leave;
}
}
@@ -1058,10 +1043,10 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
/* Compute the signature for all signers. */
gcry_md_hd_t md;
- rc = gcry_md_open (&md, 0, 0);
- if (rc)
+ err = gcry_md_open (&md, 0, 0);
+ if (err)
{
- log_error ("md_open failed: %s\n", gpg_strerror (rc));
+ log_error ("md_open failed: %s\n", gpg_strerror (err));
goto leave;
}
if (DBG_HASHING)
@@ -1086,20 +1071,20 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
}
}
- rc = ksba_cms_hash_signed_attrs (cms, signer);
- if (rc)
+ err = ksba_cms_hash_signed_attrs (cms, signer);
+ if (err)
{
log_debug ("hashing signed attrs failed: %s\n",
- gpg_strerror (rc));
+ gpg_strerror (err));
gcry_md_close (md);
goto leave;
}
- rc = gpgsm_create_cms_signature (ctrl, cl->cert,
- md, cl->hash_algo, &sigval);
- if (rc)
+ err = gpgsm_create_cms_signature (ctrl, cl->cert,
+ md, cl->hash_algo, &sigval);
+ if (err)
{
- audit_log_cert (ctrl->audit, AUDIT_SIGNED_BY, cl->cert, rc);
+ audit_log_cert (ctrl->audit, AUDIT_SIGNED_BY, cl->cert, err);
gcry_md_close (md);
goto leave;
}
@@ -1111,7 +1096,6 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
audit_log_cert (ctrl->audit, AUDIT_SIGNED_BY, cl->cert, err);
log_error ("failed to store the signature: %s\n",
gpg_strerror (err));
- rc = err;
gcry_md_close (md);
goto leave;
}
@@ -1120,11 +1104,10 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
fpr = gpgsm_get_fingerprint_hexstring (cl->cert, GCRY_MD_SHA1);
if (!fpr)
{
- rc = gpg_error (GPG_ERR_ENOMEM);
+ err = gpg_error (GPG_ERR_ENOMEM);
gcry_md_close (md);
goto leave;
}
- rc = 0;
if (opt.verbose)
{
char *pkalgostr = gpgsm_pubkey_algo_string (cl->cert, NULL);
@@ -1141,9 +1124,9 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
signed_at,
fpr);
if (!buf)
- rc = gpg_error_from_syserror ();
+ err = gpg_error_from_syserror ();
xfree (fpr);
- if (rc)
+ if (err)
{
gcry_md_close (md);
goto leave;
@@ -1157,10 +1140,10 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
}
while (stopreason != KSBA_SR_READY);
- rc = gnupg_ksba_finish_writer (b64writer);
- if (rc)
+ err = gnupg_ksba_finish_writer (b64writer);
+ if (err)
{
- log_error ("write failed: %s\n", gpg_strerror (rc));
+ log_error ("write failed: %s\n", gpg_strerror (err));
goto leave;
}
@@ -1169,13 +1152,14 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
void *blob = NULL;
size_t bloblen;
- rc = es_fclose_snatch (sig_fp, &blob, &bloblen);
+ err = (es_fclose_snatch (sig_fp, &blob, &bloblen)?
+ gpg_error_from_syserror () : 0);
sig_fp = NULL;
- if (rc)
+ if (err)
goto leave;
- rc = write_detached_signature (ctrl, blob, bloblen, out_fp);
+ err = write_detached_signature (ctrl, blob, bloblen, out_fp);
xfree (blob);
- if (rc)
+ if (err)
goto leave;
}
@@ -1184,9 +1168,9 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
log_info ("signature created\n");
leave:
- if (rc)
+ if (err)
log_error ("error creating signature: %s <%s>\n",
- gpg_strerror (rc), gpg_strsource (rc) );
+ gpg_strerror (err), gpg_strsource (err) );
if (release_signerlist)
gpgsm_release_certlist (signerlist);
xfree (curve);
@@ -1195,5 +1179,5 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
keydb_release (kh);
gcry_md_close (data_md);
es_fclose (sig_fp);
- return rc;
+ return err;
}
diff --git a/sm/verify.c b/sm/verify.c
index 9c012596d..53d1b468a 100644
--- a/sm/verify.c
+++ b/sm/verify.c
@@ -485,6 +485,7 @@ gpgsm_verify (ctrl_t ctrl, estream_t in_fp, estream_t data_fp,
audit_log_i (ctrl->audit, AUDIT_DATA_HASH_ALGO, algo);
/* Check compliance. */
+ pkalgoflags |= PK_ALGO_FLAG_ECC18;
if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION,
pkalgo, pkalgoflags, NULL, nbits, pkcurve))
{
diff --git a/tools/gpgconf.c b/tools/gpgconf.c
index 30dd8edfd..83b4bca21 100644
--- a/tools/gpgconf.c
+++ b/tools/gpgconf.c
@@ -34,6 +34,7 @@
#include "../common/init.h"
#include "../common/status.h"
#include "../common/exechelp.h"
+#include "../common/dotlock.h"
#ifdef HAVE_W32_SYSTEM
#include <windows.h>
@@ -76,7 +77,9 @@ enum cmd_and_opt_values
aCreateSocketDir,
aRemoveSocketDir,
aApplyProfile,
- aShowCodepages
+ aShowCodepages,
+ aDotlockLock,
+ aDotlockUnlock
};
@@ -109,7 +112,10 @@ static gpgrt_opt_t opts[] =
{ aRemoveSocketDir, "remove-socketdir", 256, "@"},
ARGPARSE_c (aShowVersions, "show-versions", ""),
ARGPARSE_c (aShowConfigs, "show-configs", ""),
+ /* hidden commands: for debugging */
ARGPARSE_c (aShowCodepages, "show-codepages", "@"),
+ ARGPARSE_c (aDotlockLock, "lock", "@"),
+ ARGPARSE_c (aDotlockUnlock, "unlock", "@"),
{ 301, NULL, 0, N_("@\nOptions:\n ") },
@@ -604,6 +610,41 @@ query_swdb (estream_t out, const char *name, const char *current_version)
}
+#if !defined(HAVE_W32_SYSTEM)
+/* dotlock tool to handle dotlock by command line
+ DO_LOCK: 1 for to lock, 0 for unlock
+ FILENAME: filename for the dotlock */
+static void
+dotlock_tool (int do_lock, const char *filename)
+{
+ dotlock_t h;
+ unsigned int flags = DOTLOCK_LOCK_BY_PARENT;
+
+ if (!do_lock)
+ flags |= DOTLOCK_LOCKED;
+
+ h = dotlock_create (filename, flags);
+ if (!h)
+ {
+ if (do_lock)
+ log_error ("error creating the lock file\n");
+ else
+ log_error ("no lock file found\n");
+ return;
+ }
+
+ if (do_lock)
+ {
+ if (dotlock_take (h, 0))
+ log_error ("error taking the lock\n");
+ }
+ else
+ dotlock_release (h);
+
+ dotlock_destroy (h);
+}
+#endif
+
/* gpgconf main. */
int
main (int argc, char **argv)
@@ -669,6 +710,8 @@ main (int argc, char **argv)
case aShowVersions:
case aShowConfigs:
case aShowCodepages:
+ case aDotlockLock:
+ case aDotlockUnlock:
cmd = pargs.r_opt;
break;
@@ -1024,7 +1067,32 @@ main (int argc, char **argv)
#endif
break;
+ case aDotlockLock:
+ case aDotlockUnlock:
+#if !defined(HAVE_W32_SYSTEM)
+ if (!fname)
+ {
+ es_fprintf (es_stderr, "usage: %s [options] lock|unlock NAME",
+ GPGCONF_NAME);
+ es_putc ('\n', es_stderr);
+ es_fputs (_("Need one NAME argument"), es_stderr);
+ es_putc ('\n', es_stderr);
+ gpgconf_failure (GPG_ERR_USER_2);
+ }
+ else
+ {
+ char *filename;
+
+ /* Keybox pubring.db lock is under public-keys.d. */
+ if (!strcmp (fname, "pubring.db"))
+ fname = "public-keys.d/pubring.db";
+ filename = make_absfilename (gnupg_homedir (), fname, NULL);
+ dotlock_tool (cmd == aDotlockLock, filename);
+ xfree (filename);
+ }
+#endif
+ break;
}
if (outfp != es_stdout)