mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
Merge branch 'STABLE-BRANCH-2-4'
-- Fixed conflicts in NEWS g10/encrypt.c sm/encrypt.c sm/sign.c
This commit is contained in:
commit
2764ee309a
2
AUTHORS
2
AUTHORS
@ -221,7 +221,7 @@ Kyle Butt <kylebutt@gmail.com>
|
|||||||
2013-05-29:CAAODAYLbCtqOG6msLLL0UTdASKWT6u2ptxsgUQ1JpusBESBoNQ@mail.gmail.com:
|
2013-05-29:CAAODAYLbCtqOG6msLLL0UTdASKWT6u2ptxsgUQ1JpusBESBoNQ@mail.gmail.com:
|
||||||
|
|
||||||
Mario Haustein <mario.haustein@hrz.tu-chemnitz.de>
|
Mario Haustein <mario.haustein@hrz.tu-chemnitz.de>
|
||||||
2022-09026:8149069.T7Z3S40VBb@localdomain:
|
2022-09-26:8149069.T7Z3S40VBb@localdomain:
|
||||||
|
|
||||||
Michael Haubenwallner <michael.haubenwallner@ssi-schaefer.com>
|
Michael Haubenwallner <michael.haubenwallner@ssi-schaefer.com>
|
||||||
2018-07-13:c397e637-f1ce-34f0-7e6a-df04a76e1c35@ssi-schaefer.com:
|
2018-07-13:c397e637-f1ce-34f0-7e6a-df04a76e1c35@ssi-schaefer.com:
|
||||||
|
4
NEWS
4
NEWS
@ -1,7 +1,9 @@
|
|||||||
Noteworthy changes in version 2.5.0 (unreleased)
|
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]
|
* Fix garbled time output in non-English Windows. [T6741]
|
||||||
|
|
||||||
|
30
README
30
README
@ -144,6 +144,13 @@
|
|||||||
gpg --import --import-options restore < allkeys.gpg
|
gpg --import --import-options restore < allkeys.gpg
|
||||||
gpgsm --import < allcerts.crt
|
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
|
** Socket directory
|
||||||
|
|
||||||
GnuPG uses Unix domain sockets to connect its components (on Windows
|
GnuPG uses Unix domain sockets to connect its components (on Windows
|
||||||
@ -166,6 +173,29 @@
|
|||||||
fi
|
fi
|
||||||
done )
|
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
|
* DOCUMENTATION
|
||||||
|
|
||||||
|
@ -41,7 +41,8 @@
|
|||||||
|
|
||||||
|
|
||||||
static gpg_error_t read_key_file (const unsigned char *grip,
|
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);
|
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;
|
char **tokenfields = NULL;
|
||||||
int is_regular;
|
int is_regular;
|
||||||
int blocksigs = 0;
|
int blocksigs = 0;
|
||||||
|
char *orig_key_value = NULL;
|
||||||
|
const char *s;
|
||||||
|
int force_modify = 0;
|
||||||
|
|
||||||
fname = fname_from_keygrip (grip, 0);
|
fname = fname_from_keygrip (grip, 0);
|
||||||
if (!fname)
|
if (!fname)
|
||||||
return gpg_error_from_syserror ();
|
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 (err)
|
||||||
{
|
{
|
||||||
if (gpg_err_code (err) == GPG_ERR_ENOENT)
|
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)
|
if (!pk)
|
||||||
{
|
{
|
||||||
/* Key is still in the old format or does not exist - create a
|
/* 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 ();
|
err = gpg_error_from_syserror ();
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
force_modify = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check whether we already have a regular key. */
|
/* Check whether we already have a regular key. */
|
||||||
@ -171,6 +178,19 @@ agent_write_private_key (const unsigned char *grip,
|
|||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
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. */
|
/* 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)
|
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)
|
if (serialno && keyref)
|
||||||
{
|
{
|
||||||
nve_t item;
|
nve_t item;
|
||||||
const char *s;
|
|
||||||
size_t token0len;
|
size_t token0len;
|
||||||
|
|
||||||
if (dispserialno)
|
if (dispserialno)
|
||||||
@ -242,7 +261,7 @@ agent_write_private_key (const unsigned char *grip,
|
|||||||
; /* No need to update Token entry. */
|
; /* No need to update Token entry. */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
err = nve_set (item, token);
|
err = nve_set (pk, item, token);
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
@ -263,6 +282,13 @@ agent_write_private_key (const unsigned char *grip,
|
|||||||
goto leave;
|
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. */
|
/* Create a temporary file for writing. */
|
||||||
tmpfname = fname_from_keygrip (grip, 1);
|
tmpfname = fname_from_keygrip (grip, 1);
|
||||||
fp = tmpfname ? es_fopen (tmpfname, "wbx,mode=-rw") : NULL;
|
fp = tmpfname ? es_fopen (tmpfname, "wbx,mode=-rw") : NULL;
|
||||||
@ -310,6 +336,7 @@ agent_write_private_key (const unsigned char *grip,
|
|||||||
es_fclose (fp);
|
es_fclose (fp);
|
||||||
if (removetmp && tmpfname)
|
if (removetmp && tmpfname)
|
||||||
gnupg_remove (tmpfname);
|
gnupg_remove (tmpfname);
|
||||||
|
xfree (orig_key_value);
|
||||||
xfree (fname);
|
xfree (fname);
|
||||||
xfree (tmpfname);
|
xfree (tmpfname);
|
||||||
xfree (token);
|
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
|
* 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
|
* is not NULL and the extended key format is used, the meta data
|
||||||
* items are stored there. However the "Key:" item is removed from
|
* items are stored there. However the "Key:" item is removed from
|
||||||
* it. On failure returns an error code and stores NULL at RESULT and
|
* it. If R_ORIG_KEY_VALUE is non-NULL and the Key item was removed,
|
||||||
* R_KEYMETA. */
|
* 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
|
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;
|
gpg_error_t err;
|
||||||
char *fname;
|
char *fname;
|
||||||
@ -873,6 +903,8 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta)
|
|||||||
*result = NULL;
|
*result = NULL;
|
||||||
if (r_keymeta)
|
if (r_keymeta)
|
||||||
*r_keymeta = NULL;
|
*r_keymeta = NULL;
|
||||||
|
if (r_orig_key_value)
|
||||||
|
*r_orig_key_value = NULL;
|
||||||
|
|
||||||
fname = fname_from_keygrip (grip, 0);
|
fname = fname_from_keygrip (grip, 0);
|
||||||
if (!fname)
|
if (!fname)
|
||||||
@ -927,8 +959,25 @@ 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",
|
log_error ("error getting private key from '%s': %s\n",
|
||||||
fname, gpg_strerror (err));
|
fname, gpg_strerror (err));
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
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:");
|
nvc_delete_named (pk, "Key:");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!err && r_keymeta)
|
if (!err && r_keymeta)
|
||||||
*r_keymeta = pk;
|
*r_keymeta = pk;
|
||||||
@ -1177,7 +1226,7 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce,
|
|||||||
if (!grip && !ctrl->have_keygrip)
|
if (!grip && !ctrl->have_keygrip)
|
||||||
return gpg_error (GPG_ERR_NO_SECKEY);
|
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 (err)
|
||||||
{
|
{
|
||||||
if (gpg_err_code (err) == GPG_ERR_ENOENT)
|
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;
|
*result = NULL;
|
||||||
|
|
||||||
err = read_key_file (grip, &s_skey, r_keymeta);
|
err = read_key_file (grip, &s_skey, r_keymeta, NULL);
|
||||||
if (!err)
|
if (!err)
|
||||||
*result = s_skey;
|
*result = s_skey;
|
||||||
return err;
|
return err;
|
||||||
@ -1479,7 +1528,7 @@ public_key_from_file (ctrl_t ctrl, const unsigned char *grip,
|
|||||||
if (r_sshorder)
|
if (r_sshorder)
|
||||||
*r_sshorder = 0;
|
*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)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@ -1651,7 +1700,7 @@ agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
|
|||||||
{
|
{
|
||||||
gcry_sexp_t sexp;
|
gcry_sexp_t sexp;
|
||||||
|
|
||||||
err = read_key_file (grip, &sexp, NULL);
|
err = read_key_file (grip, &sexp, NULL, NULL);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
if (gpg_err_code (err) == GPG_ERR_ENOENT)
|
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;
|
char *default_desc = NULL;
|
||||||
int key_type;
|
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)
|
if (gpg_err_code (err) == GPG_ERR_ENOENT)
|
||||||
err = gpg_error (GPG_ERR_NO_SECKEY);
|
err = gpg_error (GPG_ERR_NO_SECKEY);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -256,6 +256,13 @@ gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
|
|||||||
if (! initialized)
|
if (! initialized)
|
||||||
return 1;
|
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)
|
switch (compliance)
|
||||||
{
|
{
|
||||||
case CO_DE_VS:
|
case CO_DE_VS:
|
||||||
@ -280,7 +287,6 @@ gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
|
|||||||
default:
|
default:
|
||||||
log_assert (!"reached");
|
log_assert (!"reached");
|
||||||
}
|
}
|
||||||
(void)algo_flags;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PUBKEY_ALGO_DSA:
|
case PUBKEY_ALGO_DSA:
|
||||||
@ -301,7 +307,7 @@ gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
|
|||||||
result = (use == PK_USE_DECRYPTION);
|
result = (use == PK_USE_DECRYPTION);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PUBKEY_ALGO_ECDH:
|
case PUBKEY_ALGO_ECDH: /* Same value as GCRY_PK_ECC, i.e. 18 */
|
||||||
case GCRY_PK_ECDH:
|
case GCRY_PK_ECDH:
|
||||||
if (use == PK_USE_DECRYPTION)
|
if (use == PK_USE_DECRYPTION)
|
||||||
result = 1;
|
result = 1;
|
||||||
@ -549,6 +555,9 @@ gnupg_rng_is_compliant (enum gnupg_compliance_mode compliance)
|
|||||||
int *result;
|
int *result;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
|
/* #warning debug code ahead */
|
||||||
|
/* return 1; */
|
||||||
|
|
||||||
result = get_compliance_cache (compliance, 1);
|
result = get_compliance_cache (compliance, 1);
|
||||||
|
|
||||||
if (result && *result != -1)
|
if (result && *result != -1)
|
||||||
|
@ -50,6 +50,7 @@ enum pk_use_case
|
|||||||
|
|
||||||
/* Flags to distinguish public key algorithm variants. */
|
/* Flags to distinguish public key algorithm variants. */
|
||||||
#define PK_ALGO_FLAG_RSAPSS 1 /* Use rsaPSS padding. */
|
#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,
|
int gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
|
||||||
|
316
common/dotlock.c
316
common/dotlock.c
@ -291,6 +291,7 @@
|
|||||||
# include <sys/types.h>
|
# include <sys/types.h>
|
||||||
# include <sys/stat.h>
|
# include <sys/stat.h>
|
||||||
# include <sys/utsname.h>
|
# include <sys/utsname.h>
|
||||||
|
# include <dirent.h>
|
||||||
#endif
|
#endif
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
@ -393,9 +394,18 @@ struct dotlock_handle
|
|||||||
unsigned int locked:1; /* Lock status. */
|
unsigned int locked:1; /* Lock status. */
|
||||||
unsigned int disable:1; /* If true, locking is disabled. */
|
unsigned int disable:1; /* If true, locking is disabled. */
|
||||||
unsigned int use_o_excl:1; /* Use open (O_EXCL) for locking. */
|
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. */
|
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
|
#ifdef HAVE_DOSISH_SYSTEM
|
||||||
HANDLE lockhd; /* The W32 handle of the lock file. */
|
HANDLE lockhd; /* The W32 handle of the lock file. */
|
||||||
#else /*!HAVE_DOSISH_SYSTEM */
|
#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 )
|
if ( (fd = open (h->lockname, O_RDONLY)) == -1 )
|
||||||
{
|
{
|
||||||
int e = errno;
|
int e = errno;
|
||||||
|
if (errno != ENOENT)
|
||||||
|
{
|
||||||
my_info_2 ("error opening lockfile '%s': %s\n",
|
my_info_2 ("error opening lockfile '%s': %s\n",
|
||||||
h->lockname, strerror(errno) );
|
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)
|
if (buffer != buffer_space)
|
||||||
xfree (buffer);
|
xfree (buffer);
|
||||||
my_set_errno (e); /* Need to return ERRNO here. */
|
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;
|
int e = errno;
|
||||||
my_info_1 ("error reading lockfile '%s'\n", h->lockname );
|
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);
|
close (fd);
|
||||||
if (buffer != buffer_space)
|
if (buffer != buffer_space)
|
||||||
xfree (buffer);
|
xfree (buffer);
|
||||||
@ -583,6 +604,9 @@ read_lockfile (dotlock_t h, int *same_node, int *r_fd)
|
|||||||
if (nread < 11)
|
if (nread < 11)
|
||||||
{
|
{
|
||||||
my_info_1 ("invalid size of lockfile '%s'\n", h->lockname);
|
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)
|
if (buffer != buffer_space)
|
||||||
xfree (buffer);
|
xfree (buffer);
|
||||||
my_set_errno (EINVAL);
|
my_set_errno (EINVAL);
|
||||||
@ -594,6 +618,9 @@ read_lockfile (dotlock_t h, int *same_node, int *r_fd)
|
|||||||
|| !pid )
|
|| !pid )
|
||||||
{
|
{
|
||||||
my_error_2 ("invalid pid %d in lockfile '%s'\n", pid, h->lockname);
|
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)
|
if (buffer != buffer_space)
|
||||||
xfree (buffer);
|
xfree (buffer);
|
||||||
my_set_errno (EINVAL);
|
my_set_errno (EINVAL);
|
||||||
@ -655,6 +682,80 @@ use_hardlinks_p (const char *tname)
|
|||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_POSIX_SYSTEM
|
#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
|
/* Locking core for Unix. It used a temporary file and the link
|
||||||
system call to make locking an atomic operation. */
|
system call to make locking an atomic operation. */
|
||||||
static dotlock_t
|
static dotlock_t
|
||||||
@ -667,8 +768,10 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
|
|||||||
int dirpartlen;
|
int dirpartlen;
|
||||||
struct utsname utsbuf;
|
struct utsname utsbuf;
|
||||||
size_t tnamelen;
|
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. */
|
/* Create a temporary file. */
|
||||||
if ( uname ( &utsbuf ) )
|
if ( uname ( &utsbuf ) )
|
||||||
@ -702,10 +805,17 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
|
|||||||
}
|
}
|
||||||
h->nodename_len = strlen (nodename);
|
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 );
|
snprintf (h->tname, tnamelen, "%.*s/.#lk%p.", dirpartlen, dirpart, h );
|
||||||
h->nodename_off = strlen (h->tname);
|
h->nodename_off = strlen (h->tname);
|
||||||
snprintf (h->tname+h->nodename_off, tnamelen - h->nodename_off,
|
snprintf (h->tname+h->nodename_off, tnamelen - h->nodename_off,
|
||||||
"%s.%d", nodename, (int)getpid ());
|
"%s.%d", nodename, pid);
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -722,6 +832,10 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
|
|||||||
UNLOCK_all_lockfiles ();
|
UNLOCK_all_lockfiles ();
|
||||||
my_error_2 (_("failed to create temporary file '%s': %s\n"),
|
my_error_2 (_("failed to create temporary file '%s': %s\n"),
|
||||||
h->tname, strerror (errno));
|
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->tname);
|
||||||
xfree (h);
|
xfree (h);
|
||||||
my_set_errno (saveerrno);
|
my_set_errno (saveerrno);
|
||||||
@ -755,11 +869,16 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
|
|||||||
int saveerrno = errno;
|
int saveerrno = errno;
|
||||||
my_error_2 ("can't check whether hardlinks are supported for '%s': %s\n"
|
my_error_2 ("can't check whether hardlinks are supported for '%s': %s\n"
|
||||||
, h->tname, strerror (saveerrno));
|
, 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);
|
my_set_errno (saveerrno);
|
||||||
}
|
}
|
||||||
goto write_failed;
|
goto write_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
skip_write:
|
||||||
h->lockname = xtrymalloc (strlen (file_to_lock) + 6 );
|
h->lockname = xtrymalloc (strlen (file_to_lock) + 6 );
|
||||||
if (!h->lockname)
|
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");
|
strcpy (stpcpy (h->lockname, file_to_lock), EXTSEP_S "lock");
|
||||||
UNLOCK_all_lockfiles ();
|
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;
|
return h;
|
||||||
|
|
||||||
write_failed:
|
write_failed:
|
||||||
@ -783,6 +916,11 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
|
|||||||
all_lockfiles = h->next;
|
all_lockfiles = h->next;
|
||||||
UNLOCK_all_lockfiles ();
|
UNLOCK_all_lockfiles ();
|
||||||
my_error_2 (_("error writing to '%s': %s\n"), h->tname, strerror (errno));
|
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 )
|
if ( fd != -1 )
|
||||||
close (fd);
|
close (fd);
|
||||||
unlink (h->tname);
|
unlink (h->tname);
|
||||||
@ -849,6 +987,10 @@ dotlock_create_w32 (dotlock_t h, const char *file_to_lock)
|
|||||||
all_lockfiles = h->next;
|
all_lockfiles = h->next;
|
||||||
UNLOCK_all_lockfiles ();
|
UNLOCK_all_lockfiles ();
|
||||||
my_error_2 (_("can't create '%s': %s\n"), h->lockname, w32_strerror (-1));
|
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->lockname);
|
||||||
xfree (h);
|
xfree (h);
|
||||||
my_set_errno (saveerrno);
|
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
|
POSIX systems a temporary file ".#lk.<hostname>.pid[.threadid] is
|
||||||
used.
|
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
|
The function returns an new handle which needs to be released using
|
||||||
destroy_dotlock but gets also released at the termination of the
|
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;
|
static int initialized;
|
||||||
dotlock_t h;
|
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);
|
atexit (dotlock_remove_lockfiles);
|
||||||
initialized = 1;
|
initialized = 1;
|
||||||
@ -895,7 +1050,15 @@ dotlock_create (const char *file_to_lock, unsigned int flags)
|
|||||||
if ( !file_to_lock )
|
if ( !file_to_lock )
|
||||||
return NULL; /* Only initialization was requested. */
|
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);
|
my_set_errno (EINVAL);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -905,6 +1068,10 @@ dotlock_create (const char *file_to_lock, unsigned int flags)
|
|||||||
if (!h)
|
if (!h)
|
||||||
return NULL;
|
return NULL;
|
||||||
h->extra_fd = -1;
|
h->extra_fd = -1;
|
||||||
|
#ifndef HAVE_DOSISH_SYSTEM
|
||||||
|
h->by_parent = by_parent;
|
||||||
|
h->no_write = no_write;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (never_lock)
|
if (never_lock)
|
||||||
{
|
{
|
||||||
@ -916,6 +1083,24 @@ dotlock_create (const char *file_to_lock, unsigned int flags)
|
|||||||
return h;
|
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
|
#ifdef HAVE_DOSISH_SYSTEM
|
||||||
return dotlock_create_w32 (h, file_to_lock);
|
return dotlock_create_w32 (h, file_to_lock);
|
||||||
#else /*!HAVE_DOSISH_SYSTEM */
|
#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
|
#ifdef HAVE_POSIX_SYSTEM
|
||||||
/* Unix specific code of destroy_dotlock. */
|
/* Unix specific code of destroy_dotlock. */
|
||||||
@ -952,7 +1155,6 @@ dotlock_destroy_unix (dotlock_t h)
|
|||||||
unlink (h->lockname);
|
unlink (h->lockname);
|
||||||
if (h->tname && !h->use_o_excl)
|
if (h->tname && !h->use_o_excl)
|
||||||
unlink (h->tname);
|
unlink (h->tname);
|
||||||
xfree (h->tname);
|
|
||||||
}
|
}
|
||||||
#endif /*HAVE_POSIX_SYSTEM*/
|
#endif /*HAVE_POSIX_SYSTEM*/
|
||||||
|
|
||||||
@ -998,15 +1200,28 @@ dotlock_destroy (dotlock_t h)
|
|||||||
UNLOCK_all_lockfiles ();
|
UNLOCK_all_lockfiles ();
|
||||||
|
|
||||||
/* Then destroy the lock. */
|
/* 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
|
#ifdef HAVE_DOSISH_SYSTEM
|
||||||
dotlock_destroy_w32 (h);
|
dotlock_destroy_w32 (h);
|
||||||
#else /* !HAVE_DOSISH_SYSTEM */
|
#else /* !HAVE_DOSISH_SYSTEM */
|
||||||
dotlock_destroy_unix (h);
|
dotlock_destroy_unix (h);
|
||||||
#endif /* HAVE_DOSISH_SYSTEM */
|
#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);
|
xfree(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1061,6 +1276,7 @@ static int
|
|||||||
dotlock_take_unix (dotlock_t h, long timeout)
|
dotlock_take_unix (dotlock_t h, long timeout)
|
||||||
{
|
{
|
||||||
int wtime = 0;
|
int wtime = 0;
|
||||||
|
int timedout = 0;
|
||||||
int sumtime = 0;
|
int sumtime = 0;
|
||||||
int pid;
|
int pid;
|
||||||
int lastpid = -1;
|
int lastpid = -1;
|
||||||
@ -1089,6 +1305,10 @@ dotlock_take_unix (dotlock_t h, long timeout)
|
|||||||
saveerrno = errno;
|
saveerrno = errno;
|
||||||
my_error_2 ("lock not made: open(O_EXCL) of '%s' failed: %s\n",
|
my_error_2 ("lock not made: open(O_EXCL) of '%s' failed: %s\n",
|
||||||
h->lockname, strerror (saveerrno));
|
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);
|
my_set_errno (saveerrno);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1096,7 +1316,8 @@ dotlock_take_unix (dotlock_t h, long timeout)
|
|||||||
{
|
{
|
||||||
char pidstr[16];
|
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
|
if (write (fd, pidstr, 11 ) == 11
|
||||||
&& write (fd, h->tname + h->nodename_off,h->nodename_len)
|
&& write (fd, h->tname + h->nodename_off,h->nodename_len)
|
||||||
== h->nodename_len
|
== h->nodename_len
|
||||||
@ -1110,6 +1331,10 @@ dotlock_take_unix (dotlock_t h, long timeout)
|
|||||||
saveerrno = errno;
|
saveerrno = errno;
|
||||||
my_error_2 ("lock not made: writing to '%s' failed: %s\n",
|
my_error_2 ("lock not made: writing to '%s' failed: %s\n",
|
||||||
h->lockname, strerror (errno));
|
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);
|
close (fd);
|
||||||
unlink (h->lockname);
|
unlink (h->lockname);
|
||||||
my_set_errno (saveerrno);
|
my_set_errno (saveerrno);
|
||||||
@ -1128,6 +1353,10 @@ dotlock_take_unix (dotlock_t h, long timeout)
|
|||||||
saveerrno = errno;
|
saveerrno = errno;
|
||||||
my_error_1 ("lock not made: Oops: stat of tmp file failed: %s\n",
|
my_error_1 ("lock not made: Oops: stat of tmp file failed: %s\n",
|
||||||
strerror (errno));
|
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
|
/* In theory this might be a severe error: It is possible
|
||||||
that link succeeded but stat failed due to changed
|
that link succeeded but stat failed due to changed
|
||||||
permissions. We can't do anything about it, though. */
|
permissions. We can't do anything about it, though. */
|
||||||
@ -1149,16 +1378,19 @@ dotlock_take_unix (dotlock_t h, long timeout)
|
|||||||
{
|
{
|
||||||
saveerrno = errno;
|
saveerrno = errno;
|
||||||
my_info_0 ("cannot read lockfile\n");
|
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);
|
my_set_errno (saveerrno);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
my_info_0 ("lockfile disappeared\n");
|
my_info_0 ("lockfile disappeared\n");
|
||||||
goto again;
|
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) )
|
|| (same_node && kill (pid, 0) && errno == ESRCH) )
|
||||||
/* Stale lockfile is detected. */
|
|
||||||
{
|
{
|
||||||
|
/* Stale lockfile is detected. */
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
|
|
||||||
/* Check if it's unlocked during examining the lockfile. */
|
/* Check if it's unlocked during examining the lockfile. */
|
||||||
@ -1201,6 +1433,9 @@ dotlock_take_unix (dotlock_t h, long timeout)
|
|||||||
unlink (h->lockname);
|
unlink (h->lockname);
|
||||||
my_info_1 (_("removing stale lockfile (created by %d)\n"), pid);
|
my_info_1 (_("removing stale lockfile (created by %d)\n"), pid);
|
||||||
close (fd);
|
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;
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1218,6 +1453,8 @@ dotlock_take_unix (dotlock_t h, long timeout)
|
|||||||
wtime = 0; /* Reset because owner chnaged. */
|
wtime = 0; /* Reset because owner chnaged. */
|
||||||
|
|
||||||
wtimereal = next_wait_interval (&wtime, &timeout);
|
wtimereal = next_wait_interval (&wtime, &timeout);
|
||||||
|
if (!timeout)
|
||||||
|
timedout = 1; /* remember. */
|
||||||
|
|
||||||
sumtime += wtimereal;
|
sumtime += wtimereal;
|
||||||
if (sumtime >= 1500)
|
if (sumtime >= 1500)
|
||||||
@ -1225,6 +1462,15 @@ dotlock_take_unix (dotlock_t h, long timeout)
|
|||||||
sumtime = 0;
|
sumtime = 0;
|
||||||
my_info_3 (_("waiting for lock (held by %d%s) %s...\n"),
|
my_info_3 (_("waiting for lock (held by %d%s) %s...\n"),
|
||||||
pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):"");
|
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;
|
tv.tv_sec = wtimereal / 1000;
|
||||||
@ -1233,7 +1479,7 @@ dotlock_take_unix (dotlock_t h, long timeout)
|
|||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
my_set_errno (EACCES);
|
my_set_errno (timedout? ETIMEDOUT : EACCES);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif /*HAVE_POSIX_SYSTEM*/
|
#endif /*HAVE_POSIX_SYSTEM*/
|
||||||
@ -1246,6 +1492,7 @@ static int
|
|||||||
dotlock_take_w32 (dotlock_t h, long timeout)
|
dotlock_take_w32 (dotlock_t h, long timeout)
|
||||||
{
|
{
|
||||||
int wtime = 0;
|
int wtime = 0;
|
||||||
|
int timedout = 0;
|
||||||
int w32err;
|
int w32err;
|
||||||
OVERLAPPED ovl;
|
OVERLAPPED ovl;
|
||||||
|
|
||||||
@ -1264,7 +1511,11 @@ dotlock_take_w32 (dotlock_t h, long timeout)
|
|||||||
{
|
{
|
||||||
my_error_2 (_("lock '%s' not made: %s\n"),
|
my_error_2 (_("lock '%s' not made: %s\n"),
|
||||||
h->lockname, w32_strerror (w32err));
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1273,15 +1524,26 @@ dotlock_take_w32 (dotlock_t h, long timeout)
|
|||||||
int wtimereal;
|
int wtimereal;
|
||||||
|
|
||||||
wtimereal = next_wait_interval (&wtime, &timeout);
|
wtimereal = next_wait_interval (&wtime, &timeout);
|
||||||
|
if (!timeout)
|
||||||
|
timedout = 1; /* remember. */
|
||||||
|
|
||||||
if (wtime >= 800)
|
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);
|
Sleep (wtimereal);
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
my_set_errno (EACCES);
|
my_set_errno (timedout? ETIMEDOUT : EACCES);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif /*HAVE_DOSISH_SYSTEM*/
|
#endif /*HAVE_DOSISH_SYSTEM*/
|
||||||
@ -1328,12 +1590,18 @@ dotlock_release_unix (dotlock_t h)
|
|||||||
{
|
{
|
||||||
saveerrno = errno;
|
saveerrno = errno;
|
||||||
my_error_0 ("release_dotlock: lockfile error\n");
|
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);
|
my_set_errno (saveerrno);
|
||||||
return -1;
|
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);
|
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);
|
my_set_errno (EACCES);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1343,6 +1611,10 @@ dotlock_release_unix (dotlock_t h)
|
|||||||
saveerrno = errno;
|
saveerrno = errno;
|
||||||
my_error_1 ("release_dotlock: error removing lockfile '%s'\n",
|
my_error_1 ("release_dotlock: error removing lockfile '%s'\n",
|
||||||
h->lockname);
|
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);
|
my_set_errno (saveerrno);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1363,10 +1635,15 @@ dotlock_release_w32 (dotlock_t h)
|
|||||||
memset (&ovl, 0, sizeof ovl);
|
memset (&ovl, 0, sizeof ovl);
|
||||||
if (!UnlockFileEx (h->lockhd, 0, 1, 0, &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",
|
my_error_2 ("release_dotlock: error removing lockfile '%s': %s\n",
|
||||||
h->lockname, w32_strerror (-1));
|
h->lockname, w32_strerror (ec));
|
||||||
my_set_errno (saveerrno);
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1397,6 +1674,9 @@ dotlock_release (dotlock_t h)
|
|||||||
if ( !h->locked )
|
if ( !h->locked )
|
||||||
{
|
{
|
||||||
my_debug_1 ("Oops, '%s' is not locked\n", h->lockname);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,12 +97,35 @@ extern "C"
|
|||||||
struct dotlock_handle;
|
struct dotlock_handle;
|
||||||
typedef struct dotlock_handle *dotlock_t;
|
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);
|
void dotlock_disable (void);
|
||||||
dotlock_t dotlock_create (const char *file_to_lock, unsigned int flags);
|
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);
|
void dotlock_set_fd (dotlock_t h, int fd);
|
||||||
int dotlock_get_fd (dotlock_t h);
|
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);
|
void dotlock_destroy (dotlock_t h);
|
||||||
int dotlock_take (dotlock_t h, long timeout);
|
int dotlock_take (dotlock_t h, long timeout);
|
||||||
|
int dotlock_is_locked (dotlock_t h);
|
||||||
int dotlock_release (dotlock_t h);
|
int dotlock_release (dotlock_t h);
|
||||||
void dotlock_remove_lockfiles (void);
|
void dotlock_remove_lockfiles (void);
|
||||||
|
|
||||||
|
146
common/homedir.c
146
common/homedir.c
@ -77,6 +77,14 @@
|
|||||||
#endif
|
#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
|
/* The GnuPG homedir. This is only accessed by the functions
|
||||||
* gnupg_homedir and gnupg_set_homedir. Malloced. */
|
* gnupg_homedir and gnupg_set_homedir. Malloced. */
|
||||||
static char *the_gnupg_homedir;
|
static char *the_gnupg_homedir;
|
||||||
@ -491,11 +499,12 @@ w32_rootdir (void)
|
|||||||
* file system. If WANT_SYSCONFDIR is true the optional sysconfdir
|
* file system. If WANT_SYSCONFDIR is true the optional sysconfdir
|
||||||
* entry is returned. */
|
* entry is returned. */
|
||||||
static const char *
|
static const char *
|
||||||
unix_rootdir (int want_sysconfdir)
|
unix_rootdir (enum wantdir_values wantdir)
|
||||||
{
|
{
|
||||||
static int checked;
|
static int checked;
|
||||||
static char *dir; /* for the rootdir */
|
static char *dir; /* for the rootdir */
|
||||||
static char *sdir; /* for the sysconfdir */
|
static char *sdir; /* for the sysconfdir */
|
||||||
|
static char *s2dir; /* for the socketdir */
|
||||||
|
|
||||||
if (!checked)
|
if (!checked)
|
||||||
{
|
{
|
||||||
@ -510,8 +519,10 @@ unix_rootdir (int want_sysconfdir)
|
|||||||
estream_t fp;
|
estream_t fp;
|
||||||
char *rootdir;
|
char *rootdir;
|
||||||
char *sysconfdir;
|
char *sysconfdir;
|
||||||
|
char *socketdir;
|
||||||
const char *name;
|
const char *name;
|
||||||
int ignoreall = 0;
|
int ignoreall = 0;
|
||||||
|
int okay;
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@ -602,45 +613,44 @@ unix_rootdir (int want_sysconfdir)
|
|||||||
linelen = 0;
|
linelen = 0;
|
||||||
rootdir = NULL;
|
rootdir = NULL;
|
||||||
sysconfdir = NULL;
|
sysconfdir = NULL;
|
||||||
|
socketdir = NULL;
|
||||||
while ((length = es_read_line (fp, &line, &linelen, NULL)) > 0)
|
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. */
|
/* Strip NL and CR, if present. */
|
||||||
while (length > 0
|
while (length > 0
|
||||||
&& (line[length - 1] == '\n' || line[length - 1] == '\r'))
|
&& (line[length - 1] == '\n' || line[length - 1] == '\r'))
|
||||||
line[--length] = 0;
|
line[--length] = 0;
|
||||||
trim_spaces (line);
|
trim_spaces (line);
|
||||||
if (!strncmp (line, "rootdir=", 8))
|
/* Find the stamement. */
|
||||||
|
name = NULL;
|
||||||
|
for (i=0; i < DIM (names); i++)
|
||||||
{
|
{
|
||||||
name = "rootdir";
|
n = strlen (names[i]);
|
||||||
p = line + 8;
|
if (!strncmp (line, names[i], n))
|
||||||
}
|
|
||||||
else if (!strncmp (line, "rootdir =", 9)) /* (What a kludge) */
|
|
||||||
{
|
{
|
||||||
name = "rootdir";
|
while (line[n] == ' ' || line[n] == '\t')
|
||||||
p = line + 9;
|
n++;
|
||||||
}
|
if (line[n] == '=')
|
||||||
else if (!strncmp (line, "sysconfdir=", 11))
|
|
||||||
{
|
{
|
||||||
name = "sysconfdir";
|
name = names[i];
|
||||||
p = line + 11;
|
p = line + n + 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
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))
|
if (!name)
|
||||||
{
|
continue; /* Statement not known. */
|
||||||
name = ".enable";
|
|
||||||
p = line + 9;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
trim_spaces (p);
|
trim_spaces (p);
|
||||||
p = substitute_envvars (p);
|
p = substitute_envvars (p);
|
||||||
if (!p)
|
if (!p)
|
||||||
@ -665,6 +675,11 @@ unix_rootdir (int want_sysconfdir)
|
|||||||
xfree (sysconfdir);
|
xfree (sysconfdir);
|
||||||
sysconfdir = p;
|
sysconfdir = p;
|
||||||
}
|
}
|
||||||
|
else if (!strcmp (name, "socketdir"))
|
||||||
|
{
|
||||||
|
xfree (socketdir);
|
||||||
|
socketdir = p;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
xfree (rootdir);
|
xfree (rootdir);
|
||||||
@ -680,6 +695,7 @@ unix_rootdir (int want_sysconfdir)
|
|||||||
xfree (line);
|
xfree (line);
|
||||||
xfree (rootdir);
|
xfree (rootdir);
|
||||||
xfree (sysconfdir);
|
xfree (sysconfdir);
|
||||||
|
xfree (socketdir);
|
||||||
checked = 1;
|
checked = 1;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -687,29 +703,26 @@ unix_rootdir (int want_sysconfdir)
|
|||||||
xfree (buffer);
|
xfree (buffer);
|
||||||
xfree (line);
|
xfree (line);
|
||||||
|
|
||||||
|
okay = 0;
|
||||||
if (ignoreall)
|
if (ignoreall)
|
||||||
{
|
;
|
||||||
xfree (rootdir);
|
|
||||||
xfree (sysconfdir);
|
|
||||||
sdir = dir = NULL;
|
|
||||||
}
|
|
||||||
else if (!rootdir || !*rootdir || *rootdir != '/')
|
else if (!rootdir || !*rootdir || *rootdir != '/')
|
||||||
{
|
{
|
||||||
log_info ("invalid rootdir '%s' specified in gpgconf.ctl\n", rootdir);
|
log_info ("invalid rootdir '%s' specified in gpgconf.ctl\n", rootdir);
|
||||||
xfree (rootdir);
|
|
||||||
xfree (sysconfdir);
|
|
||||||
dir = NULL;
|
|
||||||
}
|
}
|
||||||
else if (sysconfdir && (!*sysconfdir || *sysconfdir != '/'))
|
else if (sysconfdir && (!*sysconfdir || *sysconfdir != '/'))
|
||||||
{
|
{
|
||||||
log_info ("invalid sysconfdir '%s' specified in gpgconf.ctl\n",
|
log_info ("invalid sysconfdir '%s' specified in gpgconf.ctl\n",
|
||||||
sysconfdir);
|
sysconfdir);
|
||||||
xfree (rootdir);
|
}
|
||||||
xfree (sysconfdir);
|
else if (socketdir && (!*socketdir || *socketdir != '/'))
|
||||||
dir = NULL;
|
{
|
||||||
|
log_info ("invalid socketdir '%s' specified in gpgconf.ctl\n",
|
||||||
|
socketdir);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
okay = 1;
|
||||||
while (*rootdir && rootdir[strlen (rootdir)-1] == '/')
|
while (*rootdir && rootdir[strlen (rootdir)-1] == '/')
|
||||||
rootdir[strlen (rootdir)-1] = 0;
|
rootdir[strlen (rootdir)-1] = 0;
|
||||||
dir = rootdir;
|
dir = rootdir;
|
||||||
@ -723,11 +736,34 @@ unix_rootdir (int want_sysconfdir)
|
|||||||
gpgrt_annotate_leaked_object (sdir);
|
gpgrt_annotate_leaked_object (sdir);
|
||||||
/* log_info ("want sysconfdir '%s'\n", 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;
|
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 */
|
#endif /* Unix */
|
||||||
|
|
||||||
@ -1038,7 +1074,8 @@ _gnupg_socketdir_internal (int skip_checks, unsigned *r_info)
|
|||||||
};
|
};
|
||||||
int i;
|
int i;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
char prefix[19 + 1 + 20 + 6 + 1];
|
char prefixbuffer[19 + 1 + 20 + 6 + 1];
|
||||||
|
const char *prefix;
|
||||||
const char *s;
|
const char *s;
|
||||||
char *name = NULL;
|
char *name = NULL;
|
||||||
|
|
||||||
@ -1053,11 +1090,16 @@ _gnupg_socketdir_internal (int skip_checks, unsigned *r_info)
|
|||||||
* as a background process with no (desktop) user logged in. Thus
|
* as a background process with no (desktop) user logged in. Thus
|
||||||
* we better don't do that. */
|
* we better don't do that. */
|
||||||
|
|
||||||
/* Check whether we have a /run/[gnupg/]user dir. */
|
prefix = unix_rootdir (WANTDIR_SOCKET);
|
||||||
|
if (!prefix)
|
||||||
|
{
|
||||||
|
/* gpgconf.ctl does not specify a directory. Check whether we
|
||||||
|
* have the usual /run/[gnupg/]user dir. */
|
||||||
for (i=0; bases[i]; i++)
|
for (i=0; bases[i]; i++)
|
||||||
{
|
{
|
||||||
snprintf (prefix, sizeof prefix, "%s/user/%u",
|
snprintf (prefixbuffer, sizeof prefixbuffer, "%s/user/%u",
|
||||||
bases[i], (unsigned int)getuid ());
|
bases[i], (unsigned int)getuid ());
|
||||||
|
prefix = prefixbuffer;
|
||||||
if (!stat (prefix, &sb) && S_ISDIR(sb.st_mode))
|
if (!stat (prefix, &sb) && S_ISDIR(sb.st_mode))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1074,14 +1116,16 @@ _gnupg_socketdir_internal (int skip_checks, unsigned *r_info)
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen (prefix) + 7 >= sizeof prefix)
|
if (strlen (prefix) + 7 >= sizeof prefixbuffer)
|
||||||
{
|
{
|
||||||
*r_info |= 1; /* Ooops: Buffer too short to append "/gnupg". */
|
*r_info |= 1; /* Ooops: Buffer too short to append "/gnupg". */
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
strcat (prefix, "/gnupg");
|
strcat (prefixbuffer, "/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 (stat (prefix, &sb))
|
||||||
{
|
{
|
||||||
if (errno != ENOENT)
|
if (errno != ENOENT)
|
||||||
@ -1241,7 +1285,7 @@ gnupg_sysconfdir (void)
|
|||||||
}
|
}
|
||||||
return name;
|
return name;
|
||||||
#else /*!HAVE_W32_SYSTEM*/
|
#else /*!HAVE_W32_SYSTEM*/
|
||||||
const char *dir = unix_rootdir (1);
|
const char *dir = unix_rootdir (WANTDIR_SYSCONF);
|
||||||
if (dir)
|
if (dir)
|
||||||
return dir;
|
return dir;
|
||||||
else
|
else
|
||||||
@ -1270,7 +1314,7 @@ gnupg_bindir (void)
|
|||||||
else
|
else
|
||||||
return rdir;
|
return rdir;
|
||||||
#else /*!HAVE_W32_SYSTEM*/
|
#else /*!HAVE_W32_SYSTEM*/
|
||||||
rdir = unix_rootdir (0);
|
rdir = unix_rootdir (WANTDIR_ROOT);
|
||||||
if (rdir)
|
if (rdir)
|
||||||
{
|
{
|
||||||
if (!name)
|
if (!name)
|
||||||
@ -1297,7 +1341,7 @@ gnupg_libexecdir (void)
|
|||||||
static char *name;
|
static char *name;
|
||||||
const char *rdir;
|
const char *rdir;
|
||||||
|
|
||||||
rdir = unix_rootdir (0);
|
rdir = unix_rootdir (WANTDIR_ROOT);
|
||||||
if (rdir)
|
if (rdir)
|
||||||
{
|
{
|
||||||
if (!name)
|
if (!name)
|
||||||
@ -1327,7 +1371,7 @@ gnupg_libdir (void)
|
|||||||
#else /*!HAVE_W32_SYSTEM*/
|
#else /*!HAVE_W32_SYSTEM*/
|
||||||
const char *rdir;
|
const char *rdir;
|
||||||
|
|
||||||
rdir = unix_rootdir (0);
|
rdir = unix_rootdir (WANTDIR_ROOT);
|
||||||
if (rdir)
|
if (rdir)
|
||||||
{
|
{
|
||||||
if (!name)
|
if (!name)
|
||||||
@ -1358,7 +1402,7 @@ gnupg_datadir (void)
|
|||||||
#else /*!HAVE_W32_SYSTEM*/
|
#else /*!HAVE_W32_SYSTEM*/
|
||||||
const char *rdir;
|
const char *rdir;
|
||||||
|
|
||||||
rdir = unix_rootdir (0);
|
rdir = unix_rootdir (WANTDIR_ROOT);
|
||||||
if (rdir)
|
if (rdir)
|
||||||
{
|
{
|
||||||
if (!name)
|
if (!name)
|
||||||
@ -1390,7 +1434,7 @@ gnupg_localedir (void)
|
|||||||
#else /*!HAVE_W32_SYSTEM*/
|
#else /*!HAVE_W32_SYSTEM*/
|
||||||
const char *rdir;
|
const char *rdir;
|
||||||
|
|
||||||
rdir = unix_rootdir (0);
|
rdir = unix_rootdir (WANTDIR_ROOT);
|
||||||
if (rdir)
|
if (rdir)
|
||||||
{
|
{
|
||||||
if (!name)
|
if (!name)
|
||||||
|
@ -48,6 +48,7 @@ struct name_value_container
|
|||||||
struct name_value_entry *first;
|
struct name_value_entry *first;
|
||||||
struct name_value_entry *last;
|
struct name_value_entry *last;
|
||||||
unsigned int private_key_mode:1;
|
unsigned int private_key_mode:1;
|
||||||
|
unsigned int modified:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -87,11 +88,15 @@ my_error (gpg_err_code_t ec)
|
|||||||
|
|
||||||
/* Allocation and deallocation. */
|
/* Allocation and deallocation. */
|
||||||
|
|
||||||
/* Allocate a private key container structure. */
|
/* Allocate a name value container structure. */
|
||||||
nvc_t
|
nvc_t
|
||||||
nvc_new (void)
|
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);
|
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. */
|
/* Dealing with names and values. */
|
||||||
@ -427,6 +450,8 @@ _nvc_add (nvc_t pk, char *name, char *value, strlist_t raw_value,
|
|||||||
else
|
else
|
||||||
pk->first = pk->last = e;
|
pk->first = pk->last = e;
|
||||||
|
|
||||||
|
pk->modified = 1;
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
@ -476,36 +501,29 @@ nvc_set (nvc_t pk, const char *name, const char *value)
|
|||||||
|
|
||||||
e = nvc_lookup (pk, name);
|
e = nvc_lookup (pk, name);
|
||||||
if (e)
|
if (e)
|
||||||
{
|
return nve_set (pk, e, value);
|
||||||
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;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
return nvc_add (pk, name, value);
|
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
|
gpg_error_t
|
||||||
nve_set (nve_t e, const char *value)
|
nve_set (nvc_t pk, nve_t e, const char *value)
|
||||||
{
|
{
|
||||||
char *v;
|
char *v;
|
||||||
|
|
||||||
if (!e)
|
if (!e)
|
||||||
return GPG_ERR_INV_ARG;
|
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:"");
|
v = xtrystrdup (value? value:"");
|
||||||
if (!v)
|
if (!v)
|
||||||
return my_error_from_syserror ();
|
return my_error_from_syserror ();
|
||||||
@ -516,6 +534,8 @@ nve_set (nve_t e, const char *value)
|
|||||||
wipememory (e->value, strlen (e->value));
|
wipememory (e->value, strlen (e->value));
|
||||||
xfree (e->value);
|
xfree (e->value);
|
||||||
e->value = v;
|
e->value = v;
|
||||||
|
if (pk)
|
||||||
|
pk->modified = 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -536,6 +556,7 @@ nvc_delete (nvc_t pk, nve_t entry)
|
|||||||
pk->last = entry->prev;
|
pk->last = entry->prev;
|
||||||
|
|
||||||
nve_release (entry, pk->private_key_mode);
|
nve_release (entry, pk->private_key_mode);
|
||||||
|
pk->modified = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -50,6 +50,9 @@ nvc_t nvc_new_private_key (void);
|
|||||||
/* Release a name value container structure. */
|
/* Release a name value container structure. */
|
||||||
void nvc_release (nvc_t pk);
|
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. */
|
/* Get the name. */
|
||||||
char *nve_name (nve_t pke);
|
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. */
|
first entry is updated. */
|
||||||
gpg_error_t nvc_set (nvc_t pk, const char *name, const char *value);
|
gpg_error_t nvc_set (nvc_t pk, const char *name, const char *value);
|
||||||
|
|
||||||
/* Update entry E to VALUE. */
|
/* Update entry E to VALUE. PK is optional. */
|
||||||
gpg_error_t nve_set (nve_t e, const char *value);
|
gpg_error_t nve_set (nvc_t pk, nve_t e, const char *value);
|
||||||
|
|
||||||
/* Delete the given entry from PK. */
|
/* Delete the given entry from PK. */
|
||||||
void nvc_delete (nvc_t pk, nve_t pke);
|
void nvc_delete (nvc_t pk, nve_t pke);
|
||||||
|
@ -122,6 +122,9 @@ typedef enum
|
|||||||
SIGSUBPKT_ATTST_SIGS = 37, /* Attested Certifications. */
|
SIGSUBPKT_ATTST_SIGS = 37, /* Attested Certifications. */
|
||||||
SIGSUBPKT_KEY_BLOCK = 38, /* Entire key used. */
|
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
|
SIGSUBPKT_FLAG_CRITICAL = 128
|
||||||
}
|
}
|
||||||
sigsubpkttype_t;
|
sigsubpkttype_t;
|
||||||
|
@ -52,6 +52,7 @@
|
|||||||
#ifdef HAVE_W32_SYSTEM
|
#ifdef HAVE_W32_SYSTEM
|
||||||
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
|
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
|
||||||
|
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
w32_strerror (int ec)
|
w32_strerror (int ec)
|
||||||
{
|
{
|
||||||
@ -174,6 +175,11 @@ strconcat (const char *s1, ...)
|
|||||||
|
|
||||||
#define PGM "t-dotlock"
|
#define PGM "t-dotlock"
|
||||||
|
|
||||||
|
static int opt_silent;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef HAVE_W32_SYSTEM
|
#ifndef HAVE_W32_SYSTEM
|
||||||
static volatile int ctrl_c_pending_flag;
|
static volatile int ctrl_c_pending_flag;
|
||||||
static void
|
static void
|
||||||
@ -217,6 +223,9 @@ inf (const char *format, ...)
|
|||||||
{
|
{
|
||||||
va_list arg_ptr;
|
va_list arg_ptr;
|
||||||
|
|
||||||
|
if (opt_silent)
|
||||||
|
return;
|
||||||
|
|
||||||
va_start (arg_ptr, format);
|
va_start (arg_ptr, format);
|
||||||
fprintf (stderr, PGM "[%lu]: ", (unsigned long)getpid ());
|
fprintf (stderr, PGM "[%lu]: ", (unsigned long)getpid ());
|
||||||
vfprintf (stderr, format, arg_ptr);
|
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
|
static void
|
||||||
lock_and_unlock (const char *fname)
|
lock_and_unlock (const char *fname)
|
||||||
{
|
{
|
||||||
dotlock_t h;
|
dotlock_t h;
|
||||||
unsigned long usec;
|
unsigned long usec;
|
||||||
|
|
||||||
h = dotlock_create (fname, 0);
|
h = dotlock_create (fname, DOTLOCK_PREPARE_CREATE);
|
||||||
if (!h)
|
if (!h)
|
||||||
die ("error creating lock file for '%s': %s", fname, strerror (errno));
|
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");
|
inf ("lock created");
|
||||||
|
|
||||||
do
|
do
|
||||||
@ -270,6 +299,11 @@ main (int argc, char **argv)
|
|||||||
ctrl_c_pending_flag = 1;
|
ctrl_c_pending_flag = 1;
|
||||||
argc--;
|
argc--;
|
||||||
}
|
}
|
||||||
|
if (argc > 1 && !strcmp (argv[1], "--silent"))
|
||||||
|
{
|
||||||
|
opt_silent = 1;
|
||||||
|
argc--;
|
||||||
|
}
|
||||||
|
|
||||||
if (argc > 1)
|
if (argc > 1)
|
||||||
fname = argv[argc-1];
|
fname = argv[argc-1];
|
||||||
|
@ -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
|
On Windows systems it is possible to install GnuPG as a portable
|
||||||
application. In this case only this command line option is
|
application. In this case only this command line option is
|
||||||
considered, all other ways to set a home directory are ignored.
|
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.
|
|
||||||
|
@ -1122,10 +1122,36 @@ More fields may be added in future to the output.
|
|||||||
|
|
||||||
@table @file
|
@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
|
@item /etc/gnupg/gpgconf.conf
|
||||||
@cindex gpgconf.conf
|
@cindex gpgconf.conf
|
||||||
If this file exists, it is processed as a global configuration file.
|
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
|
the modern global per component configuration files. A commented
|
||||||
example can be found in the @file{examples} directory of the
|
example can be found in the @file{examples} directory of the
|
||||||
distribution.
|
distribution.
|
||||||
|
15
doc/wks.texi
15
doc/wks.texi
@ -243,6 +243,21 @@ Display a brief help page and exit.
|
|||||||
|
|
||||||
@end table
|
@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
|
@mansect see also
|
||||||
@ifset isman
|
@ifset isman
|
||||||
|
@ -1996,7 +1996,7 @@ agent_get_passphrase (const char *cache_id,
|
|||||||
char *arg4 = NULL;
|
char *arg4 = NULL;
|
||||||
membuf_t data;
|
membuf_t data;
|
||||||
struct default_inq_parm_s dfltparm;
|
struct default_inq_parm_s dfltparm;
|
||||||
int have_newsymkey;
|
int have_newsymkey, wasconf;
|
||||||
|
|
||||||
memset (&dfltparm, 0, sizeof dfltparm);
|
memset (&dfltparm, 0, sizeof dfltparm);
|
||||||
|
|
||||||
@ -2048,10 +2048,14 @@ agent_get_passphrase (const char *cache_id,
|
|||||||
xfree (arg4);
|
xfree (arg4);
|
||||||
|
|
||||||
init_membuf_secure (&data, 64);
|
init_membuf_secure (&data, 64);
|
||||||
|
wasconf = assuan_get_flag (agent_ctx, ASSUAN_CONFIDENTIAL);
|
||||||
|
assuan_begin_confidential (agent_ctx);
|
||||||
rc = assuan_transact (agent_ctx, line,
|
rc = assuan_transact (agent_ctx, line,
|
||||||
put_membuf_cb, &data,
|
put_membuf_cb, &data,
|
||||||
default_inq_cb, &dfltparm,
|
default_inq_cb, &dfltparm,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
|
if (!wasconf)
|
||||||
|
assuan_end_confidential (agent_ctx);
|
||||||
|
|
||||||
if (rc)
|
if (rc)
|
||||||
xfree (get_membuf (&data, NULL));
|
xfree (get_membuf (&data, NULL));
|
||||||
|
@ -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. */
|
/* Communication object for STORE commands. */
|
||||||
struct store_parm_s
|
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",
|
err = assuan_transact (hd->kbl->ctx, "STORE --update",
|
||||||
NULL, NULL,
|
NULL, NULL,
|
||||||
store_inq_cb, &parm,
|
store_inq_cb, &parm,
|
||||||
NULL, NULL);
|
keydb_default_status_cb, hd);
|
||||||
|
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
iobuf_close (iobuf);
|
iobuf_close (iobuf);
|
||||||
@ -523,7 +541,7 @@ keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
|
|||||||
err = assuan_transact (hd->kbl->ctx, "STORE --insert",
|
err = assuan_transact (hd->kbl->ctx, "STORE --insert",
|
||||||
NULL, NULL,
|
NULL, NULL,
|
||||||
store_inq_cb, &parm,
|
store_inq_cb, &parm,
|
||||||
NULL, NULL);
|
keydb_default_status_cb, hd);
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
iobuf_close (iobuf);
|
iobuf_close (iobuf);
|
||||||
@ -569,7 +587,7 @@ keydb_delete_keyblock (KEYDB_HANDLE hd)
|
|||||||
err = assuan_transact (hd->kbl->ctx, line,
|
err = assuan_transact (hd->kbl->ctx, line,
|
||||||
NULL, NULL,
|
NULL, NULL,
|
||||||
NULL, NULL,
|
NULL, NULL,
|
||||||
NULL, NULL);
|
keydb_default_status_cb, hd);
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
return err;
|
return err;
|
||||||
@ -656,6 +674,8 @@ search_status_cb (void *opaque, const char *line)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
err = keydb_default_status_cb (opaque, line);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -4794,7 +4794,7 @@ fail:
|
|||||||
/*
|
/*
|
||||||
* Ask for a new additional decryption subkey and add it to the key
|
* Ask for a new additional decryption subkey and add it to the key
|
||||||
* block. Returns true if the keyblock was changed and false
|
* 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.
|
* by quick_addadsk and gives the fingerprint of the to be added key.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
|
@ -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
|
/* Create and initialize a new SQL database file if it does not
|
||||||
* exists; else open it and check that all required objects are
|
* exists; else open it and check that all required objects are
|
||||||
* available. */
|
* available. */
|
||||||
static gpg_error_t
|
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;
|
gpg_error_t err;
|
||||||
int res;
|
int res;
|
||||||
@ -542,7 +576,16 @@ create_or_open_database (const char *filename)
|
|||||||
/* To avoid races with other temporary instances of keyboxd trying
|
/* To avoid races with other temporary instances of keyboxd trying
|
||||||
* to create or update the database, we run the database with a lock
|
* to create or update the database, we run the database with a lock
|
||||||
* file held. */
|
* 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)
|
if (!database_lock)
|
||||||
{
|
{
|
||||||
err = gpg_error_from_syserror ();
|
err = gpg_error_from_syserror ();
|
||||||
@ -556,7 +599,7 @@ create_or_open_database (const char *filename)
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dotlock_take (database_lock, -1))
|
if (dotlock_take (database_lock, 10000))
|
||||||
{
|
{
|
||||||
err = gpg_error_from_syserror ();
|
err = gpg_error_from_syserror ();
|
||||||
/* This is something bad. Probably a stale lockfile. */
|
/* This is something bad. Probably a stale lockfile. */
|
||||||
@ -646,6 +689,7 @@ create_or_open_database (const char *filename)
|
|||||||
{
|
{
|
||||||
log_error (_("error creating database '%s': %s\n"),
|
log_error (_("error creating database '%s': %s\n"),
|
||||||
filename, gpg_strerror (err));
|
filename, gpg_strerror (err));
|
||||||
|
if (dotlock_is_locked (database_lock))
|
||||||
dotlock_release (database_lock);
|
dotlock_release (database_lock);
|
||||||
dotlock_destroy (database_lock);
|
dotlock_destroy (database_lock);
|
||||||
database_lock = NULL;
|
database_lock = NULL;
|
||||||
@ -660,7 +704,6 @@ gpg_error_t
|
|||||||
be_sqlite_add_resource (ctrl_t ctrl, backend_handle_t *r_hd,
|
be_sqlite_add_resource (ctrl_t ctrl, backend_handle_t *r_hd,
|
||||||
const char *filename, int readonly)
|
const char *filename, int readonly)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
|
||||||
backend_handle_t hd;
|
backend_handle_t hd;
|
||||||
|
|
||||||
(void)ctrl;
|
(void)ctrl;
|
||||||
@ -672,19 +715,10 @@ be_sqlite_add_resource (ctrl_t ctrl, backend_handle_t *r_hd,
|
|||||||
return gpg_error_from_syserror ();
|
return gpg_error_from_syserror ();
|
||||||
hd->db_type = DB_TYPE_SQLITE;
|
hd->db_type = DB_TYPE_SQLITE;
|
||||||
strcpy (hd->filename, filename);
|
strcpy (hd->filename, filename);
|
||||||
|
|
||||||
err = create_or_open_database (filename);
|
|
||||||
if (err)
|
|
||||||
goto leave;
|
|
||||||
|
|
||||||
hd->backend_id = be_new_backend_id ();
|
hd->backend_id = be_new_backend_id ();
|
||||||
|
|
||||||
*r_hd = hd;
|
*r_hd = hd;
|
||||||
hd = NULL;
|
return 0;
|
||||||
|
|
||||||
leave:
|
|
||||||
xfree (hd);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1139,6 +1173,10 @@ be_sqlite_search (ctrl_t ctrl,
|
|||||||
log_assert (backend_hd && backend_hd->db_type == DB_TYPE_SQLITE);
|
log_assert (backend_hd && backend_hd->db_type == DB_TYPE_SQLITE);
|
||||||
log_assert (request);
|
log_assert (request);
|
||||||
|
|
||||||
|
err = create_or_open_database (ctrl, backend_hd->filename);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
acquire_mutex ();
|
acquire_mutex ();
|
||||||
|
|
||||||
/* Find the specific request part or allocate it. */
|
/* Find the specific request part or allocate it. */
|
||||||
|
@ -405,10 +405,10 @@ kbx_client_data_cmd (kbx_client_data_t kcd, const char *command,
|
|||||||
status_cb, status_cb_value);
|
status_cb, status_cb_value);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
if (gpg_err_code (err) != GPG_ERR_NOT_FOUND
|
/* if (gpg_err_code (err) != GPG_ERR_NOT_FOUND */
|
||||||
&& gpg_err_code (err) != GPG_ERR_NOTHING_FOUND)
|
/* && gpg_err_code (err) != GPG_ERR_NOTHING_FOUND) */
|
||||||
log_debug ("%s: finished command with error: %s\n",
|
/* log_debug ("%s: finished command with error: %s\n", */
|
||||||
__func__, gpg_strerror (err));
|
/* __func__, gpg_strerror (err)); */
|
||||||
xfree (get_membuf (&mb, &len));
|
xfree (get_membuf (&mb, &len));
|
||||||
kcd->dlineerr = err;
|
kcd->dlineerr = err;
|
||||||
goto leave;
|
goto leave;
|
||||||
|
@ -1257,6 +1257,7 @@ create_directories (void)
|
|||||||
{
|
{
|
||||||
if (!opt.quiet)
|
if (!opt.quiet)
|
||||||
log_info (_("directory '%s' created\n"), home);
|
log_info (_("directory '%s' created\n"), home);
|
||||||
|
create_public_keys_directory (home);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
16
po/ja.po
16
po/ja.po
@ -9,9 +9,9 @@
|
|||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: gnupg 2.4.1\n"
|
"Project-Id-Version: gnupg 2.4.3\n"
|
||||||
"Report-Msgid-Bugs-To: translations@gnupg.org\n"
|
"Report-Msgid-Bugs-To: translations@gnupg.org\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 <gniibe@fsij.org>\n"
|
"Last-Translator: NIIBE Yutaka <gniibe@fsij.org>\n"
|
||||||
"Language-Team: none\n"
|
"Language-Team: none\n"
|
||||||
"Language: ja\n"
|
"Language: ja\n"
|
||||||
@ -1788,14 +1788,14 @@ msgstr "S2Kモードのため、SKESKパケットを使えません\n"
|
|||||||
msgid "using cipher %s.%s\n"
|
msgid "using cipher %s.%s\n"
|
||||||
msgstr "暗号方式 %s.%s を使います\n"
|
msgstr "暗号方式 %s.%s を使います\n"
|
||||||
|
|
||||||
#, c-format
|
|
||||||
msgid "'%s' already compressed\n"
|
|
||||||
msgstr "'%s'はもう圧縮済みです\n"
|
|
||||||
|
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "WARNING: '%s' is an empty file\n"
|
msgid "WARNING: '%s' is an empty file\n"
|
||||||
msgstr "*警告*: '%s'は空のファイルです\n"
|
msgstr "*警告*: '%s'は空のファイルです\n"
|
||||||
|
|
||||||
|
#, c-format
|
||||||
|
msgid "'%s' already compressed\n"
|
||||||
|
msgstr "'%s'はもう圧縮済みです\n"
|
||||||
|
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "digest algorithm '%s' may not be used in %s mode\n"
|
msgid "digest algorithm '%s' may not be used in %s mode\n"
|
||||||
msgstr "ダイジェスト・アルゴリズム'%s'を%sモードで使うことはできません\n"
|
msgstr "ダイジェスト・アルゴリズム'%s'を%sモードで使うことはできません\n"
|
||||||
@ -1869,7 +1869,7 @@ msgstr "'%s'への書き込み\n"
|
|||||||
|
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "key %s: key material on-card - skipped\n"
|
msgid "key %s: key material on-card - skipped\n"
|
||||||
msgstr "鍵%s: 鍵マテリアルはカード上にあります - スキップします\n"
|
msgstr "鍵%s: 鍵の実体はカード上にあります - スキップします\n"
|
||||||
|
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "exporting secret keys not allowed\n"
|
msgid "exporting secret keys not allowed\n"
|
||||||
@ -2893,7 +2893,7 @@ msgstr "鍵 %s: エージェントへの送信エラー: %s\n"
|
|||||||
|
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "key %s: card reference is overridden by key material\n"
|
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
|
#. TRANSLATORS: For a smartcard, each private key on host has a
|
||||||
#. * reference (stub) to a smartcard and actual private key data
|
#. * reference (stub) to a smartcard and actual private key data
|
||||||
|
12
scd/apdu.c
12
scd/apdu.c
@ -775,8 +775,8 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
|
|||||||
if (DBG_CARD_IO)
|
if (DBG_CARD_IO)
|
||||||
{
|
{
|
||||||
/* Do not dump the PIN in a VERIFY command. */
|
/* Do not dump the PIN in a VERIFY command. */
|
||||||
if (apdulen > 5 && apdu[1] == 0x20)
|
if (apdulen > 5 && apdu[1] == 0x20 && !opt.debug_allow_pin_logging)
|
||||||
log_debug ("PCSC_data: %02X %02X %02X %02X %02X [redacted]\n",
|
log_debug ("PCSC_data: %02X %02X %02X %02X %02X [hidden]\n",
|
||||||
apdu[0], apdu[1], apdu[2], apdu[3], apdu[4]);
|
apdu[0], apdu[1], apdu[2], apdu[3], apdu[4]);
|
||||||
else
|
else
|
||||||
log_printhex (apdu, apdulen, "PCSC_data:");
|
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)
|
if (DBG_CARD_IO)
|
||||||
{
|
{
|
||||||
/* Do not dump the PIN in a VERIFY command. */
|
/* Do not dump the PIN in a VERIFY command. */
|
||||||
if (apdulen > 5 && apdu[1] == 0x20)
|
if (apdulen > 5 && apdu[1] == 0x20 && !opt.debug_allow_pin_logging)
|
||||||
log_debug (" raw apdu: %02x%02x%02x%02x%02x [redacted]\n",
|
log_debug (" raw apdu: %02x%02x%02x%02x%02x [hidden]\n",
|
||||||
apdu[0], apdu[1], apdu[2], apdu[3], apdu[4]);
|
apdu[0], apdu[1], apdu[2], apdu[3], apdu[4]);
|
||||||
else
|
else
|
||||||
log_printhex (apdu, apdulen, " raw apdu:");
|
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);
|
sw, (unsigned int)resultlen);
|
||||||
if ( !retbuf && (sw == SW_SUCCESS || (sw & 0xff00) == SW_MORE_DATA))
|
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");
|
log_debug (" dump: [all zero]\n");
|
||||||
else
|
else
|
||||||
log_printhex (result, resultlen, " dump:");
|
log_printhex (result, resultlen, " dump:");
|
||||||
|
@ -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));
|
log_error (_("error getting new PIN: %s\n"), gpg_strerror (rc));
|
||||||
goto leave;
|
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,15 +3558,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
|
|||||||
}
|
}
|
||||||
else if (set_resetcode)
|
else if (set_resetcode)
|
||||||
{
|
{
|
||||||
size_t bufferlen = strlen (pinvalue);
|
size_t bufferlen;
|
||||||
|
|
||||||
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;
|
char *buffer = NULL;
|
||||||
|
|
||||||
rc = pin2hash_if_kdf (app, 0, pinvalue, &buffer, &bufferlen);
|
rc = pin2hash_if_kdf (app, 0, pinvalue, &buffer, &bufferlen);
|
||||||
@ -3551,7 +3568,6 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
|
|||||||
|
|
||||||
wipe_and_free (buffer, bufferlen);
|
wipe_and_free (buffer, bufferlen);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (reset_mode)
|
else if (reset_mode)
|
||||||
{
|
{
|
||||||
char *buffer = NULL;
|
char *buffer = NULL;
|
||||||
@ -4733,9 +4749,11 @@ ecc_writekey (app_t app, ctrl_t ctrl,
|
|||||||
|
|
||||||
if (algo == PUBKEY_ALGO_ECDH && !ecdh_param)
|
if (algo == PUBKEY_ALGO_ECDH && !ecdh_param)
|
||||||
{
|
{
|
||||||
log_error ("opgp: ecdh parameters missing\n");
|
/* In case this is used by older clients we fallback to our
|
||||||
err = gpg_error (GPG_ERR_INV_VALUE);
|
* default ecc parameters. */
|
||||||
goto leave;
|
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);
|
oidstr = openpgp_curve_to_oid (curve, &n, NULL);
|
||||||
|
174
scd/app-p15.c
174
scd/app-p15.c
@ -74,8 +74,10 @@ typedef enum
|
|||||||
CARD_TYPE_MICARDO,
|
CARD_TYPE_MICARDO,
|
||||||
CARD_TYPE_CARDOS_50,
|
CARD_TYPE_CARDOS_50,
|
||||||
CARD_TYPE_CARDOS_53,
|
CARD_TYPE_CARDOS_53,
|
||||||
|
CARD_TYPE_CARDOS_54,
|
||||||
CARD_TYPE_AET, /* A.E.T. Europe JCOP card. */
|
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;
|
card_type_t;
|
||||||
|
|
||||||
@ -86,7 +88,8 @@ typedef enum
|
|||||||
{
|
{
|
||||||
CARD_PRODUCT_UNKNOWN,
|
CARD_PRODUCT_UNKNOWN,
|
||||||
CARD_PRODUCT_RSCS, /* Rohde&Schwarz Cybersecurity */
|
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_GENUA, /* GeNUA mbH */
|
||||||
CARD_PRODUCT_NEXUS /* Technology Nexus */
|
CARD_PRODUCT_NEXUS /* Technology Nexus */
|
||||||
}
|
}
|
||||||
@ -123,17 +126,23 @@ static struct
|
|||||||
CARD_TYPE_CARDOS_50 }, /* CardOS 5.0 */
|
CARD_TYPE_CARDOS_50 }, /* CardOS 5.0 */
|
||||||
{ 11, X("\x3b\xd2\x18\x00\x81\x31\xfe\x58\xc9\x03\x16"),
|
{ 11, X("\x3b\xd2\x18\x00\x81\x31\xfe\x58\xc9\x03\x16"),
|
||||||
CARD_TYPE_CARDOS_53 }, /* CardOS 5.3 */
|
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"
|
{ 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"),
|
"\x36\x30\x2d\x43\x44\x30\x38\x31\x2d\x6e\x46\xa9"),
|
||||||
CARD_TYPE_AET },
|
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 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
#undef X
|
#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 \
|
#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 */
|
/* The default PKCS-15 home DF */
|
||||||
#define DEFAULT_HOME_DF 0x5015
|
#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,
|
static char const pkcs15be_aid[] = { 0xA0, 0, 0, 0x01, 0x77,
|
||||||
0x50, 0x4B, 0x43, 0x53, 0x2D, 0x31, 0x35 };
|
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 */
|
/* The PIN types as defined in pkcs#15 v1.1 */
|
||||||
typedef enum
|
typedef enum
|
||||||
@ -518,6 +532,8 @@ struct app_local_s
|
|||||||
/*** Local prototypes. ***/
|
/*** Local prototypes. ***/
|
||||||
static gpg_error_t select_ef_by_path (app_t app, const unsigned short *path,
|
static gpg_error_t select_ef_by_path (app_t app, const unsigned short *path,
|
||||||
size_t pathlen);
|
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 keygrip_from_prkdf (app_t app, prkdf_object_t prkdf);
|
||||||
static gpg_error_t readcert_by_cdf (app_t app, cdf_object_t cdf,
|
static gpg_error_t readcert_by_cdf (app_t app, cdf_object_t cdf,
|
||||||
unsigned char **r_cert, size_t *r_certlen);
|
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_MICARDO: return "Micardo";
|
||||||
case CARD_TYPE_CARDOS_50: return "CardOS 5.0";
|
case CARD_TYPE_CARDOS_50: return "CardOS 5.0";
|
||||||
case CARD_TYPE_CARDOS_53: return "CardOS 5.3";
|
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_BELPIC: return "Belgian eID";
|
||||||
case CARD_TYPE_AET: return "AET";
|
case CARD_TYPE_AET: return "AET";
|
||||||
|
case CARD_TYPE_STARCOS_32:return "STARCOS 3.2";
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@ -549,7 +567,8 @@ cardproduct2str (card_product_t cardproduct)
|
|||||||
{
|
{
|
||||||
case CARD_PRODUCT_UNKNOWN: return "";
|
case CARD_PRODUCT_UNKNOWN: return "";
|
||||||
case CARD_PRODUCT_RSCS: return "R&S";
|
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_GENUA: return "GeNUA";
|
||||||
case CARD_PRODUCT_NEXUS: return "Nexus";
|
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
|
/* 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
|
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;
|
gpg_error_t err;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
int home_df_used = 0;
|
||||||
|
|
||||||
if (!pathlen)
|
if (!pathlen)
|
||||||
return gpg_error (GPG_ERR_INV_VALUE);
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
|
|
||||||
/* log_debug ("%s: path=", __func__); */
|
if (opt.debug)
|
||||||
/* for (j=0; j < pathlen; j++) */
|
{
|
||||||
/* log_printf ("%s%04hX", j? "/":"", path[j]); */
|
log_debug ("%s: path=", __func__);
|
||||||
/* log_printf ("%s\n",app->app_local->direct_path_selection?" (direct)":"");*/
|
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)
|
if (app->app_local->direct_path_selection)
|
||||||
{
|
{
|
||||||
@ -791,35 +818,17 @@ select_ef_by_path (app_t app, const unsigned short *path, size_t pathlen)
|
|||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
home_df_used = 1;
|
||||||
err = iso7816_select_path (app_get_slot (app), path, pathlen,
|
err = iso7816_select_path (app_get_slot (app), path, pathlen,
|
||||||
app->app_local->home_df);
|
app->app_local->home_df);
|
||||||
|
}
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
log_error ("p15: error selecting path ");
|
log_error ("p15: error selecting path ");
|
||||||
goto err_print_path;
|
goto err_print_path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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);
|
|
||||||
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
|
else
|
||||||
{
|
{
|
||||||
if (pathlen && *path != 0x3f00 )
|
if (pathlen && *path != 0x3f00 )
|
||||||
@ -829,7 +838,7 @@ select_ef_by_path (app_t app, const unsigned short *path, size_t pathlen)
|
|||||||
for (i=0; i < pathlen; i++)
|
for (i=0; i < pathlen; i++)
|
||||||
{
|
{
|
||||||
err = iso7816_select_file (app_get_slot (app),
|
err = iso7816_select_file (app_get_slot (app),
|
||||||
path[i], !(i+1 == pathlen));
|
path[i], (expect_df || (i+1 < pathlen)));
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
log_error ("p15: error selecting part %d from path ", i);
|
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:
|
err_print_path:
|
||||||
if (pathlen && *path != 0x3f00 )
|
if (pathlen && *path != 0x3f00 )
|
||||||
log_printf ("3F00/");
|
log_printf ("3F00/");
|
||||||
else
|
else if (home_df_used)
|
||||||
log_printf ("%04hX/", app->app_local->home_df);
|
log_printf ("%04hX/", app->app_local->home_df);
|
||||||
for (j=0; j < pathlen; j++)
|
for (j=0; j < pathlen; j++)
|
||||||
log_printf ("%s%04hX", j? "/":"", path[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
|
/* 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
|
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
|
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)
|
if (aodf->max_length_valid)
|
||||||
log_printf (" max=%lu", aodf->max_length);
|
log_printf (" max=%lu", aodf->max_length);
|
||||||
if (aodf->pad_char_valid)
|
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=");
|
log_info ("p15: flags=");
|
||||||
s = "";
|
s = "";
|
||||||
@ -3495,7 +3518,7 @@ read_ef_tokeninfo (app_t app)
|
|||||||
ul |= (*p++) & 0xff;
|
ul |= (*p++) & 0xff;
|
||||||
n--;
|
n--;
|
||||||
}
|
}
|
||||||
if (ul)
|
if (ul > 1)
|
||||||
{
|
{
|
||||||
log_error ("p15: invalid version %lu in TokenInfo\n", ul);
|
log_error ("p15: invalid version %lu in TokenInfo\n", ul);
|
||||||
err = gpg_error (GPG_ERR_INV_OBJ);
|
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)
|
&& !strncmp (app->app_local->token_label, "D-TRUST Card V3", 15)
|
||||||
&& app->app_local->card_type == CARD_TYPE_CARDOS_50)
|
&& 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
|
/* According to our protocol analysis we need to select a
|
||||||
* special AID here. Before that the master file needs to be
|
* 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",
|
log_error ("p15: error selecting D-TRUST's AID for key %s: %s\n",
|
||||||
keyref, gpg_strerror (err));
|
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)
|
else if (prkdf)
|
||||||
{
|
{
|
||||||
/* Standard case: Select the key file. Note that this may
|
/* Standard case: Select the key file. Note that this may
|
||||||
@ -5258,7 +5295,8 @@ verify_pin (app_t app,
|
|||||||
if (prkdf
|
if (prkdf
|
||||||
&& prkdf->usageflags.non_repudiation
|
&& prkdf->usageflags.non_repudiation
|
||||||
&& (app->app_local->card_type == CARD_TYPE_BELPIC
|
&& (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 "
|
label = _("||Please enter the PIN for the key to create "
|
||||||
"qualified signatures.");
|
"qualified signatures.");
|
||||||
else if (aodf->pinflags.so_pin)
|
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;
|
goto leave;
|
||||||
}
|
}
|
||||||
if (app->app_local->card_type == CARD_TYPE_BELPIC
|
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
|
/* The default for these cards is to use a plain hash. We
|
||||||
* assume that due to the used certificate the correct hash
|
* 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
|
else
|
||||||
err = micardo_mse (app, prkdf->path[prkdf->pathlen-1]);
|
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)
|
else if (prkdf->key_reference_valid)
|
||||||
{
|
{
|
||||||
unsigned char mse[3];
|
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. */
|
/* 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
|
/* From analyzing an USB trace of a Windows signing application
|
||||||
* we see that the SE is simply reset to 0x14. It seems to be
|
* 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);
|
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)
|
else if (prkdf->key_reference_valid)
|
||||||
{
|
{
|
||||||
unsigned char mse[9];
|
unsigned char mse[9];
|
||||||
@ -5923,7 +6003,8 @@ do_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
|
|||||||
le_value = prkdf->keynbits / 8;
|
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;
|
padind = 0x81;
|
||||||
|
|
||||||
if (prkdf->is_ecc && IS_CARDOS_5(app))
|
if (prkdf->is_ecc && IS_CARDOS_5(app))
|
||||||
@ -6185,6 +6266,13 @@ app_select_p15 (app_t app)
|
|||||||
|
|
||||||
rc = iso7816_select_application_ext (slot, pkcs15_aid, sizeof pkcs15_aid, 1,
|
rc = iso7816_select_application_ext (slot, pkcs15_aid, sizeof pkcs15_aid, 1,
|
||||||
&fci, &fcilen);
|
&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)
|
if (rc)
|
||||||
{ /* Not found: Try to locate it from 2F00. We use direct path
|
{ /* Not found: Try to locate it from 2F00. We use direct path
|
||||||
selection here because it seems that the Belgian eID card
|
selection here because it seems that the Belgian eID card
|
||||||
@ -6284,9 +6372,11 @@ app_select_p15 (app_t app)
|
|||||||
{
|
{
|
||||||
case CARD_TYPE_CARDOS_50:
|
case CARD_TYPE_CARDOS_50:
|
||||||
case CARD_TYPE_CARDOS_53:
|
case CARD_TYPE_CARDOS_53:
|
||||||
|
case CARD_TYPE_CARDOS_54:
|
||||||
direct = 1;
|
direct = 1;
|
||||||
break;
|
break;
|
||||||
case CARD_TYPE_AET:
|
case CARD_TYPE_AET:
|
||||||
|
case CARD_TYPE_STARCOS_32:
|
||||||
app->app_local->no_extended_mode = 1;
|
app->app_local->no_extended_mode = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -166,7 +166,7 @@ iso7816_select_mf (int slot)
|
|||||||
{
|
{
|
||||||
int sw;
|
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);
|
return map_sw (sw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,6 +79,7 @@ enum cmd_and_opt_values
|
|||||||
oDebugAllowCoreDump,
|
oDebugAllowCoreDump,
|
||||||
oDebugCCIDDriver,
|
oDebugCCIDDriver,
|
||||||
oDebugLogTid,
|
oDebugLogTid,
|
||||||
|
oDebugAllowPINLogging,
|
||||||
oDebugAssuanLogCats,
|
oDebugAssuanLogCats,
|
||||||
oNoGreeting,
|
oNoGreeting,
|
||||||
oNoOptions,
|
oNoOptions,
|
||||||
@ -138,6 +139,7 @@ static gpgrt_opt_t opts[] = {
|
|||||||
ARGPARSE_s_n (oDebugAllowCoreDump, "debug-allow-core-dump", "@"),
|
ARGPARSE_s_n (oDebugAllowCoreDump, "debug-allow-core-dump", "@"),
|
||||||
ARGPARSE_s_n (oDebugCCIDDriver, "debug-ccid-driver", "@"),
|
ARGPARSE_s_n (oDebugCCIDDriver, "debug-ccid-driver", "@"),
|
||||||
ARGPARSE_s_n (oDebugLogTid, "debug-log-tid", "@"),
|
ARGPARSE_s_n (oDebugLogTid, "debug-log-tid", "@"),
|
||||||
|
ARGPARSE_s_n (oDebugAllowPINLogging, "debug-allow-pin-logging", "@"),
|
||||||
ARGPARSE_p_u (oDebugAssuanLogCats, "debug-assuan-log-cats", "@"),
|
ARGPARSE_p_u (oDebugAssuanLogCats, "debug-assuan-log-cats", "@"),
|
||||||
ARGPARSE_s_s (oLogFile, "log-file", N_("|FILE|write a log to FILE")),
|
ARGPARSE_s_s (oLogFile, "log-file", N_("|FILE|write a log to FILE")),
|
||||||
|
|
||||||
@ -583,6 +585,9 @@ main (int argc, char **argv )
|
|||||||
case oDebugLogTid:
|
case oDebugLogTid:
|
||||||
log_set_pid_suffix_cb (tid_log_callback);
|
log_set_pid_suffix_cb (tid_log_callback);
|
||||||
break;
|
break;
|
||||||
|
case oDebugAllowPINLogging:
|
||||||
|
opt.debug_allow_pin_logging = 1;
|
||||||
|
break;
|
||||||
case oDebugAssuanLogCats:
|
case oDebugAssuanLogCats:
|
||||||
set_libassuan_log_cats (pargs.r.ret_ulong);
|
set_libassuan_log_cats (pargs.r.ret_ulong);
|
||||||
break;
|
break;
|
||||||
|
@ -66,6 +66,7 @@ struct
|
|||||||
strlist_t disabled_applications; /* Card applications we do not
|
strlist_t disabled_applications; /* Card applications we do not
|
||||||
want to use. */
|
want to use. */
|
||||||
unsigned long card_timeout; /* Disconnect after N seconds of inactivity. */
|
unsigned long card_timeout; /* Disconnect after N seconds of inactivity. */
|
||||||
|
int debug_allow_pin_logging; /* Allow PINs in debug output. */
|
||||||
} opt;
|
} opt;
|
||||||
|
|
||||||
|
|
||||||
|
@ -1323,6 +1323,7 @@ gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg, int repeat,
|
|||||||
char *arg4 = NULL;
|
char *arg4 = NULL;
|
||||||
membuf_t data;
|
membuf_t data;
|
||||||
struct default_inq_parm_s inq_parm;
|
struct default_inq_parm_s inq_parm;
|
||||||
|
int wasconf;
|
||||||
|
|
||||||
*r_passphrase = NULL;
|
*r_passphrase = NULL;
|
||||||
|
|
||||||
@ -1341,9 +1342,13 @@ gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg, int repeat,
|
|||||||
xfree (arg4);
|
xfree (arg4);
|
||||||
|
|
||||||
init_membuf_secure (&data, 64);
|
init_membuf_secure (&data, 64);
|
||||||
|
wasconf = assuan_get_flag (agent_ctx, ASSUAN_CONFIDENTIAL);
|
||||||
|
assuan_begin_confidential (agent_ctx);
|
||||||
err = assuan_transact (agent_ctx, line,
|
err = assuan_transact (agent_ctx, line,
|
||||||
put_membuf_cb, &data,
|
put_membuf_cb, &data,
|
||||||
default_inq_cb, &inq_parm, NULL, NULL);
|
default_inq_cb, &inq_parm, NULL, NULL);
|
||||||
|
if (!wasconf)
|
||||||
|
assuan_end_confidential (agent_ctx);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
xfree (get_membuf (&data, NULL));
|
xfree (get_membuf (&data, NULL));
|
||||||
|
@ -1309,7 +1309,8 @@ gpgsm_decrypt (ctrl_t ctrl, estream_t in_fp, estream_t out_fp)
|
|||||||
/* Check compliance. */
|
/* Check compliance. */
|
||||||
if (!gnupg_pk_is_allowed (opt.compliance,
|
if (!gnupg_pk_is_allowed (opt.compliance,
|
||||||
PK_USE_DECRYPTION,
|
PK_USE_DECRYPTION,
|
||||||
pk_algo, 0, NULL, nbits, curve))
|
pk_algo, PK_ALGO_FLAG_ECC18,
|
||||||
|
NULL, nbits, curve))
|
||||||
{
|
{
|
||||||
char kidstr[10+1];
|
char kidstr[10+1];
|
||||||
|
|
||||||
|
64
sm/encrypt.c
64
sm/encrypt.c
@ -577,9 +577,8 @@ int
|
|||||||
gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
|
gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
|
||||||
estream_t out_fp)
|
estream_t out_fp)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
gpg_error_t err = 0;
|
||||||
gnupg_ksba_io_t b64writer = NULL;
|
gnupg_ksba_io_t b64writer = NULL;
|
||||||
gpg_error_t err;
|
|
||||||
ksba_writer_t writer;
|
ksba_writer_t writer;
|
||||||
ksba_reader_t reader = NULL;
|
ksba_reader_t reader = NULL;
|
||||||
ksba_cms_t cms = 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"));
|
log_error(_("no valid recipients given\n"));
|
||||||
gpgsm_status (ctrl, STATUS_NO_RECP, "0");
|
gpgsm_status (ctrl, STATUS_NO_RECP, "0");
|
||||||
audit_log_i (ctrl->audit, AUDIT_GOT_RECIPIENTS, 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;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -619,28 +618,26 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
|
|||||||
if (!kh)
|
if (!kh)
|
||||||
{
|
{
|
||||||
log_error (_("failed to allocate keyDB handle\n"));
|
log_error (_("failed to allocate keyDB handle\n"));
|
||||||
rc = gpg_error (GPG_ERR_GENERAL);
|
err = gpg_error (GPG_ERR_GENERAL);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ksba_reader_new (&reader);
|
err = ksba_reader_new (&reader);
|
||||||
|
if (!err)
|
||||||
|
err = ksba_reader_set_cb (reader, encrypt_cb, &encparm);
|
||||||
if (err)
|
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;
|
encparm.fp = data_fp;
|
||||||
|
|
||||||
ctrl->pem_name = "ENCRYPTED MESSAGE";
|
ctrl->pem_name = "ENCRYPTED MESSAGE";
|
||||||
rc = gnupg_ksba_create_writer
|
err = gnupg_ksba_create_writer
|
||||||
(&b64writer, ((ctrl->create_pem? GNUPG_KSBA_IO_PEM : 0)
|
(&b64writer, ((ctrl->create_pem? GNUPG_KSBA_IO_PEM : 0)
|
||||||
| (ctrl->create_base64? GNUPG_KSBA_IO_BASE64 : 0)),
|
| (ctrl->create_base64? GNUPG_KSBA_IO_BASE64 : 0)),
|
||||||
ctrl->pem_name, out_fp, &writer);
|
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;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -650,17 +647,13 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
|
|||||||
|
|
||||||
err = ksba_cms_new (&cms);
|
err = ksba_cms_new (&cms);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
|
||||||
rc = err;
|
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
|
||||||
|
|
||||||
err = ksba_cms_set_reader_writer (cms, reader, writer);
|
err = ksba_cms_set_reader_writer (cms, reader, writer);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
log_error ("ksba_cms_set_reader_writer failed: %s\n",
|
log_error ("ksba_cms_set_reader_writer failed: %s\n",
|
||||||
gpg_strerror (err));
|
gpg_strerror (err));
|
||||||
rc = err;
|
|
||||||
goto leave;
|
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",
|
log_error ("ksba_cms_set_content_type failed: %s\n",
|
||||||
gpg_strerror (err));
|
gpg_strerror (err));
|
||||||
rc = err;
|
|
||||||
goto leave;
|
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"),
|
log_error (_("cipher algorithm '%s' may not be used in %s mode\n"),
|
||||||
opt.def_cipher_algoid,
|
opt.def_cipher_algoid,
|
||||||
gnupg_compliance_option_string (opt.compliance));
|
gnupg_compliance_option_string (opt.compliance));
|
||||||
rc = gpg_error (GPG_ERR_CIPHER_ALGO);
|
err = gpg_error (GPG_ERR_CIPHER_ALGO);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gnupg_rng_is_compliant (opt.compliance))
|
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"),
|
log_error (_("%s is not compliant with %s mode\n"),
|
||||||
"RNG",
|
"RNG",
|
||||||
gnupg_compliance_option_string (opt.compliance));
|
gnupg_compliance_option_string (opt.compliance));
|
||||||
gpgsm_status_with_error (ctrl, STATUS_ERROR,
|
gpgsm_status_with_error (ctrl, STATUS_ERROR,
|
||||||
"random-compliance", rc);
|
"random-compliance", err);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a session key */
|
/* Create a session key */
|
||||||
dek = xtrycalloc_secure (1, sizeof *dek);
|
dek = xtrycalloc_secure (1, sizeof *dek);
|
||||||
if (!dek)
|
if (!dek)
|
||||||
rc = out_of_core ();
|
err = gpg_error_from_syserror ();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dek->algoid = opt.def_cipher_algoid;
|
dek->algoid = opt.def_cipher_algoid;
|
||||||
rc = init_dek (dek);
|
err = init_dek (dek);
|
||||||
}
|
}
|
||||||
if (rc)
|
if (err)
|
||||||
{
|
{
|
||||||
log_error ("failed to create the session key: %s\n",
|
log_error ("failed to create the session key: %s\n",
|
||||||
gpg_strerror (rc));
|
gpg_strerror (err));
|
||||||
goto leave;
|
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",
|
log_error ("ksba_cms_set_content_enc_algo failed: %s\n",
|
||||||
gpg_strerror (err));
|
gpg_strerror (err));
|
||||||
rc = err;
|
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -733,7 +724,7 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
|
|||||||
encparm.buffer = xtrymalloc (encparm.bufsize);
|
encparm.buffer = xtrymalloc (encparm.bufsize);
|
||||||
if (!encparm.buffer)
|
if (!encparm.buffer)
|
||||||
{
|
{
|
||||||
rc = out_of_core ();
|
err = gpg_error_from_syserror ();
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -775,12 +766,12 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
|
|||||||
xfree (curve);
|
xfree (curve);
|
||||||
curve = NULL;
|
curve = NULL;
|
||||||
|
|
||||||
rc = encrypt_dek (dek, cl->cert, pk_algo, &encval);
|
err = encrypt_dek (dek, cl->cert, pk_algo, &encval);
|
||||||
if (rc)
|
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",
|
log_error ("encryption failed for recipient no. %d: %s\n",
|
||||||
recpno, gpg_strerror (rc));
|
recpno, gpg_strerror (err));
|
||||||
goto leave;
|
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);
|
audit_log_cert (ctrl->audit, AUDIT_ENCRYPTED_TO, cl->cert, err);
|
||||||
log_error ("ksba_cms_add_recipient failed: %s\n",
|
log_error ("ksba_cms_add_recipient failed: %s\n",
|
||||||
gpg_strerror (err));
|
gpg_strerror (err));
|
||||||
rc = err;
|
|
||||||
xfree (encval);
|
xfree (encval);
|
||||||
goto leave;
|
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",
|
log_error ("ksba_cms_set_enc_val failed: %s\n",
|
||||||
gpg_strerror (err));
|
gpg_strerror (err));
|
||||||
rc = err;
|
|
||||||
goto leave;
|
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"
|
log_error (_("operation forced to fail due to"
|
||||||
" unfulfilled compliance rules\n"));
|
" unfulfilled compliance rules\n"));
|
||||||
gpgsm_errors_seen = 1;
|
gpgsm_errors_seen = 1;
|
||||||
rc = gpg_error (GPG_ERR_FORBIDDEN);
|
err = gpg_error (GPG_ERR_FORBIDDEN);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -828,7 +817,6 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
|
|||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
log_error ("creating CMS object failed: %s\n", gpg_strerror (err));
|
log_error ("creating CMS object failed: %s\n", gpg_strerror (err));
|
||||||
rc = err;
|
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -837,15 +825,15 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
|
|||||||
if (encparm.readerror)
|
if (encparm.readerror)
|
||||||
{
|
{
|
||||||
log_error ("error reading input: %s\n", strerror (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;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
rc = gnupg_ksba_finish_writer (b64writer);
|
err = gnupg_ksba_finish_writer (b64writer);
|
||||||
if (rc)
|
if (err)
|
||||||
{
|
{
|
||||||
log_error ("write failed: %s\n", gpg_strerror (rc));
|
log_error ("write failed: %s\n", gpg_strerror (err));
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
audit_log (ctrl->audit, AUDIT_ENCRYPTION_DONE);
|
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);
|
keydb_release (kh);
|
||||||
xfree (dek);
|
xfree (dek);
|
||||||
xfree (encparm.buffer);
|
xfree (encparm.buffer);
|
||||||
return rc;
|
return err;
|
||||||
}
|
}
|
||||||
|
23
sm/keydb.c
23
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. */
|
/* Communication object for Keyboxd STORE commands. */
|
||||||
struct store_parm_s
|
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",
|
err = assuan_transact (hd->kbl->ctx, "STORE --insert",
|
||||||
NULL, NULL,
|
NULL, NULL,
|
||||||
store_inq_cb, &parm,
|
store_inq_cb, &parm,
|
||||||
NULL, NULL);
|
keydb_default_status_cb, hd);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1335,7 +1352,7 @@ keydb_delete (KEYDB_HANDLE hd)
|
|||||||
err = assuan_transact (hd->kbl->ctx, line,
|
err = assuan_transact (hd->kbl->ctx, line,
|
||||||
NULL, NULL,
|
NULL, NULL,
|
||||||
NULL, NULL,
|
NULL, NULL,
|
||||||
NULL, NULL);
|
keydb_default_status_cb, hd);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1563,6 +1580,8 @@ search_status_cb (void *opaque, const char *line)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
err = keydb_default_status_cb (opaque, line);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -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))
|
if (gpgsm_cert_has_well_known_private_key (cert))
|
||||||
*truststring = 'w'; /* Well, this is dummy CA. */
|
*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
|
else
|
||||||
*truststring = 'i';
|
*truststring = 'i';
|
||||||
}
|
}
|
||||||
|
@ -936,6 +936,7 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, tlv_parser_t tlv)
|
|||||||
if (!datalen)
|
if (!datalen)
|
||||||
{
|
{
|
||||||
err = gpg_error (GPG_ERR_DECRYPT_FAILED);
|
err = gpg_error (GPG_ERR_DECRYPT_FAILED);
|
||||||
|
ctx->badpass = 1; /* This is the most likley reason. */
|
||||||
goto bailout;
|
goto bailout;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1461,6 +1462,7 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, tlv_parser_t tlv)
|
|||||||
if (!datalen)
|
if (!datalen)
|
||||||
{
|
{
|
||||||
err = gpg_error (GPG_ERR_DECRYPT_FAILED);
|
err = gpg_error (GPG_ERR_DECRYPT_FAILED);
|
||||||
|
ctx->badpass = 1;
|
||||||
goto bailout;
|
goto bailout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
126
sm/sign.c
126
sm/sign.c
@ -606,8 +606,8 @@ int
|
|||||||
gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
||||||
estream_t data_fp, int detached, estream_t out_fp)
|
estream_t data_fp, int detached, estream_t out_fp)
|
||||||
{
|
{
|
||||||
int i, rc;
|
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
|
int i;
|
||||||
gnupg_ksba_io_t b64writer = NULL;
|
gnupg_ksba_io_t b64writer = NULL;
|
||||||
ksba_writer_t writer;
|
ksba_writer_t writer;
|
||||||
estream_t sig_fp = NULL; /* Used for detached signatures. */
|
estream_t sig_fp = NULL; /* Used for detached signatures. */
|
||||||
@ -630,18 +630,18 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
|||||||
if (!kh)
|
if (!kh)
|
||||||
{
|
{
|
||||||
log_error (_("failed to allocate keyDB handle\n"));
|
log_error (_("failed to allocate keyDB handle\n"));
|
||||||
rc = gpg_error (GPG_ERR_GENERAL);
|
err = gpg_error (GPG_ERR_GENERAL);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gnupg_rng_is_compliant (opt.compliance))
|
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"),
|
log_error (_("%s is not compliant with %s mode\n"),
|
||||||
"RNG",
|
"RNG",
|
||||||
gnupg_compliance_option_string (opt.compliance));
|
gnupg_compliance_option_string (opt.compliance));
|
||||||
gpgsm_status_with_error (ctrl, STATUS_ERROR,
|
gpgsm_status_with_error (ctrl, STATUS_ERROR,
|
||||||
"random-compliance", rc);
|
"random-compliance", err);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -653,20 +653,20 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
|||||||
if (binary_detached)
|
if (binary_detached)
|
||||||
{
|
{
|
||||||
sig_fp = es_fopenmem (0, "w+");
|
sig_fp = es_fopenmem (0, "w+");
|
||||||
rc = sig_fp? 0 : gpg_error_from_syserror ();
|
err = sig_fp? 0 : gpg_error_from_syserror ();
|
||||||
if (!rc)
|
if (!err)
|
||||||
rc = gnupg_ksba_create_writer (&b64writer, 0, NULL, sig_fp, &writer);
|
err = gnupg_ksba_create_writer (&b64writer, 0, NULL, sig_fp, &writer);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rc = gnupg_ksba_create_writer
|
err = gnupg_ksba_create_writer
|
||||||
(&b64writer, ((ctrl->create_pem? GNUPG_KSBA_IO_PEM : 0)
|
(&b64writer, ((ctrl->create_pem? GNUPG_KSBA_IO_PEM : 0)
|
||||||
| (ctrl->create_base64? GNUPG_KSBA_IO_BASE64 : 0)),
|
| (ctrl->create_base64? GNUPG_KSBA_IO_BASE64 : 0)),
|
||||||
ctrl->pem_name, out_fp, &writer);
|
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;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -676,17 +676,13 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
|||||||
|
|
||||||
err = ksba_cms_new (&cms);
|
err = ksba_cms_new (&cms);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
|
||||||
rc = err;
|
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
|
||||||
|
|
||||||
err = ksba_cms_set_reader_writer (cms, NULL, writer);
|
err = ksba_cms_set_reader_writer (cms, NULL, writer);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
log_debug ("ksba_cms_set_reader_writer failed: %s\n",
|
log_debug ("ksba_cms_set_reader_writer failed: %s\n",
|
||||||
gpg_strerror (err));
|
gpg_strerror (err));
|
||||||
rc = err;
|
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -703,7 +699,6 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
|||||||
{
|
{
|
||||||
log_debug ("ksba_cms_set_content_type failed: %s\n",
|
log_debug ("ksba_cms_set_content_type failed: %s\n",
|
||||||
gpg_strerror (err));
|
gpg_strerror (err));
|
||||||
rc = err;
|
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -716,23 +711,23 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
|||||||
log_error ("no default signer found\n");
|
log_error ("no default signer found\n");
|
||||||
gpgsm_status2 (ctrl, STATUS_INV_SGNR,
|
gpgsm_status2 (ctrl, STATUS_INV_SGNR,
|
||||||
get_inv_recpsgnr_code (GPG_ERR_NO_SECKEY), NULL);
|
get_inv_recpsgnr_code (GPG_ERR_NO_SECKEY), NULL);
|
||||||
rc = gpg_error (GPG_ERR_GENERAL);
|
err = gpg_error (GPG_ERR_GENERAL);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Although we don't check for ambiguous specification we will
|
/* Although we don't check for ambiguous specification we will
|
||||||
check that the signer's certificate is usable and valid. */
|
check that the signer's certificate is usable and valid. */
|
||||||
rc = gpgsm_cert_use_sign_p (cert, 0);
|
err = gpgsm_cert_use_sign_p (cert, 0);
|
||||||
if (!rc)
|
if (!err)
|
||||||
rc = gpgsm_validate_chain (ctrl, cert,
|
err = gpgsm_validate_chain (ctrl, cert,
|
||||||
GNUPG_ISOTIME_NONE, NULL, 0, NULL, 0, NULL);
|
GNUPG_ISOTIME_NONE, NULL, 0, NULL, 0, NULL);
|
||||||
if (rc)
|
if (err)
|
||||||
{
|
{
|
||||||
char *tmpfpr;
|
char *tmpfpr;
|
||||||
|
|
||||||
tmpfpr = gpgsm_get_fingerprint_hexstring (cert, 0);
|
tmpfpr = gpgsm_get_fingerprint_hexstring (cert, 0);
|
||||||
gpgsm_status2 (ctrl, STATUS_INV_SGNR,
|
gpgsm_status2 (ctrl, STATUS_INV_SGNR,
|
||||||
get_inv_recpsgnr_code (rc), tmpfpr, NULL);
|
get_inv_recpsgnr_code (err), tmpfpr, NULL);
|
||||||
xfree (tmpfpr);
|
xfree (tmpfpr);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
@ -741,7 +736,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
|||||||
signerlist = xtrycalloc (1, sizeof *signerlist);
|
signerlist = xtrycalloc (1, sizeof *signerlist);
|
||||||
if (!signerlist)
|
if (!signerlist)
|
||||||
{
|
{
|
||||||
rc = out_of_core ();
|
err = gpg_error_from_syserror ();
|
||||||
ksba_cert_release (cert);
|
ksba_cert_release (cert);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
@ -822,8 +817,8 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pk_algo, 0,
|
if (!gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pk_algo,
|
||||||
NULL, nbits, curve))
|
PK_ALGO_FLAG_ECC18, NULL, nbits, curve))
|
||||||
{
|
{
|
||||||
char kidstr[10+1];
|
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. */
|
/* Gather certificates of signers and store them in the CMS object. */
|
||||||
for (cl=signerlist; cl; cl = cl->next)
|
for (cl=signerlist; cl; cl = cl->next)
|
||||||
{
|
{
|
||||||
rc = gpgsm_cert_use_sign_p (cl->cert, 0);
|
err = gpgsm_cert_use_sign_p (cl->cert, 0);
|
||||||
if (rc)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
err = ksba_cms_add_signer (cms, cl->cert);
|
err = ksba_cms_add_signer (cms, cl->cert);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
log_error ("ksba_cms_add_signer failed: %s\n", gpg_strerror (err));
|
log_error ("ksba_cms_add_signer failed: %s\n", gpg_strerror (err));
|
||||||
rc = err;
|
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
rc = add_certificate_list (ctrl, cms, cl->cert);
|
err = add_certificate_list (ctrl, cms, cl->cert);
|
||||||
if (rc)
|
if (err)
|
||||||
{
|
{
|
||||||
log_error ("failed to store list of certificates: %s\n",
|
log_error ("failed to store list of certificates: %s\n",
|
||||||
gpg_strerror(rc));
|
gpg_strerror (err));
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
/* Set the hash algorithm we are going to use */
|
/* 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",
|
log_debug ("ksba_cms_add_digest_algo failed: %s\n",
|
||||||
gpg_strerror (err));
|
gpg_strerror (err));
|
||||||
rc = err;
|
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -895,7 +888,6 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
|||||||
{
|
{
|
||||||
log_error (_("checking for qualified certificate failed: %s\n"),
|
log_error (_("checking for qualified certificate failed: %s\n"),
|
||||||
gpg_strerror (err));
|
gpg_strerror (err));
|
||||||
rc = err;
|
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
if (*buffer)
|
if (*buffer)
|
||||||
@ -903,19 +895,16 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
|||||||
else
|
else
|
||||||
err = gpgsm_not_qualified_warning (ctrl, cl->cert);
|
err = gpgsm_not_qualified_warning (ctrl, cl->cert);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
|
||||||
rc = err;
|
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Prepare hashing (actually we are figuring out what we have set
|
/* Prepare hashing (actually we are figuring out what we have set
|
||||||
above). */
|
above). */
|
||||||
rc = gcry_md_open (&data_md, 0, 0);
|
err = gcry_md_open (&data_md, 0, 0);
|
||||||
if (rc)
|
if (err)
|
||||||
{
|
{
|
||||||
log_error ("md_open failed: %s\n", gpg_strerror (rc));
|
log_error ("md_open failed: %s\n", gpg_strerror (err));
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
if (DBG_HASHING)
|
if (DBG_HASHING)
|
||||||
@ -927,7 +916,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
|||||||
if (!algo)
|
if (!algo)
|
||||||
{
|
{
|
||||||
log_error ("unknown hash algorithm '%s'\n", algoid? algoid:"?");
|
log_error ("unknown hash algorithm '%s'\n", algoid? algoid:"?");
|
||||||
rc = gpg_error (GPG_ERR_BUG);
|
err = gpg_error (GPG_ERR_BUG);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
gcry_md_enable (data_md, algo);
|
gcry_md_enable (data_md, algo);
|
||||||
@ -952,7 +941,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
|||||||
if ( !digest || !digest_len )
|
if ( !digest || !digest_len )
|
||||||
{
|
{
|
||||||
log_error ("problem getting the hash of the data\n");
|
log_error ("problem getting the hash of the data\n");
|
||||||
rc = gpg_error (GPG_ERR_BUG);
|
err = gpg_error (GPG_ERR_BUG);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
err = ksba_cms_set_message_digest (cms, signer, digest, digest_len);
|
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",
|
log_error ("ksba_cms_set_message_digest failed: %s\n",
|
||||||
gpg_strerror (err));
|
gpg_strerror (err));
|
||||||
rc = err;
|
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -974,7 +962,6 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
|||||||
{
|
{
|
||||||
log_error ("ksba_cms_set_signing_time failed: %s\n",
|
log_error ("ksba_cms_set_signing_time failed: %s\n",
|
||||||
gpg_strerror (err));
|
gpg_strerror (err));
|
||||||
rc = err;
|
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1016,7 +1003,6 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
|||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
log_error ("creating CMS object failed: %s\n", gpg_strerror (err));
|
log_error ("creating CMS object failed: %s\n", gpg_strerror (err));
|
||||||
rc = err;
|
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1028,8 +1014,8 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
|||||||
|
|
||||||
log_assert (!detached);
|
log_assert (!detached);
|
||||||
|
|
||||||
rc = hash_and_copy_data (data_fp, data_md, writer);
|
err = hash_and_copy_data (data_fp, data_md, writer);
|
||||||
if (rc)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
audit_log (ctrl->audit, AUDIT_GOT_DATA);
|
audit_log (ctrl->audit, AUDIT_GOT_DATA);
|
||||||
for (cl=signerlist,signer=0; cl; cl = cl->next, signer++)
|
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 )
|
if ( !digest || !digest_len )
|
||||||
{
|
{
|
||||||
log_error ("problem getting the hash of the data\n");
|
log_error ("problem getting the hash of the data\n");
|
||||||
rc = gpg_error (GPG_ERR_BUG);
|
err = gpg_error (GPG_ERR_BUG);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
err = ksba_cms_set_message_digest (cms, signer,
|
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",
|
log_error ("ksba_cms_set_message_digest failed: %s\n",
|
||||||
gpg_strerror (err));
|
gpg_strerror (err));
|
||||||
rc = err;
|
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1058,10 +1043,10 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
|||||||
/* Compute the signature for all signers. */
|
/* Compute the signature for all signers. */
|
||||||
gcry_md_hd_t md;
|
gcry_md_hd_t md;
|
||||||
|
|
||||||
rc = gcry_md_open (&md, 0, 0);
|
err = gcry_md_open (&md, 0, 0);
|
||||||
if (rc)
|
if (err)
|
||||||
{
|
{
|
||||||
log_error ("md_open failed: %s\n", gpg_strerror (rc));
|
log_error ("md_open failed: %s\n", gpg_strerror (err));
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
if (DBG_HASHING)
|
if (DBG_HASHING)
|
||||||
@ -1086,20 +1071,20 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = ksba_cms_hash_signed_attrs (cms, signer);
|
err = ksba_cms_hash_signed_attrs (cms, signer);
|
||||||
if (rc)
|
if (err)
|
||||||
{
|
{
|
||||||
log_debug ("hashing signed attrs failed: %s\n",
|
log_debug ("hashing signed attrs failed: %s\n",
|
||||||
gpg_strerror (rc));
|
gpg_strerror (err));
|
||||||
gcry_md_close (md);
|
gcry_md_close (md);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = gpgsm_create_cms_signature (ctrl, cl->cert,
|
err = gpgsm_create_cms_signature (ctrl, cl->cert,
|
||||||
md, cl->hash_algo, &sigval);
|
md, cl->hash_algo, &sigval);
|
||||||
if (rc)
|
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);
|
gcry_md_close (md);
|
||||||
goto leave;
|
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);
|
audit_log_cert (ctrl->audit, AUDIT_SIGNED_BY, cl->cert, err);
|
||||||
log_error ("failed to store the signature: %s\n",
|
log_error ("failed to store the signature: %s\n",
|
||||||
gpg_strerror (err));
|
gpg_strerror (err));
|
||||||
rc = err;
|
|
||||||
gcry_md_close (md);
|
gcry_md_close (md);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
@ -1120,11 +1104,10 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
|||||||
fpr = gpgsm_get_fingerprint_hexstring (cl->cert, GCRY_MD_SHA1);
|
fpr = gpgsm_get_fingerprint_hexstring (cl->cert, GCRY_MD_SHA1);
|
||||||
if (!fpr)
|
if (!fpr)
|
||||||
{
|
{
|
||||||
rc = gpg_error (GPG_ERR_ENOMEM);
|
err = gpg_error (GPG_ERR_ENOMEM);
|
||||||
gcry_md_close (md);
|
gcry_md_close (md);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
rc = 0;
|
|
||||||
if (opt.verbose)
|
if (opt.verbose)
|
||||||
{
|
{
|
||||||
char *pkalgostr = gpgsm_pubkey_algo_string (cl->cert, NULL);
|
char *pkalgostr = gpgsm_pubkey_algo_string (cl->cert, NULL);
|
||||||
@ -1141,9 +1124,9 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
|||||||
signed_at,
|
signed_at,
|
||||||
fpr);
|
fpr);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
rc = gpg_error_from_syserror ();
|
err = gpg_error_from_syserror ();
|
||||||
xfree (fpr);
|
xfree (fpr);
|
||||||
if (rc)
|
if (err)
|
||||||
{
|
{
|
||||||
gcry_md_close (md);
|
gcry_md_close (md);
|
||||||
goto leave;
|
goto leave;
|
||||||
@ -1157,10 +1140,10 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
|||||||
}
|
}
|
||||||
while (stopreason != KSBA_SR_READY);
|
while (stopreason != KSBA_SR_READY);
|
||||||
|
|
||||||
rc = gnupg_ksba_finish_writer (b64writer);
|
err = gnupg_ksba_finish_writer (b64writer);
|
||||||
if (rc)
|
if (err)
|
||||||
{
|
{
|
||||||
log_error ("write failed: %s\n", gpg_strerror (rc));
|
log_error ("write failed: %s\n", gpg_strerror (err));
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1169,13 +1152,14 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
|||||||
void *blob = NULL;
|
void *blob = NULL;
|
||||||
size_t bloblen;
|
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;
|
sig_fp = NULL;
|
||||||
if (rc)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
rc = write_detached_signature (ctrl, blob, bloblen, out_fp);
|
err = write_detached_signature (ctrl, blob, bloblen, out_fp);
|
||||||
xfree (blob);
|
xfree (blob);
|
||||||
if (rc)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1184,9 +1168,9 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
|||||||
log_info ("signature created\n");
|
log_info ("signature created\n");
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
if (rc)
|
if (err)
|
||||||
log_error ("error creating signature: %s <%s>\n",
|
log_error ("error creating signature: %s <%s>\n",
|
||||||
gpg_strerror (rc), gpg_strsource (rc) );
|
gpg_strerror (err), gpg_strsource (err) );
|
||||||
if (release_signerlist)
|
if (release_signerlist)
|
||||||
gpgsm_release_certlist (signerlist);
|
gpgsm_release_certlist (signerlist);
|
||||||
xfree (curve);
|
xfree (curve);
|
||||||
@ -1195,5 +1179,5 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
|||||||
keydb_release (kh);
|
keydb_release (kh);
|
||||||
gcry_md_close (data_md);
|
gcry_md_close (data_md);
|
||||||
es_fclose (sig_fp);
|
es_fclose (sig_fp);
|
||||||
return rc;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
audit_log_i (ctrl->audit, AUDIT_DATA_HASH_ALGO, algo);
|
||||||
|
|
||||||
/* Check compliance. */
|
/* Check compliance. */
|
||||||
|
pkalgoflags |= PK_ALGO_FLAG_ECC18;
|
||||||
if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION,
|
if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION,
|
||||||
pkalgo, pkalgoflags, NULL, nbits, pkcurve))
|
pkalgo, pkalgoflags, NULL, nbits, pkcurve))
|
||||||
{
|
{
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include "../common/init.h"
|
#include "../common/init.h"
|
||||||
#include "../common/status.h"
|
#include "../common/status.h"
|
||||||
#include "../common/exechelp.h"
|
#include "../common/exechelp.h"
|
||||||
|
#include "../common/dotlock.h"
|
||||||
|
|
||||||
#ifdef HAVE_W32_SYSTEM
|
#ifdef HAVE_W32_SYSTEM
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
@ -76,7 +77,9 @@ enum cmd_and_opt_values
|
|||||||
aCreateSocketDir,
|
aCreateSocketDir,
|
||||||
aRemoveSocketDir,
|
aRemoveSocketDir,
|
||||||
aApplyProfile,
|
aApplyProfile,
|
||||||
aShowCodepages
|
aShowCodepages,
|
||||||
|
aDotlockLock,
|
||||||
|
aDotlockUnlock
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -109,7 +112,10 @@ static gpgrt_opt_t opts[] =
|
|||||||
{ aRemoveSocketDir, "remove-socketdir", 256, "@"},
|
{ aRemoveSocketDir, "remove-socketdir", 256, "@"},
|
||||||
ARGPARSE_c (aShowVersions, "show-versions", ""),
|
ARGPARSE_c (aShowVersions, "show-versions", ""),
|
||||||
ARGPARSE_c (aShowConfigs, "show-configs", ""),
|
ARGPARSE_c (aShowConfigs, "show-configs", ""),
|
||||||
|
/* hidden commands: for debugging */
|
||||||
ARGPARSE_c (aShowCodepages, "show-codepages", "@"),
|
ARGPARSE_c (aShowCodepages, "show-codepages", "@"),
|
||||||
|
ARGPARSE_c (aDotlockLock, "lock", "@"),
|
||||||
|
ARGPARSE_c (aDotlockUnlock, "unlock", "@"),
|
||||||
|
|
||||||
{ 301, NULL, 0, N_("@\nOptions:\n ") },
|
{ 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. */
|
/* gpgconf main. */
|
||||||
int
|
int
|
||||||
main (int argc, char **argv)
|
main (int argc, char **argv)
|
||||||
@ -669,6 +710,8 @@ main (int argc, char **argv)
|
|||||||
case aShowVersions:
|
case aShowVersions:
|
||||||
case aShowConfigs:
|
case aShowConfigs:
|
||||||
case aShowCodepages:
|
case aShowCodepages:
|
||||||
|
case aDotlockLock:
|
||||||
|
case aDotlockUnlock:
|
||||||
cmd = pargs.r_opt;
|
cmd = pargs.r_opt;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1024,7 +1067,32 @@ main (int argc, char **argv)
|
|||||||
#endif
|
#endif
|
||||||
break;
|
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)
|
if (outfp != es_stdout)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user