1
0
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:
Werner Koch 2023-12-22 13:45:02 +01:00
commit 2764ee309a
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
38 changed files with 1149 additions and 370 deletions

View File

@ -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
View File

@ -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
View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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,

View File

@ -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;
} }

View File

@ -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);

View File

@ -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)

View File

@ -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;
} }

View File

@ -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);

View File

@ -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;

View File

@ -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];

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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));

View File

@ -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;
} }

View File

@ -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

View File

@ -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. */

View File

@ -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;

View File

@ -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);
} }
} }
} }

View File

@ -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

View File

@ -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:");

View File

@ -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);

View File

@ -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:

View File

@ -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);
} }

View File

@ -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;

View File

@ -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;

View File

@ -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));

View File

@ -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];

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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';
} }

View File

@ -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
View File

@ -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;
} }

View File

@ -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))
{ {

View File

@ -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)