gpg: Make sure to mark a duplicate registered keybox as primary.

* kbx/keybox-init.c (keybox_register_file): Change interface to return
the token even if the file has already been registered.
* g10/keydb.c (primary_keyring): Rename to primary_keydb.
(maybe_create_keyring_or_box): Change return type to gpg_error_t.
(keydb_add_resource): Ditto. s/rc/err/.
(keydb_add_resource): Mark an already registered as primary.
* sm/keydb.c (maybe_create_keybox): Change return type to gpg_error_t.
(keydb_add_resource): Ditto. s/rc/err/.
(keydb_add_resource): Adjust for changed keybox_register_file.
--

This change aligns the registering of keyboxes with those of
keyrings.  This fixes a potential bug:

  gpg --keyring foo.kbx --keyring bar.gpg --keyring foo.kbx

would have marked bar.gpg as primary resource and thus inserting new
keys there.  The correct and now fixed behavior is to insert to
foo.kbx.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2016-01-13 09:29:39 +01:00
parent 96237b9a63
commit 9dc355ad3a
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
5 changed files with 68 additions and 54 deletions

View File

@ -60,7 +60,10 @@ struct resource_item
static struct resource_item all_resources[MAX_KEYDB_RESOURCES]; static struct resource_item all_resources[MAX_KEYDB_RESOURCES];
static int used_resources; static int used_resources;
static void *primary_keyring=NULL;
/* A pointer used to check for the primary key database by comparing
to the struct resource_item's TOKEN. */
static void *primary_keydb;
/* This is a simple cache used to return the last result of a /* This is a simple cache used to return the last result of a
@ -261,7 +264,7 @@ keyblock_cache_clear (struct keydb_handle *hd)
the keyring or keybox will be created. the keyring or keybox will be created.
Return 0 if it is okay to access the specified file. */ Return 0 if it is okay to access the specified file. */
static int static gpg_error_t
maybe_create_keyring_or_box (char *filename, int is_box, int force_create) maybe_create_keyring_or_box (char *filename, int is_box, int force_create)
{ {
dotlock_t lockhd = NULL; dotlock_t lockhd = NULL;
@ -592,7 +595,7 @@ keydb_add_resource (const char *url, unsigned int flags)
int read_only = !!(flags&KEYDB_RESOURCE_FLAG_READONLY); int read_only = !!(flags&KEYDB_RESOURCE_FLAG_READONLY);
int is_default = !!(flags&KEYDB_RESOURCE_FLAG_DEFAULT); int is_default = !!(flags&KEYDB_RESOURCE_FLAG_DEFAULT);
int is_gpgvdef = !!(flags&KEYDB_RESOURCE_FLAG_GPGVDEF); int is_gpgvdef = !!(flags&KEYDB_RESOURCE_FLAG_GPGVDEF);
int rc = 0; gpg_error_t err = 0;
KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE; KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE;
void *token; void *token;
@ -613,7 +616,7 @@ keydb_add_resource (const char *url, unsigned int flags)
else if (strchr (resname, ':')) else if (strchr (resname, ':'))
{ {
log_error ("invalid key resource URL '%s'\n", url ); log_error ("invalid key resource URL '%s'\n", url );
rc = gpg_error (GPG_ERR_GENERAL); err = gpg_error (GPG_ERR_GENERAL);
goto leave; goto leave;
} }
#endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */ #endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */
@ -708,22 +711,22 @@ keydb_add_resource (const char *url, unsigned int flags)
{ {
case KEYDB_RESOURCE_TYPE_NONE: case KEYDB_RESOURCE_TYPE_NONE:
log_error ("unknown type of key resource '%s'\n", url ); log_error ("unknown type of key resource '%s'\n", url );
rc = gpg_error (GPG_ERR_GENERAL); err = gpg_error (GPG_ERR_GENERAL);
goto leave; goto leave;
case KEYDB_RESOURCE_TYPE_KEYRING: case KEYDB_RESOURCE_TYPE_KEYRING:
rc = maybe_create_keyring_or_box (filename, 0, create); err = maybe_create_keyring_or_box (filename, 0, create);
if (rc) if (err)
goto leave; goto leave;
if (keyring_register_filename (filename, read_only, &token)) if (keyring_register_filename (filename, read_only, &token))
{ {
if (used_resources >= MAX_KEYDB_RESOURCES) if (used_resources >= MAX_KEYDB_RESOURCES)
rc = gpg_error (GPG_ERR_RESOURCE_LIMIT); err = gpg_error (GPG_ERR_RESOURCE_LIMIT);
else else
{ {
if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY)) if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY))
primary_keyring = token; primary_keydb = token;
all_resources[used_resources].type = rt; all_resources[used_resources].type = rt;
all_resources[used_resources].u.kr = NULL; /* Not used here */ all_resources[used_resources].u.kr = NULL; /* Not used here */
all_resources[used_resources].token = token; all_resources[used_resources].token = token;
@ -736,26 +739,25 @@ keydb_add_resource (const char *url, unsigned int flags)
However, we can still mark it as primary even if it was However, we can still mark it as primary even if it was
already registered. */ already registered. */
if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY)) if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY))
primary_keyring = token; primary_keydb = token;
} }
break; break;
case KEYDB_RESOURCE_TYPE_KEYBOX: case KEYDB_RESOURCE_TYPE_KEYBOX:
{ {
rc = maybe_create_keyring_or_box (filename, 1, create); err = maybe_create_keyring_or_box (filename, 1, create);
if (rc) if (err)
goto leave; goto leave;
/* FIXME: How do we register a read-only keybox? */ err = keybox_register_file (filename, 0, &token);
token = keybox_register_file (filename, 0); if (!err)
if (token)
{ {
if (used_resources >= MAX_KEYDB_RESOURCES) if (used_resources >= MAX_KEYDB_RESOURCES)
rc = gpg_error (GPG_ERR_RESOURCE_LIMIT); err = gpg_error (GPG_ERR_RESOURCE_LIMIT);
else else
{ {
/* if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY)) */ if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY))
/* primary_keyring = token; */ primary_keydb = token;
all_resources[used_resources].type = rt; all_resources[used_resources].type = rt;
all_resources[used_resources].u.kb = NULL; /* Not used here */ all_resources[used_resources].u.kb = NULL; /* Not used here */
all_resources[used_resources].token = token; all_resources[used_resources].token = token;
@ -766,32 +768,31 @@ keydb_add_resource (const char *url, unsigned int flags)
used_resources++; used_resources++;
} }
} }
else else if (gpg_err_code (err) == GPG_ERR_EEXIST)
{ {
/* Already registered. We will mark it as the primary key /* Already registered. We will mark it as the primary key
if requested. */ if requested. */
/* FIXME: How to do that? Change the keybox interface? */ if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY))
/* if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY)) */ primary_keydb = token;
/* primary_keyring = token; */
} }
} }
break; break;
default: default:
log_error ("resource type of '%s' not supported\n", url); log_error ("resource type of '%s' not supported\n", url);
rc = gpg_error (GPG_ERR_GENERAL); err = gpg_error (GPG_ERR_GENERAL);
goto leave; goto leave;
} }
/* fixme: check directory permissions and print a warning */ /* fixme: check directory permissions and print a warning */
leave: leave:
if (rc) if (err)
log_error (_("keyblock resource '%s': %s\n"), filename, gpg_strerror (rc)); log_error (_("keyblock resource '%s': %s\n"), filename, gpg_strerror (err));
else else
any_registered = 1; any_registered = 1;
xfree (filename); xfree (filename);
return rc; return err;
} }
@ -1685,11 +1686,11 @@ keydb_locate_writable (KEYDB_HANDLE hd)
return rc; return rc;
/* If we have a primary set, try that one first */ /* If we have a primary set, try that one first */
if (primary_keyring) if (primary_keydb)
{ {
for ( ; hd->current >= 0 && hd->current < hd->used; hd->current++) for ( ; hd->current >= 0 && hd->current < hd->used; hd->current++)
{ {
if(hd->active[hd->current].token==primary_keyring) if(hd->active[hd->current].token == primary_keydb)
{ {
if(keyring_is_writable (hd->active[hd->current].token)) if(keyring_is_writable (hd->active[hd->current].token))
return 0; return 0;

View File

@ -30,23 +30,30 @@
static KB_NAME kb_names; static KB_NAME kb_names;
/* Register a filename for plain keybox files. Returns a pointer to /* Register a filename for plain keybox files. Returns 0 on success,
be used to create a handles and so on. Returns NULL to indicate * GPG_ERR_EEXIST if it has already been registered, or another error
that FNAME has already been registered. */ * code. On success or with error code GPG_ERR_EEXIST a token usable
void * * to access the keybox handle is stored at R_TOKEN, NULL is stored
keybox_register_file (const char *fname, int secret) * for all other errors. */
gpg_error_t
keybox_register_file (const char *fname, int secret, void **r_token)
{ {
KB_NAME kr; KB_NAME kr;
*r_token = NULL;
for (kr=kb_names; kr; kr = kr->next) for (kr=kb_names; kr; kr = kr->next)
{ {
if (same_file_p (kr->fname, fname) ) if (same_file_p (kr->fname, fname) )
return NULL; /* Already registered. */ {
*r_token = kr;
return gpg_error (GPG_ERR_EEXIST); /* Already registered. */
}
} }
kr = xtrymalloc (sizeof *kr + strlen (fname)); kr = xtrymalloc (sizeof *kr + strlen (fname));
if (!kr) if (!kr)
return NULL; return gpg_error_from_syserror ();
strcpy (kr->fname, fname); strcpy (kr->fname, fname);
kr->secret = !!secret; kr->secret = !!secret;
@ -64,7 +71,8 @@ keybox_register_file (const char *fname, int secret)
/* if (!kb_offtbl) */ /* if (!kb_offtbl) */
/* kb_offtbl = new_offset_hash_table (); */ /* kb_offtbl = new_offset_hash_table (); */
return kr; *r_token = kr;
return 0;
} }
int int

View File

@ -64,7 +64,8 @@ typedef enum
/*-- keybox-init.c --*/ /*-- keybox-init.c --*/
void *keybox_register_file (const char *fname, int secret); gpg_error_t keybox_register_file (const char *fname, int secret,
void **r_token);
int keybox_is_writable (void *token); int keybox_is_writable (void *token);
KEYBOX_HANDLE keybox_new_openpgp (void *token, int secret); KEYBOX_HANDLE keybox_new_openpgp (void *token, int secret);

View File

@ -107,7 +107,7 @@ try_make_homedir (const char *fname)
locked. This lock check does not work if the directory itself is locked. This lock check does not work if the directory itself is
not yet available. If R_CREATED is not NULL it will be set to true not yet available. If R_CREATED is not NULL it will be set to true
if the function created a new keybox. */ if the function created a new keybox. */
static int static gpg_error_t
maybe_create_keybox (char *filename, int force, int *r_created) maybe_create_keybox (char *filename, int force, int *r_created)
{ {
dotlock_t lockhd = NULL; dotlock_t lockhd = NULL;
@ -237,13 +237,13 @@ maybe_create_keybox (char *filename, int force, int *r_created)
* does not exist. If AUTO_CREATED is not NULL it will be set to true * does not exist. If AUTO_CREATED is not NULL it will be set to true
* if the function has created a new keybox. * if the function has created a new keybox.
*/ */
int gpg_error_t
keydb_add_resource (const char *url, int force, int secret, int *auto_created) keydb_add_resource (const char *url, int force, int secret, int *auto_created)
{ {
static int any_secret, any_public; static int any_secret, any_public;
const char *resname = url; const char *resname = url;
char *filename = NULL; char *filename = NULL;
int rc = 0; gpg_error_t err = 0;
KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE; KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE;
if (auto_created) if (auto_created)
@ -264,7 +264,7 @@ keydb_add_resource (const char *url, int force, int secret, int *auto_created)
else if (strchr (resname, ':')) else if (strchr (resname, ':'))
{ {
log_error ("invalid key resource URL '%s'\n", url ); log_error ("invalid key resource URL '%s'\n", url );
rc = gpg_error (GPG_ERR_GENERAL); err = gpg_error (GPG_ERR_GENERAL);
goto leave; goto leave;
} }
#endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */ #endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */
@ -312,20 +312,24 @@ keydb_add_resource (const char *url, int force, int secret, int *auto_created)
{ {
case KEYDB_RESOURCE_TYPE_NONE: case KEYDB_RESOURCE_TYPE_NONE:
log_error ("unknown type of key resource '%s'\n", url ); log_error ("unknown type of key resource '%s'\n", url );
rc = gpg_error (GPG_ERR_GENERAL); err = gpg_error (GPG_ERR_GENERAL);
goto leave; goto leave;
case KEYDB_RESOURCE_TYPE_KEYBOX: case KEYDB_RESOURCE_TYPE_KEYBOX:
rc = maybe_create_keybox (filename, force, auto_created); err = maybe_create_keybox (filename, force, auto_created);
if (rc) if (err)
goto leave; goto leave;
/* Now register the file */ /* Now register the file */
{ {
void *token = keybox_register_file (filename, secret); void *token;
if (!token)
; /* already registered - ignore it */ err = keybox_register_file (filename, secret, &token);
if (gpg_err_code (err) == GPG_ERR_EEXIST)
; /* Already registered - ignore. */
else if (err)
; /* Other error. */
else if (used_resources >= MAX_KEYDB_RESOURCES) else if (used_resources >= MAX_KEYDB_RESOURCES)
rc = gpg_error (GPG_ERR_RESOURCE_LIMIT); err = gpg_error (GPG_ERR_RESOURCE_LIMIT);
else else
{ {
all_resources[used_resources].type = rt; all_resources[used_resources].type = rt;
@ -358,21 +362,21 @@ keydb_add_resource (const char *url, int force, int secret, int *auto_created)
default: default:
log_error ("resource type of '%s' not supported\n", url); log_error ("resource type of '%s' not supported\n", url);
rc = gpg_error (GPG_ERR_NOT_SUPPORTED); err = gpg_error (GPG_ERR_NOT_SUPPORTED);
goto leave; goto leave;
} }
/* fixme: check directory permissions and print a warning */ /* fixme: check directory permissions and print a warning */
leave: leave:
if (rc) if (err)
log_error ("keyblock resource '%s': %s\n", filename, gpg_strerror(rc)); log_error ("keyblock resource '%s': %s\n", filename, gpg_strerror (err));
else if (secret) else if (secret)
any_secret = 1; any_secret = 1;
else else
any_public = 1; any_public = 1;
xfree (filename); xfree (filename);
return rc; return err;
} }

View File

@ -31,8 +31,8 @@ typedef struct keydb_handle *KEYDB_HANDLE;
/*-- keydb.c --*/ /*-- keydb.c --*/
int keydb_add_resource (const char *url, int force, int secret, gpg_error_t keydb_add_resource (const char *url, int force, int secret,
int *auto_created); int *auto_created);
KEYDB_HANDLE keydb_new (int secret); KEYDB_HANDLE keydb_new (int secret);
void keydb_release (KEYDB_HANDLE hd); void keydb_release (KEYDB_HANDLE hd);
int keydb_set_ephemeral (KEYDB_HANDLE hd, int yes); int keydb_set_ephemeral (KEYDB_HANDLE hd, int yes);