core: New function gpgme_op_setownertrust

* src/Makefile.am (main_sources): Add new file.
* src/context.h (ctx_op_data_id_t): Add OPDATA_SETOWNERTRUST.
* src/engine.c, src/engine.h (_gpgme_engine_op_setownertrust): New.
* src/engine-backend.h (engine_ops): Add 'setownertrust' and adjust all
engine initializers.
* src/engine-gpg.c (gpg_setownertrust): New.
(_gpgme_engine_ops_gpg): Set setownertrust to gpg_setownertrust.
* src/gpgme.h.in (gpgme_op_setownertrust_start, gpgme_op_setownertrust):
New.
* src/gpgme.def, src/libgpgme.vers: Add new functions.
* src/setownertrust.c: New.

* doc/gpgme.texi: Document new functions.

* tests/Makefile.am (noinst_PROGRAMS): Add new test program.
* tests/run-setownertrust.c: New.

* tests/gpg/Makefile.am (c_tests): Add new file. (LDADD): Add
@GPG_ERROR_LIBS@.
* tests/gpg/t-setownertrust.c: New.
* tests/gpg/t-support.h (have_gpg_version): New.

--

This extends GPGME to support the --quick-set-ownertrust command added
by GnuPG 2.4.6. This allows changing the owner trust of keys and
enabling/disabling keys without using the editinteractor interface.

GnuPG-bug-id: 7239
This commit is contained in:
Ingo Klöcker 2024-08-05 17:14:01 +02:00
parent 9272b0fb6e
commit d804a7a4bc
No known key found for this signature in database
GPG Key ID: F5A5D1692277A1E9
23 changed files with 589 additions and 7 deletions

6
NEWS
View File

@ -11,6 +11,10 @@ Noteworthy changes in version 1.24.0 (unrelease)
* New context flag "import-options". [T7152] * New context flag "import-options". [T7152]
* New function gpgme_op_setownertrust to make changing the owner trust
easier and to allow enabling/disabling of keys (requires GnuPG 2.4.6).
[T7239]
* cpp: Provide information about designated revocation keys for a Key. * cpp: Provide information about designated revocation keys for a Key.
[T7118] [T7118]
@ -38,6 +42,8 @@ Noteworthy changes in version 1.24.0 (unrelease)
gpgme_key_t EXTENDED: New field 'revkeys'. gpgme_key_t EXTENDED: New field 'revkeys'.
gpgme_revocation_key_t NEW. gpgme_revocation_key_t NEW.
gpgme_set_ctx_flag EXTENDED: New flag 'import-options'. gpgme_set_ctx_flag EXTENDED: New flag 'import-options'.
gpgme_op_setownertrust_start NEW.
gpgme_op_setownertrust NEW.
cpp: Context::EncryptFile NEW. cpp: Context::EncryptFile NEW.
cpp: SignatureMode::SignFile NEW. cpp: SignatureMode::SignFile NEW.
cpp: RevocationKey NEW. cpp: RevocationKey NEW.

View File

@ -4277,6 +4277,53 @@ be completed by calling @code{gpgme_wait} on the context.
@end deftypefun @end deftypefun
@c
@c gpgme_op_setownertrust
@c
@deftypefun gpgme_error_t gpgme_op_setownertrust @
(@w{gpgme_ctx_t @var{ctx}}, @
@w{gpgme_key_t @var{key}}, @
@w{const char *@var{value}});
@since{1.24.0}
The function @code{gpgme_op_setownertrust} sets the owner trust of the
key @var{key} or it sets the disable flag of the key @var{key}.
This function only works for OpenPGP and requires at least version 2.4.6
of GnuPG.
@var{key} specifies the key to operate on.
@var{value} specifies the owner trust value to set. Valid values are
"undefined", "never", "marginal", "full", "ultimate". If @var{value} is
the string "disable" then the key @var{key} is disabled. If @var{value}
is the string "enable" then the key @var{key} is re-enabled.
The function returns the error code @code{GPG_ERR_NO_ERROR} if the
operation was completed successfully, @code{GPG_ERR_NOT_SUPPORTED} if
the engine does not support the command, and @code{GPG_ERR_INV_VALUE} if
@var{key} is not a valid pointer or not a valid key or if @var{value} is
not a valid pointer or the empty string.
@end deftypefun
@deftypefun gpgme_error_t gpgme_op_setownertrust_start @
(@w{gpgme_ctx_t @var{ctx}}, @
@w{gpgme_key_t @var{key}}, @
@w{const char *@var{value}});
@since{1.24.0}
The function @code{gpgme_op_setownertrust_start} initiates a
@code{gpgme_op_setownertrust} operation; see there for details. It must
be completed by calling @code{gpgme_wait} on the context.
@xref{Waiting For Completion}.
The function returns the same error codes as @code{gpgme_op_setownertrust}.
@end deftypefun
@node Generating Keys @node Generating Keys
@subsection Generating Keys @subsection Generating Keys

View File

@ -85,7 +85,7 @@ main_sources = \
key.c keylist.c keysign.c trust-item.c trustlist.c tofupolicy.c \ key.c keylist.c keysign.c trust-item.c trustlist.c tofupolicy.c \
revsig.c \ revsig.c \
import.c export.c genkey.c delete.c edit.c getauditlog.c \ import.c export.c genkey.c delete.c edit.c getauditlog.c \
setexpire.c \ setexpire.c setownertrust.c \
opassuan.c passwd.c spawn.c assuan-support.c \ opassuan.c passwd.c spawn.c assuan-support.c \
engine.h engine-backend.h engine.c engine-gpg.c status-table.c \ engine.h engine-backend.h engine.c engine-gpg.c status-table.c \
engine-gpgsm.c engine-assuan.c engine-gpgconf.c \ engine-gpgsm.c engine-assuan.c engine-gpgconf.c \

View File

@ -39,7 +39,7 @@ typedef enum
OPDATA_IMPORT, OPDATA_GENKEY, OPDATA_KEYLIST, OPDATA_EDIT, OPDATA_IMPORT, OPDATA_GENKEY, OPDATA_KEYLIST, OPDATA_EDIT,
OPDATA_VERIFY, OPDATA_TRUSTLIST, OPDATA_ASSUAN, OPDATA_VFS_MOUNT, OPDATA_VERIFY, OPDATA_TRUSTLIST, OPDATA_ASSUAN, OPDATA_VFS_MOUNT,
OPDATA_PASSWD, OPDATA_EXPORT, OPDATA_KEYSIGN, OPDATA_TOFU_POLICY, OPDATA_PASSWD, OPDATA_EXPORT, OPDATA_KEYSIGN, OPDATA_TOFU_POLICY,
OPDATA_QUERY_SWDB, OPDATA_SETEXPIRE, OPDATA_REVSIG OPDATA_QUERY_SWDB, OPDATA_SETEXPIRE, OPDATA_REVSIG, OPDATA_SETOWNERTRUST
} ctx_op_data_id_t; } ctx_op_data_id_t;

View File

@ -839,6 +839,7 @@ struct engine_ops _gpgme_engine_ops_assuan =
NULL, /* verify */ NULL, /* verify */
NULL, /* getauditlog */ NULL, /* getauditlog */
NULL, /* setexpire */ NULL, /* setexpire */
NULL, /* setownertrust */
llass_transact, /* opassuan_transact */ llass_transact, /* opassuan_transact */
NULL, /* conf_load */ NULL, /* conf_load */
NULL, /* conf_save */ NULL, /* conf_save */

View File

