Skip to content

Commit a3834ed

Browse files
committed
service/polkit: address review comments
1 parent 16809c6 commit a3834ed

File tree

13 files changed

+229
-97
lines changed

13 files changed

+229
-97
lines changed

src/services/polkit/agentimpl.cpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
#include <algorithm>
33
#include <utility>
44

5-
#include <glib-object.h>
65
#include <qlist.h>
76
#include <qloggingcategory.h>
87
#include <qobject.h>
98
#include <qtmetamacros.h>
109

1110
#include "../../core/generation.hpp"
1211
#include "../../core/logcat.hpp"
12+
#include "gobjectref.hpp"
1313
#include "listener.hpp"
1414
#include "qml.hpp"
1515

@@ -22,10 +22,10 @@ PolkitAgentImpl* PolkitAgentImpl::instance = nullptr;
2222

2323
PolkitAgentImpl::PolkitAgentImpl(PolkitAgent* agent)
2424
: QObject(nullptr)
25-
, listener(qs_polkit_agent_new(this))
25+
, listener(qs_polkit_agent_new(this), G_OBJECT_NO_REF)
2626
, qmlAgent(agent) {
2727
auto path = this->qmlAgent->path().toUtf8();
28-
qs_polkit_agent_register(this->listener, path.constData());
28+
qs_polkit_agent_register(this->listener.get(), path.constData());
2929
}
3030

3131
PolkitAgentImpl::~PolkitAgentImpl() {
@@ -41,8 +41,7 @@ PolkitAgentImpl::~PolkitAgentImpl() {
4141
this->activeFlow->deleteLater();
4242
}
4343

44-
if (this->isRegistered) qs_polkit_agent_unregister(this->listener);
45-
g_object_unref(this->listener);
44+
if (this->isRegistered) qs_polkit_agent_unregister(this->listener.get());
4645
}
4746

