mirror of
git://git.gnupg.org/gnupg.git
synced 2025-03-11 22:52:47 +01:00
kbx: Add first version of STORE command to keyboxd.
* kbx/Makefile.am (keyboxd_CFLAGS): -DKEYBOX_WITH_X509. (keyboxd_LDADD): Add libksba. * kbx/kbxserver.c (cmd_store): New. * kbx/frontend.c (kbxd_store): New. * kbx/backend-support.c (is_x509_blob): New. (be_fingerprint_from_blob): New. * kbx/backend-kbx.c (be_kbx_seek): Add args FPR and FPRLEN. (be_kbx_insert): New. Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
61765136cf
commit
c7293a4d12
@ -81,10 +81,10 @@ keyboxd_SOURCES = \
|
|||||||
backend-kbx.c \
|
backend-kbx.c \
|
||||||
$(common_sources)
|
$(common_sources)
|
||||||
|
|
||||||
keyboxd_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) $(NPTH_CFLAGS) \
|
keyboxd_CFLAGS = $(AM_CFLAGS) -DKEYBOX_WITH_X509=1 \
|
||||||
$(INCICONV)
|
$(LIBASSUAN_CFLAGS) $(NPTH_CFLAGS) $(INCICONV)
|
||||||
keyboxd_LDADD = $(commonpth_libs) \
|
keyboxd_LDADD = $(commonpth_libs) \
|
||||||
$(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(NPTH_LIBS) \
|
$(KSBA_LIBS) $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(NPTH_LIBS) \
|
||||||
$(GPG_ERROR_LIBS) $(LIBINTL) $(NETLIBS) $(LIBICONV) \
|
$(GPG_ERROR_LIBS) $(LIBINTL) $(NETLIBS) $(LIBICONV) \
|
||||||
$(resource_objs)
|
$(resource_objs)
|
||||||
keyboxd_LDFLAGS = $(extra_bin_ldflags)
|
keyboxd_LDFLAGS = $(extra_bin_ldflags)
|
||||||
|
@ -288,13 +288,15 @@ be_kbx_search (ctrl_t ctrl, backend_handle_t backend_hd, db_request_t request,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Seek in the keybox to the given UBID. BACKEND_HD is the handle for
|
/* Seek in the keybox to the given UBID (if UBID is not NULL) or to
|
||||||
* this backend and REQUEST is the current database request object.
|
* the primary fingerprint specified by (FPR,FPRLEN). BACKEND_HD is
|
||||||
* This does a dummy read so that the next search operation starts
|
* the handle for this backend and REQUEST is the current database
|
||||||
* right after that UBID. */
|
* request object. This does a dummy read so that the next search
|
||||||
|
* operation starts right after that UBID. */
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
be_kbx_seek (ctrl_t ctrl, backend_handle_t backend_hd,
|
be_kbx_seek (ctrl_t ctrl, backend_handle_t backend_hd,
|
||||||
db_request_t request, unsigned char *ubid)
|
db_request_t request, const unsigned char *ubid,
|
||||||
|
const unsigned char *fpr, unsigned int fprlen)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
db_request_part_t part;
|
db_request_part_t part;
|
||||||
@ -308,8 +310,19 @@ be_kbx_seek (ctrl_t ctrl, backend_handle_t backend_hd,
|
|||||||
log_assert (request);
|
log_assert (request);
|
||||||
|
|
||||||
memset (&desc, 0, sizeof desc);
|
memset (&desc, 0, sizeof desc);
|
||||||
desc.mode = KEYDB_SEARCH_MODE_UBID;
|
if (ubid)
|
||||||
memcpy (desc.u.ubid, ubid, 20);
|
{
|
||||||
|
desc.mode = KEYDB_SEARCH_MODE_FPR;
|
||||||
|
memcpy (desc.u.ubid, ubid, 20);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (fprlen > sizeof desc.u.fpr)
|
||||||
|
return gpg_error (GPG_ERR_TOO_LARGE);
|
||||||
|
desc.mode = KEYDB_SEARCH_MODE_FPR;
|
||||||
|
memcpy (desc.u.fpr, fpr, fprlen);
|
||||||
|
desc.fprlen = fprlen;
|
||||||
|
}
|
||||||
|
|
||||||
/* Find the specific request part or allocate it. */
|
/* Find the specific request part or allocate it. */
|
||||||
err = be_find_request_part (backend_hd, request, &part);
|
err = be_find_request_part (backend_hd, request, &part);
|
||||||
@ -326,3 +339,50 @@ be_kbx_seek (ctrl_t ctrl, backend_handle_t backend_hd,
|
|||||||
leave:
|
leave:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Insert (BLOB,BLOBLEN) into the keybox. BACKEND_HD is the handle
|
||||||
|
* for this backend and REQUEST is the current database request
|
||||||
|
* object. */
|
||||||
|
gpg_error_t
|
||||||
|
be_kbx_insert (ctrl_t ctrl, backend_handle_t backend_hd,
|
||||||
|
db_request_t request, enum pubkey_types pktype,
|
||||||
|
const void *blob, size_t bloblen)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
db_request_part_t part;
|
||||||
|
ksba_cert_t cert = NULL;
|
||||||
|
|
||||||
|
(void)ctrl;
|
||||||
|
|
||||||
|
log_assert (backend_hd && backend_hd->db_type == DB_TYPE_KBX);
|
||||||
|
log_assert (request);
|
||||||
|
|
||||||
|
/* Find the specific request part or allocate it. */
|
||||||
|
err = be_find_request_part (backend_hd, request, &part);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
if (pktype == PUBKEY_TYPE_OPGP)
|
||||||
|
err = keybox_insert_keyblock (part->kbx_hd, blob, bloblen);
|
||||||
|
else if (pktype == PUBKEY_TYPE_X509)
|
||||||
|
{
|
||||||
|
unsigned char sha1[20];
|
||||||
|
|
||||||
|
err = ksba_cert_new (&cert);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
err = ksba_cert_init_from_mem (cert, blob, bloblen);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
gcry_md_hash_buffer (GCRY_MD_SHA1, sha1, blob, bloblen);
|
||||||
|
|
||||||
|
err = keybox_insert_cert (part->kbx_hd, cert, sha1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
err = gpg_error (GPG_ERR_WRONG_BLOB_TYPE);
|
||||||
|
|
||||||
|
leave:
|
||||||
|
ksba_cert_release (cert);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
@ -27,8 +27,9 @@
|
|||||||
#include "keyboxd.h"
|
#include "keyboxd.h"
|
||||||
#include "../common/i18n.h"
|
#include "../common/i18n.h"
|
||||||
#include "../common/asshelp.h"
|
#include "../common/asshelp.h"
|
||||||
|
#include "../common/tlv.h"
|
||||||
#include "backend.h"
|
#include "backend.h"
|
||||||
#include "keybox.h"
|
#include "keybox-defs.h"
|
||||||
|
|
||||||
|
|
||||||
/* Common definition part of all backend handle. All definitions of
|
/* Common definition part of all backend handle. All definitions of
|
||||||
@ -169,3 +170,107 @@ be_return_pubkey (ctrl_t ctrl, const void *buffer, size_t buflen,
|
|||||||
leave:
|
leave:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Return true if (BLOB/BLOBLEN) seems to be an X509 certificate. */
|
||||||
|
static int
|
||||||
|
is_x509_blob (const unsigned char *blob, size_t bloblen)
|
||||||
|
{
|
||||||
|
const unsigned char *p;
|
||||||
|
size_t n, objlen, hdrlen;
|
||||||
|
int class, tag, cons, ndef;
|
||||||
|
|
||||||
|
/* An X.509 certificate can be identified by this DER encoding:
|
||||||
|
*
|
||||||
|
* 30 82 05 B8 30 82 04 A0 A0 03 02 01 02 02 07 15 46 A0 BF 30 07 39
|
||||||
|
* ----------- +++++++++++ ----- ++++++++ --------------------------
|
||||||
|
* SEQUENCE SEQUENCE [0] INTEGER INTEGER
|
||||||
|
* (tbs) (version) (s/n)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
p = blob;
|
||||||
|
n = bloblen;
|
||||||
|
if (parse_ber_header (&p, &n, &class, &tag, &cons, &ndef, &objlen, &hdrlen))
|
||||||
|
return 0; /* Not a proper BER object. */
|
||||||
|
if (!(class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE && cons))
|
||||||
|
return 0; /* Does not start with a sequence. */
|
||||||
|
|
||||||
|
if (parse_ber_header (&p, &n, &class, &tag, &cons, &ndef, &objlen, &hdrlen))
|
||||||
|
return 0; /* Not a proper BER object. */
|
||||||
|
if (!(class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE && cons))
|
||||||
|
return 0; /* No TBS sequence. */
|
||||||
|
if (n < 7 || objlen < 7)
|
||||||
|
return 0; /* Too short: [0], version and min. s/n required. */
|
||||||
|
|
||||||
|
if (parse_ber_header (&p, &n, &class, &tag, &cons, &ndef, &objlen, &hdrlen))
|
||||||
|
return 0; /* Not a proper BER object. */
|
||||||
|
if (!(class == CLASS_CONTEXT && tag == 0 && cons))
|
||||||
|
return 0; /* No context tag. */
|
||||||
|
|
||||||
|
if (parse_ber_header (&p, &n, &class, &tag, &cons, &ndef, &objlen, &hdrlen))
|
||||||
|
return 0; /* Not a proper BER object. */
|
||||||
|
|
||||||
|
if (!(class == CLASS_UNIVERSAL && tag == TAG_INTEGER
|
||||||
|
&& !cons && objlen == 1 && n && (*p == 1 || *p == 2)))
|
||||||
|
return 0; /* Unknown X.509 version. */
|
||||||
|
p++; /* Skip version number. */
|
||||||
|
n--;
|
||||||
|
|
||||||
|
if (parse_ber_header (&p, &n, &class, &tag, &cons, &ndef, &objlen, &hdrlen))
|
||||||
|
return 0; /* Not a proper BER object. */
|
||||||
|
if (!(class == CLASS_UNIVERSAL && tag == TAG_INTEGER && !cons))
|
||||||
|
return 0; /* No s/n. */
|
||||||
|
|
||||||
|
return 1; /* Looks like an X.509 certificate. */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the public key type and the (primary) fingerprint for
|
||||||
|
* (BLOB,BLOBLEN). R_FPR must point to a buffer of at least 32 bytes,
|
||||||
|
* it received the fi gerprint on success with the length of that
|
||||||
|
* fingerprint stored at R_FPRLEN. R_PKTYPE receives the public key
|
||||||
|
* type. */
|
||||||
|
gpg_error_t
|
||||||
|
be_fingerprint_from_blob (const void *blob, size_t bloblen,
|
||||||
|
enum pubkey_types *r_pktype,
|
||||||
|
char *r_fpr, unsigned int *r_fprlen)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
|
||||||
|
if (is_x509_blob (blob, bloblen))
|
||||||
|
{
|
||||||
|
/* Although libksba has a dedicated function to compute the
|
||||||
|
* fingerprint we compute it here directly because we know that
|
||||||
|
* we have the entire certificate here (we checked the start of
|
||||||
|
* the blob and assume that the length is also okay). */
|
||||||
|
*r_pktype = PUBKEY_TYPE_X509;
|
||||||
|
gcry_md_hash_buffer (GCRY_MD_SHA1, r_fpr, blob, bloblen);
|
||||||
|
*r_fprlen = 20;
|
||||||
|
|
||||||
|
err = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct _keybox_openpgp_info info;
|
||||||
|
|
||||||
|
err = _keybox_parse_openpgp (blob, bloblen, NULL, &info);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_info ("error parsing OpenPGP blob: %s\n", gpg_strerror (err));
|
||||||
|
err = gpg_error (GPG_ERR_WRONG_BLOB_TYPE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*r_pktype = PUBKEY_TYPE_OPGP;
|
||||||
|
log_assert (info.primary.fprlen <= 32);
|
||||||
|
memcpy (r_fpr, info.primary.fpr, info.primary.fprlen);
|
||||||
|
*r_fprlen = info.primary.fprlen;
|
||||||
|
|
||||||
|
_keybox_destroy_openpgp_info (&info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
@ -106,6 +106,9 @@ gpg_error_t be_find_request_part (backend_handle_t backend_hd,
|
|||||||
gpg_error_t be_return_pubkey (ctrl_t ctrl, const void *buffer, size_t buflen,
|
gpg_error_t be_return_pubkey (ctrl_t ctrl, const void *buffer, size_t buflen,
|
||||||
enum pubkey_types pubkey_type,
|
enum pubkey_types pubkey_type,
|
||||||
const unsigned char *ubid);
|
const unsigned char *ubid);
|
||||||
|
gpg_error_t be_fingerprint_from_blob (const void *blob, size_t bloblen,
|
||||||
|
enum pubkey_types *r_pktype,
|
||||||
|
char *r_fpr, unsigned int *r_fprlen);
|
||||||
|
|
||||||
|
|
||||||
/*-- backend-cache.c --*/
|
/*-- backend-cache.c --*/
|
||||||
@ -134,7 +137,11 @@ gpg_error_t be_kbx_search (ctrl_t ctrl, backend_handle_t hd,
|
|||||||
db_request_t request,
|
db_request_t request,
|
||||||
KEYDB_SEARCH_DESC *desc, unsigned int ndesc);
|
KEYDB_SEARCH_DESC *desc, unsigned int ndesc);
|
||||||
gpg_error_t be_kbx_seek (ctrl_t ctrl, backend_handle_t backend_hd,
|
gpg_error_t be_kbx_seek (ctrl_t ctrl, backend_handle_t backend_hd,
|
||||||
db_request_t request, unsigned char *ubid);
|
db_request_t request, const unsigned char *ubid,
|
||||||
|
const unsigned char *fpr, unsigned int fprlen);
|
||||||
|
gpg_error_t be_kbx_insert (ctrl_t ctrl, backend_handle_t backend_hd,
|
||||||
|
db_request_t request, enum pubkey_types pktype,
|
||||||
|
const void *blob, size_t bloblen);
|
||||||
|
|
||||||
|
|
||||||
#endif /*KBX_BACKEND_H*/
|
#endif /*KBX_BACKEND_H*/
|
||||||
|
@ -58,12 +58,12 @@ take_read_lock (ctrl_t ctrl)
|
|||||||
|
|
||||||
|
|
||||||
/* Take a lock for reading and writing the databases. */
|
/* Take a lock for reading and writing the databases. */
|
||||||
/* static void */
|
static void
|
||||||
/* take_read_write_lock (ctrl_t ctrl) */
|
take_read_write_lock (ctrl_t ctrl)
|
||||||
/* { */
|
{
|
||||||
/* /\* FIXME *\/ */
|
/* FIXME */
|
||||||
/* (void)ctrl; */
|
(void)ctrl;
|
||||||
/* } */
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Release a lock. It is valid to call this even if no lock has been
|
/* Release a lock. It is valid to call this even if no lock has been
|
||||||
@ -339,7 +339,7 @@ kbxd_search (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, unsigned int ndesc,
|
|||||||
{
|
{
|
||||||
/* We need to set the startpoint for the search. */
|
/* We need to set the startpoint for the search. */
|
||||||
err = be_kbx_seek (ctrl, db->backend_handle, request,
|
err = be_kbx_seek (ctrl, db->backend_handle, request,
|
||||||
request->last_cached_ubid);
|
request->last_cached_ubid, NULL, 0);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
log_debug ("%s: seeking %s to an UBID failed: %s\n",
|
log_debug ("%s: seeking %s to an UBID failed: %s\n",
|
||||||
@ -383,3 +383,83 @@ kbxd_search (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, unsigned int ndesc,
|
|||||||
log_clock ("%s: leave (%s)", __func__, err? "not found" : "found");
|
log_clock ("%s: leave (%s)", __func__, err? "not found" : "found");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Store; that is insert or update the key (BLOB,BLOBLEN). If
|
||||||
|
* ONLY_UPDATE is set the key must exist. */
|
||||||
|
gpg_error_t
|
||||||
|
kbxd_store (ctrl_t ctrl, const void *blob, size_t bloblen, int only_update)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
db_request_t request;
|
||||||
|
unsigned int dbidx;
|
||||||
|
db_desc_t db;
|
||||||
|
char fpr[32];
|
||||||
|
unsigned int fprlen;
|
||||||
|
enum pubkey_types pktype;
|
||||||
|
int insert = 0;
|
||||||
|
|
||||||
|
if (DBG_CLOCK)
|
||||||
|
log_clock ("%s: enter", __func__);
|
||||||
|
|
||||||
|
take_read_write_lock (ctrl);
|
||||||
|
|
||||||
|
/* Allocate a handle object if none exists for this context. */
|
||||||
|
if (!ctrl->opgp_req)
|
||||||
|
{
|
||||||
|
ctrl->opgp_req = xtrycalloc (1, sizeof *ctrl->opgp_req);
|
||||||
|
if (!ctrl->opgp_req)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
request = ctrl->opgp_req;
|
||||||
|
|
||||||
|
/* Check whether to insert or update. */
|
||||||
|
err = be_fingerprint_from_blob (blob, bloblen, &pktype, fpr, &fprlen);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
/* FIXME: We force the use of the KBX backend. */
|
||||||
|
for (dbidx=0; dbidx < no_of_databases; dbidx++)
|
||||||
|
if (databases[dbidx].db_type == DB_TYPE_KBX)
|
||||||
|
break;
|
||||||
|
if (!(dbidx < no_of_databases))
|
||||||
|
{
|
||||||
|
err = gpg_error (GPG_ERR_NOT_INITIALIZED);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
db = databases + dbidx;
|
||||||
|
|
||||||
|
err = be_kbx_seek (ctrl, db->backend_handle, request, NULL, fpr, fprlen);
|
||||||
|
if (!err)
|
||||||
|
; /* Found - need to update. */
|
||||||
|
else if (gpg_err_code (err) == GPG_ERR_EOF)
|
||||||
|
insert = 1; /* Not found - need to insert. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_debug ("%s: searching fingerprint failed: %s\n",
|
||||||
|
__func__, gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (insert)
|
||||||
|
{
|
||||||
|
err = be_kbx_insert (ctrl, db->backend_handle, request,
|
||||||
|
pktype, blob, bloblen);
|
||||||
|
}
|
||||||
|
else if (only_update)
|
||||||
|
err = gpg_error (GPG_ERR_DUP_KEY);
|
||||||
|
else /* Update. */
|
||||||
|
{
|
||||||
|
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
leave:
|
||||||
|
release_lock (ctrl);
|
||||||
|
if (DBG_CLOCK)
|
||||||
|
log_clock ("%s: leave", __func__);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
@ -31,6 +31,8 @@ void kbxd_release_session_info (ctrl_t ctrl);
|
|||||||
gpg_error_t kbxd_search (ctrl_t ctrl,
|
gpg_error_t kbxd_search (ctrl_t ctrl,
|
||||||
KEYDB_SEARCH_DESC *desc, unsigned int ndesc,
|
KEYDB_SEARCH_DESC *desc, unsigned int ndesc,
|
||||||
int reset);
|
int reset);
|
||||||
|
gpg_error_t kbxd_store (ctrl_t ctrl, const void *blob, size_t bloblen,
|
||||||
|
int only_update);
|
||||||
|
|
||||||
|
|
||||||
#endif /*KBX_FRONTEND_H*/
|
#endif /*KBX_FRONTEND_H*/
|
||||||
|
@ -465,6 +465,55 @@ cmd_next (assuan_context_t ctx, char *line)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char hlp_store[] =
|
||||||
|
"STORE [--update]\n"
|
||||||
|
"\n"
|
||||||
|
"Insert a key into the database. Whether to insert or update\n"
|
||||||
|
"the key is decided by looking at the primary key's fingerprint.\n"
|
||||||
|
"With option --update the key must already exist. The actual key\n"
|
||||||
|
"material is requested by this function using\n"
|
||||||
|
" INQUIRE BLOB";
|
||||||
|
static gpg_error_t
|
||||||
|
cmd_store (assuan_context_t ctx, char *line)
|
||||||
|
{
|
||||||
|
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||||
|
int opt_update;
|
||||||
|
gpg_error_t err;
|
||||||
|
unsigned char *value = NULL;
|
||||||
|
size_t valuelen;
|
||||||
|
|
||||||
|
opt_update = has_option (line, "--update");
|
||||||
|
line = skip_options (line);
|
||||||
|
if (*line)
|
||||||
|
{
|
||||||
|
err = set_error (GPG_ERR_INV_ARG, "no args expected");
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ask for the key material. */
|
||||||
|
err = assuan_inquire (ctx, "BLOB", &value, &valuelen, 0);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!valuelen) /* No data received. */
|
||||||
|
{
|
||||||
|
err = gpg_error (GPG_ERR_MISSING_VALUE);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = kbxd_store (ctrl, value, valuelen, opt_update);
|
||||||
|
|
||||||
|
|
||||||
|
leave:
|
||||||
|
xfree (value);
|
||||||
|
return leave_cmd (ctx, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static const char hlp_getinfo[] =
|
static const char hlp_getinfo[] =
|
||||||
"GETINFO <what>\n"
|
"GETINFO <what>\n"
|
||||||
@ -584,6 +633,7 @@ register_commands (assuan_context_t ctx)
|
|||||||
} table[] = {
|
} table[] = {
|
||||||
{ "SEARCH", cmd_search, hlp_search },
|
{ "SEARCH", cmd_search, hlp_search },
|
||||||
{ "NEXT", cmd_next, hlp_next },
|
{ "NEXT", cmd_next, hlp_next },
|
||||||
|
{ "STORE", cmd_store, hlp_store },
|
||||||
{ "GETINFO", cmd_getinfo, hlp_getinfo },
|
{ "GETINFO", cmd_getinfo, hlp_getinfo },
|
||||||
{ "OUTPUT", NULL, hlp_output },
|
{ "OUTPUT", NULL, hlp_output },
|
||||||
{ "KILLKEYBOXD",cmd_killkeyboxd,hlp_killkeyboxd },
|
{ "KILLKEYBOXD",cmd_killkeyboxd,hlp_killkeyboxd },
|
||||||
|
@ -667,7 +667,7 @@ _keybox_destroy_openpgp_info (keybox_openpgp_info_t info)
|
|||||||
struct _keybox_openpgp_key_info *k, *k2;
|
struct _keybox_openpgp_key_info *k, *k2;
|
||||||
struct _keybox_openpgp_uid_info *u, *u2;
|
struct _keybox_openpgp_uid_info *u, *u2;
|
||||||
|
|
||||||
assert (!info->primary.next);
|
log_assert (!info->primary.next);
|
||||||
for (k=info->subkeys.next; k; k = k2)
|
for (k=info->subkeys.next; k; k = k2)
|
||||||
{
|
{
|
||||||
k2 = k->next;
|
k2 = k->next;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user