@ -129,6 +129,8 @@ struct engine_ops
gpgme_error_t (*setexpire) (void *engine, gpgme_key_t key, gpgme_error_t (*setexpire) (void *engine, gpgme_key_t key,
unsigned long expires, const char *subfprs, unsigned long expires, const char *subfprs,
unsigned int reserved); unsigned int reserved);
gpgme_error_t (*setownertrust) (void *engine, gpgme_key_t key,
const char *value);
gpgme_error_t (*opassuan_transact) (void *engine, gpgme_error_t (*opassuan_transact) (void *engine,
const char *command, const char *command,
gpgme_assuan_data_cb_t data_cb, gpgme_assuan_data_cb_t data_cb,

View File

@ -810,6 +810,7 @@ struct engine_ops _gpgme_engine_ops_g13 =
NULL, /* verify */ NULL, /* verify */
NULL, /* getauditlog */ NULL, /* getauditlog */
NULL, /* setexpire */ NULL, /* setexpire */
NULL, /* setownertrust */
g13_transact, g13_transact,
NULL, /* conf_load */ NULL, /* conf_load */
NULL, /* conf_save */ NULL, /* conf_save */

View File

@ -4017,6 +4017,38 @@ gpg_setexpire (void *engine, gpgme_key_t key, unsigned long expires,
} }
static gpgme_error_t
gpg_setownertrust (void *engine, gpgme_key_t key, const char *value)
{
engine_gpg_t gpg = engine;
gpgme_error_t err;
if (!have_gpg_version (gpg, "2.4.6"))
return gpg_error (GPG_ERR_NOT_SUPPORTED);
if (!key || !key->fpr)
return gpg_error (GPG_ERR_INV_VALUE);
if (!value || !*value)
return gpg_error (GPG_ERR_INV_VALUE);
err = add_arg (gpg, "--quick-set-ownertrust");
if (!err)
err = add_arg (gpg, "--");
if (!err)
err = add_arg (gpg, key->fpr);
if (!err)
err = add_arg (gpg, value);
if (!err)
err = start (gpg);
return err;
}
struct engine_ops _gpgme_engine_ops_gpg = struct engine_ops _gpgme_engine_ops_gpg =
{ {
@ -4056,6 +4088,7 @@ struct engine_ops _gpgme_engine_ops_gpg =
gpg_verify, gpg_verify,
gpg_getauditlog, gpg_getauditlog,
gpg_setexpire, gpg_setexpire,
gpg_setownertrust,
NULL, /* opassuan_transact */ NULL, /* opassuan_transact */
NULL, /* conf_load */ NULL, /* conf_load */
NULL, /* conf_save */ NULL, /* conf_save */

View File

@ -1310,6 +1310,7 @@ struct engine_ops _gpgme_engine_ops_gpgconf =
NULL, /* verify */ NULL, /* verify */
NULL, /* getauditlog */ NULL, /* getauditlog */
NULL, /* setexpire */ NULL, /* setexpire */
NULL, /* setownertrust */
NULL, /* opassuan_transact */ NULL, /* opassuan_transact */
gpgconf_conf_load, gpgconf_conf_load,
gpgconf_conf_save, gpgconf_conf_save,

View File

@ -2444,6 +2444,7 @@ struct engine_ops _gpgme_engine_ops_gpgsm =
gpgsm_verify, gpgsm_verify,
gpgsm_getauditlog, gpgsm_getauditlog,
NULL, /* setexpire */ NULL, /* setexpire */
NULL, /* setownertrust */
NULL, /* opassuan_transact */ NULL, /* opassuan_transact */
NULL, /* conf_load */ NULL, /* conf_load */
NULL, /* conf_save */ NULL, /* conf_save */

View File

@ -470,6 +470,7 @@ struct engine_ops _gpgme_engine_ops_spawn =
NULL, /* verify */ NULL, /* verify */
NULL, /* getauditlog */ NULL, /* getauditlog */
NULL, /* setexpire */ NULL, /* setexpire */
NULL, /* setownertrust */
NULL, /* opassuan_transact */ NULL, /* opassuan_transact */
NULL, /* conf_load */ NULL, /* conf_load */
NULL, /* conf_save */ NULL, /* conf_save */

View File

@ -1453,6 +1453,7 @@ struct engine_ops _gpgme_engine_ops_uiserver =
uiserver_verify, uiserver_verify,
NULL, /* getauditlog */ NULL, /* getauditlog */
NULL, /* setexpire */ NULL, /* setexpire */
NULL, /* setownertrust */
NULL, /* opassuan_transact */ NULL, /* opassuan_transact */
NULL, /* conf_load */ NULL, /* conf_load */
NULL, /* conf_save */ NULL, /* conf_save */

View File

@ -1161,3 +1161,16 @@ _gpgme_engine_op_setexpire (engine_t engine, gpgme_key_t key,
return (*engine->ops->setexpire) (engine->engine, key, expires, subfprs, reserved); return (*engine->ops->setexpire) (engine->engine, key, expires, subfprs, reserved);
} }
gpgme_error_t
_gpgme_engine_op_setownertrust (engine_t engine, gpgme_key_t key,
const char *value)
{
if (!engine)
return gpg_error (GPG_ERR_INV_VALUE);
if (!engine->ops->setownertrust)
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
return (*engine->ops->setownertrust) (engine->engine, key, value);
}

View File

@ -225,6 +225,8 @@ gpgme_error_t _gpgme_engine_op_setexpire (engine_t engine,
unsigned long expires, unsigned long expires,
const char *subfprs, const char *subfprs,
unsigned int reserved); unsigned int reserved);
gpgme_error_t _gpgme_engine_op_setownertrust (engine_t engine,
gpgme_key_t key,
const char *value);
#endif /* ENGINE_H */ #endif /* ENGINE_H */

View File

@ -285,5 +285,8 @@ EXPORTS
gpgme_op_verify_ext @211 gpgme_op_verify_ext @211
gpgme_op_verify_ext_start @212 gpgme_op_verify_ext_start @212
gpgme_op_setownertrust @213
gpgme_op_setownertrust_start @214
; END ; END

View File

@ -1969,6 +1969,12 @@ gpgme_error_t gpgme_op_setexpire (gpgme_ctx_t ctx,
gpgme_key_t key, unsigned long expires, gpgme_key_t key, unsigned long expires,
const char *subfprs, unsigned int reserved); const char *subfprs, unsigned int reserved);
/* Change the ownertrust of a key. */
gpgme_error_t gpgme_op_setownertrust_start (gpgme_ctx_t ctx,
gpgme_key_t key, const char *value);
gpgme_error_t gpgme_op_setownertrust (gpgme_ctx_t ctx,
gpgme_key_t key, const char *value);
/* Retrieve a pointer to the result of a genkey, createkey, or /* Retrieve a pointer to the result of a genkey, createkey, or
* createsubkey operation. */ * createsubkey operation. */
gpgme_genkey_result_t gpgme_op_genkey_result (gpgme_ctx_t ctx); gpgme_genkey_result_t gpgme_op_genkey_result (gpgme_ctx_t ctx);

