Commit be41844d authored by Ingo Klöcker's avatar Ingo Klöcker
Browse files

Add functions for communicating with the GnuPG agent

These functions are largely based on the gpgagent_* functions in
readerstatus.cpp in kleopatra.

GnuPG-bug-id: 5666
parent a9940a02
......@@ -44,6 +44,7 @@ target_sources(KF5Libkleo PRIVATE
models/keyrearrangecolumnsproxymodel.cpp
models/subkeylistmodel.cpp
models/useridlistmodel.cpp
utils/assuan.cpp
utils/filesystemwatcher.cpp
utils/formatting.cpp
utils/classify.cpp
......@@ -175,6 +176,7 @@ ecm_generate_headers(libkleo_CamelCase_models_HEADERS
ecm_generate_headers(libkleo_CamelCase_utils_HEADERS
HEADER_NAMES
Algorithm
Assuan
Classify
CryptoConfig
FileSystemWatcher
......
/*
utils/assuan.cpp
This file is part of libkleopatra
SPDX-FileCopyrightText: 2021 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-libkleo.h>
#include "assuan.h"
#include <QThread>
#if __has_include(<QGpgME/Debug>)
# include <QGpgME/Debug>
#endif
#include <gpgme++/defaultassuantransaction.h>
#include <gpgme++/context.h>
#include <gpgme++/error.h>
#include "libkleo_debug.h"
using namespace GpgME;
using namespace Kleo;
using namespace Kleo::Assuan;
namespace
{
static QDebug operator<<(QDebug s, const std::string &string)
{
return s << QString::fromStdString(string);
}
static QDebug operator<<(QDebug s, const std::vector< std::pair<std::string, std::string> > &v)
{
using pair = std::pair<std::string, std::string>;
s << '(';
for (const pair &p : v) {
s << "status(" << QString::fromStdString(p.first) << ") =" << QString::fromStdString(p.second) << '\n';
}
return s << ')';
}
}
std::unique_ptr<GpgME::AssuanTransaction> Kleo::Assuan::sendCommand(std::shared_ptr<GpgME::Context> &context, const std::string &command, std::unique_ptr<GpgME::AssuanTransaction> transaction, GpgME::Error &err)
{
qCDebug(LIBKLEO_LOG) << __func__ << command;
err = context->assuanTransact(command.c_str(), std::move(transaction));
static int cnt = 0;
while (err.code() == GPG_ERR_ASS_CONNECT_FAILED && cnt < 5) {
// Esp. on Windows the agent processes may take their time so we try
// in increasing waits for them to start up
qCDebug(LIBKLEO_LOG) << "Waiting for the daemons to start up";
cnt++;
QThread::msleep(250 * cnt);
err = context->assuanTransact(command.c_str(), context->takeLastAssuanTransaction());
}
if (err.code()) {
qCDebug(LIBKLEO_LOG) << __func__ << command << "failed:" << err;
if (err.code() >= GPG_ERR_ASS_GENERAL && err.code() <= GPG_ERR_ASS_UNKNOWN_INQUIRE) {
qCDebug(LIBKLEO_LOG) << "Assuan problem, killing context";
context.reset();
}
return {};
}
return context->takeLastAssuanTransaction();
}
std::unique_ptr<DefaultAssuanTransaction> Kleo::Assuan::sendCommand(std::shared_ptr<Context> &context, const std::string &command, Error &err)
{
std::unique_ptr<AssuanTransaction> t = sendCommand(context, command, std::make_unique<DefaultAssuanTransaction>(), err);
return std::unique_ptr<DefaultAssuanTransaction>(dynamic_cast<DefaultAssuanTransaction*>(t.release()));
}
std::string Kleo::Assuan::sendDataCommand(std::shared_ptr<Context> context, const std::string &command, Error &err)
{
std::string data;
const std::unique_ptr<DefaultAssuanTransaction> t = sendCommand(context, command, err);
if (t.get()) {
data = t->data();
qCDebug(LIBKLEO_LOG) << __func__ << command << ": got" << QString::fromStdString(data);
} else {
qCDebug(LIBKLEO_LOG) << __func__ << command << ": t == NULL";
}
return data;
}
std::vector<std::pair<std::string, std::string>> Kleo::Assuan::sendStatusLinesCommand(std::shared_ptr<Context> context, const std::string &command, Error &err)
{
std::vector<std::pair<std::string, std::string>> statusLines;
const std::unique_ptr<DefaultAssuanTransaction> t = sendCommand(context, command, err);
if (t.get()) {
statusLines = t->statusLines();
qCDebug(LIBKLEO_LOG) << __func__ << command << ": got" << statusLines;
} else {
qCDebug(LIBKLEO_LOG) << __func__ << command << ": t == NULL";
}
return statusLines;
}
std::string Kleo::Assuan::sendStatusCommand(const std::shared_ptr<Context> &context, const std::string &command, Error &err)
{
const auto lines = sendStatusLinesCommand(context, command, err);
// The status is only the last attribute
// e.g. for SCD SERIALNO it would only be "SERIALNO" and for SCD GETATTR FOO
// it would only be FOO
const auto lastSpace = command.rfind(' ');
const auto needle = lastSpace == std::string::npos ? command : command.substr(lastSpace + 1);
for (const auto &pair: lines) {
if (pair.first == needle) {
return pair.second;
}
}
return {};
}
/*
utils/assuan.h
This file is part of libkleopatra
SPDX-FileCopyrightText: 2021 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <memory>
#include <vector>
#include "kleo_export.h"
namespace GpgME
{
class AssuanTransaction;
class Context;
class DefaultAssuanTransaction;
class Error;
}
namespace Kleo
{
/** The Assuan namespace collects functions for communicating with the GnuPG
* agent via the Assuan protocol. */
namespace Assuan
{
/** Sends the Assuan @p command using the @p transaction and the @p assuanContext
* to the GnuPG agent and waits for the result. The returned transaction can be used
* to retrieve the result.
* If an error occurred, then @p err provides details. */
KLEO_EXPORT std::unique_ptr<GpgME::AssuanTransaction> sendCommand(std::shared_ptr<GpgME::Context> &assuanContext, const std::string &command, std::unique_ptr<GpgME::AssuanTransaction> transaction, GpgME::Error &err);
/** Sends the Assuan @p command using a default Assuan transaction and the @p assuanContext
* to the GnuPG agent and waits for the result. The returned transaction can be used
* to retrieve the result.
* If an error occurred, then @p err provides details. */
KLEO_EXPORT std::unique_ptr<GpgME::DefaultAssuanTransaction> sendCommand(std::shared_ptr<GpgME::Context> &assuanContext, const std::string &command, GpgME::Error &err);
/** Sends the Assuan @p command using a default Assuan transaction and the @p assuanContext
* to the GnuPG agent and waits for the result. Returns the data that was sent by
* GnuPG agent in response to the @p command.
* If an error occurred, then @p err provides details. */
KLEO_EXPORT std::string sendDataCommand(std::shared_ptr<GpgME::Context> assuanContext, const std::string &command, GpgME::Error &err);
/** Sends the Assuan @p command using a default Assuan transaction and the @p assuanContext
* to the GnuPG agent and waits for the result. Returns the status lines that were sent by
* GnuPG agent in response to the @p command.
* If an error occurred, then @p err provides details. */
KLEO_EXPORT std::vector<std::pair<std::string, std::string>> sendStatusLinesCommand(std::shared_ptr<GpgME::Context> assuanContext, const std::string &command, GpgME::Error &err);
/** Sends the Assuan @p command using a default Assuan transaction and the @p assuanContext
* to the GnuPG agent and waits for the result. Returns the status that was sent by
* GnuPG agent in response to the @p command.
* If an error occurred, then @p err provides details. */
KLEO_EXPORT std::string sendStatusCommand(const std::shared_ptr<GpgME::Context> &assuanContext, const std::string &command, GpgME::Error &err);
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment