2001-11-10 18:10:11 +00:00
|
|
|
|
/* keydb.c - key database dispatcher
|
|
|
|
|
* Copyright (C) 2001 Free Software Foundation, Inc.
|
|
|
|
|
*
|
|
|
|
|
* 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;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct resource_item all_resources[MAX_KEYDB_RESOURCES];
|
|
|
|
|
static int used_resources;
|
|
|
|
|
|
|
|
|
|
struct keydb_handle {
|
|
|
|
|
int locked;
|
|
|
|
|
int found;
|
|
|
|
|
int current;
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
static int any_secret, any_public;
|
|
|
|
|
const char *resname = url;
|
|
|
|
|
char *filename = NULL;
|
2001-11-13 12:50:14 +00:00
|
|
|
|
int rc = 0;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE;
|
2001-11-13 12:50:14 +00:00
|
|
|
|
/* const char *created_fname = NULL; */
|
2001-11-10 18:10:11 +00:00
|
|
|
|
|
|
|
|
|
/* Do we have an URL?
|
|
|
|
|
* gnupg-ring:filename := this is a plain keybox
|
|
|
|
|
* filename := See what is is, but create as plain keybox.
|
|
|
|
|
*/
|
|
|
|
|
if (strlen (resname) > 11) {
|
2001-11-13 12:50:14 +00:00
|
|
|
|
if (!strncmp( resname, "gnupg-kbx:", 10) ) {
|
2001-11-10 18:10:11 +00:00
|
|
|
|
rt = KEYDB_RESOURCE_TYPE_KEYBOX;
|
|
|
|
|
resname += 11;
|
|
|
|
|
}
|
|
|
|
|
#if !defined(HAVE_DRIVE_LETTERS) && !defined(__riscos__)
|
|
|
|
|
else if (strchr (resname, ':')) {
|
|
|
|
|
log_error ("invalid key resource URL `%s'\n", url );
|
2001-11-13 12:50:14 +00:00
|
|
|
|
rc = GPGSM_General_Error;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
#endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (*resname != DIRSEP_C ) { /* do tilde expansion etc */
|
|
|
|
|
if (strchr(resname, DIRSEP_C) )
|
|
|
|
|
filename = make_filename (resname, NULL);
|
|
|
|
|
else
|
2001-11-13 12:50:14 +00:00
|
|
|
|
filename = make_filename (opt.homedir, resname, NULL);
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2001-11-13 12:50:14 +00:00
|
|
|
|
filename = xstrdup (resname);
|
2001-11-10 18:10:11 +00:00
|
|
|
|
|
|
|
|
|
if (!force)
|
|
|
|
|
force = secret? !any_secret : !any_public;
|
|
|
|
|
|
|
|
|
|
/* see whether we can determine the filetype */
|
|
|
|
|
if (rt == KEYDB_RESOURCE_TYPE_NONE) {
|
2001-11-13 12:50:14 +00:00
|
|
|
|
FILE *fp2 = fopen( filename, "rb" );
|
2001-11-10 18:10:11 +00:00
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
if (fp2) {
|
2001-11-10 18:10:11 +00:00
|
|
|
|
u32 magic;
|
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
/* FIXME: check for the keybox magic */
|
|
|
|
|
if (fread( &magic, 4, 1, fp2) == 1 )
|
|
|
|
|
{
|
2001-11-10 18:10:11 +00:00
|
|
|
|
if (magic == 0x13579ace || magic == 0xce9a5713)
|
2001-11-13 12:50:14 +00:00
|
|
|
|
; /* GDBM magic - no more support */
|
2001-11-10 18:10:11 +00:00
|
|
|
|
else
|
2001-11-13 12:50:14 +00:00
|
|
|
|
rt = KEYDB_RESOURCE_TYPE_KEYBOX;
|
|
|
|
|
}
|
2001-11-10 18:10:11 +00:00
|
|
|
|
else /* maybe empty: assume ring */
|
2001-11-13 12:50:14 +00:00
|
|
|
|
rt = KEYDB_RESOURCE_TYPE_KEYBOX;
|
|
|
|
|
fclose (fp2);
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
|
|
|
|
else /* no file yet: create ring */
|
2001-11-13 12:50:14 +00:00
|
|
|
|
rt = KEYDB_RESOURCE_TYPE_KEYBOX;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (rt) {
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
|
|
|
|
log_error ("unknown type of key resource `%s'\n", url );
|
2001-11-13 12:50:14 +00:00
|
|
|
|
rc = GPGSM_General_Error;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
goto leave;
|
|
|
|
|
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
2001-11-13 12:50:14 +00:00
|
|
|
|
#if 0
|
|
|
|
|
fp = fopen (filename);
|
2001-11-10 18:10:11 +00:00
|
|
|
|
if (!iobuf && !force) {
|
|
|
|
|
rc = G10ERR_OPEN_FILE;
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-13 12:50:14 +00:00
|
|
|
|
if (!fp) {
|
2001-11-10 18:10:11 +00:00
|
|
|
|
char *last_slash_in_filename;
|
|
|
|
|
|
|
|
|
|
last_slash_in_filename = strrchr (filename, DIRSEP_C);
|
|
|
|
|
*last_slash_in_filename = 0;
|
|
|
|
|
|
|
|
|
|
if (access(filename, F_OK)) {
|
2001-11-13 12:50:14 +00:00
|
|
|
|
/* on the first time we try to create the default
|
|
|
|
|
homedir and in this case the process will be
|
|
|
|
|
terminated, so that on the next invocation it can
|
|
|
|
|
read the options file in on startup */
|
2001-11-10 18:10:11 +00:00
|
|
|
|
try_make_homedir (filename);
|
|
|
|
|
rc = G10ERR_OPEN_FILE;
|
|
|
|
|
*last_slash_in_filename = DIRSEP_C;
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*last_slash_in_filename = DIRSEP_C;
|
|
|
|
|
|
|
|
|
|
iobuf = iobuf_create (filename);
|
|
|
|
|
if (!iobuf) {
|
|
|
|
|
log_error ( _("error creating keybox `%s': %s\n"),
|
|
|
|
|
filename, strerror(errno));
|
|
|
|
|
rc = G10ERR_OPEN_FILE;
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
#ifndef HAVE_DOSISH_SYSTEM
|
2001-11-13 12:50:14 +00:00
|
|
|
|
if (secret && !opt.preserve_permissionws) {
|
2001-11-10 18:10:11 +00:00
|
|
|
|
if (chmod (filename, S_IRUSR | S_IWUSR) ) {
|
|
|
|
|
log_error (_("changing permission of "
|
|
|
|
|
" `%s' failed: %s\n"),
|
|
|
|
|
filename, strerror(errno) );
|
|
|
|
|
rc = G10ERR_WRITE_FILE;
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2001-11-13 12:50:14 +00:00
|
|
|
|
if (!opt.quiet)
|
2001-11-10 18:10:11 +00:00
|
|
|
|
log_info (_("keybox `%s' created\n"), filename);
|
|
|
|
|
created_fname = filename;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
iobuf_close (iobuf);
|
|
|
|
|
iobuf = NULL;
|
|
|
|
|
if (created_fname) /* must invalidate that ugly cache */
|
|
|
|
|
iobuf_ioctl (NULL, 2, 0, (char*)created_fname);
|
2001-11-13 12:50:14 +00:00
|
|
|
|
#endif
|
2001-11-10 18:10:11 +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)
|
2001-11-13 12:50:14 +00:00
|
|
|
|
rc = GPGSM_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;
|
|
|
|
|
used_resources++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
log_error ("resource type of `%s' not supported\n", url);
|
2001-11-13 12:50:14 +00:00
|
|
|
|
rc = GPGSM_General_Error;
|
2001-11-10 18:10:11 +00:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* fixme: check directory permissions and print a warning */
|
|
|
|
|
|
|
|
|
|
leave:
|
|
|
|
|
if (rc)
|
2001-11-13 12:50:14 +00:00
|
|
|
|
log_error ("keyblock resource `%s': %s\n", filename, gpgsm_strerror(rc));
|
2001-11-10 18:10:11 +00:00
|
|
|
|
else if (secret)
|
|
|
|
|
any_secret = 1;
|
|
|
|
|
else
|
|
|
|
|
any_public = 1;
|
2001-11-13 12:50:14 +00:00
|
|
|
|
xfree (filename);
|
2001-11-10 18:10:11 +00:00
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
hd->active[j].u.kr = keybox_new (all_resources[i].token, secret);
|
|
|
|
|
if (!hd->active[j].u.kr) {
|
2001-11-13 12:50:14 +00:00
|
|
|
|
xfree (hd);
|
2001-11-10 18:10:11 +00:00
|
|
|
|
return NULL; /* fixme: release all previously allocated handles*/
|
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
for (i=0; !rc && i < hd->used; i++)
|
|
|
|
|
{
|
|
|
|
|
switch (hd->active[i].type)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
/* FIXME rc = keybox_lock (hd->active[i].u.kr, 1);*/
|
|
|
|
|
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:
|
2001-11-13 12:50:14 +00:00
|
|
|
|
/* Fixme: keybox_lock (hd->active[i].u.kr, 0);*/
|
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:
|
|
|
|
|
/* fixme: keybox_lock (hd->active[i].u.kr, 0);*/
|
|
|
|
|
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)
|
|
|
|
|
return GPGSM_Invalid_Value;
|
|
|
|
|
|
|
|
|
|
if ( hd->found < 0 || hd->found >= hd->used)
|
|
|
|
|
return -1; /* nothing found */
|
|
|
|
|
|
|
|
|
|
switch (hd->active[hd->found].type)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
|
|
|
|
rc = GPGSM_General_Error; /* oops */
|
|
|
|
|
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)
|
|
|
|
|
return GPGSM_Invalid_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
|
|
|
|
|
return GPGSM_General_Error;
|
|
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
rc = GPGSM_General_Error;
|
|
|
|
|
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)
|
|
|
|
|
return GPGSM_Invalid_Value;
|
|
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
rc = GPGSM_General_Error; /* oops */
|
|
|
|
|
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)
|
|
|
|
|
return GPGSM_Invalid_Value;
|
|
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
rc = GPGSM_General_Error;
|
|
|
|
|
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)
|
2001-11-13 12:50:14 +00:00
|
|
|
|
return GPGSM_Invalid_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)
|
|
|
|
|
return GPGSM_Invalid_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)
|
|
|
|
|
return GPGSM_Invalid_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,
|
|
|
|
|
const char *issuer, const unsigned char *serial)
|
|
|
|
|
{
|
|
|
|
|
KEYDB_SEARCH_DESC desc;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
memset (&desc, 0, sizeof desc);
|
|
|
|
|
desc.mode = KEYDB_SEARCH_MODE_ISSUER_SN;
|
|
|
|
|
desc.sn = serial;
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|