View File

@ -285,6 +285,9 @@ GPGME_1.0 {
gpgme_op_verify_ext; gpgme_op_verify_ext;
gpgme_op_verify_ext_start; gpgme_op_verify_ext_start;
gpgme_op_setownertrust;
gpgme_op_setownertrust_start;
local: local:
*; *;

181
src/setownertrust.c Normal file
View File

@ -0,0 +1,181 @@
/* setownertrust.c - Set ownertrust helpers.
* Copyright (C) 2024 g10 Code GmbH
*
* This file is part of GPGME.
*
* GPGME is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* GPGME 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <https://gnu.org/licenses/>.
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include "gpgme.h"
#include "debug.h"
#include "context.h"
#include "ops.h"
typedef struct
{
/* The error code from a FAILURE status line or 0. */
gpg_error_t failure_code;
/* The error code from an ERROR status line or 0. */
gpg_error_t error_code;
} *op_data_t;
/* Parse an error status line. Return the error location and the
error code. The function may modify ARGS. */
static char *
parse_error (char *args, gpg_error_t *r_err)
{
char *where = strchr (args, ' ');
char *which;
if (where)
{
*where = '\0';
which = where + 1;
where = strchr (which, ' ');
if (where)
*where = '\0';
where = args;
}
else
{
*r_err = trace_gpg_error (GPG_ERR_INV_ENGINE);
return NULL;
}
*r_err = atoi (which);
return where;
}
static gpgme_error_t
setownertrust_status_handler (void *priv, gpgme_status_code_t code, char *args)
{
gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
gpgme_error_t err;
void *hook;
op_data_t opd;
char *loc;
err = _gpgme_op_data_lookup (ctx, OPDATA_SETOWNERTRUST, &hook, -1, NULL);
opd = hook;
if (err)
return err;
switch (code)
{
case GPGME_STATUS_ERROR:
loc = parse_error (args, &err);
if (!loc)
return err;
if (!opd->error_code)
opd->error_code = err;
break;
case GPGME_STATUS_FAILURE:
if (!opd->failure_code
|| gpg_err_code (opd->failure_code) == GPG_ERR_GENERAL)
opd->failure_code = _gpgme_parse_failure (args);
break;
case GPGME_STATUS_EOF:
if (opd->error_code)
err = opd->error_code;
else if (opd->failure_code)
err = opd->failure_code;
break;
default:
break;
}
return err;
}
/* Set the ownertrust of a key or enable/disable a key. See
--quick-set-ownertrust in the gnupg documentation. */
static gpg_error_t
setownertrust (gpgme_ctx_t ctx, int synchronous,
gpgme_key_t key,
const char *value)
{
gpgme_error_t err;
void *hook;
op_data_t opd;
TRACE_BEG (DEBUG_CTX, "gpgme_op_setownertrust", ctx,
"%d key=%p value: %s",
synchronous, key, value);
if (!ctx)
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
if (ctx->protocol != GPGME_PROTOCOL_OPENPGP)
return TRACE_ERR (gpgme_error (GPG_ERR_UNSUPPORTED_PROTOCOL));
if (!key)
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
err = _gpgme_op_reset (ctx, synchronous);
if (err)
return err;
err = _gpgme_op_data_lookup (ctx, OPDATA_SETOWNERTRUST, &hook, sizeof (*opd),
NULL);
opd = hook;
if (err)
return err;
_gpgme_engine_set_status_handler (ctx->engine, setownertrust_status_handler,
ctx);
err = _gpgme_engine_op_setownertrust (ctx->engine, key, value);
if (synchronous && !err)
err = _gpgme_wait_one (ctx);
return TRACE_ERR (err);
}
/* See setownertrust. */
gpgme_error_t
gpgme_op_setownertrust_start (gpgme_ctx_t ctx,
gpgme_key_t key,
const char *value)
{
return setownertrust (ctx, 0, key, value);
}
/* See setownertrust. This is the synchronous variant. */
gpgme_error_t
gpgme_op_setownertrust (gpgme_ctx_t ctx,
gpgme_key_t key,
const char *value)
{
return setownertrust (ctx, 1, key, value);
}