4847
PolkitAgentImpl* PolkitAgentImpl::tryGetOrCreate(PolkitAgent* agent) {
@@ -58,7 +57,7 @@ PolkitAgentImpl* PolkitAgentImpl::tryGet(const PolkitAgent* agent) {
5857
}
5958

6059
PolkitAgentImpl* PolkitAgentImpl::tryTakeover(PolkitAgent* agent) {
61-
if (auto* impl = tryGet(agent); impl != nullptr) return impl;
60+
if (auto* impl = tryGetOrCreate(agent); impl != nullptr) return impl;
6261

6362
auto* prevGen = EngineGeneration::findObjectGeneration(instance->qmlAgent);
6463
auto* myGen = EngineGeneration::findObjectGeneration(agent);
@@ -128,7 +127,7 @@ void PolkitAgentImpl::activateAuthenticationRequest() {
128127
<< ", cookie: " << req->cookie;
129128

130129
QList<Identity*> identities;
131-
for (auto* identity: req->identities) {
130+
for (auto& identity: req->identities) {
132131
auto* obj = Identity::fromPolkitIdentity(identity);
133132
if (obj) identities.append(obj);
134133
}

src/services/polkit/agentimpl.hpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <qobject.h>
66

77
#include "flow.hpp"
8+
#include "gobjectref.hpp"
89
#include "listener.hpp"
910

1011
namespace qs::service::polkit {
@@ -14,8 +15,11 @@ class PolkitAgentImpl
1415
: public QObject
1516
, public ListenerCb {
1617
Q_OBJECT;
18+
Q_DISABLE_COPY_MOVE(PolkitAgentImpl);
1719

1820
public:
21+
~PolkitAgentImpl() override;
22+
1923
static PolkitAgentImpl* tryGetOrCreate(PolkitAgent* agent);
2024
static PolkitAgentImpl* tryGet(const PolkitAgent* agent);
2125
static PolkitAgentImpl* tryTakeover(PolkitAgent* agent);
@@ -27,7 +31,6 @@ class PolkitAgentImpl
2731

2832
private:
2933
PolkitAgentImpl(PolkitAgent* agent);
30-
~PolkitAgentImpl() override;
3134

3235
static PolkitAgentImpl* instance;
3336

@@ -36,7 +39,7 @@ class PolkitAgentImpl
3639
/// Finalize and remove the current authentication request.
3740
void finishAuthenticationRequest();
3841

39-
QsPolkitAgent* listener = nullptr;
42+
GObjectRef<QsPolkitAgent> listener;
4043
bool isRegistered = false;
4144

4245
PolkitAgent* qmlAgent = nullptr;

src/services/polkit/flow.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <qlist.h>
55
#include <qloggingcategory.h>
66
#include <qobject.h>
7+
#include <qqmlinfo.h>
78
#include <qtmetamacros.h>
89

910
#include "../../core/logcat.hpp"
@@ -20,9 +21,15 @@ AuthFlow::AuthFlow(AuthRequest* request, QList<Identity*>&& identities, QObject*
2021
: QObject(parent)
2122
, mRequest(request)
2223
, mIdentities(std::move(identities))
23-
, mSelectedIdentity(mIdentities.isEmpty() ? nullptr : mIdentities.first()) {
24+
, mSelectedIdentity(this->mIdentities.isEmpty() ? nullptr : this->mIdentities.first()) {
25+
// We reject auth requests with no identities before a flow is created.
26+
// This should never happen.
2427
if (!this->mSelectedIdentity)
25-
qCCritical(logPolkitState) << "AuthFlow created with no valid identities!";
28+
qCFatal(logPolkitState) << "AuthFlow created with no valid identities!";
29+
30+
for (auto* identity: this->mIdentities) {
31+
identity->setParent(this);
32+
}
2633

2734
this->setupSession();
2835
}
@@ -39,7 +46,10 @@ Identity* AuthFlow::selectedIdentity() const { return this->mSelectedIdentity; }
3946

4047
void AuthFlow::setSelectedIdentity(Identity* identity) {
4148
if (this->mSelectedIdentity == identity) return;
42-
if (!identity) return; // ignore null changes
49+
if (!identity) {
50+
qmlWarning(this) << "Cannot set selected identity to null.";
51+
return;
52+
}
4353
for (auto* id: this->mIdentities) {
4454
if (id == identity) {
4555
this->mSelectedIdentity = id;
@@ -101,7 +111,7 @@ void AuthFlow::setupSession() {
101111
qCDebug(logPolkitState) << "setting up session for identity" << this->mSelectedIdentity->name();
102112

103113
this->currentSession =
104-
new Session(this->mSelectedIdentity->polkitIdentity, this->mRequest->cookie, this);
114+
new Session(this->mSelectedIdentity->polkitIdentity.get(), this->mRequest->cookie, this);
105115
QObject::connect(this->currentSession, &Session::request, this, &AuthFlow::request);
106116
QObject::connect(this->currentSession, &Session::completed, this, &AuthFlow::completed);
107117
QObject::connect(this->currentSession, &Session::showError, this, &AuthFlow::showError);

src/services/polkit/flow.hpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class AuthFlow
1515
, public Retainable {
1616
Q_OBJECT;
1717
QML_ELEMENT;
18+
Q_DISABLE_COPY_MOVE(AuthFlow);
1819
QML_UNCREATABLE("AuthFlow can only be obtained from PolkitAgent.");
1920

2021
// clang-format off
@@ -24,6 +25,8 @@ class AuthFlow
2425
/// The icon to present to the user in association with the message.
2526
///
2627
/// The icon name follows the [FreeDesktop icon naming specification](https://specifications.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html).
28+
/// Use @@Quickshell.Quickshell.iconPath() to resolve the icon name to an
29+
/// actual file path for display.
2730
Q_PROPERTY(QString iconName READ iconName CONSTANT);
2831

2932
/// The action ID represents the action that is being authorized.
@@ -44,10 +47,10 @@ class AuthFlow
4447
Q_PROPERTY(QList<Identity*> identities READ identities CONSTANT);
4548

4649
/// The identity that will be used to authenticate.
47-
///
48-
/// Setting this will abort any ongoing authentication conversations and start a new one.
50+
///
51+
/// Changing this will abort any ongoing authentication conversations and start a new one.
4952
Q_PROPERTY(Identity* selectedIdentity READ selectedIdentity WRITE setSelectedIdentity NOTIFY selectedIdentityChanged);
50-
53+
5154
/// Indicates that a response from the user is required from the user,
5255
/// typically a password.
5356
Q_PROPERTY(bool isResponseRequired READ isResponseRequired NOTIFY responseRequestChanged);
@@ -61,6 +64,7 @@ class AuthFlow
6164
/// An additional message to present to the user.
6265
///
6366
/// This may be used to show errors or supplementary information.
67+
/// See @@supplementaryIsError to determine if this is an error message.
6468
Q_PROPERTY(QString supplementaryMessage READ supplementaryMessage NOTIFY supplementaryChanged);
6569

6670
/// Indicates whether the supplementary message is an error.

src/services/polkit/gobjectref.hpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#pragma once
2+
3+
#include <glib-object.h>
4+
5+
namespace qs::service::polkit {
6+
7+
struct GObjectNoRefTag {};
8+
constexpr GObjectNoRefTag G_OBJECT_NO_REF;
9+
10+
template <typename T>
11+
class GObjectRef {
12+
public:
13+
explicit GObjectRef(T* ptr = nullptr): ptr(ptr) {
14+
if (this->ptr) {
15+
g_object_ref(this->ptr);
16+
}
17+
}
18+
19+
explicit GObjectRef(T* ptr, GObjectNoRefTag /*tag*/): ptr(ptr) {}
20+
21+
~GObjectRef() {
22+
if (this->ptr) {
23+
g_object_unref(this->ptr);
24+
}
25+
}
26+
27+
// We do handle self-assignment in a more general case by checking the
28+
// included pointers rather than the wrapper objects themselves.
29+
// NOLINTBEGIN(bugprone-unhandled-self-assignment)
30+
31+
GObjectRef(const GObjectRef& other): GObjectRef(other.ptr) {}
32+
GObjectRef& operator=(const GObjectRef& other) {
33+
if (*this == other) return *this;
34+
if (this->ptr) {
35+
g_object_unref(this->ptr);
36+
}
37+
this->ptr = other.ptr;
38+
if (this->ptr) {
39+
g_object_ref(this->ptr);
40+
}
41+
return *this;
42+
}
43+
44+
GObjectRef(GObjectRef&& other) noexcept: ptr(other.ptr) { other.ptr = nullptr; }
45+
GObjectRef& operator=(GObjectRef&& other) noexcept {
46+
if (*this == other) return *this;
47+
if (this->ptr) {
48+
g_object_unref(this->ptr);
49+
}
50+
this->ptr = other.ptr;
51+
other.ptr = nullptr;
52+
return *this;
53+
}
54+
55+
// NOLINTEND(bugprone-unhandled-self-assignment)
56+
57+
[[nodiscard]] T* get() const { return this->ptr; }
58+
T* operator->() const { return this->ptr; }
59+
60+
bool operator==(const GObjectRef<T>& other) const { return this->ptr == other.ptr; }
61+
62+
private:
63+
T* ptr;
64+
};
65+
} // namespace qs::service::polkit

src/services/polkit/identity.cpp

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
#include "identity.hpp"
2+
#include <type_traits>
23
#include <utility>
4+
#include <vector>
35

46
#include <qobject.h>
57
#include <qtmetamacros.h>
8+
#include <qtypes.h>
69
#include <sys/types.h>
710

811
#define POLKIT_AGENT_I_KNOW_API_IS_SUBJECT_TO_CHANGE
@@ -12,53 +15,77 @@
1215
#define signals Q_SIGNALS
1316
#include <grp.h>
1417
#include <pwd.h>
18+
#include <unistd.h>
19+
20+
#include "gobjectref.hpp"
1521

1622
namespace qs::service::polkit {
1723
Identity::Identity(
1824
id_t id,
1925
QString name,
2026
QString displayName,
2127
bool isGroup,
22-
PolkitIdentity* polkitIdentity,
28+
GObjectRef<PolkitIdentity> polkitIdentity,
2329
QObject* parent
2430
)
2531
: QObject(parent)
26-
, polkitIdentity(polkitIdentity)
32+
, polkitIdentity(std::move(polkitIdentity))
2733
, mId(id)
2834
, mName(std::move(name))
2935
, mDisplayName(std::move(displayName))
3036
, mIsGroup(isGroup) {}
3137

3238
Identity::~Identity() = default;
3339

34-
Identity* Identity::fromPolkitIdentity(PolkitIdentity* identity) {
35-
if (POLKIT_IS_UNIX_USER(identity)) {
36-
auto uid = polkit_unix_user_get_uid(POLKIT_UNIX_USER(identity));
37-
auto* pw = getpwuid(uid);
40+
Identity* Identity::fromPolkitIdentity(GObjectRef<PolkitIdentity> identity) {
41+
if (POLKIT_IS_UNIX_USER(identity.get())) {
42+
auto uid = polkit_unix_user_get_uid(POLKIT_UNIX_USER(identity.get()));
43+
44+
auto bufSize = sysconf(_SC_GETPW_R_SIZE_MAX);
45+
// The call can fail with -1, in this case choose a default that is
46+
// big enough.
47+
if (bufSize == -1) bufSize = 16384;
48+
auto buffer = std::vector<char>(bufSize);
49+
50+
std::aligned_storage_t<sizeof(passwd), alignof(passwd)> pwBuf;
51+
passwd* pw = nullptr;
52+
getpwuid_r(uid, reinterpret_cast<passwd*>(&pwBuf), buffer.data(), bufSize, &pw);
53+
3854
auto name =
3955
(pw && pw->pw_name && *pw->pw_name) ? QString::fromUtf8(pw->pw_name) : QString::number(uid);
56+
4057
return new Identity(
4158
uid,
4259
name,
4360
(pw && pw->pw_gecos && *pw->pw_gecos) ? QString::fromUtf8(pw->pw_gecos) : name,
4461
false,
45-
identity
62+
std::move(identity)
4663
);
4764
}
4865

49-
if (POLKIT_IS_UNIX_GROUP(identity)) {
50-
auto gid = polkit_unix_group_get_gid(POLKIT_UNIX_GROUP(identity));
51-
auto* gr = getgrgid(gid);
66+
if (POLKIT_IS_UNIX_GROUP(identity.get())) {
67+
auto gid = polkit_unix_group_get_gid(POLKIT_UNIX_GROUP(identity.get()));
68+
69+
auto bufSize = sysconf(_SC_GETGR_R_SIZE_MAX);
70+
// The call can fail with -1, in this case choose a default that is
71+
// big enough.
72+
if (bufSize == -1) bufSize = 16384;
73+
auto buffer = std::vector<char>(bufSize);
74+
75+
std::aligned_storage_t<sizeof(group), alignof(group)> grBuf;
76+
group* gr = nullptr;
77+
getgrgid_r(gid, reinterpret_cast<group*>(&grBuf), buffer.data(), bufSize, &gr);
78+
5279
auto name =
5380
(gr && gr->gr_name && *gr->gr_name) ? QString::fromUtf8(gr->gr_name) : QString::number(gid);
54-
return new Identity(gid, name, name, true, identity);
81+
return new Identity(gid, name, name, true, std::move(identity));
5582
}
5683

5784
// A different type of identity is netgroup.
5885
return nullptr;
5986
}
6087

61-
id_t Identity::id() const { return this->mId; }
88+
quint32 Identity::id() const { return this->mId; }
6289
const QString& Identity::name() const { return this->mName; }
6390
const QString& Identity::displayName() const { return this->mDisplayName; }
6491
bool Identity::isGroup() const { return this->mIsGroup; }

src/services/polkit/identity.hpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,21 @@
33
#include <qobject.h>
44
#include <qqmlintegration.h>
55

6-
using PolkitIdentity = struct _PolkitIdentity;
6+
#include "gobjectref.hpp"
7+
8+
// _PolkitIdentity is considered a reserved identifier, but I am specifically
9+
// forward declaring this reserved name.
10+
using PolkitIdentity = struct _PolkitIdentity; // NOLINT(bugprone-reserved-identifier)
711

812
namespace qs::service::polkit {
913
//! Represents a user or group that can be used to authenticate.
1014
class Identity: public QObject {
1115
Q_OBJECT;
16+
Q_DISABLE_COPY_MOVE(Identity);
1217

1318
// clang-format off
1419
/// The Id of the identity. If the identity is a user, this is the user's uid. See @@isGroup.
15-
Q_PROPERTY(id_t id READ id CONSTANT);
20+
Q_PROPERTY(quint32 id READ id CONSTANT);
1621

1722
/// The name of the user or group.
1823
///
@@ -36,19 +41,19 @@ class Identity: public QObject {
3641
QString name,
3742
QString displayName,
3843
bool isGroup,
39-
PolkitIdentity* polkitIdentity,
44+
GObjectRef<PolkitIdentity> polkitIdentity,
4045
QObject* parent = nullptr
4146
);
4247
~Identity() override;
4348

44-
static Identity* fromPolkitIdentity(PolkitIdentity* identity);
49+
static Identity* fromPolkitIdentity(GObjectRef<PolkitIdentity> identity);
4550

46-
[[nodiscard]] id_t id() const;
51+
[[nodiscard]] quint32 id() const;
4752
[[nodiscard]] const QString& name() const;
4853
[[nodiscard]] const QString& displayName() const;
4954
[[nodiscard]] bool isGroup() const;
5055

51-
PolkitIdentity* polkitIdentity;
56+
GObjectRef<PolkitIdentity> polkitIdentity;
5257

5358
private:
5459
id_t mId;

0 commit comments

Comments
 (0)