Support interactive authorization flag in DBusMessage

This flag was introduced to serve as a replacement for a dedicated "interactive" boolean
argument in method calls guarded by Polkit.

Change-Id: Ida91c9872e70f8ca6672563d0ca6642f38c498ab
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Kai Uwe Broulik 2018-04-04 15:48:53 +02:00
parent 5c5af7155a
commit d743df975d
7 changed files with 149 additions and 2 deletions

View File

@ -161,6 +161,19 @@ template <> struct TraceReturn<void> { typedef void Type; };
funcret DEBUGRET(ret) ptr argcall; \
}
# define DEFINEFUNC_CONDITIONALLY(ret, func, args, argcall, funcret, failret) \
typedef ret (* _q_PTR_##func) args; \
static inline ret q_##func args \
{ \
static _q_PTR_##func ptr; \
DEBUGCALL(#func, argcall); \
if (!ptr) \
ptr = (_q_PTR_##func) qdbus_resolve_conditionally(#func); \
if (!ptr) \
failret; \
funcret DEBUGRET(ret) ptr argcall; \
}
#else // defined QT_LINKED_LIBDBUS
inline bool qdbus_loadLibDBus() { return true; }
@ -300,6 +313,26 @@ DEFINEFUNC(const char* , dbus_message_get_signature, (DBusMessage *message),
(message), return)
DEFINEFUNC(int , dbus_message_get_type, (DBusMessage *message),
(message), return)
#if !defined QT_LINKED_LIBDBUS
DEFINEFUNC_CONDITIONALLY(dbus_bool_t , dbus_message_get_allow_interactive_authorization, (DBusMessage *message),
(message), return, return false)
#else // defined QT_LINKED_LIBDBUS
static inline dbus_bool_t q_dbus_message_get_allow_interactive_authorization(DBusMessage *message)
{
#ifdef DBUS_HEADER_FLAG_ALLOW_INTERACTIVE_AUTHORIZATION
return dbus_message_get_allow_interactive_authorization(message);
#else
Q_UNUSED(message);
return false;
#endif
}
#endif // defined QT_LINKED_LIBDBUS
DEFINEFUNC(dbus_bool_t , dbus_message_iter_append_basic, (DBusMessageIter *iter,
int type,
const void *value),
@ -378,9 +411,33 @@ DEFINEFUNC(dbus_bool_t , dbus_message_set_sender, (DBusMessage *message,
DEFINEFUNC(void , dbus_message_unref, (DBusMessage *message),
(message), )
#if !defined QT_LINKED_LIBDBUS
DEFINEFUNC_CONDITIONALLY(void, dbus_message_set_allow_interactive_authorization,
(DBusMessage *message, dbus_bool_t allow), (message, allow), return, return)
#else // defined QT_LINKED_LIBDBUS
static inline void q_dbus_message_set_allow_interactive_authorization(DBusMessage *message, dbus_bool_t allow)
{
#ifdef DBUS_HEADER_FLAG_ALLOW_INTERACTIVE_AUTHORIZATION
dbus_message_set_allow_interactive_authorization(message, allow);
#else
Q_UNUSED(message);
Q_UNUSED(allow);
#endif
}
#endif // defined QT_LINKED_LIBDBUS
/* dbus-misc.h */
DEFINEFUNC(char* , dbus_get_local_machine_id , (void), (), return)
DEFINEFUNC(void , dbus_get_version , (int *major_version, int *minor_version, int *micro_version)
, (major_version, minor_version, micro_version)
, return)
/* dbus-pending-call.h */
DEFINEFUNC(dbus_bool_t , dbus_pending_call_set_notify, (DBusPendingCall *pending,

View File

@ -70,7 +70,8 @@ static inline const char *data(const QByteArray &arr)
QDBusMessagePrivate::QDBusMessagePrivate()
: msg(0), reply(0), localReply(0), ref(1), type(QDBusMessage::InvalidMessage),
delayedReply(false), localMessage(false),
parametersValidated(false), autoStartService(true)
parametersValidated(false), autoStartService(true),
interactiveAuthorizationAllowed(false)
{
}
@ -138,6 +139,8 @@ DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message, QDB
msg = q_dbus_message_new_method_call(data(d_ptr->service.toUtf8()), d_ptr->path.toUtf8(),
data(d_ptr->interface.toUtf8()), d_ptr->name.toUtf8());
q_dbus_message_set_auto_start( msg, d_ptr->autoStartService );
q_dbus_message_set_allow_interactive_authorization(msg, d_ptr->interactiveAuthorizationAllowed);
break;
case QDBusMessage::ReplyMessage:
msg = q_dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
@ -242,6 +245,7 @@ QDBusMessage QDBusMessagePrivate::fromDBusMessage(DBusMessage *dmsg, QDBusConnec
QString::fromUtf8(q_dbus_message_get_member(dmsg));
message.d_ptr->service = QString::fromUtf8(q_dbus_message_get_sender(dmsg));
message.d_ptr->signature = QString::fromUtf8(q_dbus_message_get_signature(dmsg));
message.d_ptr->interactiveAuthorizationAllowed = q_dbus_message_get_allow_interactive_authorization(dmsg);
message.d_ptr->msg = q_dbus_message_ref(dmsg);
QDBusDemarshaller demarshaller(capabilities);
@ -724,6 +728,44 @@ bool QDBusMessage::autoStartService() const
return d_ptr->autoStartService;
}
/*!
Sets the interactive authorization flag to \a enable.
This flag only makes sense for method call messages, where it
tells the D-Bus server that the caller of the method is prepared
to wait for interactive authorization to take place (for instance
via Polkit) before the actual method is processed.
By default this flag is false and the other end is expected to
make any authorization decisions non-interactively and promptly.
The \c org.freedesktop.DBus.Error.InteractiveAuthorizationRequired
error indicates that authorization failed, but could have succeeded
if this flag had been set.
\sa isInteractiveAuthorizationAllowed()
\since 5.12
*/
void QDBusMessage::setInteractiveAuthorizationAllowed(bool enable)
{
d_ptr->interactiveAuthorizationAllowed = enable;
}
/*!
Returns the interactive authorization allowed flag, as set by
setInteractiveAuthorizationAllowed(). By default this flag
is false and the other end is expected to make any authorization
decisions non-interactively and promptly.
\sa setInteractiveAuthorizationAllowed()
\since 5.12
*/
bool QDBusMessage::isInteractiveAuthorizationAllowed() const
{
return d_ptr->interactiveAuthorizationAllowed;
}
/*!
Sets the arguments that are going to be sent over D-Bus to \a arguments. Those
will be the arguments to a method call or the parameters in the signal.

View File

@ -119,6 +119,9 @@ public:
void setAutoStartService(bool enable);
bool autoStartService() const;
void setInteractiveAuthorizationAllowed(bool enable);
bool isInteractiveAuthorizationAllowed() const;
void setArguments(const QList<QVariant> &arguments);
QList<QVariant> arguments() const;

View File

@ -87,6 +87,7 @@ public:
uint localMessage : 1;
mutable uint parametersValidated : 1;
uint autoStartService : 1;
uint interactiveAuthorizationAllowed : 1;
static void setParametersValidated(QDBusMessage &msg, bool enable)
{ msg.d_ptr->parametersValidated = enable; }

View File

@ -4,4 +4,11 @@ HEADERS += ../myobject.h
TARGET = ../tst_qdbusinterface
DESTDIR = ./
QT = core core-private dbus testlib
QT = core core-private dbus dbus-private testlib
qtConfig(dbus-linked) {
DEFINES += QT_LINKED_LIBDBUS
QMAKE_USE += dbus
} else {
SOURCES += ../../../../src/dbus/qdbus_symbols.cpp
}

View File

@ -115,6 +115,16 @@ public slots:
return obj.m_complexProp;
}
bool interactiveAuthorization()
{
if (message().isInteractiveAuthorizationAllowed())
return true;
sendErrorReply(QStringLiteral("org.freedesktop.DBus.Error.InteractiveAuthorizationRequired"),
QStringLiteral("Interactive authentication required."));
return false;
}
void quit()
{
qApp->quit();

View File

@ -33,6 +33,7 @@
#include <QtTest/QtTest>
#include <QtCore/qvariant.h>
#include <QtDBus/QtDBus>
#include <QtDBus/private/qdbus_symbols_p.h>
#include <qdebug.h>
#include "../qdbusmarshall/common.h"
#include "myobject.h"
@ -213,6 +214,8 @@ private slots:
void propertyWritePeer();
void complexPropertyReadPeer();
void complexPropertyWritePeer();
void interactiveAuthorizationRequired();
private:
QProcess proc;
};
@ -1127,6 +1130,30 @@ void tst_QDBusInterface::complexPropertyWritePeer()
QCOMPARE(complexPropPeer(), arg);
}
void tst_QDBusInterface::interactiveAuthorizationRequired()
{
int major;
int minor;
int micro;
q_dbus_get_version(&major, &minor, &micro);
QVersionNumber dbusVersion(major, minor, micro);
if (dbusVersion < QVersionNumber(1, 9, 2))
QSKIP("Your DBus library is too old to support interactive authorization");
QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "interactiveAuthorization");
QDBusMessage reply = QDBusConnection::sessionBus().call(req);
QCOMPARE(reply.type(), QDBusMessage::ErrorMessage);
QCOMPARE(reply.errorName(), QStringLiteral("org.freedesktop.DBus.Error.InteractiveAuthorizationRequired"));
req.setInteractiveAuthorizationAllowed(true);
reply = QDBusConnection::sessionBus().call(req);
QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);
QVERIFY(reply.arguments().at(0).toBool());
}
QTEST_MAIN(tst_QDBusInterface)
#include "tst_qdbusinterface.moc"