summaryrefslogtreecommitdiffstats
path: root/g10/keydb.c
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2012-12-27 15:04:29 +0100
committerWerner Koch <wk@gnupg.org>2012-12-27 15:04:42 +0100
commit91e61d52539b1808e209c43e51465c76cebb06f9 (patch)
tree3ec3f91ece84ef574234df03eed9baf9b6b3b93f /g10/keydb.c
parentgpg: Import only packets which are allowed in a keyblock. (diff)
downloadgnupg2-91e61d52539b1808e209c43e51465c76cebb06f9.tar.xz
gnupg2-91e61d52539b1808e209c43e51465c76cebb06f9.zip
gpg: First patches to support a keybox storage backend.
* kbx/keybox-defs.h (_keybox_write_header_blob): Move prototype to .. * kbx/keybox.h: here. * kbx/keybox-init.c (keybox_lock): Add dummy function * g10/keydb.c: Include keybox.h. (KeydbResourceType): Add KEYDB_RESOURCE_TYPE_KEYBOX. (struct resource_item): Add field kb. (maybe_create_keyring_or_box): Add error descriptions to diagnostics. Add arg IS_BOX. Write a header for a new keybox file. (keydb_add_resource): No more need for the force flag. Rename the local variable "force" to "create". Add URL scheme "gnupg-kbx". Add magic test to detect a keybox file. Add basic support for keybox. (keydb_new, keydb_get_resource_name, keydb_delete_keyblock) (keydb_locate_writable, keydb_search_reset, keydb_search2): Add support for keybox. (lock_all, unlock_all): Ditto. * g10/Makefile.am (needed_libs): Add libkeybox.a. (gpg2_LDADD, gpgv2_LDADD): Add KSBA_LIBS as a workaround. * g10/keydb.h (KEYDB_RESOURCE_FLAG_PRIMARY) KEYDB_RESOURCE_FLAG_DEFAULT, KEYDB_RESOURCE_FLAG_READONLY): New. * g10/gpg.c, g10/gpgv.c (main): Use new constants. -- I did most of these changes back in 2011 and only cleaned them up now. More to follow soon.
Diffstat (limited to 'g10/keydb.c')
-rw-r--r--g10/keydb.c254
1 files changed, 196 insertions, 58 deletions
diff --git a/g10/keydb.c b/g10/keydb.c
index 75c036cf5..ab727b6c6 100644
--- a/g10/keydb.c
+++ b/g10/keydb.c
@@ -34,6 +34,7 @@
#include "main.h" /*try_make_homedir ()*/
#include "packet.h"
#include "keyring.h"
+#include "../kbx/keybox.h"
#include "keydb.h"
#include "i18n.h"
@@ -42,7 +43,8 @@ static int active_handles;
typedef enum
{
KEYDB_RESOURCE_TYPE_NONE = 0,
- KEYDB_RESOURCE_TYPE_KEYRING
+ KEYDB_RESOURCE_TYPE_KEYRING,
+ KEYDB_RESOURCE_TYPE_KEYBOX
} KeydbResourceType;
#define MAX_KEYDB_RESOURCES 40
@@ -51,6 +53,7 @@ struct resource_item
KeydbResourceType type;
union {
KEYRING_HANDLE kr;
+ KEYBOX_HANDLE kb;
} u;
void *token;
};
@@ -73,12 +76,12 @@ static int lock_all (KEYDB_HANDLE hd);
static void unlock_all (KEYDB_HANDLE hd);
-/* Handle the creation of a keyring if it does not yet exist. Take
- into acount that other processes might have the keyring already
- locked. This lock check does not work if the directory itself is
- not yet available. */
+/* Handle the creation of a keyring or a keybox if it does not yet
+ exist. Take into acount that other processes might have the
+ keyring/keybox already locked. This lock check does not work if
+ the directory itself is not yet available. */
static int
-maybe_create_keyring (char *filename, int force)
+maybe_create_keyring_or_box (char *filename, int is_box, int force)
{
dotlock_t lockhd = NULL;
IOBUF iobuf;
@@ -139,29 +142,31 @@ maybe_create_keyring (char *filename, int force)
lockhd = dotlock_create (filename, 0);
if (!lockhd)
{
+ rc = gpg_error_from_syserror ();
/* A reason for this to fail is that the directory is not
writable. However, this whole locking stuff does not make
sense if this is the case. An empty non-writable directory
with no keyring is not really useful at all. */
if (opt.verbose)
- log_info ("can't allocate lock for '%s'\n", filename );
+ log_info ("can't allocate lock for '%s': %s\n",
+ filename, gpg_strerror (rc));
if (!force)
return gpg_error (GPG_ERR_ENOENT);
else
- return gpg_error (GPG_ERR_GENERAL);
+ return rc;
}
if ( dotlock_take (lockhd, -1) )
{
+ rc = gpg_error_from_syserror ();
/* This is something bad. Probably a stale lockfile. */
- log_info ("can't lock '%s'\n", filename );
- rc = G10ERR_GENERAL;
+ log_info ("can't lock '%s': %s\n", filename, gpg_strerror (rc));
goto leave;
}
/* Now the real test while we are locked. */
- if (!access(filename, F_OK))
+ if (!access (filename, F_OK))
{
rc = 0; /* Okay, we may access the file now. */
goto leave;
@@ -180,17 +185,51 @@ maybe_create_keyring (char *filename, int force)
if (!iobuf)
{
rc = gpg_error_from_syserror ();
- log_error ( _("error creating keyring '%s': %s\n"),
- filename, strerror(errno));
+ if (is_box)
+ log_error (_("error creating keybox '%s': %s\n"),
+ filename, gpg_strerror (rc));
+ else
+ log_error (_("error creating keyring '%s': %s\n"),
+ filename, gpg_strerror (rc));
goto leave;
}
- if (!opt.quiet)
- log_info (_("keyring '%s' created\n"), filename);
-
iobuf_close (iobuf);
/* Must invalidate that ugly cache */
iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, filename);
+
+ /* Make sure that at least one record is in a new keybox file, so
+ that the detection magic will work the next time it is used. */
+ if (is_box)
+ {
+ FILE *fp = fopen (filename, "w");
+ if (!fp)
+ rc = gpg_error_from_syserror ();
+ else
+ {
+ rc = _keybox_write_header_blob (fp);
+ fclose (fp);
+ }
+ if (rc)
+ {
+ if (is_box)
+ log_error (_("error creating keybox '%s': %s\n"),
+ filename, gpg_strerror (rc));
+ else
+ log_error (_("error creating keyring '%s': %s\n"),
+ filename, gpg_strerror (rc));
+ goto leave;
+ }
+ }
+
+ if (!opt.quiet)
+ {
+ if (is_box)
+ log_info (_("keybox '%s' created\n"), filename);
+ else
+ log_info (_("keyring '%s' created\n"), filename);
+ }
+
rc = 0;
leave:
@@ -204,51 +243,49 @@ maybe_create_keyring (char *filename, int force)
/*
- * Register a resource (which currently may only be a keyring file).
- * The first keyring which is added by this function is
- * created if it does not exist.
- * Note: this function may be called before secure memory is
- * available.
- * Flag 1 - Force.
- * Flag 2 - Mark resource as primary.
- * Flag 4 - This is a default resources.
- * Flag 8 - Open as read-only.
+ * Register a resource (keyring or aeybox). The first keyring or
+ * keybox which is added by this function is created if it does not
+ * exist. FLAGS are a combination of the KEYDB_RESOURCE_FLAG_
+ * constants as defined in keydb.h.
*/
gpg_error_t
-keydb_add_resource (const char *url, int flags)
+keydb_add_resource (const char *url, unsigned int flags)
{
- static int any_public;
+ static int any_registered;
const char *resname = url;
char *filename = NULL;
- int force = (flags&1);
- int read_only = !!(flags&8);
+ int create;
+ int read_only = !!(flags&KEYDB_RESOURCE_FLAG_READONLY);
int rc = 0;
KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE;
void *token;
- if (read_only)
- force = 0;
+ /* Create the resource if it is the first registered one. */
+ create = (!read_only && !any_registered);
/* Do we have an URL?
- * gnupg-ring:filename := this is a plain keyring
+ * gnupg-ring:filename := this is a plain keyring.
+ * gnupg-kbx:filename := this is a keybox file.
* filename := See what is is, but create as plain keyring.
*/
- if (strlen (resname) > 11)
+ if (strlen (resname) > 11 && !strncmp( resname, "gnupg-ring:", 11) )
{
- if (!strncmp( resname, "gnupg-ring:", 11) )
- {
- rt = KEYDB_RESOURCE_TYPE_KEYRING;
- resname += 11;
- }
+ rt = KEYDB_RESOURCE_TYPE_KEYRING;
+ resname += 11;
+ }
+ else if (strlen (resname) > 10 && !strncmp (resname, "gnupg-kbx:", 10) )
+ {
+ rt = KEYDB_RESOURCE_TYPE_KEYBOX;
+ resname += 10;
+ }
#if !defined(HAVE_DRIVE_LETTERS) && !defined(__riscos__)
- else if (strchr (resname, ':'))
- {
- log_error ("invalid key resource URL '%s'\n", url );
- rc = gpg_error (GPG_ERR_GENERAL);
- goto leave;
- }
-#endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */
+ else if (strchr (resname, ':'))
+ {
+ log_error ("invalid key resource URL '%s'\n", url );
+ rc = gpg_error (GPG_ERR_GENERAL);
+ goto leave;
}
+#endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */
if (*resname != DIRSEP_C )
{
@@ -261,9 +298,6 @@ keydb_add_resource (const char *url, int flags)
else
filename = xstrdup (resname);
- if (!force && !read_only)
- force = !any_public;
-
/* See whether we can determine the filetype. */
if (rt == KEYDB_RESOURCE_TYPE_NONE)
{
@@ -273,20 +307,25 @@ keydb_add_resource (const char *url, int flags)
{
u32 magic;
- if (fread( &magic, 4, 1, fp) == 1 )
+ if (fread (&magic, 4, 1, fp) == 1 )
{
if (magic == 0x13579ace || magic == 0xce9a5713)
; /* GDBM magic - not anymore supported. */
+ else if (fread (&magic, 4, 1, fp) == 1
+ && !memcmp (&magic, "\x01", 1)
+ && fread (&magic, 4, 1, fp) == 1
+ && !memcmp (&magic, "KBXf", 4))
+ rt = KEYDB_RESOURCE_TYPE_KEYBOX;
else
rt = KEYDB_RESOURCE_TYPE_KEYRING;
}
else /* Maybe empty: assume keyring. */
rt = KEYDB_RESOURCE_TYPE_KEYRING;
- fclose( fp );
+ fclose (fp);
}
- else /* No file yet: create keyring. */
- rt = KEYDB_RESOURCE_TYPE_KEYRING;
+ else /* No file yet: create keybox. */
+ rt = KEYDB_RESOURCE_TYPE_KEYBOX;
}
switch (rt)
@@ -297,7 +336,7 @@ keydb_add_resource (const char *url, int flags)
goto leave;
case KEYDB_RESOURCE_TYPE_KEYRING:
- rc = maybe_create_keyring (filename, force);
+ rc = maybe_create_keyring_or_box (filename, create, 0);
if (rc)
goto leave;
@@ -307,7 +346,7 @@ keydb_add_resource (const char *url, int flags)
rc = gpg_error (GPG_ERR_RESOURCE_LIMIT);
else
{
- if (flags&2)
+ if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY))
primary_keyring = token;
all_resources[used_resources].type = rt;
all_resources[used_resources].u.kr = NULL; /* Not used here */
@@ -320,24 +359,61 @@ keydb_add_resource (const char *url, int flags)
/* This keyring was already registered, so ignore it.
However, we can still mark it as primary even if it was
already registered. */
- if (flags&2)
+ if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY))
primary_keyring = token;
}
break;
+ case KEYDB_RESOURCE_TYPE_KEYBOX:
+ {
+ rc = maybe_create_keyring_or_box (filename, create, 1);
+ if (rc)
+ goto leave;
+
+ /* FIXME: How do we register a read-only keybox? */
+ token = keybox_register_file (filename, 0);
+ if (token)
+ {
+ if (used_resources >= MAX_KEYDB_RESOURCES)
+ rc = gpg_error (GPG_ERR_RESOURCE_LIMIT);
+ else
+ {
+ /* if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY)) */
+ /* primary_keyring = token; */
+ all_resources[used_resources].type = rt;
+ all_resources[used_resources].u.kb = NULL; /* Not used here */
+ all_resources[used_resources].token = token;
+
+ /* FIXME: Do a compress run if needed and no other
+ user is currently using the keybox. */
+
+ used_resources++;
+ }
+ }
+ else
+ {
+ /* Already registered. We will mark it as the primary key
+ if requested. */
+ /* FIXME: How to do that? Change the keybox interface? */
+ /* if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY)) */
+ /* primary_keyring = token; */
+ }
+ }
+ break;
+
default:
log_error ("resource type of '%s' not supported\n", url);
rc = gpg_error (GPG_ERR_GENERAL);
goto leave;
}
- /* fixme: check directory permissions and print a warning */
+ /* fixme: check directory permissions and print a warning */
leave:
if (rc)
log_error (_("keyblock resource '%s': %s\n"), filename, gpg_strerror (rc));
else
- any_public = 1;
+ any_registered = 1;
xfree (filename);
return rc;
}
@@ -371,6 +447,17 @@ keydb_new (void)
}
j++;
break;
+ case KEYDB_RESOURCE_TYPE_KEYBOX:
+ hd->active[j].type = all_resources[i].type;
+ hd->active[j].token = all_resources[i].token;
+ hd->active[j].u.kb = keybox_new (all_resources[i].token, 0);
+ if (!hd->active[j].u.kb)
+ {
+ xfree (hd);
+ return NULL; /* fixme: release all previously allocated handles*/
+ }
+ j++;
+ break;
}
}
hd->used = j;
@@ -399,6 +486,9 @@ keydb_release (KEYDB_HANDLE hd)
case KEYDB_RESOURCE_TYPE_KEYRING:
keyring_release (hd->active[i].u.kr);
break;
+ case KEYDB_RESOURCE_TYPE_KEYBOX:
+ keybox_release (hd->active[i].u.kb);
+ break;
}
}
@@ -438,6 +528,9 @@ keydb_get_resource_name (KEYDB_HANDLE hd)
case KEYDB_RESOURCE_TYPE_KEYRING:
s = keyring_get_resource_name (hd->active[idx].u.kr);
break;
+ case KEYDB_RESOURCE_TYPE_KEYBOX:
+ s = keybox_get_resource_name (hd->active[idx].u.kb);
+ break;
}
return s? s: "";
@@ -450,6 +543,13 @@ lock_all (KEYDB_HANDLE hd)
{
int i, rc = 0;
+ /* Fixme: This locking scheme may lead to a deadlock if the resources
+ are not added in the same order by all processes. We are
+ currently only allowing one resource so it is not a problem.
+ [Oops: Who claimed the latter]
+
+ To fix this we need to use a lock file to protect lock_all. */
+
for (i=0; !rc && i < hd->used; i++)
{
switch (hd->active[i].type)
@@ -459,12 +559,15 @@ lock_all (KEYDB_HANDLE hd)
case KEYDB_RESOURCE_TYPE_KEYRING:
rc = keyring_lock (hd->active[i].u.kr, 1);
break;
+ case KEYDB_RESOURCE_TYPE_KEYBOX:
+ rc = keybox_lock (hd->active[i].u.kb, 1);
+ break;
}
}
if (rc)
{
- /* Revert the already set locks. */
+ /* Revert the already taken locks. */
for (i--; i >= 0; i--)
{
switch (hd->active[i].type)
@@ -474,6 +577,9 @@ lock_all (KEYDB_HANDLE hd)
case KEYDB_RESOURCE_TYPE_KEYRING:
keyring_lock (hd->active[i].u.kr, 0);
break;
+ case KEYDB_RESOURCE_TYPE_KEYBOX:
+ rc = keybox_lock (hd->active[i].u.kb, 0);
+ break;
}
}
}
@@ -501,6 +607,9 @@ unlock_all (KEYDB_HANDLE hd)
case KEYDB_RESOURCE_TYPE_KEYRING:
keyring_lock (hd->active[i].u.kr, 0);
break;
+ case KEYDB_RESOURCE_TYPE_KEYBOX:
+ keybox_lock (hd->active[i].u.kb, 0);
+ break;
}
}
hd->locked = 0;
@@ -532,6 +641,11 @@ keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
case KEYDB_RESOURCE_TYPE_KEYRING:
err = keyring_get_keyblock (hd->active[hd->found].u.kr, ret_kb);
break;
+ /* case KEYDB_RESOURCE_TYPE_KEYBOX: */
+ /* err = keybox_get_keyblock (hd->active[hd->found].u.kb, ret_kb); */
+ /* if (!err) */
+ /* err = parse_keyblock (image, imagelen) */
+ /* break; */
}
return err;
@@ -566,6 +680,12 @@ keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
case KEYDB_RESOURCE_TYPE_KEYRING:
rc = keyring_update_keyblock (hd->active[hd->found].u.kr, kb);
break;
+ /* case KEYDB_RESOURCE_TYPE_KEYRING: */
+ /* rc = build_keyblock (kb, &image, &imagelen); */
+ /* if (!rc) */
+ /* rc = keybox_update_keyblock (hd->active[hd->found].u.kb, */
+ /* image, imagelen); */
+ /* break; */
}
unlock_all (hd);
@@ -607,6 +727,11 @@ keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
case KEYDB_RESOURCE_TYPE_KEYRING:
rc = keyring_insert_keyblock (hd->active[idx].u.kr, kb);
break;
+ /* case KEYDB_RESOURCE_TYPE_KEYBOX: */
+ /* rc = build_keyblock (kb, &image, &imagelen); */
+ /* if (!rc) */
+ /* rc = keybox_insert_keyblock (hd->active[idx].u.kb, image, imagelen); */
+ /* break; */
}
unlock_all (hd);
@@ -643,6 +768,9 @@ keydb_delete_keyblock (KEYDB_HANDLE hd)
case KEYDB_RESOURCE_TYPE_KEYRING:
rc = keyring_delete_keyblock (hd->active[hd->found].u.kr);
break;
+ case KEYDB_RESOURCE_TYPE_KEYBOX:
+ rc = keybox_delete (hd->active[hd->found].u.kb);
+ break;
}
unlock_all (hd);
@@ -700,6 +828,10 @@ keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved)
if (keyring_is_writable (hd->active[hd->current].token))
return 0; /* found (hd->current is set to it) */
break;
+ case KEYDB_RESOURCE_TYPE_KEYBOX:
+ if (keybox_is_writable (hd->active[hd->current].token))
+ return 0; /* found (hd->current is set to it) */
+ break;
}
}
@@ -758,6 +890,9 @@ keydb_search_reset (KEYDB_HANDLE hd)
case KEYDB_RESOURCE_TYPE_KEYRING:
rc = keyring_search_reset (hd->active[i].u.kr);
break;
+ case KEYDB_RESOURCE_TYPE_KEYBOX:
+ rc = keybox_search_reset (hd->active[i].u.kb);
+ break;
}
}
return rc;
@@ -792,6 +927,9 @@ keydb_search2 (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
rc = keyring_search (hd->active[hd->current].u.kr, desc,
ndesc, descindex);
break;
+ case KEYDB_RESOURCE_TYPE_KEYBOX:
+ rc = keybox_search (hd->active[hd->current].u.kb, desc, ndesc);
+ break;
}
if (rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF)
{