2003-08-05 19:11:04 +02:00
|
|
|
|
/* keydb.c - key database dispatcher
|
2004-02-02 18:09:35 +01:00
|
|
|
|
* Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
|
2020-09-13 20:48:53 +02:00
|
|
|
|
* Copyright (C) 2014, 2020 g10 Code GmbH
|
2003-08-05 19:11:04 +02: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
|
2007-07-04 21:49:40 +02:00
|
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2003-08-05 19:11:04 +02:00
|
|
|
|
* (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
|
2016-11-05 12:02:19 +01:00
|
|
|
|
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
2003-08-05 19:11:04 +02:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
|
|
#include "gpgsm.h"
|
2020-09-03 13:46:54 +02:00
|
|
|
|
#include <assuan.h>
|
2003-08-05 19:11:04 +02:00
|
|
|
|
#include "../kbx/keybox.h"
|
2011-02-04 12:57:53 +01:00
|
|
|
|
#include "keydb.h"
|
2017-03-07 12:21:23 +01:00
|
|
|
|
#include "../common/i18n.h"
|
2020-09-03 13:46:54 +02:00
|
|
|
|
#include "../common/asshelp.h"
|
2023-04-04 16:39:59 +02:00
|
|
|
|
#include "../common/comopt.h"
|
2020-09-03 13:46:54 +02:00
|
|
|
|
#include "../kbx/kbx-client-util.h"
|
2003-08-05 19:11:04 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
};
|
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
|
|
|
|
|
/* Data used to keep track of keybox daemon sessions. This allows us
|
|
|
|
|
* to use several sessions with the keyboxd and also to re-use already
|
|
|
|
|
* established sessions. Note that gpgdm.h defines the type
|
|
|
|
|
* keydb_local_t for this structure. */
|
|
|
|
|
struct keydb_local_s
|
|
|
|
|
{
|
|
|
|
|
/* Link to other keyboxd contexts which are used simultaneously. */
|
|
|
|
|
struct keydb_local_s *next;
|
|
|
|
|
|
|
|
|
|
/* The active Assuan context. */
|
|
|
|
|
assuan_context_t ctx;
|
|
|
|
|
|
|
|
|
|
/* The client data helper context. */
|
|
|
|
|
kbx_client_data_t kcd;
|
|
|
|
|
|
|
|
|
|
/* I/O buffer with the last search result or NULL. Used if
|
|
|
|
|
* D-lines are used to convey the keyblocks. */
|
2020-09-10 13:05:17 +02:00
|
|
|
|
struct {
|
|
|
|
|
char *buf;
|
|
|
|
|
size_t len;
|
|
|
|
|
} search_result;
|
2021-06-11 20:15:13 +02:00
|
|
|
|
/* The "stack" used by keydb_push_found_state. */
|
|
|
|
|
struct {
|
|
|
|
|
char *buf;
|
|
|
|
|
size_t len;
|
|
|
|
|
} saved_search_result;
|
2020-09-03 13:46:54 +02:00
|
|
|
|
|
|
|
|
|
/* This flag set while an operation is running on this context. */
|
|
|
|
|
unsigned int is_active : 1;
|
|
|
|
|
|
|
|
|
|
/* Flag indicating that a search reset is required. */
|
|
|
|
|
unsigned int need_search_reset : 1;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
static struct resource_item all_resources[MAX_KEYDB_RESOURCES];
|
|
|
|
|
static int used_resources;
|
|
|
|
|
|
2016-11-10 17:01:19 +01:00
|
|
|
|
/* Whether we have successfully registered any resource. */
|
|
|
|
|
static int any_registered;
|
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
/* Number of active handles. */
|
|
|
|
|
static int active_handles;
|
|
|
|
|
|
|
|
|
|
|
2016-11-10 17:01:19 +01:00
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
struct keydb_handle {
|
2019-05-14 13:36:08 +02:00
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
/* CTRL object passed to keydb_new. */
|
|
|
|
|
ctrl_t ctrl;
|
|
|
|
|
|
|
|
|
|
/* If set the keyboxdd is used instead of the local files. */
|
|
|
|
|
int use_keyboxd;
|
|
|
|
|
|
|
|
|
|
/* BEGIN USE_KEYBOXD */
|
|
|
|
|
/* (These fields are only valid if USE_KEYBOXD is set.) */
|
|
|
|
|
|
|
|
|
|
/* Connection info which also keeps the local state. (This points
|
|
|
|
|
* into the CTRL->keybox_local list.) */
|
|
|
|
|
keydb_local_t kbl;
|
|
|
|
|
|
|
|
|
|
/* Various flags. */
|
|
|
|
|
unsigned int last_ubid_valid:1;
|
2020-09-13 20:48:53 +02:00
|
|
|
|
unsigned int last_is_ephemeral; /* Last found key is ephemeral. */
|
2020-09-03 13:46:54 +02:00
|
|
|
|
|
|
|
|
|
/* The UBID of the last returned keyblock. */
|
|
|
|
|
unsigned char last_ubid[UBID_LEN];
|
|
|
|
|
|
|
|
|
|
/* END USE_KEYBOXD */
|
|
|
|
|
|
|
|
|
|
/* BEGIN !USE_KEYBOXD */
|
|
|
|
|
/* (The remaining fields are only valid if USE_KEYBOXD is cleared.) */
|
|
|
|
|
|
2019-05-14 13:36:08 +02:00
|
|
|
|
/* If this flag is set the resources is locked. */
|
2003-08-05 19:11:04 +02:00
|
|
|
|
int locked;
|
2019-05-14 13:36:08 +02:00
|
|
|
|
|
|
|
|
|
/* If this flag is set a lock will only be released by
|
|
|
|
|
* keydb_release. */
|
|
|
|
|
int keep_lock;
|
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
int found;
|
2014-06-02 15:55:00 +02:00
|
|
|
|
int saved_found;
|
2003-08-05 19:11:04 +02:00
|
|
|
|
int current;
|
|
|
|
|
int is_ephemeral;
|
|
|
|
|
int used; /* items in active */
|
|
|
|
|
struct resource_item active[MAX_KEYDB_RESOURCES];
|
2020-09-03 13:46:54 +02:00
|
|
|
|
|
|
|
|
|
/* END !USE_KEYBOXD */
|
2003-08-05 19:11:04 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int lock_all (KEYDB_HANDLE hd);
|
|
|
|
|
static void unlock_all (KEYDB_HANDLE hd);
|
|
|
|
|
|
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
|
|
|
|
|
/* Deinitialize all session resources pertaining to the keyboxd. */
|
|
|
|
|
void
|
|
|
|
|
gpgsm_keydb_deinit_session_data (ctrl_t ctrl)
|
|
|
|
|
{
|
|
|
|
|
keydb_local_t kbl;
|
|
|
|
|
|
|
|
|
|
while ((kbl = ctrl->keydb_local))
|
|
|
|
|
{
|
|
|
|
|
ctrl->keydb_local = kbl->next;
|
|
|
|
|
if (kbl->is_active)
|
|
|
|
|
log_error ("oops: trying to cleanup an active keydb context\n");
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
assuan_release (kbl->ctx);
|
|
|
|
|
kbl->ctx = NULL;
|
2023-06-07 08:26:34 +02:00
|
|
|
|
/*
|
|
|
|
|
* Since there may be pipe output FD sent to the server (so
|
|
|
|
|
* that it can receive data through the pipe), we should
|
|
|
|
|
* release the assuan connection before releasing KBL->KCD.
|
|
|
|
|
* This way, the data receiving thread can finish cleanly,
|
|
|
|
|
* and we can join the thread.
|
|
|
|
|
*/
|
|
|
|
|
kbx_client_data_release (kbl->kcd);
|
|
|
|
|
kbl->kcd = NULL;
|
2020-09-03 13:46:54 +02:00
|
|
|
|
}
|
|
|
|
|
xfree (kbl);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-08-14 17:14:21 +02:00
|
|
|
|
static void
|
|
|
|
|
try_make_homedir (const char *fname)
|
|
|
|
|
{
|
|
|
|
|
if ( opt.dry_run || opt.no_homedir_creation )
|
|
|
|
|
return;
|
|
|
|
|
|
2020-11-04 15:36:52 +01:00
|
|
|
|
gnupg_maybe_make_homedir (fname, opt.quiet);
|
2014-08-14 17:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Handle the creation of a keybox if it does not yet exist. Take
|
2018-10-24 21:56:18 +02:00
|
|
|
|
into account that other processes might have the keybox already
|
2014-08-14 17:14:21 +02:00
|
|
|
|
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
|
|
|
|
|
if the function created a new keybox. */
|
2016-01-13 09:29:39 +01:00
|
|
|
|
static gpg_error_t
|
2014-08-14 17:14:21 +02:00
|
|
|
|
maybe_create_keybox (char *filename, int force, int *r_created)
|
|
|
|
|
{
|
2020-10-20 10:43:55 +02:00
|
|
|
|
gpg_err_code_t ec;
|
2014-08-14 17:14:21 +02:00
|
|
|
|
dotlock_t lockhd = NULL;
|
2020-10-20 11:52:16 +02:00
|
|
|
|
estream_t fp;
|
2014-08-14 17:14:21 +02:00
|
|
|
|
int rc;
|
|
|
|
|
mode_t oldmask;
|
|
|
|
|
char *last_slash_in_filename;
|
|
|
|
|
int save_slash;
|
|
|
|
|
|
|
|
|
|
if (r_created)
|
|
|
|
|
*r_created = 0;
|
|
|
|
|
|
|
|
|
|
/* A quick test whether the filename already exists. */
|
2020-10-20 10:43:55 +02:00
|
|
|
|
if (!gnupg_access (filename, F_OK))
|
|
|
|
|
return !gnupg_access (filename, R_OK)? 0 : gpg_error (GPG_ERR_EACCES);
|
2014-08-14 17:14:21 +02:00
|
|
|
|
|
|
|
|
|
/* If we don't want to create a new file at all, there is no need to
|
|
|
|
|
go any further - bail out right here. */
|
|
|
|
|
if (!force)
|
|
|
|
|
return gpg_error (GPG_ERR_ENOENT);
|
|
|
|
|
|
|
|
|
|
/* First of all we try to create the home directory. Note, that we
|
|
|
|
|
don't do any locking here because any sane application of gpg
|
|
|
|
|
would create the home directory by itself and not rely on gpg's
|
|
|
|
|
tricky auto-creation which is anyway only done for some home
|
|
|
|
|
directory name patterns. */
|
|
|
|
|
last_slash_in_filename = strrchr (filename, DIRSEP_C);
|
|
|
|
|
#if HAVE_W32_SYSTEM
|
|
|
|
|
{
|
|
|
|
|
/* Windows may either have a slash or a backslash. Take care of it. */
|
|
|
|
|
char *p = strrchr (filename, '/');
|
|
|
|
|
if (!last_slash_in_filename || p > last_slash_in_filename)
|
|
|
|
|
last_slash_in_filename = p;
|
|
|
|
|
}
|
|
|
|
|
#endif /*HAVE_W32_SYSTEM*/
|
|
|
|
|
if (!last_slash_in_filename)
|
|
|
|
|
return gpg_error (GPG_ERR_ENOENT); /* No slash at all - should
|
|
|
|
|
not happen though. */
|
|
|
|
|
save_slash = *last_slash_in_filename;
|
|
|
|
|
*last_slash_in_filename = 0;
|
2020-10-26 12:39:26 +01:00
|
|
|
|
if (gnupg_access(filename, F_OK))
|
2014-08-14 17:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
static int tried;
|
|
|
|
|
|
|
|
|
|
if (!tried)
|
|
|
|
|
{
|
|
|
|
|
tried = 1;
|
|
|
|
|
try_make_homedir (filename);
|
|
|
|
|
}
|
2020-10-20 10:43:55 +02:00
|
|
|
|
if ((ec = gnupg_access (filename, F_OK)))
|
2014-08-14 17:14:21 +02:00
|
|
|
|
{
|
2020-10-20 10:43:55 +02:00
|
|
|
|
rc = gpg_error (ec);
|
2014-08-14 17:14:21 +02:00
|
|
|
|
*last_slash_in_filename = save_slash;
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2023-04-04 16:39:59 +02:00
|
|
|
|
*last_slash_in_filename = save_slash;
|
|
|
|
|
|
|
|
|
|
if (!opt.use_keyboxd
|
|
|
|
|
&& !parse_comopt (GNUPG_MODULE_NAME_GPG, 0)
|
|
|
|
|
&& comopt.use_keyboxd)
|
|
|
|
|
{
|
|
|
|
|
/* The above try_make_homedir created a new default hoemdir
|
|
|
|
|
* and also wrote a new common.conf. Thus we now see that
|
|
|
|
|
* use-keyboxd has been set. Let's set this option and
|
|
|
|
|
* return a dedicated error code. */
|
|
|
|
|
opt.use_keyboxd = comopt.use_keyboxd;
|
|
|
|
|
rc = gpg_error (GPG_ERR_TRUE);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2014-08-14 17:14:21 +02:00
|
|
|
|
}
|
2023-04-04 16:39:59 +02:00
|
|
|
|
else
|
|
|
|
|
*last_slash_in_filename = save_slash;
|
2014-08-14 17:14:21 +02:00
|
|
|
|
|
|
|
|
|
/* To avoid races with other instances of gpg trying to create or
|
|
|
|
|
update the keybox (it is removed during an update for a short
|
|
|
|
|
time), we do the next stuff in a locked state. */
|
|
|
|
|
lockhd = dotlock_create (filename, 0);
|
|
|
|
|
if (!lockhd)
|
|
|
|
|
{
|
|
|
|
|
/* 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 );
|
|
|
|
|
|
|
|
|
|
if (!force)
|
|
|
|
|
return gpg_error (GPG_ERR_ENOENT);
|
|
|
|
|
else
|
|
|
|
|
return gpg_error (GPG_ERR_GENERAL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( dotlock_take (lockhd, -1) )
|
|
|
|
|
{
|
|
|
|
|
/* This is something bad. Probably a stale lockfile. */
|
|
|
|
|
log_info ("can't lock '%s'\n", filename);
|
|
|
|
|
rc = gpg_error (GPG_ERR_GENERAL);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now the real test while we are locked. */
|
2021-07-29 11:51:25 +02:00
|
|
|
|
if (!gnupg_access(filename, F_OK))
|
2014-08-14 17:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
rc = 0; /* Okay, we may access the file now. */
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The file does not yet exist, create it now. */
|
|
|
|
|
oldmask = umask (077);
|
2020-10-20 11:52:16 +02:00
|
|
|
|
fp = es_fopen (filename, "wb");
|
2014-08-14 17:14:21 +02:00
|
|
|
|
if (!fp)
|
|
|
|
|
{
|
|
|
|
|
rc = gpg_error_from_syserror ();
|
|
|
|
|
umask (oldmask);
|
|
|
|
|
log_error (_("error creating keybox '%s': %s\n"),
|
|
|
|
|
filename, gpg_strerror (rc));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
umask (oldmask);
|
|
|
|
|
|
2016-03-17 15:15:48 +01:00
|
|
|
|
/* Make sure that at least one record is in a new keybox file, so
|
|
|
|
|
that the detection magic for OpenPGP keyboxes works the next time
|
|
|
|
|
it is used. */
|
2020-10-20 11:52:16 +02:00
|
|
|
|
rc = _keybox_write_header_blob (fp, 0);
|
2016-03-17 15:15:48 +01:00
|
|
|
|
if (rc)
|
|
|
|
|
{
|
2020-10-20 11:52:16 +02:00
|
|
|
|
es_fclose (fp);
|
2016-03-17 15:15:48 +01:00
|
|
|
|
log_error (_("error creating keybox '%s': %s\n"),
|
|
|
|
|
filename, gpg_strerror (rc));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-14 17:14:21 +02:00
|
|
|
|
if (!opt.quiet)
|
|
|
|
|
log_info (_("keybox '%s' created\n"), filename);
|
|
|
|
|
if (r_created)
|
|
|
|
|
*r_created = 1;
|
|
|
|
|
|
2020-10-20 11:52:16 +02:00
|
|
|
|
es_fclose (fp);
|
2014-08-14 17:14:21 +02:00
|
|
|
|
rc = 0;
|
|
|
|
|
|
|
|
|
|
leave:
|
|
|
|
|
if (lockhd)
|
|
|
|
|
{
|
|
|
|
|
dotlock_release (lockhd);
|
|
|
|
|
dotlock_destroy (lockhd);
|
|
|
|
|
}
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
/*
|
|
|
|
|
* Register a resource (which currently may only be a keybox file).
|
2006-09-18 11:28:58 +02:00
|
|
|
|
* The first keybox which is added by this function is created if it
|
|
|
|
|
* does not exist. If AUTO_CREATED is not NULL it will be set to true
|
2014-08-14 17:14:21 +02:00
|
|
|
|
* if the function has created a new keybox.
|
2003-08-05 19:11:04 +02:00
|
|
|
|
*/
|
2016-01-13 09:29:39 +01:00
|
|
|
|
gpg_error_t
|
2016-11-10 17:01:19 +01:00
|
|
|
|
keydb_add_resource (ctrl_t ctrl, const char *url, int force, int *auto_created)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
|
|
|
|
const char *resname = url;
|
|
|
|
|
char *filename = NULL;
|
2016-01-13 09:29:39 +01:00
|
|
|
|
gpg_error_t err = 0;
|
2003-08-05 19:11:04 +02:00
|
|
|
|
KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE;
|
|
|
|
|
|
2006-09-18 11:28:58 +02:00
|
|
|
|
if (auto_created)
|
|
|
|
|
*auto_created = 0;
|
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
/* Do we have an URL?
|
|
|
|
|
gnupg-kbx:filename := this is a plain keybox
|
2017-02-20 22:19:50 +01:00
|
|
|
|
filename := See what it is, but create as plain keybox.
|
2003-08-05 19:11:04 +02:00
|
|
|
|
*/
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (strlen (resname) > 10)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
|
|
|
|
if (!strncmp (resname, "gnupg-kbx:", 10) )
|
|
|
|
|
{
|
|
|
|
|
rt = KEYDB_RESOURCE_TYPE_KEYBOX;
|
|
|
|
|
resname += 10;
|
|
|
|
|
}
|
|
|
|
|
#if !defined(HAVE_DRIVE_LETTERS) && !defined(__riscos__)
|
|
|
|
|
else if (strchr (resname, ':'))
|
|
|
|
|
{
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_error ("invalid key resource URL '%s'\n", url );
|
2016-01-13 09:29:39 +01:00
|
|
|
|
err = gpg_error (GPG_ERR_GENERAL);
|
2003-08-05 19:11:04 +02: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
|
2016-06-07 10:59:46 +02:00
|
|
|
|
filename = make_filename (gnupg_homedir (), resname, NULL);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
filename = xstrdup (resname);
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
if (!force)
|
2016-11-10 17:01:19 +01:00
|
|
|
|
force = !any_registered;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
/* see whether we can determine the filetype */
|
|
|
|
|
if (rt == KEYDB_RESOURCE_TYPE_NONE)
|
|
|
|
|
{
|
2020-10-20 11:52:16 +02:00
|
|
|
|
estream_t fp;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2020-10-20 11:52:16 +02:00
|
|
|
|
fp = es_fopen( filename, "rb" );
|
2014-08-14 17:14:21 +02:00
|
|
|
|
if (fp)
|
|
|
|
|
{
|
|
|
|
|
u32 magic;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2014-08-14 17:14:21 +02:00
|
|
|
|
/* FIXME: check for the keybox magic */
|
2020-10-20 11:52:16 +02:00
|
|
|
|
if (es_fread (&magic, 4, 1, fp) == 1 )
|
2014-08-14 17:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
if (magic == 0x13579ace || magic == 0xce9a5713)
|
|
|
|
|
; /* GDBM magic - no more support */
|
|
|
|
|
else
|
|
|
|
|
rt = KEYDB_RESOURCE_TYPE_KEYBOX;
|
|
|
|
|
}
|
|
|
|
|
else /* maybe empty: assume keybox */
|
|
|
|
|
rt = KEYDB_RESOURCE_TYPE_KEYBOX;
|
2020-10-20 11:52:16 +02:00
|
|
|
|
|
|
|
|
|
es_fclose (fp);
|
2014-08-14 17:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
else /* no file yet: create keybox */
|
2003-08-05 19:11:04 +02:00
|
|
|
|
rt = KEYDB_RESOURCE_TYPE_KEYBOX;
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
switch (rt)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_error ("unknown type of key resource '%s'\n", url );
|
2016-01-13 09:29:39 +01:00
|
|
|
|
err = gpg_error (GPG_ERR_GENERAL);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
goto leave;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
2016-01-13 09:29:39 +01:00
|
|
|
|
err = maybe_create_keybox (filename, force, auto_created);
|
|
|
|
|
if (err)
|
2014-08-14 17:14:21 +02:00
|
|
|
|
goto leave;
|
|
|
|
|
/* Now register the file */
|
|
|
|
|
{
|
2016-01-13 09:29:39 +01:00
|
|
|
|
void *token;
|
|
|
|
|
|
2016-11-10 15:38:14 +01:00
|
|
|
|
err = keybox_register_file (filename, 0, &token);
|
2016-01-13 09:29:39 +01:00
|
|
|
|
if (gpg_err_code (err) == GPG_ERR_EEXIST)
|
|
|
|
|
; /* Already registered - ignore. */
|
|
|
|
|
else if (err)
|
|
|
|
|
; /* Other error. */
|
2014-08-14 17:14:21 +02:00
|
|
|
|
else if (used_resources >= MAX_KEYDB_RESOURCES)
|
2016-01-13 09:29:39 +01:00
|
|
|
|
err = gpg_error (GPG_ERR_RESOURCE_LIMIT);
|
2014-08-14 17:14:21 +02:00
|
|
|
|
else
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
2019-05-14 13:36:08 +02:00
|
|
|
|
KEYBOX_HANDLE kbxhd;
|
|
|
|
|
|
2014-08-14 17:14:21 +02:00
|
|
|
|
all_resources[used_resources].type = rt;
|
|
|
|
|
all_resources[used_resources].u.kr = NULL; /* Not used here */
|
|
|
|
|
all_resources[used_resources].token = token;
|
|
|
|
|
|
2019-05-14 13:36:08 +02:00
|
|
|
|
/* Do a compress run if needed and the keybox is not locked. */
|
|
|
|
|
kbxhd = keybox_new_x509 (token, 0);
|
|
|
|
|
if (kbxhd)
|
2014-08-14 17:14:21 +02:00
|
|
|
|
{
|
2019-05-14 13:36:08 +02:00
|
|
|
|
if (!keybox_lock (kbxhd, 1, 0))
|
2019-08-23 15:51:13 +02:00
|
|
|
|
{
|
|
|
|
|
keybox_compress (kbxhd);
|
|
|
|
|
keybox_lock (kbxhd, 0, 0);
|
|
|
|
|
}
|
2019-05-14 13:36:08 +02:00
|
|
|
|
|
|
|
|
|
keybox_release (kbxhd);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
}
|
2004-04-26 10:09:25 +02:00
|
|
|
|
|
2014-08-14 17:14:21 +02:00
|
|
|
|
used_resources++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2004-04-26 10:09:25 +02:00
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
default:
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_error ("resource type of '%s' not supported\n", url);
|
2016-01-13 09:29:39 +01:00
|
|
|
|
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* fixme: check directory permissions and print a warning */
|
|
|
|
|
|
|
|
|
|
leave:
|
2016-01-13 09:29:39 +01:00
|
|
|
|
if (err)
|
2016-11-10 17:01:19 +01:00
|
|
|
|
{
|
2023-04-04 16:39:59 +02:00
|
|
|
|
if (gpg_err_code (err) != GPG_ERR_TRUE)
|
|
|
|
|
{
|
|
|
|
|
log_error ("keyblock resource '%s': %s\n",
|
|
|
|
|
filename, gpg_strerror (err));
|
|
|
|
|
gpgsm_status_with_error (ctrl, STATUS_ERROR,
|
|
|
|
|
"add_keyblock_resource", err);
|
|
|
|
|
}
|
2016-11-10 17:01:19 +01:00
|
|
|
|
}
|
2003-08-05 19:11:04 +02:00
|
|
|
|
else
|
2016-11-10 17:01:19 +01:00
|
|
|
|
any_registered = 1;
|
2003-08-05 19:11:04 +02:00
|
|
|
|
xfree (filename);
|
2016-01-13 09:29:39 +01:00
|
|
|
|
return err;
|
2003-08-05 19:11:04 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
/* Print a warning if the server's version number is less than our
|
|
|
|
|
version number. Returns an error code on a connection problem. */
|
|
|
|
|
static gpg_error_t
|
2020-10-05 17:54:26 +02:00
|
|
|
|
warn_version_mismatch (ctrl_t ctrl, assuan_context_t ctx,
|
|
|
|
|
const char *servername)
|
2020-09-03 13:46:54 +02:00
|
|
|
|
{
|
|
|
|
|
return warn_server_version_mismatch (ctx, servername, 0,
|
2020-10-05 17:54:26 +02:00
|
|
|
|
gpgsm_status2, ctrl,
|
2020-09-03 13:46:54 +02:00
|
|
|
|
!opt.quiet);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Connect to the keybox daemon and launch it if necessary. Handle
|
|
|
|
|
* the server's initial greeting and set global options. Returns a
|
|
|
|
|
* new assuan context or an error. */
|
|
|
|
|
static gpg_error_t
|
|
|
|
|
create_new_context (ctrl_t ctrl, assuan_context_t *r_ctx)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
assuan_context_t ctx;
|
|
|
|
|
|
|
|
|
|
*r_ctx = NULL;
|
|
|
|
|
|
|
|
|
|
err = start_new_keyboxd (&ctx,
|
|
|
|
|
GPG_ERR_SOURCE_DEFAULT,
|
|
|
|
|
opt.keyboxd_program,
|
2023-08-29 13:18:13 +02:00
|
|
|
|
opt.autostart?ASSHELP_FLAG_AUTOSTART:0,
|
|
|
|
|
opt.verbose, DBG_IPC,
|
2020-09-03 13:46:54 +02:00
|
|
|
|
NULL, ctrl);
|
|
|
|
|
if (!opt.autostart && gpg_err_code (err) == GPG_ERR_NO_KEYBOXD)
|
|
|
|
|
{
|
|
|
|
|
static int shown;
|
|
|
|
|
|
|
|
|
|
if (!shown)
|
|
|
|
|
{
|
|
|
|
|
shown = 1;
|
|
|
|
|
log_info (_("no keyboxd running in this session\n"));
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-10-05 17:54:26 +02:00
|
|
|
|
else if (!err && !(err = warn_version_mismatch (ctrl, ctx, KEYBOXD_NAME)))
|
2020-09-03 13:46:54 +02:00
|
|
|
|
{
|
|
|
|
|
/* Place to emit global options. */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (err)
|
|
|
|
|
assuan_release (ctx);
|
|
|
|
|
else
|
|
|
|
|
*r_ctx = ctx;
|
|
|
|
|
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Get a context for accessing keyboxd. If no context is available a
|
|
|
|
|
* new one is created and if necessary keyboxd is started. R_KBL
|
|
|
|
|
* receives a pointer to the local context object. */
|
|
|
|
|
static gpg_error_t
|
|
|
|
|
open_context (ctrl_t ctrl, keydb_local_t *r_kbl)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
keydb_local_t kbl;
|
|
|
|
|
|
|
|
|
|
*r_kbl = NULL;
|
|
|
|
|
for (;;)
|
|
|
|
|
{
|
|
|
|
|
for (kbl = ctrl->keydb_local; kbl && kbl->is_active; kbl = kbl->next)
|
|
|
|
|
;
|
|
|
|
|
if (kbl)
|
|
|
|
|
{
|
|
|
|
|
/* Found an inactive keyboxd session - return that. */
|
|
|
|
|
log_assert (!kbl->is_active);
|
|
|
|
|
|
|
|
|
|
kbl->is_active = 1;
|
|
|
|
|
kbl->need_search_reset = 1;
|
|
|
|
|
|
|
|
|
|
*r_kbl = kbl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* None found. Create a new session and retry. */
|
|
|
|
|
kbl = xtrycalloc (1, sizeof *kbl);
|
|
|
|
|
if (!kbl)
|
|
|
|
|
return gpg_error_from_syserror ();
|
|
|
|
|
|
|
|
|
|
err = create_new_context (ctrl, &kbl->ctx);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
xfree (kbl);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-07 08:26:34 +02:00
|
|
|
|
err = kbx_client_data_new (&kbl->kcd, kbl->ctx, 0);
|
2020-09-03 13:46:54 +02:00
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
assuan_release (kbl->ctx);
|
|
|
|
|
xfree (kbl);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* For thread-saftey we add it to the list and retry; this is
|
|
|
|
|
* easier than to employ a lock. */
|
|
|
|
|
kbl->next = ctrl->keydb_local;
|
|
|
|
|
ctrl->keydb_local = kbl;
|
|
|
|
|
}
|
|
|
|
|
/*NOTREACHED*/
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
KEYDB_HANDLE
|
2020-09-02 17:27:30 +02:00
|
|
|
|
keydb_new (ctrl_t ctrl)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
2020-09-03 13:46:54 +02:00
|
|
|
|
gpg_error_t err;
|
2003-08-05 19:11:04 +02:00
|
|
|
|
KEYDB_HANDLE hd;
|
2020-09-03 13:46:54 +02:00
|
|
|
|
int rc, i, j;
|
2020-09-02 17:27:30 +02:00
|
|
|
|
|
2019-05-14 20:03:44 +02:00
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("%s: enter\n", __func__);
|
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
hd = xcalloc (1, sizeof *hd);
|
|
|
|
|
hd->found = -1;
|
2014-06-02 15:55:00 +02:00
|
|
|
|
hd->saved_found = -1;
|
2020-09-03 13:46:54 +02:00
|
|
|
|
hd->use_keyboxd = opt.use_keyboxd;
|
|
|
|
|
hd->ctrl = ctrl;
|
|
|
|
|
if (hd->use_keyboxd)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
2020-09-03 13:46:54 +02:00
|
|
|
|
err = open_context (ctrl, &hd->kbl);
|
|
|
|
|
if (err)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
2020-09-03 13:46:54 +02:00
|
|
|
|
log_error (_("error opening key DB: %s\n"), gpg_strerror (err));
|
|
|
|
|
xfree (hd);
|
|
|
|
|
hd = NULL;
|
|
|
|
|
if (!(rc = gpg_err_code_to_errno (err)))
|
|
|
|
|
rc = gpg_err_code_to_errno (GPG_ERR_EIO);
|
|
|
|
|
gpg_err_set_errno (rc);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else /* Use the local keybox. */
|
|
|
|
|
{
|
|
|
|
|
log_assert (used_resources <= MAX_KEYDB_RESOURCES);
|
|
|
|
|
for (i=j=0; i < used_resources; i++)
|
|
|
|
|
{
|
|
|
|
|
switch (all_resources[i].type)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
2020-09-03 13:46:54 +02:00
|
|
|
|
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].u.kr = keybox_new_x509 (all_resources[i].token, 0);
|
|
|
|
|
if (!hd->active[j].u.kr)
|
|
|
|
|
{
|
|
|
|
|
xfree (hd);
|
|
|
|
|
return NULL; /* fixme: free all previously allocated handles*/
|
|
|
|
|
}
|
|
|
|
|
j++;
|
|
|
|
|
break;
|
2003-08-05 19:11:04 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-03 13:46:54 +02:00
|
|
|
|
hd->used = j;
|
2003-08-05 19:11:04 +02:00
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
active_handles++;
|
2020-09-03 13:46:54 +02:00
|
|
|
|
|
|
|
|
|
leave:
|
2019-05-14 20:03:44 +02:00
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("%s: leave (hd=%p)\n", __func__, hd);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
return hd;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
void
|
2003-08-05 19:11:04 +02:00
|
|
|
|
keydb_release (KEYDB_HANDLE hd)
|
|
|
|
|
{
|
2020-09-03 13:46:54 +02:00
|
|
|
|
keydb_local_t kbl;
|
2003-08-05 19:11:04 +02:00
|
|
|
|
int i;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
if (!hd)
|
|
|
|
|
return;
|
2019-05-14 20:03:44 +02:00
|
|
|
|
|
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("%s: enter (hd=%p)\n", __func__, hd);
|
|
|
|
|
|
|
|
|
|
log_assert (active_handles > 0);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
active_handles--;
|
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
if (hd->use_keyboxd)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
2020-09-03 13:46:54 +02:00
|
|
|
|
kbl = hd->kbl;
|
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("close_context (found)");
|
|
|
|
|
if (!kbl->is_active)
|
|
|
|
|
log_fatal ("closing inactive keyboxd context %p\n", kbl);
|
|
|
|
|
kbl->is_active = 0;
|
|
|
|
|
hd->kbl = NULL;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
hd->keep_lock = 0;
|
|
|
|
|
unlock_all (hd);
|
|
|
|
|
for (i=0; i < hd->used; i++)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
2020-09-03 13:46:54 +02:00
|
|
|
|
switch (hd->active[i].type)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
2023-05-04 11:55:26 +02:00
|
|
|
|
break;
|
2020-09-03 13:46:54 +02:00
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
keybox_release (hd->active[i].u.kr);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2003-08-05 19:11:04 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-14 20:03:44 +02:00
|
|
|
|
xfree (hd);
|
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("%s: leave\n", __func__);
|
2003-08-05 19:11:04 +02: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. */
|
|
|
|
|
const char *
|
|
|
|
|
keydb_get_resource_name (KEYDB_HANDLE hd)
|
|
|
|
|
{
|
|
|
|
|
int idx;
|
|
|
|
|
const char *s = NULL;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
|
|
|
|
if (!hd)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
return NULL;
|
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
if (hd->use_keyboxd)
|
|
|
|
|
return "[keyboxd]";
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if ( hd->found >= 0 && hd->found < hd->used)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
idx = hd->found;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
else if ( hd->current >= 0 && hd->current < hd->used)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
idx = hd->current;
|
|
|
|
|
else
|
|
|
|
|
idx = 0;
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
switch (hd->active[idx].type)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
2011-02-04 12:57:53 +01:00
|
|
|
|
s = NULL;
|
2003-08-05 19:11:04 +02:00
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
s = keybox_get_resource_name (hd->active[idx].u.kr);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
return s? s: "";
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-16 12:41:46 +01:00
|
|
|
|
/* Switch the handle into ephemeral mode and return the original value. */
|
2003-08-05 19:11:04 +02:00
|
|
|
|
int
|
|
|
|
|
keydb_set_ephemeral (KEYDB_HANDLE hd, int yes)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (!hd)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
if (hd->use_keyboxd)
|
|
|
|
|
return 0; /* FIXME: No support yet. */
|
|
|
|
|
|
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
yes = !!yes;
|
|
|
|
|
if (hd->is_ephemeral != yes)
|
|
|
|
|
{
|
|
|
|
|
for (i=0; i < hd->used; i++)
|
|
|
|
|
{
|
2011-02-04 12:57:53 +01:00
|
|
|
|
switch (hd->active[i].type)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
keybox_set_ephemeral (hd->active[i].u.kr, yes);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
i = hd->is_ephemeral;
|
|
|
|
|
hd->is_ephemeral = yes;
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2004-02-02 18:09:35 +01:00
|
|
|
|
/* If the keyring has not yet been locked, lock it now. This
|
2019-05-14 13:36:08 +02:00
|
|
|
|
* operation is required before any update operation; it is optional
|
|
|
|
|
* for an insert operation. The lock is kept until a keydb_release so
|
|
|
|
|
* that internal unlock_all calls have no effect. */
|
2004-02-02 18:09:35 +01:00
|
|
|
|
gpg_error_t
|
|
|
|
|
keydb_lock (KEYDB_HANDLE hd)
|
|
|
|
|
{
|
2019-05-14 13:36:08 +02:00
|
|
|
|
gpg_error_t err;
|
|
|
|
|
|
2004-02-02 18:09:35 +01:00
|
|
|
|
if (!hd)
|
|
|
|
|
return gpg_error (GPG_ERR_INV_HANDLE);
|
2020-09-03 13:46:54 +02:00
|
|
|
|
if (hd->use_keyboxd)
|
|
|
|
|
return 0;
|
2019-05-14 13:36:08 +02:00
|
|
|
|
|
2019-05-14 20:03:44 +02:00
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("%s: enter (hd=%p)\n", __func__, hd);
|
2019-05-14 13:36:08 +02:00
|
|
|
|
err = lock_all (hd);
|
|
|
|
|
if (!err)
|
|
|
|
|
hd->keep_lock = 1;
|
|
|
|
|
|
2019-05-14 20:03:44 +02:00
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("%s: leave (err=%s)\n", __func__, gpg_strerror (err));
|
2019-05-14 13:36:08 +02:00
|
|
|
|
return err;
|
2004-02-02 18:09:35 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
static int
|
2003-08-05 19:11:04 +02:00
|
|
|
|
lock_all (KEYDB_HANDLE hd)
|
|
|
|
|
{
|
|
|
|
|
int i, rc = 0;
|
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
if (hd->use_keyboxd)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
/* Fixme: This locking scheme may lead to deadlock if the resources
|
2004-06-06 15:00:59 +02:00
|
|
|
|
are not added in the same order by all processes. We are
|
2004-02-02 18:09:35 +01:00
|
|
|
|
currently only allowing one resource so it is not a problem. */
|
2011-02-04 12:57:53 +01:00
|
|
|
|
for (i=0; i < hd->used; i++)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
2011-02-04 12:57:53 +01:00
|
|
|
|
switch (hd->active[i].type)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
2019-05-14 13:36:08 +02:00
|
|
|
|
rc = keybox_lock (hd->active[i].u.kr, 1, -1);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (rc)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (rc)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
2019-05-14 13:36:08 +02:00
|
|
|
|
/* Revert the already set locks. */
|
2011-02-04 12:57:53 +01:00
|
|
|
|
for (i--; i >= 0; i--)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
2011-02-04 12:57:53 +01:00
|
|
|
|
switch (hd->active[i].type)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
2019-05-14 13:36:08 +02:00
|
|
|
|
keybox_lock (hd->active[i].u.kr, 0, 0);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
hd->locked = 1;
|
|
|
|
|
|
2019-05-14 13:36:08 +02:00
|
|
|
|
return rc;
|
2003-08-05 19:11:04 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
unlock_all (KEYDB_HANDLE hd)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
if (hd->use_keyboxd)
|
|
|
|
|
return;
|
|
|
|
|
|
2019-05-14 13:36:08 +02:00
|
|
|
|
if (!hd->locked || hd->keep_lock)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
return;
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
for (i=hd->used-1; i >= 0; i--)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
2011-02-04 12:57:53 +01:00
|
|
|
|
switch (hd->active[i].type)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
2019-05-14 13:36:08 +02:00
|
|
|
|
keybox_lock (hd->active[i].u.kr, 0, 0);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
hd->locked = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-02 15:55:00 +02:00
|
|
|
|
|
|
|
|
|
|
2021-06-11 20:15:13 +02:00
|
|
|
|
/* Push the last found state if any. Only one state is saved. */
|
2014-06-02 15:55:00 +02:00
|
|
|
|
void
|
|
|
|
|
keydb_push_found_state (KEYDB_HANDLE hd)
|
|
|
|
|
{
|
|
|
|
|
if (!hd)
|
|
|
|
|
return;
|
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
if (hd->use_keyboxd)
|
2014-06-02 15:55:00 +02:00
|
|
|
|
{
|
2021-06-11 20:15:13 +02:00
|
|
|
|
xfree (hd->kbl->saved_search_result.buf);
|
|
|
|
|
hd->kbl->saved_search_result.buf = hd->kbl->search_result.buf;
|
|
|
|
|
hd->kbl->saved_search_result.len = hd->kbl->search_result.len;
|
|
|
|
|
hd->kbl->search_result.buf = NULL;
|
|
|
|
|
hd->kbl->search_result.len = 0;
|
2014-06-02 15:55:00 +02:00
|
|
|
|
}
|
2021-06-11 20:15:13 +02:00
|
|
|
|
else
|
2014-06-02 15:55:00 +02:00
|
|
|
|
{
|
2021-06-11 20:15:13 +02:00
|
|
|
|
if (hd->found < 0 || hd->found >= hd->used)
|
|
|
|
|
hd->saved_found = -1;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
switch (hd->active[hd->found].type)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
keybox_push_found_state (hd->active[hd->found].u.kr);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hd->saved_found = hd->found;
|
|
|
|
|
hd->found = -1;
|
|
|
|
|
}
|
2014-06-02 15:55:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-14 20:03:44 +02:00
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("%s: done (hd=%p)\n", __func__, hd);
|
2014-06-02 15:55:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Pop the last found state. */
|
|
|
|
|
void
|
|
|
|
|
keydb_pop_found_state (KEYDB_HANDLE hd)
|
|
|
|
|
{
|
|
|
|
|
if (!hd)
|
|
|
|
|
return;
|
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
if (hd->use_keyboxd)
|
2014-06-02 15:55:00 +02:00
|
|
|
|
{
|
2021-06-11 20:15:13 +02:00
|
|
|
|
xfree (hd->kbl->search_result.buf);
|
|
|
|
|
hd->kbl->search_result.buf = hd->kbl->saved_search_result.buf;
|
|
|
|
|
hd->kbl->search_result.len = hd->kbl->saved_search_result.len;
|
|
|
|
|
hd->kbl->saved_search_result.buf = NULL;
|
|
|
|
|
hd->kbl->saved_search_result.len = 0;
|
2014-06-02 15:55:00 +02:00
|
|
|
|
}
|
2021-06-11 20:15:13 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
hd->found = hd->saved_found;
|
|
|
|
|
hd->saved_found = -1;
|
|
|
|
|
if (hd->found < 0 || hd->found >= hd->used)
|
|
|
|
|
;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
switch (hd->active[hd->found].type)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
keybox_pop_found_state (hd->active[hd->found].u.kr);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-14 20:03:44 +02:00
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("%s: done (hd=%p)\n", __func__, hd);
|
2014-06-02 15:55:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
|
2020-09-10 13:05:17 +02:00
|
|
|
|
/* Return the last found certificate. Caller must free it. */
|
2003-08-05 19:11:04 +02:00
|
|
|
|
int
|
2003-12-17 13:28:24 +01:00
|
|
|
|
keydb_get_cert (KEYDB_HANDLE hd, ksba_cert_t *r_cert)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
2020-09-10 13:05:17 +02:00
|
|
|
|
int err = 0;
|
2003-08-05 19:11:04 +02:00
|
|
|
|
|
|
|
|
|
if (!hd)
|
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2019-05-14 20:03:44 +02:00
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("%s: enter (hd=%p)\n", __func__, hd);
|
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
if (hd->use_keyboxd)
|
|
|
|
|
{
|
2020-09-10 13:05:17 +02:00
|
|
|
|
ksba_cert_t cert;
|
|
|
|
|
|
|
|
|
|
/* Fixme: We should clear that also in non-keyboxd mode but we
|
|
|
|
|
* did not in the past and thus all code should be checked
|
|
|
|
|
* whether this is okay. If we run into error in keyboxd mode,
|
|
|
|
|
* this is a not as severe because keyboxd is currently
|
|
|
|
|
* experimental. */
|
|
|
|
|
*r_cert = NULL;
|
|
|
|
|
|
|
|
|
|
if (!hd->kbl->search_result.buf || !hd->kbl->search_result.len)
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error (GPG_ERR_VALUE_NOT_FOUND);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
err = ksba_cert_new (&cert);
|
|
|
|
|
if (err)
|
|
|
|
|
goto leave;
|
|
|
|
|
err = ksba_cert_init_from_mem (cert,
|
|
|
|
|
hd->kbl->search_result.buf,
|
|
|
|
|
hd->kbl->search_result.len);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
ksba_cert_release (cert);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
*r_cert = cert;
|
2020-09-03 13:46:54 +02:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if ( hd->found < 0 || hd->found >= hd->used)
|
2019-05-14 20:03:44 +02:00
|
|
|
|
{
|
2020-09-10 13:05:17 +02:00
|
|
|
|
/* Fixme: It would be better to use GPG_ERR_VALUE_NOT_FOUND here
|
|
|
|
|
* but for now we use NOT_FOUND because that is our standard
|
|
|
|
|
* replacement for the formerly used (-1). */
|
|
|
|
|
err = gpg_error (GPG_ERR_NOT_FOUND); /* nothing found */
|
2019-05-14 20:03:44 +02:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2020-09-10 13:05:17 +02:00
|
|
|
|
err = GPG_ERR_BUG;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
switch (hd->active[hd->found].type)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
2020-09-10 13:05:17 +02:00
|
|
|
|
err = gpg_error (GPG_ERR_GENERAL); /* oops */
|
2003-08-05 19:11:04 +02:00
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
2020-09-10 13:05:17 +02:00
|
|
|
|
err = keybox_get_cert (hd->active[hd->found].u.kr, r_cert);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2019-05-14 20:03:44 +02:00
|
|
|
|
leave:
|
|
|
|
|
if (DBG_CLOCK)
|
2020-09-10 13:05:17 +02:00
|
|
|
|
log_clock ("%s: leave (rc=%d)\n", __func__, err);
|
|
|
|
|
return err;
|
2003-08-05 19:11:04 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-14 20:03:44 +02:00
|
|
|
|
|
2004-02-02 18:09:35 +01:00
|
|
|
|
/* Return a flag of the last found object. WHICH is the flag requested;
|
|
|
|
|
it should be one of the KEYBOX_FLAG_ values. If the operation is
|
|
|
|
|
successful, the flag value will be stored at the address given by
|
|
|
|
|
VALUE. Return 0 on success or an error code. */
|
|
|
|
|
gpg_error_t
|
|
|
|
|
keydb_get_flags (KEYDB_HANDLE hd, int which, int idx, unsigned int *value)
|
|
|
|
|
{
|
2019-05-14 20:03:44 +02:00
|
|
|
|
gpg_error_t err;
|
2004-02-02 18:09:35 +01:00
|
|
|
|
|
|
|
|
|
if (!hd)
|
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2019-05-14 20:03:44 +02:00
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("%s: enter (hd=%p)\n", __func__, hd);
|
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
if (hd->use_keyboxd)
|
|
|
|
|
{
|
|
|
|
|
/* FIXME */
|
2020-09-10 13:05:17 +02:00
|
|
|
|
*value = 0;
|
|
|
|
|
err = 0;
|
2020-09-03 13:46:54 +02:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if ( hd->found < 0 || hd->found >= hd->used)
|
2019-05-14 20:03:44 +02:00
|
|
|
|
{
|
|
|
|
|
err = gpg_error (GPG_ERR_NOTHING_FOUND);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2019-05-14 20:03:44 +02:00
|
|
|
|
err = gpg_error (GPG_ERR_BUG);
|
2011-02-04 12:57:53 +01:00
|
|
|
|
switch (hd->active[hd->found].type)
|
2004-02-02 18:09:35 +01:00
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
|
|
|
|
err = gpg_error (GPG_ERR_GENERAL); /* oops */
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
err = keybox_get_flags (hd->active[hd->found].u.kr, which, idx, value);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2019-05-14 20:03:44 +02:00
|
|
|
|
leave:
|
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("%s: leave (err=%s)\n", __func__, gpg_strerror (err));
|
2004-02-02 18:09:35 +01:00
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-14 20:03:44 +02:00
|
|
|
|
|
2004-02-02 18:09:35 +01:00
|
|
|
|
/* Set a flag of the last found object. WHICH is the flag to be set; it
|
|
|
|
|
should be one of the KEYBOX_FLAG_ values. If the operation is
|
|
|
|
|
successful, the flag value will be stored in the keybox. Note,
|
2004-03-15 09:39:48 +01:00
|
|
|
|
that some flag values can't be updated and thus may return an
|
2004-02-02 18:09:35 +01:00
|
|
|
|
error, some other flag values may be masked out before an update.
|
|
|
|
|
Returns 0 on success or an error code. */
|
|
|
|
|
gpg_error_t
|
|
|
|
|
keydb_set_flags (KEYDB_HANDLE hd, int which, int idx, unsigned int value)
|
|
|
|
|
{
|
2019-05-14 20:03:44 +02:00
|
|
|
|
gpg_error_t err = 0;
|
2004-02-02 18:09:35 +01:00
|
|
|
|
|
|
|
|
|
if (!hd)
|
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2019-05-14 20:03:44 +02:00
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("%s: enter (hd=%p)\n", __func__, hd);
|
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
if (hd->use_keyboxd)
|
|
|
|
|
{
|
|
|
|
|
/* FIXME */
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if ( hd->found < 0 || hd->found >= hd->used)
|
2019-05-14 20:03:44 +02:00
|
|
|
|
{
|
|
|
|
|
err = gpg_error (GPG_ERR_NOTHING_FOUND);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2004-02-02 18:09:35 +01:00
|
|
|
|
if (!hd->locked)
|
2019-05-14 20:03:44 +02:00
|
|
|
|
{
|
|
|
|
|
err = gpg_error (GPG_ERR_NOT_LOCKED);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2004-02-02 18:09:35 +01:00
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
switch (hd->active[hd->found].type)
|
2004-02-02 18:09:35 +01:00
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
|
|
|
|
err = gpg_error (GPG_ERR_GENERAL); /* oops */
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
err = keybox_set_flags (hd->active[hd->found].u.kr, which, idx, value);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2019-05-14 20:03:44 +02:00
|
|
|
|
leave:
|
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("%s: leave (err=%s)\n", __func__, gpg_strerror (err));
|
2004-02-02 18:09:35 +01:00
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-10 13:05:17 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Communication object for Keyboxd STORE commands. */
|
|
|
|
|
struct store_parm_s
|
|
|
|
|
{
|
|
|
|
|
assuan_context_t ctx;
|
|
|
|
|
const void *data; /* The certificate in X.509 binary format. */
|
|
|
|
|
size_t datalen; /* The length of DATA. */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Handle the inquiries from the STORE command. */
|
|
|
|
|
static gpg_error_t
|
|
|
|
|
store_inq_cb (void *opaque, const char *line)
|
|
|
|
|
{
|
|
|
|
|
struct store_parm_s *parm = opaque;
|
|
|
|
|
gpg_error_t err = 0;
|
|
|
|
|
|
|
|
|
|
if (has_leading_keyword (line, "BLOB"))
|
|
|
|
|
{
|
|
|
|
|
if (parm->data)
|
|
|
|
|
err = assuan_send_data (parm->ctx, parm->data, parm->datalen);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
|
|
|
|
|
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
/*
|
|
|
|
|
* Insert a new Certificate into one of the resources.
|
2003-08-05 19:11:04 +02:00
|
|
|
|
*/
|
2019-05-14 20:03:44 +02:00
|
|
|
|
gpg_error_t
|
2003-12-17 13:28:24 +01:00
|
|
|
|
keydb_insert_cert (KEYDB_HANDLE hd, ksba_cert_t cert)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
2019-05-14 20:03:44 +02:00
|
|
|
|
gpg_error_t err;
|
2003-08-05 19:11:04 +02:00
|
|
|
|
int idx;
|
2005-06-16 10:12:03 +02:00
|
|
|
|
unsigned char digest[20];
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
|
|
|
|
if (!hd)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
|
|
|
|
|
|
|
|
|
if (opt.dry_run)
|
|
|
|
|
return 0;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2019-05-14 20:03:44 +02:00
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("%s: enter (hd=%p)\n", __func__, hd);
|
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
if (hd->use_keyboxd)
|
|
|
|
|
{
|
2020-09-10 13:05:17 +02:00
|
|
|
|
struct store_parm_s parm;
|
|
|
|
|
|
|
|
|
|
parm.ctx = hd->kbl->ctx;
|
|
|
|
|
parm.data = ksba_cert_get_image (cert, &parm.datalen);
|
|
|
|
|
if (!parm.data)
|
|
|
|
|
{
|
|
|
|
|
log_debug ("broken ksba cert object\n");
|
|
|
|
|
err = gpg_error (GPG_ERR_GENERAL);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
err = assuan_transact (hd->kbl->ctx, "STORE --insert",
|
|
|
|
|
NULL, NULL,
|
|
|
|
|
store_inq_cb, &parm,
|
|
|
|
|
NULL, NULL);
|
2020-09-03 13:46:54 +02:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if ( hd->found >= 0 && hd->found < hd->used)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
idx = hd->found;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
else if ( hd->current >= 0 && hd->current < hd->used)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
idx = hd->current;
|
|
|
|
|
else
|
2019-05-14 20:03:44 +02:00
|
|
|
|
{
|
|
|
|
|
err = gpg_error (GPG_ERR_GENERAL);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2003-08-05 19:11:04 +02:00
|
|
|
|
|
2006-05-22 16:35:04 +02:00
|
|
|
|
if (!hd->locked)
|
2019-05-14 20:03:44 +02:00
|
|
|
|
{
|
|
|
|
|
err = gpg_error (GPG_ERR_NOT_LOCKED);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2003-08-05 19:11:04 +02:00
|
|
|
|
|
|
|
|
|
gpgsm_get_fingerprint (cert, GCRY_MD_SHA1, digest, NULL); /* kludge*/
|
|
|
|
|
|
2019-05-14 20:03:44 +02:00
|
|
|
|
err = gpg_error (GPG_ERR_BUG);
|
2011-02-04 12:57:53 +01:00
|
|
|
|
switch (hd->active[idx].type)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
2019-05-14 20:03:44 +02:00
|
|
|
|
err = gpg_error (GPG_ERR_GENERAL);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
2019-05-14 20:03:44 +02:00
|
|
|
|
err = keybox_insert_cert (hd->active[idx].u.kr, cert, digest);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
unlock_all (hd);
|
2019-05-14 20:03:44 +02:00
|
|
|
|
|
|
|
|
|
leave:
|
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("%s: leave (err=%s)\n", __func__, gpg_strerror (err));
|
|
|
|
|
return err;
|
2003-08-05 19:11:04 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2007-03-20 17:57:40 +01:00
|
|
|
|
/* Update the current keyblock with KB. */
|
2019-05-14 20:03:44 +02:00
|
|
|
|
/* Note: This function is currently not called. */
|
|
|
|
|
gpg_error_t
|
2003-12-17 13:28:24 +01:00
|
|
|
|
keydb_update_cert (KEYDB_HANDLE hd, ksba_cert_t cert)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
2020-09-13 20:48:53 +02:00
|
|
|
|
(void)hd;
|
|
|
|
|
(void)cert;
|
|
|
|
|
return GPG_ERR_BUG;
|
|
|
|
|
#if 0
|
2019-05-14 20:03:44 +02:00
|
|
|
|
gpg_error_t err;
|
2005-06-16 10:12:03 +02:00
|
|
|
|
unsigned char digest[20];
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
if (!hd)
|
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if ( hd->found < 0 || hd->found >= hd->used)
|
2019-05-14 20:03:44 +02:00
|
|
|
|
return gpg_error (GPG_ERR_NOT_FOUND);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
|
|
|
|
|
if (opt.dry_run)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2019-05-14 20:03:44 +02:00
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("%s: enter (hd=%p)\n", __func__, hd);
|
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
if (hd->use_keyboxd)
|
|
|
|
|
{
|
|
|
|
|
/* FIXME */
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-14 20:03:44 +02:00
|
|
|
|
err = lock_all (hd);
|
|
|
|
|
if (err)
|
|
|
|
|
goto leave;
|
2003-08-05 19:11:04 +02:00
|
|
|
|
|
|
|
|
|
gpgsm_get_fingerprint (cert, GCRY_MD_SHA1, digest, NULL); /* kludge*/
|
|
|
|
|
|
2019-05-14 20:03:44 +02:00
|
|
|
|
err = gpg_error (GPG_ERR_BUG);
|
2011-02-04 12:57:53 +01:00
|
|
|
|
switch (hd->active[hd->found].type)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
2019-05-14 20:03:44 +02:00
|
|
|
|
err = gpg_error (GPG_ERR_GENERAL); /* oops */
|
2003-08-05 19:11:04 +02:00
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
2019-05-14 20:03:44 +02:00
|
|
|
|
err = keybox_update_cert (hd->active[hd->found].u.kr, cert, digest);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unlock_all (hd);
|
2019-05-14 20:03:44 +02:00
|
|
|
|
leave:
|
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("%s: leave (err=%s)\n", __func__, gpg_strerror (err));
|
|
|
|
|
return err;
|
2020-09-13 20:48:53 +02:00
|
|
|
|
#endif /*0*/
|
2003-08-05 19:11:04 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
/*
|
2003-08-05 19:11:04 +02:00
|
|
|
|
* The current keyblock or cert will be deleted.
|
|
|
|
|
*/
|
2019-05-14 20:03:44 +02:00
|
|
|
|
gpg_error_t
|
2019-05-14 13:36:08 +02:00
|
|
|
|
keydb_delete (KEYDB_HANDLE hd)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
2019-05-14 20:03:44 +02:00
|
|
|
|
gpg_error_t err;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
if (!hd)
|
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
|
|
|
|
|
2020-09-13 20:48:53 +02:00
|
|
|
|
if (!hd->use_keyboxd && (hd->found < 0 || hd->found >= hd->used))
|
2019-05-14 20:03:44 +02:00
|
|
|
|
return gpg_error (GPG_ERR_NOT_FOUND);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
|
2019-05-14 20:03:44 +02:00
|
|
|
|
if (opt.dry_run)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
return 0;
|
|
|
|
|
|
2019-05-14 20:03:44 +02:00
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("%s: enter (hd=%p)\n", __func__, hd);
|
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
if (hd->use_keyboxd)
|
|
|
|
|
{
|
2020-09-13 20:48:53 +02:00
|
|
|
|
unsigned char hexubid[UBID_LEN * 2 + 1];
|
|
|
|
|
char line[ASSUAN_LINELENGTH];
|
|
|
|
|
|
|
|
|
|
if (!hd->last_ubid_valid)
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error (GPG_ERR_VALUE_NOT_FOUND);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bin2hex (hd->last_ubid, UBID_LEN, hexubid);
|
|
|
|
|
snprintf (line, sizeof line, "DELETE %s", hexubid);
|
|
|
|
|
err = assuan_transact (hd->kbl->ctx, line,
|
|
|
|
|
NULL, NULL,
|
|
|
|
|
NULL, NULL,
|
|
|
|
|
NULL, NULL);
|
2020-09-03 13:46:54 +02:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
2004-02-02 18:09:35 +01:00
|
|
|
|
if (!hd->locked)
|
2019-05-14 20:03:44 +02:00
|
|
|
|
{
|
|
|
|
|
err = gpg_error (GPG_ERR_NOT_LOCKED);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2003-08-05 19:11:04 +02:00
|
|
|
|
|
2019-05-14 20:03:44 +02:00
|
|
|
|
err = gpg_error (GPG_ERR_BUG);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
switch (hd->active[hd->found].type)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
2019-05-14 20:03:44 +02:00
|
|
|
|
err = gpg_error (GPG_ERR_GENERAL);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
2019-05-14 20:03:44 +02:00
|
|
|
|
err = keybox_delete (hd->active[hd->found].u.kr);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-14 13:36:08 +02:00
|
|
|
|
unlock_all (hd);
|
2019-05-14 20:03:44 +02:00
|
|
|
|
|
|
|
|
|
leave:
|
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("%s: leave (err=%s)\n", __func__, gpg_strerror (err));
|
|
|
|
|
return err;
|
2003-08-05 19:11:04 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Locate the default writable key resource, so that the next
|
|
|
|
|
* operation (which is only relevant for inserts) will be done on this
|
2011-02-04 12:57:53 +01:00
|
|
|
|
* resource.
|
2003-08-05 19:11:04 +02:00
|
|
|
|
*/
|
2020-09-10 13:05:17 +02:00
|
|
|
|
static gpg_error_t
|
2003-08-05 19:11:04 +02:00
|
|
|
|
keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved)
|
|
|
|
|
{
|
|
|
|
|
int rc;
|
2008-10-20 15:53:23 +02:00
|
|
|
|
|
|
|
|
|
(void)reserved;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
if (!hd)
|
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
if (hd->use_keyboxd)
|
|
|
|
|
return 0; /* Not required. */
|
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
rc = keydb_search_reset (hd); /* this does reset hd->current */
|
|
|
|
|
if (rc)
|
|
|
|
|
return rc;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
|
|
|
|
for ( ; hd->current >= 0 && hd->current < hd->used; hd->current++)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
2011-02-04 12:57:53 +01:00
|
|
|
|
switch (hd->active[hd->current].type)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2020-09-10 13:05:17 +02:00
|
|
|
|
return gpg_error (GPG_ERR_NOT_FOUND);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Rebuild the caches of all key resources.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
keydb_rebuild_caches (void)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
/* This function does nothing and thus we don't need to handle keyboxd in a
|
|
|
|
|
* special way. */
|
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
for (i=0; i < used_resources; i++)
|
|
|
|
|
{
|
|
|
|
|
switch (all_resources[i].type)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE: /* ignore */
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
/* rc = keybox_rebuild_cache (all_resources[i].token); */
|
|
|
|
|
/* if (rc) */
|
|
|
|
|
/* log_error (_("failed to rebuild keybox cache: %s\n"), */
|
|
|
|
|
/* g10_errstr (rc)); */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
/*
|
2003-08-05 19:11:04 +02:00
|
|
|
|
* Start the next search on this handle right at the beginning
|
|
|
|
|
*/
|
2016-01-13 15:08:42 +01:00
|
|
|
|
gpg_error_t
|
2003-08-05 19:11:04 +02:00
|
|
|
|
keydb_search_reset (KEYDB_HANDLE hd)
|
|
|
|
|
{
|
2019-05-14 20:03:44 +02:00
|
|
|
|
gpg_error_t err = 0;
|
2016-01-13 15:08:42 +01:00
|
|
|
|
int i;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
if (!hd)
|
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
|
|
|
|
|
2019-05-14 20:03:44 +02:00
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("%s: enter (hd=%p)\n", __func__, hd);
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
hd->current = 0;
|
2003-08-05 19:11:04 +02:00
|
|
|
|
hd->found = -1;
|
2020-09-03 13:46:54 +02:00
|
|
|
|
if (hd->use_keyboxd)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
2020-09-10 13:05:17 +02:00
|
|
|
|
/* All we need is to tell search that a reset is pending. Note that
|
|
|
|
|
* keydb_new sets this flag as well. To comply with the
|
|
|
|
|
* specification of keydb_delete_keyblock we also need to clear the
|
|
|
|
|
* ubid flag so that after a reset a delete can't be performed. */
|
|
|
|
|
hd->kbl->need_search_reset = 1;
|
|
|
|
|
hd->last_ubid_valid = 0;
|
|
|
|
|
}
|
2020-09-03 13:46:54 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
2020-09-10 13:05:17 +02:00
|
|
|
|
/* Reset all resources */
|
2020-09-03 13:46:54 +02:00
|
|
|
|
for (i=0; !err && i < hd->used; i++)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
2020-09-03 13:46:54 +02:00
|
|
|
|
switch (hd->active[i].type)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
|
|
|
|
err = keybox_search_reset (hd->active[i].u.kr);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2003-08-05 19:11:04 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-05-14 20:03:44 +02:00
|
|
|
|
|
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("%s: leave (err=%s)\n", __func__, gpg_strerror (err));
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
keydb_search_desc_dump (struct keydb_search_desc *desc)
|
|
|
|
|
{
|
|
|
|
|
char *fpr;
|
|
|
|
|
char *result;
|
|
|
|
|
|
|
|
|
|
switch (desc->mode)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_SEARCH_MODE_EXACT:
|
|
|
|
|
return xasprintf ("EXACT: '%s'", desc->u.name);
|
|
|
|
|
case KEYDB_SEARCH_MODE_SUBSTR:
|
|
|
|
|
return xasprintf ("SUBSTR: '%s'", desc->u.name);
|
|
|
|
|
case KEYDB_SEARCH_MODE_MAIL:
|
|
|
|
|
return xasprintf ("MAIL: '%s'", desc->u.name);
|
|
|
|
|
case KEYDB_SEARCH_MODE_MAILSUB:
|
|
|
|
|
return xasprintf ("MAILSUB: '%s'", desc->u.name);
|
|
|
|
|
case KEYDB_SEARCH_MODE_MAILEND:
|
|
|
|
|
return xasprintf ("MAILEND: '%s'", desc->u.name);
|
|
|
|
|
case KEYDB_SEARCH_MODE_WORDS:
|
|
|
|
|
return xasprintf ("WORDS: '%s'", desc->u.name);
|
|
|
|
|
case KEYDB_SEARCH_MODE_SHORT_KID:
|
|
|
|
|
return xasprintf ("SHORT_KID: '%08lX'", (ulong)desc->u.kid[1]);
|
|
|
|
|
case KEYDB_SEARCH_MODE_LONG_KID:
|
|
|
|
|
return xasprintf ("LONG_KID: '%08lX%08lX'",
|
|
|
|
|
(ulong)desc->u.kid[0], (ulong)desc->u.kid[1]);
|
|
|
|
|
case KEYDB_SEARCH_MODE_FPR:
|
|
|
|
|
fpr = bin2hexcolon (desc->u.fpr, desc->fprlen, NULL);
|
|
|
|
|
result = xasprintf ("FPR%02d: '%s'", desc->fprlen, fpr);
|
|
|
|
|
xfree (fpr);
|
|
|
|
|
return result;
|
|
|
|
|
case KEYDB_SEARCH_MODE_ISSUER:
|
|
|
|
|
return xasprintf ("ISSUER: '%s'", desc->u.name);
|
|
|
|
|
case KEYDB_SEARCH_MODE_ISSUER_SN:
|
2020-09-08 10:05:08 +02:00
|
|
|
|
return xasprintf ("ISSUER_SN: '#%.*s/%s'",
|
|
|
|
|
(int)desc->snlen,desc->sn, desc->u.name);
|
2019-05-14 20:03:44 +02:00
|
|
|
|
case KEYDB_SEARCH_MODE_SN:
|
2020-09-08 10:05:08 +02:00
|
|
|
|
return xasprintf ("SN: '%.*s'",
|
|
|
|
|
(int)desc->snlen, desc->sn);
|
2019-05-14 20:03:44 +02:00
|
|
|
|
case KEYDB_SEARCH_MODE_SUBJECT:
|
|
|
|
|
return xasprintf ("SUBJECT: '%s'", desc->u.name);
|
|
|
|
|
case KEYDB_SEARCH_MODE_KEYGRIP:
|
|
|
|
|
return xasprintf ("KEYGRIP: %s", desc->u.grip);
|
|
|
|
|
case KEYDB_SEARCH_MODE_FIRST:
|
|
|
|
|
return xasprintf ("FIRST");
|
|
|
|
|
case KEYDB_SEARCH_MODE_NEXT:
|
|
|
|
|
return xasprintf ("NEXT");
|
|
|
|
|
default:
|
|
|
|
|
return xasprintf ("Bad search mode (%d)", desc->mode);
|
|
|
|
|
}
|
2003-08-05 19:11:04 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-14 20:03:44 +02:00
|
|
|
|
|
2020-09-10 13:05:17 +02:00
|
|
|
|
|
|
|
|
|
/* Status callback for SEARCH and NEXT operaions. */
|
|
|
|
|
static gpg_error_t
|
|
|
|
|
search_status_cb (void *opaque, const char *line)
|
|
|
|
|
{
|
|
|
|
|
KEYDB_HANDLE hd = opaque;
|
|
|
|
|
gpg_error_t err = 0;
|
|
|
|
|
const char *s;
|
2020-09-22 16:15:47 +02:00
|
|
|
|
unsigned int n;
|
2020-09-10 13:05:17 +02:00
|
|
|
|
|
|
|
|
|
if ((s = has_leading_keyword (line, "PUBKEY_INFO")))
|
|
|
|
|
{
|
|
|
|
|
if (atoi (s) != PUBKEY_TYPE_X509)
|
|
|
|
|
err = gpg_error (GPG_ERR_WRONG_BLOB_TYPE);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
hd->last_ubid_valid = 0;
|
|
|
|
|
while (*s && !spacep (s))
|
|
|
|
|
s++;
|
2020-09-22 16:15:47 +02:00
|
|
|
|
if (!(n=hex2fixedbuf (s, hd->last_ubid, sizeof hd->last_ubid)))
|
2020-09-10 13:05:17 +02:00
|
|
|
|
err = gpg_error (GPG_ERR_INV_VALUE);
|
2020-09-22 16:15:47 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
hd->last_ubid_valid = 1;
|
|
|
|
|
s += n;
|
|
|
|
|
hd->last_is_ephemeral = (*s == 'e');
|
|
|
|
|
}
|
2020-09-10 13:05:17 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Search through all keydb resources, starting at the current
|
|
|
|
|
* position, for a keyblock which contains one of the keys described
|
|
|
|
|
* in the DESC array. In keyboxd mode the search is instead delegated
|
|
|
|
|
* to the keyboxd.
|
|
|
|
|
*
|
|
|
|
|
* DESC is an array of search terms with NDESC entries. The search
|
|
|
|
|
* terms are or'd together. That is, the next entry in the DB that
|
|
|
|
|
* matches any of the descriptions will be returned.
|
|
|
|
|
*
|
|
|
|
|
* Note: this function resumes searching where the last search left
|
|
|
|
|
* off (i.e., at the current file position). If you want to search
|
|
|
|
|
* from the start of the database, then you need to first call
|
|
|
|
|
* keydb_search_reset().
|
|
|
|
|
*
|
|
|
|
|
* If no key matches the search description, the error code
|
|
|
|
|
* GPG_ERR_NOT_FOUND is retruned. If there was a match, 0 is
|
|
|
|
|
* returned. If an error occurred, that error code is returned.
|
|
|
|
|
*
|
|
|
|
|
* The returned key is considered to be selected and the certificate
|
|
|
|
|
* can be detched via keydb_get_cert. */
|
|
|
|
|
gpg_error_t
|
2016-11-10 17:01:19 +01:00
|
|
|
|
keydb_search (ctrl_t ctrl, KEYDB_HANDLE hd,
|
|
|
|
|
KEYDB_SEARCH_DESC *desc, size_t ndesc)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
2020-09-10 13:05:17 +02:00
|
|
|
|
gpg_error_t err = gpg_error (GPG_ERR_EOF);
|
2014-10-09 21:01:49 +02:00
|
|
|
|
unsigned long skipped;
|
2019-05-14 20:03:44 +02:00
|
|
|
|
int i;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
if (!hd)
|
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
if (!any_registered && !hd->use_keyboxd)
|
2016-11-10 17:01:19 +01:00
|
|
|
|
{
|
|
|
|
|
gpgsm_status_with_error (ctrl, STATUS_ERROR, "keydb_search",
|
|
|
|
|
gpg_error (GPG_ERR_KEYRING_OPEN));
|
|
|
|
|
return gpg_error (GPG_ERR_NOT_FOUND);
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-14 20:03:44 +02:00
|
|
|
|
if (DBG_CLOCK)
|
|
|
|
|
log_clock ("%s: enter (hd=%p)\n", __func__, hd);
|
|
|
|
|
|
|
|
|
|
if (DBG_LOOKUP)
|
|
|
|
|
{
|
|
|
|
|
log_debug ("%s: %zd search description(s):\n", __func__, ndesc);
|
|
|
|
|
for (i = 0; i < ndesc; i ++)
|
|
|
|
|
{
|
|
|
|
|
char *t = keydb_search_desc_dump (&desc[i]);
|
|
|
|
|
log_debug ("%s: %d: %s\n", __func__, i, t);
|
|
|
|
|
xfree (t);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
if (hd->use_keyboxd)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
2020-09-10 13:05:17 +02:00
|
|
|
|
char line[ASSUAN_LINELENGTH];
|
|
|
|
|
|
|
|
|
|
/* Clear the result objects. */
|
|
|
|
|
if (hd->kbl->search_result.buf)
|
|
|
|
|
{
|
|
|
|
|
xfree (hd->kbl->search_result.buf);
|
|
|
|
|
hd->kbl->search_result.buf = NULL;
|
|
|
|
|
hd->kbl->search_result.len = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check whether this is a NEXT search. */
|
|
|
|
|
if (!hd->kbl->need_search_reset)
|
|
|
|
|
{
|
|
|
|
|
/* A reset was not requested thus continue the search. The
|
|
|
|
|
* keyboxd keeps the context of the search and thus the NEXT
|
|
|
|
|
* operates on the last search pattern. This is the way how
|
|
|
|
|
* we always used the keydb functions. In theory we were
|
|
|
|
|
* able to modify the search pattern between searches but
|
|
|
|
|
* that is not anymore supported by keyboxd and a cursory
|
|
|
|
|
* check does not show that we actually made use of that
|
|
|
|
|
* misfeature. */
|
|
|
|
|
snprintf (line, sizeof line, "NEXT --x509");
|
|
|
|
|
goto do_search;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hd->kbl->need_search_reset = 0;
|
|
|
|
|
|
|
|
|
|
if (!ndesc)
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error (GPG_ERR_INV_ARG);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* FIXME: Implement --multi */
|
|
|
|
|
switch (desc->mode)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_SEARCH_MODE_EXACT:
|
|
|
|
|
snprintf (line, sizeof line, "SEARCH --x509 =%s", desc[0].u.name);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case KEYDB_SEARCH_MODE_SUBSTR:
|
|
|
|
|
snprintf (line, sizeof line, "SEARCH --x509 *%s", desc[0].u.name);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case KEYDB_SEARCH_MODE_MAIL:
|
2021-04-21 14:31:57 +02:00
|
|
|
|
snprintf (line, sizeof line, "SEARCH --x509 <%s",
|
|
|
|
|
desc[0].u.name + (desc[0].u.name[0] == '<'));
|
2020-09-10 13:05:17 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case KEYDB_SEARCH_MODE_MAILSUB:
|
|
|
|
|
snprintf (line, sizeof line, "SEARCH --x509 @%s", desc[0].u.name);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case KEYDB_SEARCH_MODE_MAILEND:
|
|
|
|
|
snprintf (line, sizeof line, "SEARCH --x509 .%s", desc[0].u.name);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case KEYDB_SEARCH_MODE_WORDS:
|
|
|
|
|
snprintf (line, sizeof line, "SEARCH --x509 +%s", desc[0].u.name);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case KEYDB_SEARCH_MODE_SHORT_KID:
|
|
|
|
|
snprintf (line, sizeof line, "SEARCH --x509 0x%08lX",
|
|
|
|
|
(ulong)desc->u.kid[1]);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case KEYDB_SEARCH_MODE_LONG_KID:
|
|
|
|
|
snprintf (line, sizeof line, "SEARCH --x509 0x%08lX%08lX",
|
|
|
|
|
(ulong)desc->u.kid[0], (ulong)desc->u.kid[1]);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case KEYDB_SEARCH_MODE_FPR:
|
|
|
|
|
{
|
|
|
|
|
unsigned char hexfpr[MAX_FINGERPRINT_LEN * 2 + 1];
|
|
|
|
|
log_assert (desc[0].fprlen <= MAX_FINGERPRINT_LEN);
|
|
|
|
|
bin2hex (desc[0].u.fpr, desc[0].fprlen, hexfpr);
|
|
|
|
|
snprintf (line, sizeof line, "SEARCH --x509 0x%s", hexfpr);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case KEYDB_SEARCH_MODE_ISSUER:
|
|
|
|
|
snprintf (line, sizeof line, "SEARCH --x509 #/%s", desc[0].u.name);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case KEYDB_SEARCH_MODE_ISSUER_SN:
|
|
|
|
|
if (desc[0].snhex)
|
|
|
|
|
snprintf (line, sizeof line, "SEARCH --x509 #%.*s/%s",
|
|
|
|
|
(int)desc[0].snlen, desc[0].sn, desc[0].u.name);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
char *hexsn = bin2hex (desc[0].sn, desc[0].snlen, NULL);
|
|
|
|
|
if (!hexsn)
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
snprintf (line, sizeof line, "SEARCH --x509 #%s/%s",
|
|
|
|
|
hexsn, desc[0].u.name);
|
|
|
|
|
xfree (hexsn);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case KEYDB_SEARCH_MODE_SN:
|
|
|
|
|
snprintf (line, sizeof line, "SEARCH --x509 #%s", desc[0].u.name);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case KEYDB_SEARCH_MODE_SUBJECT:
|
|
|
|
|
snprintf (line, sizeof line, "SEARCH --x509 /%s", desc[0].u.name);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case KEYDB_SEARCH_MODE_KEYGRIP:
|
|
|
|
|
{
|
|
|
|
|
unsigned char hexgrip[KEYGRIP_LEN * 2 + 1];
|
|
|
|
|
bin2hex (desc[0].u.grip, KEYGRIP_LEN, hexgrip);
|
|
|
|
|
snprintf (line, sizeof line, "SEARCH --x509 &%s", hexgrip);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case KEYDB_SEARCH_MODE_UBID:
|
|
|
|
|
{
|
|
|
|
|
unsigned char hexubid[UBID_LEN * 2 + 1];
|
|
|
|
|
bin2hex (desc[0].u.ubid, UBID_LEN, hexubid);
|
|
|
|
|
snprintf (line, sizeof line, "SEARCH --x509 ^%s", hexubid);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case KEYDB_SEARCH_MODE_FIRST:
|
|
|
|
|
snprintf (line, sizeof line, "SEARCH --x509");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case KEYDB_SEARCH_MODE_NEXT:
|
|
|
|
|
log_debug ("%s: mode next - we should not get to here!\n", __func__);
|
|
|
|
|
snprintf (line, sizeof line, "NEXT --x509");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
err = gpg_error (GPG_ERR_INV_ARG);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
do_search:
|
|
|
|
|
hd->last_ubid_valid = 0;
|
|
|
|
|
/* To avoid silent truncation we error out on a too long line. */
|
|
|
|
|
if (strlen (line) + 5 >= sizeof line)
|
|
|
|
|
err = gpg_error (GPG_ERR_ASS_LINE_TOO_LONG);
|
|
|
|
|
else
|
|
|
|
|
err = kbx_client_data_cmd (hd->kbl->kcd, line, search_status_cb, hd);
|
|
|
|
|
if (!err && !(err = kbx_client_data_wait (hd->kbl->kcd,
|
|
|
|
|
&hd->kbl->search_result.buf,
|
|
|
|
|
&hd->kbl->search_result.len)))
|
|
|
|
|
{
|
|
|
|
|
/* if (hd->last_ubid_valid) */
|
2020-09-13 20:48:53 +02:00
|
|
|
|
/* log_printhex (hd->last_ubid, 20, "found UBID%s:", */
|
|
|
|
|
/* hd->last_is_ephemeral? "(ephemeral)":""); */
|
2020-09-10 13:05:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
}
|
2020-09-10 13:05:17 +02:00
|
|
|
|
else /* Local keyring search. */
|
2020-09-03 13:46:54 +02:00
|
|
|
|
{
|
2020-09-10 13:05:17 +02:00
|
|
|
|
while (gpg_err_code (err) == GPG_ERR_EOF
|
2020-09-03 13:46:54 +02:00
|
|
|
|
&& hd->current >= 0 && hd->current < hd->used)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
2020-09-03 13:46:54 +02:00
|
|
|
|
switch (hd->active[hd->current].type)
|
|
|
|
|
{
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_NONE:
|
|
|
|
|
BUG(); /* we should never see it here */
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
2020-09-10 13:05:17 +02:00
|
|
|
|
err = keybox_search (hd->active[hd->current].u.kr, desc, ndesc,
|
|
|
|
|
KEYBOX_BLOBTYPE_X509,
|
|
|
|
|
NULL, &skipped);
|
|
|
|
|
if (err == -1) /* Map legacy code. */
|
|
|
|
|
err = gpg_error (GPG_ERR_EOF);
|
2020-09-03 13:46:54 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
2019-05-14 20:03:44 +02:00
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
if (DBG_LOOKUP)
|
|
|
|
|
log_debug ("%s: searched %s (resource %d of %d) => %s\n",
|
|
|
|
|
__func__,
|
|
|
|
|
hd->active[hd->current].type==KEYDB_RESOURCE_TYPE_KEYBOX
|
|
|
|
|
? "keybox" : "unknown type",
|
2020-09-10 13:05:17 +02:00
|
|
|
|
hd->current, hd->used, gpg_strerror (err));
|
2020-09-03 13:46:54 +02:00
|
|
|
|
|
2020-09-10 13:05:17 +02:00
|
|
|
|
if (gpg_err_code (err) == GPG_ERR_EOF)
|
2020-09-03 13:46:54 +02:00
|
|
|
|
{ /* EOF -> switch to next resource */
|
|
|
|
|
hd->current++;
|
|
|
|
|
}
|
2020-09-10 13:05:17 +02:00
|
|
|
|
else if (!err)
|
2020-09-03 13:46:54 +02:00
|
|
|
|
hd->found = hd->current;
|
2016-01-13 15:08:42 +01:00
|
|
|
|
}
|
2003-08-05 19:11:04 +02:00
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2020-09-10 13:05:17 +02:00
|
|
|
|
leave:
|
|
|
|
|
/* The NOTHING_FOUND error is triggered by a NEXT command. */
|
|
|
|
|
if (gpg_err_code (err) == GPG_ERR_EOF
|
|
|
|
|
|| gpg_err_code (err) == GPG_ERR_NOTHING_FOUND)
|
|
|
|
|
err = gpg_error (GPG_ERR_NOT_FOUND);
|
2019-05-14 20:03:44 +02:00
|
|
|
|
if (DBG_CLOCK)
|
2020-09-10 13:05:17 +02:00
|
|
|
|
log_clock ("%s: leave (%s)\n", __func__, gpg_strerror (err));
|
|
|
|
|
return err;
|
2003-08-05 19:11:04 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2016-11-10 17:01:19 +01:00
|
|
|
|
keydb_search_first (ctrl_t ctrl, KEYDB_HANDLE hd)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
|
|
|
|
KEYDB_SEARCH_DESC desc;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
memset (&desc, 0, sizeof desc);
|
|
|
|
|
desc.mode = KEYDB_SEARCH_MODE_FIRST;
|
2016-11-10 17:01:19 +01:00
|
|
|
|
return keydb_search (ctrl, hd, &desc, 1);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
2016-11-10 17:01:19 +01:00
|
|
|
|
keydb_search_next (ctrl_t ctrl, KEYDB_HANDLE hd)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
|
|
|
|
KEYDB_SEARCH_DESC desc;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
memset (&desc, 0, sizeof desc);
|
|
|
|
|
desc.mode = KEYDB_SEARCH_MODE_NEXT;
|
2016-11-10 17:01:19 +01:00
|
|
|
|
return keydb_search (ctrl, hd, &desc, 1);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
2016-11-10 17:01:19 +01:00
|
|
|
|
keydb_search_kid (ctrl_t ctrl, KEYDB_HANDLE hd, u32 *kid)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
|
|
|
|
KEYDB_SEARCH_DESC desc;
|
2008-10-20 15:53:23 +02:00
|
|
|
|
|
|
|
|
|
(void)kid;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
memset (&desc, 0, sizeof desc);
|
|
|
|
|
desc.mode = KEYDB_SEARCH_MODE_LONG_KID;
|
2009-12-08 17:30:33 +01:00
|
|
|
|
desc.u.kid[0] = kid[0];
|
|
|
|
|
desc.u.kid[1] = kid[1];
|
2016-11-10 17:01:19 +01:00
|
|
|
|
return keydb_search (ctrl, hd, &desc, 1);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
2016-11-10 17:01:19 +01:00
|
|
|
|
keydb_search_fpr (ctrl_t ctrl, KEYDB_HANDLE hd, const byte *fpr)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
|
|
|
|
KEYDB_SEARCH_DESC desc;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
memset (&desc, 0, sizeof desc);
|
|
|
|
|
desc.mode = KEYDB_SEARCH_MODE_FPR;
|
|
|
|
|
memcpy (desc.u.fpr, fpr, 20);
|
2019-03-14 08:54:59 +01:00
|
|
|
|
desc.fprlen = 20;
|
2016-11-10 17:01:19 +01:00
|
|
|
|
return keydb_search (ctrl, hd, &desc, 1);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
2016-11-10 17:01:19 +01:00
|
|
|
|
keydb_search_issuer (ctrl_t ctrl, KEYDB_HANDLE hd, const char *issuer)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
|
|
|
|
KEYDB_SEARCH_DESC desc;
|
|
|
|
|
int rc;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
memset (&desc, 0, sizeof desc);
|
|
|
|
|
desc.mode = KEYDB_SEARCH_MODE_ISSUER;
|
|
|
|
|
desc.u.name = issuer;
|
2016-11-10 17:01:19 +01:00
|
|
|
|
rc = keydb_search (ctrl, hd, &desc, 1);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
2016-11-10 17:01:19 +01:00
|
|
|
|
keydb_search_issuer_sn (ctrl_t ctrl, KEYDB_HANDLE hd,
|
2003-12-17 13:28:24 +01:00
|
|
|
|
const char *issuer, ksba_const_sexp_t serial)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
|
|
|
|
KEYDB_SEARCH_DESC desc;
|
|
|
|
|
int rc;
|
|
|
|
|
const unsigned char *s;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
memset (&desc, 0, sizeof desc);
|
|
|
|
|
desc.mode = KEYDB_SEARCH_MODE_ISSUER_SN;
|
|
|
|
|
s = serial;
|
|
|
|
|
if (*s !='(')
|
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
|
|
|
|
s++;
|
|
|
|
|
for (desc.snlen = 0; digitp (s); s++)
|
|
|
|
|
desc.snlen = 10*desc.snlen + atoi_1 (s);
|
|
|
|
|
if (*s !=':')
|
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
|
|
|
|
desc.sn = s+1;
|
|
|
|
|
desc.u.name = issuer;
|
2016-11-10 17:01:19 +01:00
|
|
|
|
rc = keydb_search (ctrl, hd, &desc, 1);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
2016-11-10 17:01:19 +01:00
|
|
|
|
keydb_search_subject (ctrl_t ctrl, KEYDB_HANDLE hd, const char *name)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
|
|
|
|
KEYDB_SEARCH_DESC desc;
|
|
|
|
|
int rc;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
memset (&desc, 0, sizeof desc);
|
|
|
|
|
desc.mode = KEYDB_SEARCH_MODE_SUBJECT;
|
|
|
|
|
desc.u.name = name;
|
2016-11-10 17:01:19 +01:00
|
|
|
|
rc = keydb_search (ctrl, hd, &desc, 1);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* 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. */
|
|
|
|
|
int
|
2016-11-10 17:01:19 +01:00
|
|
|
|
keydb_store_cert (ctrl_t ctrl, ksba_cert_t cert, int ephemeral, int *existed)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
|
|
|
|
KEYDB_HANDLE kh;
|
|
|
|
|
int rc;
|
|
|
|
|
unsigned char fpr[20];
|
|
|
|
|
|
|
|
|
|
if (existed)
|
|
|
|
|
*existed = 0;
|
|
|
|
|
|
|
|
|
|
if (!gpgsm_get_fingerprint (cert, 0, fpr, NULL))
|
|
|
|
|
{
|
|
|
|
|
log_error (_("failed to get the fingerprint\n"));
|
|
|
|
|
return gpg_error (GPG_ERR_GENERAL);
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-02 17:27:30 +02:00
|
|
|
|
kh = keydb_new (ctrl);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
if (!kh)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("failed to allocate keyDB handle\n"));
|
|
|
|
|
return gpg_error (GPG_ERR_ENOMEM);;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-24 18:55:24 +02:00
|
|
|
|
/* Set the ephemeral flag so that the search looks at all
|
|
|
|
|
records. */
|
|
|
|
|
keydb_set_ephemeral (kh, 1);
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
if (!kh->use_keyboxd)
|
|
|
|
|
{
|
|
|
|
|
rc = lock_all (kh);
|
|
|
|
|
if (rc)
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
2006-05-22 16:35:04 +02:00
|
|
|
|
|
2016-11-10 17:01:19 +01:00
|
|
|
|
rc = keydb_search_fpr (ctrl, kh, fpr);
|
2020-09-10 13:05:17 +02:00
|
|
|
|
if (gpg_err_code (rc) != GPG_ERR_NOT_FOUND)
|
2003-08-05 19:11:04 +02:00
|
|
|
|
{
|
|
|
|
|
keydb_release (kh);
|
|
|
|
|
if (!rc)
|
|
|
|
|
{
|
|
|
|
|
if (existed)
|
|
|
|
|
*existed = 1;
|
2015-06-24 18:55:24 +02:00
|
|
|
|
if (!ephemeral)
|
|
|
|
|
{
|
|
|
|
|
/* Remove ephemeral flags from existing certificate to "store"
|
|
|
|
|
it permanently. */
|
2016-11-10 17:01:19 +01:00
|
|
|
|
rc = keydb_set_cert_flags (ctrl, cert, 1, KEYBOX_FLAG_BLOB, 0,
|
2015-06-24 18:55:24 +02:00
|
|
|
|
KEYBOX_FLAG_BLOB_EPHEMERAL, 0);
|
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
log_error ("clearing ephemeral flag failed: %s\n",
|
|
|
|
|
gpg_strerror (rc));
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-08-05 19:11:04 +02:00
|
|
|
|
return 0; /* okay */
|
|
|
|
|
}
|
|
|
|
|
log_error (_("problem looking for existing certificate: %s\n"),
|
|
|
|
|
gpg_strerror (rc));
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-24 18:55:24 +02:00
|
|
|
|
/* Reset the ephemeral flag if not requested. */
|
|
|
|
|
if (!ephemeral)
|
|
|
|
|
keydb_set_ephemeral (kh, 0);
|
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
|
rc = keydb_locate_writable (kh, 0);
|
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("error finding writable keyDB: %s\n"), gpg_strerror (rc));
|
|
|
|
|
keydb_release (kh);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = keydb_insert_cert (kh, cert);
|
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("error storing certificate: %s\n"), gpg_strerror (rc));
|
|
|
|
|
keydb_release (kh);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
keydb_release (kh);
|
2003-08-05 19:11:04 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2004-02-02 18:09:35 +01:00
|
|
|
|
/* This is basically keydb_set_flags but it implements a complete
|
2004-04-28 10:59:34 +02:00
|
|
|
|
transaction by locating the certificate in the DB and updating the
|
2004-02-02 18:09:35 +01:00
|
|
|
|
flags. */
|
|
|
|
|
gpg_error_t
|
2016-11-10 17:01:19 +01:00
|
|
|
|
keydb_set_cert_flags (ctrl_t ctrl, ksba_cert_t cert, int ephemeral,
|
2011-02-04 12:57:53 +01:00
|
|
|
|
int which, int idx,
|
2007-03-20 17:57:40 +01:00
|
|
|
|
unsigned int mask, unsigned int value)
|
2004-02-02 18:09:35 +01:00
|
|
|
|
{
|
|
|
|
|
KEYDB_HANDLE kh;
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
unsigned char fpr[20];
|
|
|
|
|
unsigned int old_value;
|
|
|
|
|
|
|
|
|
|
if (!gpgsm_get_fingerprint (cert, 0, fpr, NULL))
|
|
|
|
|
{
|
|
|
|
|
log_error (_("failed to get the fingerprint\n"));
|
|
|
|
|
return gpg_error (GPG_ERR_GENERAL);
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-02 17:27:30 +02:00
|
|
|
|
kh = keydb_new (ctrl);
|
2004-02-02 18:09:35 +01:00
|
|
|
|
if (!kh)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("failed to allocate keyDB handle\n"));
|
|
|
|
|
return gpg_error (GPG_ERR_ENOMEM);;
|
|
|
|
|
}
|
|
|
|
|
|
2007-03-20 17:57:40 +01:00
|
|
|
|
if (ephemeral)
|
|
|
|
|
keydb_set_ephemeral (kh, 1);
|
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
if (!kh->use_keyboxd)
|
2004-02-02 18:09:35 +01:00
|
|
|
|
{
|
2020-09-03 13:46:54 +02:00
|
|
|
|
err = keydb_lock (kh);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("error locking keybox: %s\n"), gpg_strerror (err));
|
|
|
|
|
keydb_release (kh);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
2004-02-02 18:09:35 +01:00
|
|
|
|
}
|
|
|
|
|
|
2016-11-10 17:01:19 +01:00
|
|
|
|
err = keydb_search_fpr (ctrl, kh, fpr);
|
2004-02-02 18:09:35 +01:00
|
|
|
|
if (err)
|
|
|
|
|
{
|
2022-12-05 17:30:26 +01:00
|
|
|
|
if (gpg_err_code (err) != GPG_ERR_NOT_FOUND)
|
2007-03-20 17:57:40 +01:00
|
|
|
|
log_error (_("problem re-searching certificate: %s\n"),
|
|
|
|
|
gpg_strerror (err));
|
2004-02-02 18:09:35 +01:00
|
|
|
|
keydb_release (kh);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = keydb_get_flags (kh, which, idx, &old_value);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("error getting stored flags: %s\n"), gpg_strerror (err));
|
|
|
|
|
keydb_release (kh);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
2007-03-20 17:57:40 +01:00
|
|
|
|
|
|
|
|
|
value = ((old_value & ~mask) | (value & mask));
|
|
|
|
|
|
2004-02-02 18:09:35 +01:00
|
|
|
|
if (value != old_value)
|
|
|
|
|
{
|
|
|
|
|
err = keydb_set_flags (kh, which, idx, value);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("error storing flags: %s\n"), gpg_strerror (err));
|
|
|
|
|
keydb_release (kh);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-03-20 17:57:40 +01:00
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
keydb_release (kh);
|
2004-02-02 18:09:35 +01:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2003-08-05 19:11:04 +02:00
|
|
|
|
|
2004-04-28 10:59:34 +02:00
|
|
|
|
|
|
|
|
|
/* Reset all the certificate flags we have stored with the certificates
|
|
|
|
|
for performance reasons. */
|
|
|
|
|
void
|
2006-10-02 13:54:35 +02:00
|
|
|
|
keydb_clear_some_cert_flags (ctrl_t ctrl, strlist_t names)
|
2004-04-28 10:59:34 +02:00
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
KEYDB_HANDLE hd = NULL;
|
|
|
|
|
KEYDB_SEARCH_DESC *desc = NULL;
|
|
|
|
|
int ndesc;
|
2006-10-02 13:54:35 +02:00
|
|
|
|
strlist_t sl;
|
2004-04-28 10:59:34 +02:00
|
|
|
|
int rc=0;
|
|
|
|
|
unsigned int old_value, value;
|
2008-10-20 15:53:23 +02:00
|
|
|
|
|
|
|
|
|
(void)ctrl;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2020-09-02 17:27:30 +02:00
|
|
|
|
hd = keydb_new (ctrl);
|
2004-04-28 10:59:34 +02:00
|
|
|
|
if (!hd)
|
|
|
|
|
{
|
|
|
|
|
log_error ("keydb_new failed\n");
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!names)
|
|
|
|
|
ndesc = 1;
|
|
|
|
|
else
|
|
|
|
|
{
|
2011-02-04 12:57:53 +01:00
|
|
|
|
for (sl=names, ndesc=0; sl; sl = sl->next, ndesc++)
|
2004-04-28 10:59:34 +02:00
|
|
|
|
;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
desc = xtrycalloc (ndesc, sizeof *desc);
|
|
|
|
|
if (!ndesc)
|
|
|
|
|
{
|
|
|
|
|
log_error ("allocating memory failed: %s\n",
|
2006-09-06 18:35:52 +02:00
|
|
|
|
gpg_strerror (out_of_core ()));
|
2004-04-28 10:59:34 +02:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!names)
|
|
|
|
|
desc[0].mode = KEYDB_SEARCH_MODE_FIRST;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
else
|
2004-04-28 10:59:34 +02:00
|
|
|
|
{
|
2011-02-04 12:57:53 +01:00
|
|
|
|
for (ndesc=0, sl=names; sl; sl = sl->next)
|
2004-04-28 10:59:34 +02:00
|
|
|
|
{
|
2011-04-25 23:56:47 +02:00
|
|
|
|
rc = classify_user_id (sl->d, desc+ndesc, 0);
|
2004-04-28 10:59:34 +02:00
|
|
|
|
if (rc)
|
2016-01-06 17:51:58 +01:00
|
|
|
|
log_error ("key '%s' not found: %s\n", sl->d, gpg_strerror (rc));
|
2004-04-28 10:59:34 +02:00
|
|
|
|
else
|
|
|
|
|
ndesc++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-03 13:46:54 +02:00
|
|
|
|
if (!hd->use_keyboxd)
|
2004-04-28 10:59:34 +02:00
|
|
|
|
{
|
2020-09-03 13:46:54 +02:00
|
|
|
|
err = keydb_lock (hd);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("error locking keybox: %s\n"), gpg_strerror (err));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2004-04-28 10:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-11-10 17:01:19 +01:00
|
|
|
|
while (!(rc = keydb_search (ctrl, hd, desc, ndesc)))
|
2004-04-28 10:59:34 +02:00
|
|
|
|
{
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (!names)
|
2004-04-28 10:59:34 +02:00
|
|
|
|
desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
|
|
|
|
|
|
|
|
|
|
err = keydb_get_flags (hd, KEYBOX_FLAG_VALIDITY, 0, &old_value);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("error getting stored flags: %s\n"),
|
|
|
|
|
gpg_strerror (err));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2004-04-28 10:59:34 +02:00
|
|
|
|
value = (old_value & ~VALIDITY_REVOKED);
|
|
|
|
|
if (value != old_value)
|
|
|
|
|
{
|
|
|
|
|
err = keydb_set_flags (hd, KEYBOX_FLAG_VALIDITY, 0, value);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("error storing flags: %s\n"), gpg_strerror (err));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-10 13:05:17 +02:00
|
|
|
|
if (rc && gpg_err_code (rc) != GPG_ERR_NOT_FOUND)
|
2004-04-28 10:59:34 +02:00
|
|
|
|
log_error ("keydb_search failed: %s\n", gpg_strerror (rc));
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2004-04-28 10:59:34 +02:00
|
|
|
|
leave:
|
|
|
|
|
xfree (desc);
|
|
|
|
|
keydb_release (hd);
|
|
|
|
|
}
|