View File

@ -42,7 +42,7 @@ noinst_HEADERS = run-support.h
noinst_PROGRAMS = $(TESTS) run-keylist run-export run-import run-sign \ noinst_PROGRAMS = $(TESTS) run-keylist run-export run-import run-sign \
run-verify run-encrypt run-identify run-decrypt run-genkey \ run-verify run-encrypt run-identify run-decrypt run-genkey \
run-keysign run-tofu run-swdb run-threaded \ run-keysign run-tofu run-swdb run-threaded \
run-receive-keys run-receive-keys run-setownertrust
run_threaded_CPPFLAGS = -I$(top_builddir)/src @GPG_ERROR_MT_CFLAGS@ run_threaded_CPPFLAGS = -I$(top_builddir)/src @GPG_ERROR_MT_CFLAGS@
run_threaded_LDADD = ../src/libgpgme.la \ run_threaded_LDADD = ../src/libgpgme.la \

View File

@ -40,6 +40,7 @@ c_tests = \
t-decrypt t-verify t-decrypt-verify t-sig-notation t-export \ t-decrypt t-verify t-decrypt-verify t-sig-notation t-export \
t-import t-edit t-keylist t-keylist-sig t-keylist-secret-sig t-wait \ t-import t-edit t-keylist t-keylist-sig t-keylist-secret-sig t-wait \
t-encrypt-large t-file-name t-gpgconf t-encrypt-mixed t-edit-sign \ t-encrypt-large t-file-name t-gpgconf t-encrypt-mixed t-edit-sign \
t-setownertrust \
$(tests_unix) $(tests_unix)
TESTS = initial.test $(c_tests) final.test TESTS = initial.test $(c_tests) final.test
@ -67,7 +68,7 @@ BUILT_SOURCES = gpg.conf gpg-agent.conf pubring-stamp \
gpg-sample.stamp gpg-sample.stamp
AM_CPPFLAGS = -I$(top_builddir)/src @GPG_ERROR_CFLAGS@ AM_CPPFLAGS = -I$(top_builddir)/src @GPG_ERROR_CFLAGS@
AM_LDFLAGS = -no-install AM_LDFLAGS = -no-install
LDADD = ../../src/libgpgme.la @LDADD_FOR_TESTS_KLUDGE@ LDADD = ../../src/libgpgme.la @GPG_ERROR_LIBS@ @LDADD_FOR_TESTS_KLUDGE@
WITH_THREAD_CPPFLAGS = -I$(top_builddir)/src @GPG_ERROR_MT_CFLAGS@ WITH_THREAD_CPPFLAGS = -I$(top_builddir)/src @GPG_ERROR_MT_CFLAGS@
WITH_THREAD_LDADD = ../../src/libgpgme.la \ WITH_THREAD_LDADD = ../../src/libgpgme.la \

