I'm trying to ask polkit for authorization but I can't seem to find out how to provide a struct as an argument.
QDBusArgument subject;
subject.beginStructure();
subject << "unix-process";
subject << QMap<QString, QVariant>{
{"pid", static_cast<uint32_t>(QCoreApplication::applicationPid())},
{"start-time", static_cast<uint64_t>(0)},
};
subject.endStructure();
QDBusInterface polkit("org.freedesktop.PolicyKit1", "/org/freedesktop/PolicyKit1/Authority", "org.freedesktop.PolicyKit1.Authority");
auto result = polkit.callWithArgumentList(
QDBus::CallMode::AutoDetect,
"CheckAuthorization",
{
// how to provide the subject here?
}
);
The QDBusArgument shows what the argument should look like and I somehow need to translate this to a format that can be used in callWithArgumentList
.
FreeDesktop specifies the struct as such:
{
String subject_kind,
Dict<String,Variant> subject_details
}
More specifically, I'm trying to replace this with a dbus call:
// checkProcess is *QProcess
checkProcess->start("pkcheck", {
"--process",
QString::number(QCoreApplication::applicationPid()),
"--action-id",
"my-custom-action-id",
"--allow-user-interaction"
});
CodePudding user response:
I'm not too familiar with D-Bus or its Qt interface, but I do happen to have a linux system I could test this on. It seems that you were already well on your way, I was able to get a response from the polkit service after some small adjustments:
#include <QtDBus>
int main() {
// Not all Qt types are compatible with the D-Bus interface by default:
// QMap<QString, QVariant> is, but QMap<QString, QString> is not.
// If you need such a type, even if only to pass an empty
// Dict<String, String>, it must first be registered like so:
qDBusRegisterMetaType<QMap<QString, QString>>();
// Subject kind should be provided as a QString, integers as Qt types
QDBusArgument subject;
subject.beginStructure();
subject << QString("unix-process");
subject << QMap<QString, QVariant>{
{"pid", static_cast<quint32>(QCoreApplication::applicationPid())},
{"start-time", static_cast<quint64>(0)},
};
subject.endStructure();
// PolicyKit1 is on the system bus
QDBusInterface polkit(
"org.freedesktop.PolicyKit1",
"/org/freedesktop/PolicyKit1/Authority",
"org.freedesktop.PolicyKit1.Authority",
QDBusConnection::systemBus()
);
// callWithArgumentList only takes actual QVariantLists as the arguments,
// call is a more convenient variadic function template
auto result = polkit.call(
QDBus::CallMode::AutoDetect,
"CheckAuthorization",
QVariant::fromValue(subject),
"org.freedesktop.login1.set-user-linger",
QVariant::fromValue(QMap<QString, QString>{}),
0x1u, // AllowUserInteraction = 0x00000001
""
);
qInfo() << result;
}
This resulted in the following output:
QDBusMessage(type=MethodReturn, service=":1.1", signature="(bba{ss})", contents=([Argument: (bba{ss}) false, true, [Argument: a{ss} {"polkit.retains_authorization_after_challenge" = "1"}]]) )
Some further remarks:
- Types registered with the D-Bus type system must be convertible to and from QDBusArgument by the << and >> operators, which is why you can run into issues when using those with non-Qt types. You can implement these operators for other types to allow registering them;
- Types passed to a D-Bus call must be implicitly convertible to QVariant. If they are not, you can convert them explicitly using QVariant::fromValue().
Once these requirements are met, you should be able to get meaningful output from D-Bus, even if you pass the wrong arguments. For example, leaving out the last string argument to CheckAuthorization leads to an InvalidArgs error response with the message
Type of message, “((sa{sv})sa{ss}u)”, does not match expected type “((sa{sv})sa{ss}us)”
The string encodes the expected types
{
{
String,
Dict<String, Variant>
},
String,
Dict<String, String>,
Uint32,
String
}