Consider the following program:
#include <gpgme.h>
int
main (int argc, char *argv[])
{
gpgme_ctx_t ctx;
gpgme_error_t err;
const char *version = gpgme_check_version (NULL);
printf("gpgme version: %s\n", version);
err = gpgme_new (&ctx);
if (err)
{
printf ("gpgme_new: %s (%d)\n", gpgme_strerror (err), err);
return 1;
}
const char *fpr = "CD25ED96421EC550CBC581CD6572DDCA38F80155";
gpgme_key_t key;
err = gpgme_get_key (ctx, fpr, &key, 0);
if (err)
{
printf ("gpgme_get_key (%s): %s (%d)\n", fpr, gpgme_strerror (err), err);
return 1;
}
gpgme_set_pinentry_mode (ctx, GPGME_PINENTRY_MODE_LOOPBACK);
err = gpgme_op_delete (ctx, key, 1);
if (err)
{
printf ("gpgme_op_delete: %s (%d)\n", gpgme_strerror (err), err);
return 1;
}
gpgme_key_unref (key);
return 0;
}This tries to delete a secret key while loopback mode is enabled. Unfortunately, this program returns success, but it does not actually delete the key in question:
/tmp/tmp.QASe7zmW0e$ gpg -K
/tmp/tmp.QASe7zmW0e/pubring.kbx
-------------------------------
sec rsa2048 2017-09-19 [SC] [expires: 2019-09-19]
CD25ED96421EC550CBC581CD6572DDCA38F80155
uid [ultimate] test@example.com
ssb rsa2048 2017-09-19 [E]
us@grit:/tmp/tmp.QASe7zmW0e$ ../gpgme/gpgme-test
gpgme version: 1.8.0
us@grit:/tmp/tmp.QASe7zmW0e$ echo $?
0
/tmp/tmp.QASe7zmW0e$ gpg -K
/tmp/tmp.QASe7zmW0e/pubring.kbx
-------------------------------
sec rsa2048 2017-09-19 [SC] [expires: 2019-09-19]
CD25ED96421EC550CBC581CD6572DDCA38F80155
uid [ultimate] test@example.com
ssb rsa2048 2017-09-19 [E]
/tmp/tmp.QASe7zmW0e$Disabling loopback mode causes a pinentry prompt to appear and if the user presses ok, then the key is deleted.
Also, running the equivalent (?) from the command line appears to correctly fail:
$ gpg --batch --pinentry-mode=loopback --delete-secret-keys CD25ED96421EC550CBC581CD6572DDCA38F80155 gpg: deleting secret key failed: No pinentry gpg: deleting secret subkey failed: No pinentry gpg: CD25ED96421EC550CBC581CD6572DDCA38F80155: delete key failed: No pinentry /tmp/tmp.QASe7zmW0e$ echo $? 2