132
tests/gpg/t-setownertrust.c Normal file
View File

@ -0,0 +1,132 @@
/* t-setownertrust.c - Regression test.
* Copyright (C) 2024 g10 Code GmbH
*
* This file is part of GPGME.
*
* GPGME is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* GPGME 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <https://gnu.org/licenses/>.
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
/* We need to include config.h so that we know whether we are building
with large file system (LFS) support. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define PGM "t-setownertrust"
#include "t-support.h"
#include <gpgme.h>
#include <stdio.h>
#include <stdlib.h>
static gpgme_key_t
list_one_key (gpgme_ctx_t ctx, const char *pattern, int secret_only)
{
gpgme_error_t err;
gpgme_key_t key = NULL;
err = gpgme_op_keylist_start (ctx, pattern, secret_only);
fail_if_err (err);
err = gpgme_op_keylist_next (ctx, &key);
fail_if_err (err);
err = gpgme_op_keylist_end (ctx);
fail_if_err (err);
return key;
}
int
main (int argc, char **argv)
{
gpgme_ctx_t ctx;
gpgme_error_t err;
gpgme_key_t key = NULL;
const char *pattern = "Alpha";
(void)argc;
(void)argv;
if (!have_gpg_version ("2.4.6"))
{
printf ("Testsuite skipped. Minimum GnuPG version (2.4.6) "
"not found.\n");
exit(0);
}
init_gpgme (GPGME_PROTOCOL_OpenPGP);
err = gpgme_new (&ctx);
fail_if_err (err);
key = list_one_key (ctx, pattern, 0);
err = gpgme_op_setownertrust (ctx, key, "disable");
fail_if_err (err);
gpgme_key_unref (key);
key = list_one_key (ctx, pattern, 0);
if (!key->disabled)
{
fprintf (stderr, "%s:%i: Key is unexpectedly not disabled\n",
PGM, __LINE__);
exit (1);
}
gpgme_key_unref (key);
key = list_one_key (ctx, pattern, 0);
err = gpgme_op_setownertrust (ctx, key, "enable");
fail_if_err (err);
gpgme_key_unref (key);
key = list_one_key (ctx, pattern, 0);
if (key->disabled)
{
fprintf (stderr, "%s:%i: Key is unexpectedly disabled\n",
PGM, __LINE__);
exit (1);
}
gpgme_key_unref (key);
/* Check error handling */
err = gpgme_op_setownertrust (ctx, NULL, "ultimate");
if (gpgme_err_code (err) != GPG_ERR_INV_VALUE)
{
fprintf (stderr, "%s:%i: Unexpected error code: %s\n",
PGM, __LINE__, gpgme_strerror (err));
exit (1);
}
key = list_one_key (ctx, pattern, 0);
err = gpgme_op_setownertrust (ctx, key, NULL);
if (gpgme_err_code (err) != GPG_ERR_INV_VALUE)
{
fprintf (stderr, "%s:%i: Unexpected error code: %s\n",
PGM, __LINE__, gpgme_strerror (err));
exit (1);
}
err = gpgme_op_setownertrust (ctx, key, "");
if (gpgme_err_code (err) != GPG_ERR_INV_VALUE)
{
fprintf (stderr, "%s:%i: Unexpected error code: %s\n",
PGM, __LINE__, gpgme_strerror (err));
exit (1);
}
gpgme_key_unref (key);
gpgme_release (ctx);
return 0;
}

