2001-11-10 18:10:11 +00:00
|
|
|
|
/* keydb.c - key database dispatcher
|
2003-06-03 19:55:50 +00:00
|
|
|
|
* Copyright (C) 2001, 2003 Free Software Foundation, Inc.
|
2001-11-10 18:10:11 +00:00
|
|
|
|
*
|
|
|
|
|
* This file is part of GnuPG.
|
|
|
|
|
*
|
|
|
|
|
* GnuPG is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* GnuPG is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
#include "gpgsm.h"
|
|
|
|
|
#include "../kbx/keybox.h"
|
2001-11-10 18:10:11 +00:00
|
|
|
|
#include "keydb.h"
|
|
|
|
|
#include "i18n.h"
|
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
#define DIRSEP_C '/'
|
2001-11-10 18:10:11 +00:00
|
|
|
|
|
|
|
|
|
static int active_handles;
|
|
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
|
KEYDB_RESOURCE_TYPE_NONE = 0,
|
|
|
|
|
KEYDB_RESOURCE_TYPE_KEYBOX
|
|
|
|
|
} KeydbResourceType;
|
|
|
|
|
#define MAX_KEYDB_RESOURCES 20
|
|
|
|
|
|
|
|
|
|
struct resource_item {
|
|
|
|
|
KeydbResourceType type;
|
|
|
|
|
union {
|
|
|
|
|
KEYBOX_HANDLE kr;
|
|
|
|
|
} u;
|
|
|
|
|
void *token;
|
|
|
|
|
int secret;
|
2002-07-22 13:14:48 +00:00
|
|
|
|
DOTLOCK lockhandle;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct resource_item all_resources[MAX_KEYDB_RESOURCES];
|
|
|
|
|
static int used_resources;
|
|
|
|
|
|
|
|
|
|
struct keydb_handle {
|
|
|
|
|
int locked;
|
|
|
|
|
int found;
|
|
|
|
|
int current;
|
2002-06-29 14:01:53 +00:00
|
|
|
|
int is_ephemeral;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
int used; /* items in active */
|
|
|
|
|
struct resource_item active[MAX_KEYDB_RESOURCES];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int lock_all (KEYDB_HANDLE hd);
|
|
|
|
|
static void unlock_all (KEYDB_HANDLE hd);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Register a resource (which currently may only be a keybox file).
|
|
|
|
|
* The first keybox which is added by this function is
|
|
|
|
|
* created if it does not exist.
|
|
|
|
|
* Note: this function may be called before secure memory is
|
|
|
|
|
* available.
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
keydb_add_resource (const char *url, int force, int secret)
|
|
|
|
|
{
|
2001-11-26 13:08:36 +00:00
|
|
|
|
static int any_secret, any_public;
|
|
|
|
|
const char *resname = url;
|
|
|
|
|
char *filename = NULL;
|
|
|
|
|
int rc = 0;
|
|
|
|
|
FILE *fp;
|
|
|
|
|
KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE;
|
|
|
|
|
const char *created_fname = NULL;
|
|
|
|
|
|
|
|
|
|
/* Do we have an URL?
|
|
|
|
|
gnupg-kbx:filename := this is a plain keybox
|
|
|
|
|
filename := See what is is, but create as plain keybox.
|
|
|
|
|
*/
|
|
|
|
|
if (strlen (resname) > 10)
|
|
|
|
|
{
|
|
|
|
|
if (!strncmp (resname, "gnupg-kbx:", 10) )
|
|
|
|
|
{
|
|
|
|
|
rt = KEYDB_RESOURCE_TYPE_KEYBOX;
|
|
|
|
|
resname += 10;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
2001-11-26 13:08:36 +00:00
|
|
|
|
#if !defined(HAVE_DRIVE_LETTERS) && !defined(__riscos__)
|
|
|
|
|
else if (strchr (resname, ':'))
|
|
|
|
|
{
|
|
|
|
|
log_error ("invalid key resource URL `%s'\n", url );
|
2003-06-03 19:55:50 +00:00
|
|
|
|
rc = gpg_error (GPG_ERR_GENERAL);
|
2001-11-26 13:08:36 +00:00
|
|
|
|
goto leave;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
2001-11-26 13:08:36 +00:00
|
|
|
|
#endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-11-26 13:08:36 +00:00
|
|
|
|
if (*resname != DIRSEP_C )
|
|
|
|
|
{ /* do tilde expansion etc */
|
|
|
|
|
if (strchr(resname, DIRSEP_C) )
|
|
|
|
|
filename = make_filename (resname, NULL);
|
|
|
|
|
else
|
|
|
|
|
filename = make_filename (opt.homedir, resname, NULL);
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
2001-11-26 13:08:36 +00:00
|
|
|
|
else
|
|
|
|
|
filename = xstrdup (resname);
|
|
|
|
|
|
|
|
|
|
if (!force)
|
|
|
|
|
force = secret? !any_secret : !any_public;
|
|
|
|
|
|
|
|
|
|
/* see whether we can determine the filetype */
|
|
|
|
|
if (rt == KEYDB_RESOURCE_TYPE_NONE)
|
|
|
|
|
{
|
|
|
|
|
FILE *fp2 = fopen( filename, "rb" );
|
|
|
|
|
|
|
|
|
|
if (fp2) {
|
|
|
|
|
u32 magic;
|
|
|
|
|
|
|
|
|
|
/* FIXME: check for the keybox magic */
|
|
|
|
|
if (fread( &magic, 4, 1, fp2) == 1 )
|
|
|
|
|
{
|
|
|
|
|
if (magic == 0x13579ace || magic == 0xce9a5713)
|
|
|
|
|
; /* GDBM magic - no more support */
|
|
|
|
|
else
|
2001-11-13 12:50:14 +00:00
|
|
|
|
rt = KEYDB_RESOURCE_TYPE_KEYBOX;
|
2001-11-26 13:08:36 +00:00
|
|
|
|
}
|
|
|
|
|
else /* maybe empty: assume ring */
|
2001-11-13 12:50:14 +00:00
|
|
|
|
rt = KEYDB_RESOURCE_TYPE_KEYBOX;
|
2001-11-26 13:08:36 +00:00
|
|
|
|
fclose (fp2);
|
|
|
|
|
}
|
|
|
|
|
else /* no file yet: create ring */
|
|
|
|
|
rt = KEYDB_RESOURCE_TYPE_KEYBOX;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
2001-11-26 13:08:36 +00:00
|
|
|
|
|
|
|
|
|
switch (rt)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
|
|
|
|
log_error ("unknown type of key resource `%s'\n", url );
|
2003-06-03 19:55:50 +00:00
|
|
|
|
rc = gpg_error (GPG_ERR_GENERAL);
|
2001-11-26 13:08:36 +00:00
|
|
|
|
goto leave;
|
|
|
|
|
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
fp = fopen (filename, "rb");
|
|
|
|
|
if (!fp && !force)
|
|
|
|
|
{
|
2003-06-03 19:55:50 +00:00
|
|
|
|
rc = gpg_error (gpg_err_code_from_errno (errno));
|
2001-11-26 13:08:36 +00:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!fp)
|
|
|
|
|
{ /* no file */
|
|
|
|
|
#if 0 /* no autocreate of the homedirectory yet */
|
|
|
|
|
{
|
|
|
|
|
char *last_slash_in_filename;
|
|
|
|
|
|
|
|
|
|
last_slash_in_filename = strrchr (filename, DIRSEP_C);
|
|
|
|
|
*last_slash_in_filename = 0;
|
|
|
|
|
if (access (filename, F_OK))
|
|
|
|
|
{ /* on the first time we try to create the default
|
2001-11-13 12:50:14 +00:00
|
|
|
|
homedir and in this case the process will be
|
2001-11-26 13:08:36 +00:00
|
|
|
|
terminated, so that on the next invocation can
|
2001-11-13 12:50:14 +00:00
|
|
|
|
read the options file in on startup */
|
2001-11-26 13:08:36 +00:00
|
|
|
|
try_make_homedir (filename);
|
2003-06-03 19:55:50 +00:00
|
|
|
|
rc = gpg_error (GPG_ERR_FILE_OPEN_ERROR);
|
2001-11-26 13:08:36 +00:00
|
|
|
|
*last_slash_in_filename = DIRSEP_C;
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
*last_slash_in_filename = DIRSEP_C;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
fp = fopen (filename, "w");
|
|
|
|
|
if (!fp)
|
|
|
|
|
{
|
2003-06-03 19:55:50 +00:00
|
|
|
|
rc = gpg_error (gpg_err_code_from_errno (errno));
|
2001-11-26 13:08:36 +00:00
|
|
|
|
log_error (_("error creating keybox `%s': %s\n"),
|
|
|
|
|
filename, strerror(errno));
|
|
|
|
|
goto leave;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-11-26 13:08:36 +00:00
|
|
|
|
if (!opt.quiet)
|
|
|
|
|
log_info (_("keybox `%s' created\n"), filename);
|
|
|
|
|
created_fname = filename;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
2001-11-26 13:08:36 +00:00
|
|
|
|
fclose (fp);
|
|
|
|
|
fp = NULL;
|
2002-07-22 13:14:48 +00:00
|
|
|
|
/* now register the file */
|
2001-11-10 18:10:11 +00:00
|
|
|
|
{
|
2002-07-22 13:14:48 +00:00
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
void *token = keybox_register_file (filename, secret);
|
2001-11-10 18:10:11 +00:00
|
|
|
|
if (!token)
|
|
|
|
|
; /* already registered - ignore it */
|
|
|
|
|
else if (used_resources >= MAX_KEYDB_RESOURCES)
|
2003-06-03 19:55:50 +00:00
|
|
|
|
rc = gpg_error (GPG_ERR_RESOURCE_LIMIT);
|
2001-11-10 18:10:11 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
all_resources[used_resources].type = rt;
|
|
|
|
|
all_resources[used_resources].u.kr = NULL; /* Not used here */
|
|
|
|
|
all_resources[used_resources].token = token;
|
|
|
|
|
all_resources[used_resources].secret = secret;
|
2002-07-22 13:14:48 +00:00
|
|
|
|
|
|
|
|
|
all_resources[used_resources].lockhandle
|
|
|
|
|
= create_dotlock (filename);
|
|
|
|
|
if (!all_resources[used_resources].lockhandle)
|
|
|
|
|
log_fatal ( _("can't create lock for `%s'\n"), filename);
|
|
|
|
|
|
2001-11-10 18:10:11 +00:00
|
|
|
|
used_resources++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2001-11-26 13:08:36 +00:00
|
|
|
|
default:
|
|
|
|
|
log_error ("resource type of `%s' not supported\n", url);
|
2003-06-03 19:55:50 +00:00
|
|
|
|
rc = gpg_error (GPG_ERR_NOT_SUPPORTED);
|
2001-11-26 13:08:36 +00:00
|
|
|
|
goto leave;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-11-26 13:08:36 +00:00
|
|
|
|
/* fixme: check directory permissions and print a warning */
|
|
|
|
|
|
|
|
|
|
leave:
|
|
|
|
|
if (rc)
|
|
|
|
|
log_error ("keyblock resource `%s': %s\n", filename, gnupg_strerror(rc));
|
|
|
|
|
else if (secret)
|
|
|
|
|
any_secret = 1;
|
|
|
|
|
else
|
|
|
|
|
any_public = 1;
|
|
|
|
|
xfree (filename);
|
|
|
|
|
return rc;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
KEYDB_HANDLE
|
|
|
|
|
keydb_new (int secret)
|
|
|
|
|
{
|
|
|
|
|
KEYDB_HANDLE hd;
|
|
|
|
|
int i, j;
|
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
hd = xcalloc (1, sizeof *hd);
|
2001-11-10 18:10:11 +00:00
|
|
|
|
hd->found = -1;
|
|
|
|
|
|
|
|
|
|
assert (used_resources <= MAX_KEYDB_RESOURCES);
|
|
|
|
|
for (i=j=0; i < used_resources; i++)
|
|
|
|
|
{
|
|
|
|
|
if (!all_resources[i].secret != !secret)
|
|
|
|
|
continue;
|
|
|
|
|
switch (all_resources[i].type)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE: /* ignore */
|
|
|
|
|
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].secret = all_resources[i].secret;
|
2002-07-22 13:14:48 +00:00
|
|
|
|
hd->active[j].lockhandle = all_resources[i].lockhandle;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
hd->active[j].u.kr = keybox_new (all_resources[i].token, secret);
|
2002-07-22 13:14:48 +00:00
|
|
|
|
if (!hd->active[j].u.kr)
|
|
|
|
|
{
|
|
|
|
|
xfree (hd);
|
|
|
|
|
return NULL; /* fixme: release all previously allocated handles*/
|
|
|
|
|
}
|
2001-11-10 18:10:11 +00:00
|
|
|
|
j++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
hd->used = j;
|
|
|
|
|
|
|
|
|
|
active_handles++;
|
|
|
|
|
return hd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
keydb_release (KEYDB_HANDLE hd)
|
|
|
|
|
{
|
2001-11-13 12:50:14 +00:00
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (!hd)
|
|
|
|
|
return;
|
|
|
|
|
assert (active_handles > 0);
|
|
|
|
|
active_handles--;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
unlock_all (hd);
|
|
|
|
|
for (i=0; i < hd->used; i++)
|
|
|
|
|
{
|
|
|
|
|
switch (hd->active[i].type)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
keybox_release (hd->active[i].u.kr);
|
|
|
|
|
break;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
xfree (hd);
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
/* Return the name of the current resource. This is function first
|
|
|
|
|
looks for the last found found, then for the current search
|
|
|
|
|
position, and last returns the first available resource. The
|
|
|
|
|
returned string is only valid as long as the handle exists. This
|
|
|
|
|
function does only return NULL if no handle is specified, in all
|
|
|
|
|
other error cases an empty string is returned. */
|
2001-11-10 18:10:11 +00:00
|
|
|
|
const char *
|
|
|
|
|
keydb_get_resource_name (KEYDB_HANDLE hd)
|
|
|
|
|
{
|
2001-11-13 12:50:14 +00:00
|
|
|
|
int idx;
|
|
|
|
|
const char *s = NULL;
|
|
|
|
|
|
|
|
|
|
if (!hd)
|
|
|
|
|
return NULL;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
if ( hd->found >= 0 && hd->found < hd->used)
|
|
|
|
|
idx = hd->found;
|
|
|
|
|
else if ( hd->current >= 0 && hd->current < hd->used)
|
|
|
|
|
idx = hd->current;
|
|
|
|
|
else
|
|
|
|
|
idx = 0;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
switch (hd->active[idx].type)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
|
|
|
|
s = NULL;
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
s = keybox_get_resource_name (hd->active[idx].u.kr);
|
|
|
|
|
break;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
2001-11-13 12:50:14 +00:00
|
|
|
|
|
|
|
|
|
return s? s: "";
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-06-29 14:01:53 +00:00
|
|
|
|
/* Switch the handle into ephemeral mode and return the orginal value. */
|
2002-06-19 08:30:10 +00:00
|
|
|
|
int
|
|
|
|
|
keydb_set_ephemeral (KEYDB_HANDLE hd, int yes)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (!hd)
|
2002-06-29 14:01:53 +00:00
|
|
|
|
return 0;
|
2002-06-19 08:30:10 +00:00
|
|
|
|
|
2002-06-29 14:01:53 +00:00
|
|
|
|
yes = !!yes;
|
|
|
|
|
if (hd->is_ephemeral != yes)
|
2002-06-19 08:30:10 +00:00
|
|
|
|
{
|
2002-06-29 14:01:53 +00:00
|
|
|
|
for (i=0; i < hd->used; i++)
|
2002-06-19 08:30:10 +00:00
|
|
|
|
{
|
2002-06-29 14:01:53 +00:00
|
|
|
|
switch (hd->active[i].type)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
keybox_set_ephemeral (hd->active[i].u.kr, yes);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2002-06-19 08:30:10 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2002-06-29 14:01:53 +00:00
|
|
|
|
|
|
|
|
|
i = hd->is_ephemeral;
|
|
|
|
|
hd->is_ephemeral = yes;
|
|
|
|
|
return i;
|
2002-06-19 08:30:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-11-10 18:10:11 +00:00
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
|
2001-11-10 18:10:11 +00:00
|
|
|
|
static int
|
|
|
|
|
lock_all (KEYDB_HANDLE hd)
|
|
|
|
|
{
|
2001-11-13 12:50:14 +00:00
|
|
|
|
int i, rc = 0;
|
|
|
|
|
|
2002-07-22 13:14:48 +00:00
|
|
|
|
/* Fixme: This locking scheme may lead to deadlock if the resources
|
|
|
|
|
are not added in the same sequence by all processes. We are
|
|
|
|
|
cuurently only allowing one resource so it is not a problem. */
|
|
|
|
|
for (i=0; i < hd->used; i++)
|
2001-11-13 12:50:14 +00:00
|
|
|
|
{
|
|
|
|
|
switch (hd->active[i].type)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
2002-07-22 13:14:48 +00:00
|
|
|
|
if (hd->active[i].lockhandle)
|
|
|
|
|
rc = make_dotlock (hd->active[i].lockhandle, -1);
|
2001-11-13 12:50:14 +00:00
|
|
|
|
break;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
2002-07-22 13:14:48 +00:00
|
|
|
|
if (rc)
|
|
|
|
|
break;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
if (rc)
|
|
|
|
|
{
|
2001-11-10 18:10:11 +00:00
|
|
|
|
/* revert the already set locks */
|
2001-11-13 12:50:14 +00:00
|
|
|
|
for (i--; i >= 0; i--)
|
|
|
|
|
{
|
|
|
|
|
switch (hd->active[i].type)
|
|
|
|
|
{
|
2001-11-10 18:10:11 +00:00
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
2002-07-22 13:14:48 +00:00
|
|
|
|
if (hd->active[i].lockhandle)
|
|
|
|
|
release_dotlock (hd->active[i].lockhandle);
|
2001-11-10 18:10:11 +00:00
|
|
|
|
break;
|
2001-11-13 12:50:14 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-11-10 18:10:11 +00:00
|
|
|
|
else
|
2001-11-13 12:50:14 +00:00
|
|
|
|
hd->locked = 1;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
unlock_all (KEYDB_HANDLE hd)
|
|
|
|
|
{
|
2001-11-13 12:50:14 +00:00
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (!hd->locked)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
for (i=hd->used-1; i >= 0; i--)
|
|
|
|
|
{
|
|
|
|
|
switch (hd->active[i].type)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
2002-07-22 13:14:48 +00:00
|
|
|
|
if (hd->active[i].lockhandle)
|
|
|
|
|
release_dotlock (hd->active[i].lockhandle);
|
2001-11-13 12:50:14 +00:00
|
|
|
|
break;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2001-11-13 12:50:14 +00:00
|
|
|
|
hd->locked = 0;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
|
|
|
|
|
#if 0
|
2001-11-10 18:10:11 +00:00
|
|
|
|
/*
|
|
|
|
|
* Return the last found keybox. Caller must free it.
|
|
|
|
|
* The returned keyblock has the kbode flag bit 0 set for the node with
|
|
|
|
|
* the public key used to locate the keyblock or flag bit 1 set for
|
|
|
|
|
* the user ID node.
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
|
|
|
|
|
{
|
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
|
|
if (!hd)
|
|
|
|
|
return G10ERR_INV_ARG;
|
|
|
|
|
|
|
|
|
|
if ( hd->found < 0 || hd->found >= hd->used)
|
|
|
|
|
return -1; /* nothing found */
|
|
|
|
|
|
|
|
|
|
switch (hd->active[hd->found].type) {
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
|
|
|
|
rc = G10ERR_GENERAL; /* oops */
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
rc = keybox_get_keyblock (hd->active[hd->found].u.kr, ret_kb);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* update the current keyblock with KB
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
keydb_update_keyblock (KEYDB_HANDLE hd, KBNODE kb)
|
|
|
|
|
{
|
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
|
|
if (!hd)
|
|
|
|
|
return G10ERR_INV_ARG;
|
|
|
|
|
|
|
|
|
|
if ( hd->found < 0 || hd->found >= hd->used)
|
|
|
|
|
return -1; /* nothing found */
|
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
if( opt.dry_run )
|
2001-11-10 18:10:11 +00:00
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
rc = lock_all (hd);
|
|
|
|
|
if (rc)
|
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
|
|
switch (hd->active[hd->found].type) {
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
|
|
|
|
rc = G10ERR_GENERAL; /* oops */
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
rc = keybox_update_keyblock (hd->active[hd->found].u.kr, kb);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unlock_all (hd);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Insert a new KB into one of the resources.
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
keydb_insert_keyblock (KEYDB_HANDLE hd, KBNODE kb)
|
|
|
|
|
{
|
|
|
|
|
int rc = -1;
|
|
|
|
|
int idx;
|
|
|
|
|
|
|
|
|
|
if (!hd)
|
|
|
|
|
return G10ERR_INV_ARG;
|
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
if( opt.dry_run )
|
2001-11-10 18:10:11 +00:00
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if ( hd->found >= 0 && hd->found < hd->used)
|
|
|
|
|
idx = hd->found;
|
|
|
|
|
else if ( hd->current >= 0 && hd->current < hd->used)
|
|
|
|
|
idx = hd->current;
|
|
|
|
|
else
|
|
|
|
|
return G10ERR_GENERAL;
|
|
|
|
|
|
|
|
|
|
rc = lock_all (hd);
|
|
|
|
|
if (rc)
|
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
|
|
switch (hd->active[idx].type) {
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
|
|
|
|
rc = G10ERR_GENERAL; /* oops */
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
rc = keybox_insert_keyblock (hd->active[idx].u.kr, kb);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unlock_all (hd);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
#endif /*disabled code*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Return the last found keybox. Caller must free it. The returned
|
|
|
|
|
keyblock has the kbode flag bit 0 set for the node with the public
|
|
|
|
|
key used to locate the keyblock or flag bit 1 set for the user ID
|
|
|
|
|
node. */
|
|
|
|
|
int
|
|
|
|
|
keydb_get_cert (KEYDB_HANDLE hd, KsbaCert *r_cert)
|
|
|
|
|
{
|
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
|
|
if (!hd)
|
2003-06-04 21:37:56 +00:00
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2001-11-13 12:50:14 +00:00
|
|
|
|
|
|
|
|
|
if ( hd->found < 0 || hd->found >= hd->used)
|
|
|
|
|
return -1; /* nothing found */
|
|
|
|
|
|
|
|
|
|
switch (hd->active[hd->found].type)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
2003-06-03 19:55:50 +00:00
|
|
|
|
rc = gpg_error (GPG_ERR_GENERAL); /* oops */
|
2001-11-13 12:50:14 +00:00
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
rc = keybox_get_cert (hd->active[hd->found].u.kr, r_cert);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
2001-11-10 18:10:11 +00:00
|
|
|
|
|
|
|
|
|
/*
|
2001-11-13 12:50:14 +00:00
|
|
|
|
* Insert a new Certificate into one of the resources.
|
2001-11-10 18:10:11 +00:00
|
|
|
|
*/
|
|
|
|
|
int
|
2001-11-13 12:50:14 +00:00
|
|
|
|
keydb_insert_cert (KEYDB_HANDLE hd, KsbaCert cert)
|
2001-11-10 18:10:11 +00:00
|
|
|
|
{
|
2001-11-13 12:50:14 +00:00
|
|
|
|
int rc = -1;
|
|
|
|
|
int idx;
|
|
|
|
|
char digest[20];
|
|
|
|
|
|
|
|
|
|
if (!hd)
|
2003-06-04 21:37:56 +00:00
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2001-11-10 18:10:11 +00:00
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
if (opt.dry_run)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if ( hd->found >= 0 && hd->found < hd->used)
|
|
|
|
|
idx = hd->found;
|
|
|
|
|
else if ( hd->current >= 0 && hd->current < hd->used)
|
|
|
|
|
idx = hd->current;
|
|
|
|
|
else
|
2003-06-03 19:55:50 +00:00
|
|
|
|
return gpg_error (GPG_ERR_GENERAL);
|
2001-11-13 12:50:14 +00:00
|
|
|
|
|
|
|
|
|
rc = lock_all (hd);
|
|
|
|
|
if (rc)
|
|
|
|
|
return rc;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
gpgsm_get_fingerprint (cert, GCRY_MD_SHA1, digest, NULL); /* kludge*/
|
2001-11-10 18:10:11 +00:00
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
switch (hd->active[idx].type)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
2003-06-03 19:55:50 +00:00
|
|
|
|
rc = gpg_error (GPG_ERR_GENERAL);
|
2001-11-13 12:50:14 +00:00
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
rc = keybox_insert_cert (hd->active[idx].u.kr, cert, digest);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unlock_all (hd);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
2001-11-10 18:10:11 +00:00
|
|
|
|
|
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
|
|
|
|
|
/* update the current keyblock with KB */
|
|
|
|
|
int
|
|
|
|
|
keydb_update_cert (KEYDB_HANDLE hd, KsbaCert cert)
|
|
|
|
|
{
|
|
|
|
|
int rc = 0;
|
|
|
|
|
char digest[20];
|
|
|
|
|
|
|
|
|
|
if (!hd)
|
2003-06-04 21:37:56 +00:00
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2001-11-13 12:50:14 +00:00
|
|
|
|
|
|
|
|
|
if ( hd->found < 0 || hd->found >= hd->used)
|
|
|
|
|
return -1; /* nothing found */
|
|
|
|
|
|
|
|
|
|
if (opt.dry_run)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
rc = lock_all (hd);
|
|
|
|
|
if (rc)
|
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
|
|
gpgsm_get_fingerprint (cert, GCRY_MD_SHA1, digest, NULL); /* kludge*/
|
|
|
|
|
|
|
|
|
|
switch (hd->active[hd->found].type)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
2003-06-03 19:55:50 +00:00
|
|
|
|
rc = gpg_error (GPG_ERR_GENERAL); /* oops */
|
2001-11-13 12:50:14 +00:00
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
rc = keybox_update_cert (hd->active[hd->found].u.kr, cert, digest);
|
|
|
|
|
break;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
unlock_all (hd);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The current keyblock or cert will be deleted.
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
keydb_delete (KEYDB_HANDLE hd)
|
|
|
|
|
{
|
|
|
|
|
int rc = -1;
|
|
|
|
|
|
|
|
|
|
if (!hd)
|
2003-06-04 21:37:56 +00:00
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2001-11-13 12:50:14 +00:00
|
|
|
|
|
|
|
|
|
if ( hd->found < 0 || hd->found >= hd->used)
|
|
|
|
|
return -1; /* nothing found */
|
|
|
|
|
|
|
|
|
|
if( opt.dry_run )
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
rc = lock_all (hd);
|
|
|
|
|
if (rc)
|
2001-11-10 18:10:11 +00:00
|
|
|
|
return rc;
|
2001-11-13 12:50:14 +00:00
|
|
|
|
|
|
|
|
|
switch (hd->active[hd->found].type)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
2003-06-03 19:55:50 +00:00
|
|
|
|
rc = gpg_error (GPG_ERR_GENERAL);
|
2001-11-13 12:50:14 +00:00
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
rc = keybox_delete (hd->active[hd->found].u.kr);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unlock_all (hd);
|
|
|
|
|
return rc;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
|
2001-11-10 18:10:11 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Locate the default writable key resource, so that the next
|
|
|
|
|
* operation (which is only relevant for inserts) will be done on this
|
|
|
|
|
* resource.
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved)
|
|
|
|
|
{
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
if (!hd)
|
2003-06-04 21:37:56 +00:00
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2001-11-10 18:10:11 +00:00
|
|
|
|
|
|
|
|
|
rc = keydb_search_reset (hd); /* this does reset hd->current */
|
|
|
|
|
if (rc)
|
|
|
|
|
return rc;
|
2001-11-13 12:50:14 +00:00
|
|
|
|
|
2001-11-10 18:10:11 +00:00
|
|
|
|
for ( ; hd->current >= 0 && hd->current < hd->used; hd->current++)
|
|
|
|
|
{
|
|
|
|
|
switch (hd->active[hd->current].type)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
|
|
|
|
BUG();
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Rebuild the caches of all key resources.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
keydb_rebuild_caches (void)
|
|
|
|
|
{
|
2001-11-13 12:50:14 +00:00
|
|
|
|
int i;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
|
|
|
|
|
for (i=0; i < used_resources; i++)
|
|
|
|
|
{
|
|
|
|
|
if (all_resources[i].secret)
|
|
|
|
|
continue;
|
|
|
|
|
switch (all_resources[i].type)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE: /* ignore */
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
2001-11-13 12:50:14 +00:00
|
|
|
|
/* rc = keybox_rebuild_cache (all_resources[i].token); */
|
|
|
|
|
/* if (rc) */
|
|
|
|
|
/* log_error (_("failed to rebuild keybox cache: %s\n"), */
|
|
|
|
|
/* g10_errstr (rc)); */
|
2001-11-10 18:10:11 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Start the next search on this handle right at the beginning
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
keydb_search_reset (KEYDB_HANDLE hd)
|
|
|
|
|
{
|
2001-11-13 12:50:14 +00:00
|
|
|
|
int i, rc = 0;
|
|
|
|
|
|
|
|
|
|
if (!hd)
|
2003-06-04 21:37:56 +00:00
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2001-11-10 18:10:11 +00:00
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
hd->current = 0;
|
|
|
|
|
hd->found = -1;
|
|
|
|
|
/* and reset all resources */
|
|
|
|
|
for (i=0; !rc && i < hd->used; i++)
|
|
|
|
|
{
|
|
|
|
|
switch (hd->active[i].type)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
rc = keybox_search_reset (hd->active[i].u.kr);
|
|
|
|
|
break;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2001-11-13 12:50:14 +00:00
|
|
|
|
return rc; /* fixme: we need to map error codes or share them with
|
|
|
|
|
all modules*/
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Search through all keydb resources, starting at the current position,
|
|
|
|
|
* for a keyblock which contains one of the keys described in the DESC array.
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc)
|
|
|
|
|
{
|
2001-11-13 12:50:14 +00:00
|
|
|
|
int rc = -1;
|
|
|
|
|
|
|
|
|
|
if (!hd)
|
2003-06-04 21:37:56 +00:00
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2001-11-10 18:10:11 +00:00
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
while (rc == -1 && hd->current >= 0 && hd->current < hd->used)
|
|
|
|
|
{
|
|
|
|
|
switch (hd->active[hd->current].type)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
|
|
|
|
BUG(); /* we should never see it here */
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
rc = keybox_search (hd->active[hd->current].u.kr, desc, ndesc);
|
|
|
|
|
break;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
2001-11-13 12:50:14 +00:00
|
|
|
|
if (rc == -1) /* EOF -> switch to next resource */
|
|
|
|
|
hd->current++;
|
|
|
|
|
else if (!rc)
|
|
|
|
|
hd->found = hd->current;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
2001-11-13 12:50:14 +00:00
|
|
|
|
|
|
|
|
|
return rc;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
keydb_search_first (KEYDB_HANDLE hd)
|
|
|
|
|
{
|
2001-11-13 12:50:14 +00:00
|
|
|
|
KEYDB_SEARCH_DESC desc;
|
|
|
|
|
|
|
|
|
|
memset (&desc, 0, sizeof desc);
|
|
|
|
|
desc.mode = KEYDB_SEARCH_MODE_FIRST;
|
|
|
|
|
return keydb_search (hd, &desc, 1);
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
keydb_search_next (KEYDB_HANDLE hd)
|
|
|
|
|
{
|
2001-11-13 12:50:14 +00:00
|
|
|
|
KEYDB_SEARCH_DESC desc;
|
|
|
|
|
|
|
|
|
|
memset (&desc, 0, sizeof desc);
|
|
|
|
|
desc.mode = KEYDB_SEARCH_MODE_NEXT;
|
|
|
|
|
return keydb_search (hd, &desc, 1);
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
keydb_search_kid (KEYDB_HANDLE hd, u32 *kid)
|
|
|
|
|
{
|
2001-11-13 12:50:14 +00:00
|
|
|
|
KEYDB_SEARCH_DESC desc;
|
|
|
|
|
|
|
|
|
|
memset (&desc, 0, sizeof desc);
|
|
|
|
|
desc.mode = KEYDB_SEARCH_MODE_LONG_KID;
|
|
|
|
|
/* desc.u.kid[0] = kid[0]; */
|
|
|
|
|
/* desc.u.kid[1] = kid[1]; */
|
|
|
|
|
return keydb_search (hd, &desc, 1);
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr)
|
|
|
|
|
{
|
2001-11-13 12:50:14 +00:00
|
|
|
|
KEYDB_SEARCH_DESC desc;
|
|
|
|
|
|
|
|
|
|
memset (&desc, 0, sizeof desc);
|
|
|
|
|
desc.mode = KEYDB_SEARCH_MODE_FPR;
|
|
|
|
|
memcpy (desc.u.fpr, fpr, 20);
|
|
|
|
|
return keydb_search (hd, &desc, 1);
|
|
|
|
|
}
|
2001-11-10 18:10:11 +00:00
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
int
|
|
|
|
|
keydb_search_issuer (KEYDB_HANDLE hd, const char *issuer)
|
|
|
|
|
{
|
|
|
|
|
KEYDB_SEARCH_DESC desc;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
memset (&desc, 0, sizeof desc);
|
|
|
|
|
desc.mode = KEYDB_SEARCH_MODE_ISSUER;
|
|
|
|
|
desc.u.name = issuer;
|
|
|
|
|
rc = keydb_search (hd, &desc, 1);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
keydb_search_issuer_sn (KEYDB_HANDLE hd,
|
2001-12-18 17:37:48 +00:00
|
|
|
|
const char *issuer, KsbaConstSexp serial)
|
2001-11-13 12:50:14 +00:00
|
|
|
|
{
|
|
|
|
|
KEYDB_SEARCH_DESC desc;
|
|
|
|
|
int rc;
|
2001-12-18 17:37:48 +00:00
|
|
|
|
const unsigned char *s;
|
2001-11-13 12:50:14 +00:00
|
|
|
|
|
|
|
|
|
memset (&desc, 0, sizeof desc);
|
|
|
|
|
desc.mode = KEYDB_SEARCH_MODE_ISSUER_SN;
|
2001-12-20 13:25:08 +00:00
|
|
|
|
s = serial;
|
|
|
|
|
if (*s !='(')
|
2003-06-04 21:37:56 +00:00
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2001-12-20 13:25:08 +00:00
|
|
|
|
s++;
|
|
|
|
|
for (desc.snlen = 0; digitp (s); s++)
|
2001-12-18 17:37:48 +00:00
|
|
|
|
desc.snlen = 10*desc.snlen + atoi_1 (s);
|
|
|
|
|
if (*s !=':')
|
2003-06-04 21:37:56 +00:00
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2001-12-18 17:37:48 +00:00
|
|
|
|
desc.sn = s+1;
|
2001-11-13 12:50:14 +00:00
|
|
|
|
desc.u.name = issuer;
|
|
|
|
|
rc = keydb_search (hd, &desc, 1);
|
|
|
|
|
return rc;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-11-16 17:56:23 +00:00
|
|
|
|
int
|
|
|
|
|
keydb_search_subject (KEYDB_HANDLE hd, const char *name)
|
|
|
|
|
{
|
|
|
|
|
KEYDB_SEARCH_DESC desc;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
memset (&desc, 0, sizeof desc);
|
|
|
|
|
desc.mode = KEYDB_SEARCH_MODE_SUBJECT;
|
|
|
|
|
desc.u.name = name;
|
|
|
|
|
rc = keydb_search (hd, &desc, 1);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-10 18:10:11 +00:00
|
|
|
|
|
2001-12-11 12:31:04 +00:00
|
|
|
|
static int
|
|
|
|
|
hextobyte (const unsigned char *s)
|
|
|
|
|
{
|
|
|
|
|
int c;
|
|
|
|
|
|
|
|
|
|
if( *s >= '0' && *s <= '9' )
|
|
|
|
|
c = 16 * (*s - '0');
|
|
|
|
|
else if ( *s >= 'A' && *s <= 'F' )
|
|
|
|
|
c = 16 * (10 + *s - 'A');
|
|
|
|
|
else if ( *s >= 'a' && *s <= 'f' )
|
|
|
|
|
c = 16 * (10 + *s - 'a');
|
|
|
|
|
else
|
|
|
|
|
return -1;
|
|
|
|
|
s++;
|
|
|
|
|
if ( *s >= '0' && *s <= '9' )
|
|
|
|
|
c += *s - '0';
|
|
|
|
|
else if ( *s >= 'A' && *s <= 'F' )
|
|
|
|
|
c += 10 + *s - 'A';
|
|
|
|
|
else if ( *s >= 'a' && *s <= 'f' )
|
|
|
|
|
c += 10 + *s - 'a';
|
|
|
|
|
else
|
|
|
|
|
return -1;
|
|
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
classify_user_id (const char *name,
|
|
|
|
|
KEYDB_SEARCH_DESC *desc,
|
|
|
|
|
int *force_exact )
|
|
|
|
|
{
|
|
|
|
|
const char *s;
|
|
|
|
|
int hexprefix = 0;
|
|
|
|
|
int hexlength;
|
|
|
|
|
int mode = 0;
|
|
|
|
|
|
|
|
|
|
/* clear the structure so that the mode field is set to zero unless
|
|
|
|
|
* we set it to the correct value right at the end of this function */
|
|
|
|
|
memset (desc, 0, sizeof *desc);
|
|
|
|
|
*force_exact = 0;
|
|
|
|
|
/* skip leading spaces. Fixme: what about trailing white space? */
|
2002-01-10 19:47:20 +00:00
|
|
|
|
for(s = name; *s && spacep (s); s++ )
|
2001-12-11 12:31:04 +00:00
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
switch (*s)
|
|
|
|
|
{
|
|
|
|
|
case 0: /* empty string is an error */
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
case '.': /* an email address, compare from end */
|
|
|
|
|
mode = KEYDB_SEARCH_MODE_MAILEND;
|
|
|
|
|
s++;
|
|
|
|
|
desc->u.name = s;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '<': /* an email address */
|
|
|
|
|
mode = KEYDB_SEARCH_MODE_MAIL;
|
2001-12-14 20:48:26 +00:00
|
|
|
|
s++;
|
2001-12-11 12:31:04 +00:00
|
|
|
|
desc->u.name = s;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '@': /* part of an email address */
|
|
|
|
|
mode = KEYDB_SEARCH_MODE_MAILSUB;
|
|
|
|
|
s++;
|
|
|
|
|
desc->u.name = s;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '=': /* exact compare */
|
|
|
|
|
mode = KEYDB_SEARCH_MODE_EXACT;
|
|
|
|
|
s++;
|
|
|
|
|
desc->u.name = s;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '*': /* case insensitive substring search */
|
|
|
|
|
mode = KEYDB_SEARCH_MODE_SUBSTR;
|
|
|
|
|
s++;
|
|
|
|
|
desc->u.name = s;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '+': /* compare individual words */
|
|
|
|
|
mode = KEYDB_SEARCH_MODE_WORDS;
|
|
|
|
|
s++;
|
|
|
|
|
desc->u.name = s;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '/': /* subject's DN */
|
|
|
|
|
s++;
|
2002-01-10 19:47:20 +00:00
|
|
|
|
if (!*s || spacep (s))
|
2001-12-11 12:31:04 +00:00
|
|
|
|
return 0; /* no DN or prefixed with a space */
|
|
|
|
|
desc->u.name = s;
|
|
|
|
|
mode = KEYDB_SEARCH_MODE_SUBJECT;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '#':
|
|
|
|
|
{
|
|
|
|
|
const char *si;
|
|
|
|
|
|
|
|
|
|
s++;
|
|
|
|
|
if ( *s == '/')
|
|
|
|
|
{ /* "#/" indicates an issuer's DN */
|
|
|
|
|
s++;
|
2002-01-10 19:47:20 +00:00
|
|
|
|
if (!*s || spacep (s))
|
2001-12-11 12:31:04 +00:00
|
|
|
|
return 0; /* no DN or prefixed with a space */
|
|
|
|
|
desc->u.name = s;
|
|
|
|
|
mode = KEYDB_SEARCH_MODE_ISSUER;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{ /* serialnumber + optional issuer ID */
|
|
|
|
|
for (si=s; *si && *si != '/'; si++)
|
|
|
|
|
{
|
|
|
|
|
if (!strchr("01234567890abcdefABCDEF", *si))
|
|
|
|
|
return 0; /* invalid digit in serial number*/
|
|
|
|
|
}
|
|
|
|
|
desc->sn = s;
|
2001-12-18 17:37:48 +00:00
|
|
|
|
desc->snlen = -1;
|
2001-12-11 12:31:04 +00:00
|
|
|
|
if (!*si)
|
|
|
|
|
mode = KEYDB_SEARCH_MODE_SN;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
s = si+1;
|
2002-01-10 19:47:20 +00:00
|
|
|
|
if (!*s || spacep (s))
|
2001-12-11 12:31:04 +00:00
|
|
|
|
return 0; /* no DN or prefixed with a space */
|
|
|
|
|
desc->u.name = s;
|
|
|
|
|
mode = KEYDB_SEARCH_MODE_ISSUER_SN;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ':': /*Unified fingerprint */
|
|
|
|
|
{
|
|
|
|
|
const char *se, *si;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
se = strchr (++s,':');
|
|
|
|
|
if (!se)
|
|
|
|
|
return 0;
|
|
|
|
|
for (i=0,si=s; si < se; si++, i++ )
|
|
|
|
|
{
|
|
|
|
|
if (!strchr("01234567890abcdefABCDEF", *si))
|
|
|
|
|
return 0; /* invalid digit */
|
|
|
|
|
}
|
|
|
|
|
if (i != 32 && i != 40)
|
|
|
|
|
return 0; /* invalid length of fpr*/
|
|
|
|
|
for (i=0,si=s; si < se; i++, si +=2)
|
|
|
|
|
desc->u.fpr[i] = hextobyte(si);
|
|
|
|
|
for (; i < 20; i++)
|
|
|
|
|
desc->u.fpr[i]= 0;
|
|
|
|
|
s = se + 1;
|
|
|
|
|
mode = KEYDB_SEARCH_MODE_FPR;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
if (s[0] == '0' && s[1] == 'x')
|
|
|
|
|
{
|
|
|
|
|
hexprefix = 1;
|
|
|
|
|
s += 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hexlength = strspn(s, "0123456789abcdefABCDEF");
|
|
|
|
|
if (hexlength >= 8 && s[hexlength] =='!')
|
|
|
|
|
{
|
|
|
|
|
*force_exact = 1;
|
|
|
|
|
hexlength++; /* just for the following check */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* check if a hexadecimal number is terminated by EOS or blank */
|
2002-01-10 19:47:20 +00:00
|
|
|
|
if (hexlength && s[hexlength] && !spacep (s+hexlength))
|
2001-12-11 12:31:04 +00:00
|
|
|
|
{
|
|
|
|
|
if (hexprefix) /* a "0x" prefix without correct */
|
|
|
|
|
return 0; /* termination is an error */
|
|
|
|
|
/* The first chars looked like a hex number, but really is
|
|
|
|
|
not */
|
|
|
|
|
hexlength = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (*force_exact)
|
|
|
|
|
hexlength--; /* remove the bang */
|
|
|
|
|
|
|
|
|
|
if (hexlength == 8
|
|
|
|
|
|| (!hexprefix && hexlength == 9 && *s == '0'))
|
|
|
|
|
{ /* short keyid */
|
|
|
|
|
unsigned long kid;
|
|
|
|
|
if (hexlength == 9)
|
|
|
|
|
s++;
|
|
|
|
|
kid = strtoul( s, NULL, 16 );
|
|
|
|
|
desc->u.kid[4] = kid >> 24;
|
|
|
|
|
desc->u.kid[5] = kid >> 16;
|
|
|
|
|
desc->u.kid[6] = kid >> 8;
|
|
|
|
|
desc->u.kid[7] = kid;
|
|
|
|
|
mode = KEYDB_SEARCH_MODE_SHORT_KID;
|
|
|
|
|
}
|
|
|
|
|
else if (hexlength == 16
|
|
|
|
|
|| (!hexprefix && hexlength == 17 && *s == '0'))
|
|
|
|
|
{ /* complete keyid */
|
|
|
|
|
unsigned long kid0, kid1;
|
|
|
|
|
char buf[9];
|
|
|
|
|
if (hexlength == 17)
|
|
|
|
|
s++;
|
|
|
|
|
mem2str(buf, s, 9 );
|
|
|
|
|
kid0 = strtoul (buf, NULL, 16);
|
|
|
|
|
kid1 = strtoul (s+8, NULL, 16);
|
|
|
|
|
desc->u.kid[0] = kid0 >> 24;
|
|
|
|
|
desc->u.kid[1] = kid0 >> 16;
|
|
|
|
|
desc->u.kid[2] = kid0 >> 8;
|
|
|
|
|
desc->u.kid[3] = kid0;
|
|
|
|
|
desc->u.kid[4] = kid1 >> 24;
|
|
|
|
|
desc->u.kid[5] = kid1 >> 16;
|
|
|
|
|
desc->u.kid[6] = kid1 >> 8;
|
|
|
|
|
desc->u.kid[7] = kid1;
|
|
|
|
|
mode = KEYDB_SEARCH_MODE_LONG_KID;
|
|
|
|
|
}
|
|
|
|
|
else if (hexlength == 32
|
|
|
|
|
|| (!hexprefix && hexlength == 33 && *s == '0'))
|
|
|
|
|
{ /* md5 fingerprint */
|
|
|
|
|
int i;
|
|
|
|
|
if (hexlength == 33)
|
|
|
|
|
s++;
|
|
|
|
|
memset(desc->u.fpr+16, 0, 4);
|
|
|
|
|
for (i=0; i < 16; i++, s+=2)
|
|
|
|
|
{
|
|
|
|
|
int c = hextobyte(s);
|
|
|
|
|
if (c == -1)
|
|
|
|
|
return 0;
|
|
|
|
|
desc->u.fpr[i] = c;
|
|
|
|
|
}
|
|
|
|
|
mode = KEYDB_SEARCH_MODE_FPR16;
|
|
|
|
|
}
|
|
|
|
|
else if (hexlength == 40
|
|
|
|
|
|| (!hexprefix && hexlength == 41 && *s == '0'))
|
|
|
|
|
{ /* sha1/rmd160 fingerprint */
|
|
|
|
|
int i;
|
|
|
|
|
if (hexlength == 41)
|
|
|
|
|
s++;
|
|
|
|
|
for (i=0; i < 20; i++, s+=2)
|
|
|
|
|
{
|
|
|
|
|
int c = hextobyte(s);
|
|
|
|
|
if (c == -1)
|
|
|
|
|
return 0;
|
|
|
|
|
desc->u.fpr[i] = c;
|
|
|
|
|
}
|
|
|
|
|
mode = KEYDB_SEARCH_MODE_FPR20;
|
|
|
|
|
}
|
|
|
|
|
else if (!hexprefix)
|
2002-06-20 10:43:02 +00:00
|
|
|
|
{
|
|
|
|
|
/* The fingerprint in an X.509 listing is often delimited by
|
|
|
|
|
colons, so we try to single this case out. */
|
|
|
|
|
mode = 0;
|
|
|
|
|
hexlength = strspn (s, ":0123456789abcdefABCDEF");
|
|
|
|
|
if (hexlength == 59 && (!s[hexlength] || spacep (s+hexlength)))
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i=0; i < 20; i++, s += 3)
|
|
|
|
|
{
|
|
|
|
|
int c = hextobyte(s);
|
|
|
|
|
if (c == -1 || (i < 19 && s[2] != ':'))
|
|
|
|
|
break;
|
|
|
|
|
desc->u.fpr[i] = c;
|
|
|
|
|
}
|
|
|
|
|
if (i == 20)
|
|
|
|
|
mode = KEYDB_SEARCH_MODE_FPR20;
|
|
|
|
|
}
|
|
|
|
|
if (!mode) /* default is substring search */
|
|
|
|
|
{
|
|
|
|
|
*force_exact = 0;
|
|
|
|
|
desc->u.name = s;
|
|
|
|
|
mode = KEYDB_SEARCH_MODE_SUBSTR;
|
|
|
|
|
}
|
2001-12-11 12:31:04 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{ /* hex number with a prefix but a wrong length */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
desc->mode = mode;
|
|
|
|
|
return mode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
keydb_classify_name (const char *name, KEYDB_SEARCH_DESC *desc)
|
|
|
|
|
{
|
|
|
|
|
int dummy;
|
|
|
|
|
KEYDB_SEARCH_DESC dummy_desc;
|
|
|
|
|
|
|
|
|
|
if (!desc)
|
|
|
|
|
desc = &dummy_desc;
|
|
|
|
|
|
|
|
|
|
if (!classify_user_id (name, desc, &dummy))
|
2003-06-03 19:55:50 +00:00
|
|
|
|
return gpg_error (GPG_ERR_INV_NAME);
|
2001-12-11 12:31:04 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2001-11-10 18:10:11 +00:00
|
|
|
|
|
2002-01-15 13:02:47 +00:00
|
|
|
|
|
2002-07-02 10:40:12 +00:00
|
|
|
|
/* Store the certificate in the key DB but make sure that it does not
|
|
|
|
|
already exists. We do this simply by comparing the fingerprint.
|
|
|
|
|
If EXISTED is not NULL it will be set to true if the certificate
|
|
|
|
|
was already in the DB. */
|
2002-01-15 13:02:47 +00:00
|
|
|
|
int
|
2002-07-02 10:40:12 +00:00
|
|
|
|
keydb_store_cert (KsbaCert cert, int ephemeral, int *existed)
|
2002-01-15 13:02:47 +00:00
|
|
|
|
{
|
|
|
|
|
KEYDB_HANDLE kh;
|
|
|
|
|
int rc;
|
|
|
|
|
unsigned char fpr[20];
|
|
|
|
|
|
2002-07-02 10:40:12 +00:00
|
|
|
|
if (existed)
|
|
|
|
|
*existed = 0;
|
|
|
|
|
|
2002-01-15 13:02:47 +00:00
|
|
|
|
if (!gpgsm_get_fingerprint (cert, 0, fpr, NULL))
|
|
|
|
|
{
|
|
|
|
|
log_error (_("failed to get the fingerprint\n"));
|
2003-06-03 19:55:50 +00:00
|
|
|
|
return gpg_error (GPG_ERR_GENERAL);
|
2002-01-15 13:02:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
kh = keydb_new (0);
|
|
|
|
|
if (!kh)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("failed to allocate keyDB handle\n"));
|
2003-06-03 19:55:50 +00:00
|
|
|
|
return gpg_error (GPG_ERR_ENOMEM);;
|
2002-01-15 13:02:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-06-19 08:30:10 +00:00
|
|
|
|
if (ephemeral)
|
|
|
|
|
keydb_set_ephemeral (kh, 1);
|
|
|
|
|
|
2002-01-15 13:02:47 +00:00
|
|
|
|
rc = keydb_search_fpr (kh, fpr);
|
|
|
|
|
if (rc != -1)
|
|
|
|
|
{
|
|
|
|
|
keydb_release (kh);
|
|
|
|
|
if (!rc)
|
2002-07-02 10:40:12 +00:00
|
|
|
|
{
|
|
|
|
|
if (existed)
|
|
|
|
|
*existed = 1;
|
|
|
|
|
return 0; /* okay */
|
|
|
|
|
}
|
2002-01-15 13:02:47 +00:00
|
|
|
|
log_error (_("problem looking for existing certificate: %s\n"),
|
|
|
|
|
gnupg_strerror (rc));
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = keydb_locate_writable (kh, 0);
|
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("error finding writable keyDB: %s\n"), gnupg_strerror (rc));
|
|
|
|
|
keydb_release (kh);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = keydb_insert_cert (kh, cert);
|
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("error storing certificate: %s\n"), gnupg_strerror (rc));
|
|
|
|
|
keydb_release (kh);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
keydb_release (kh);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-07-02 10:40:12 +00:00
|
|
|
|
|