View File

@ -19,19 +19,21 @@
* SPDX-License-Identifier: LGPL-2.1-or-later * SPDX-License-Identifier: LGPL-2.1-or-later
*/ */
#include <gpgme.h>
#include <gpg-error.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <stdlib.h> #include <stdlib.h>
#include <locale.h> #include <locale.h>
#include <limits.h> #include <limits.h>
#include <ctype.h> #include <ctype.h>
#include <string.h>
#ifdef HAVE_W32_SYSTEM #ifdef HAVE_W32_SYSTEM
#include <windows.h> #include <windows.h>
#endif #endif
#include <gpgme.h>
#ifndef PGM #ifndef PGM
#define PGM "unknown program; define PGM before including t-support.h" #define PGM "unknown program; define PGM before including t-support.h"
#endif #endif
@ -271,3 +273,21 @@ print_import_result (gpgme_import_result_t r)
r->not_imported, r->not_imported,
r->skipped_v3_keys); r->skipped_v3_keys);
} }
/* Return true if the gpg engine's version is at least REQ_VERSION. */
int
have_gpg_version (const char *req_version)
{
gpgme_engine_info_t engine_info;
init_gpgme (GPGME_PROTOCOL_OpenPGP);
fail_if_err (gpgme_get_engine_info (&engine_info));
for (; engine_info; engine_info = engine_info->next)
if (engine_info->protocol == GPGME_PROTOCOL_OpenPGP)
break;
test (engine_info);
return gpgrt_cmp_version (engine_info->version, req_version, 3) >= 0;
}

127
tests/run-setownertrust.c Normal file
View File

@ -0,0 +1,127 @@
/* run-setownertrust.c - Test tool to perform ownertrust changes
* Copyright (C) 2024 g10 Code GmbH
*
* This file is part of GPGME.
*
* GPGME is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* GPGME 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <https://gnu.org/licenses/>.
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
/* We need to include config.h so that we know whether we are building
with large file system (LFS) support. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <gpgme.h>
#define PGM "run-setownertrust"
#include "run-support.h"
static gpg_error_t
status_cb (void *opaque, const char *keyword, const char *value)
{
(void)opaque;
fprintf (stderr, "status_cb: %s %s\n", nonnull(keyword), nonnull(value));
return 0;
}
static int
show_usage (int ex)
{
fputs ("usage: " PGM " [options] USERID VALUE\n"
"Options:\n"
" --status print status lines from the backend\n"
, stderr);
exit (ex);
}
int
main (int argc, char **argv)
{
int last_argc = -1;
gpgme_error_t err;
gpgme_ctx_t ctx;
gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP;
int print_status = 0;
const char *userid;
const char *value;
gpgme_key_t key;
if (argc)
{ argc--; argv++; }
while (argc && last_argc != argc )
{
last_argc = argc;
if (!strcmp (*argv, "--"))
{
argc--; argv++;
break;
}
else if (!strcmp (*argv, "--help"))
show_usage (0);
else if (!strcmp (*argv, "--status"))
{
print_status = 1;
argc--; argv++;
}
else if (!strncmp (*argv, "--", 2))
show_usage (1);
}
if (argc != 2)
show_usage (1);
userid = argv[0];
value = argv[1];
init_gpgme (protocol);
err = gpgme_new (&ctx);
fail_if_err (err);
gpgme_set_protocol (ctx, protocol);
gpgme_set_armor (ctx, 1);
if (print_status)
{
gpgme_set_status_cb (ctx, status_cb, NULL);
gpgme_set_ctx_flag (ctx, "full-status", "1");
}
err = gpgme_get_key (ctx, userid, &key, 0);
if (err)
{
fprintf (stderr, PGM ": error getting public key for '%s': %s\n",
userid, gpg_strerror (err));
exit (1);
}
err = gpgme_op_setownertrust (ctx, key, value);
if (err)
{
fprintf (stderr, PGM ": gpgme_op_setownertrust failed: %s\n",
gpg_strerror (err));
exit (1);
}
gpgme_key_unref (key);
gpgme_release (ctx);
return 0;
}