Skip to content

Commit f21117d

Browse files
deepin-ci-robotxionglinlin
authored andcommitted
sync: from linuxdeepin/dde-session-shell
Synchronize source files from linuxdeepin/dde-session-shell. Source-pull-request: linuxdeepin/dde-session-shell#68
1 parent 115a750 commit f21117d

7 files changed

Lines changed: 318 additions & 2 deletions

File tree

CMakeLists.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ set(LOCK_SRCS
252252
src/dde-lock/lockframe.cpp
253253
src/dde-lock/lockworker.cpp
254254
src/dde-lock/updateworker.cpp
255+
src/dde-lock/securityloaderhelper.cpp
255256
src/dde-lock/dbus/dbuslockagent.cpp
256257
src/dde-lock/dbus/dbuslockfrontservice.cpp
257258
src/dde-lock/dbus/dbusshutdownagent.cpp
@@ -426,7 +427,13 @@ else () # snipe
426427
install(PROGRAMS ${SCRIPTS} DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/deepin/greeters.d)
427428
endif ()
428429

429-
install(TARGETS dde-lock lightdm-deepin-greeter greeter-display-setting DESTINATION ${CMAKE_INSTALL_BINDIR})
430+
# dde-lock binary installed to libexec/deepin for security-loader
431+
install(TARGETS dde-lock DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/deepin)
432+
install(TARGETS lightdm-deepin-greeter greeter-display-setting DESTINATION ${CMAKE_INSTALL_BINDIR})
433+
# Install loader wrapper script as /usr/bin/dde-lock
434+
install(PROGRAMS files/dde-lock-loader-wrapper DESTINATION ${CMAKE_INSTALL_BINDIR}
435+
RENAME dde-lock
436+
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
430437

431438
# 指定greeter,优先级最低,允许被其他应用以更高的配置文件覆盖
432439
install(FILES files/50-deepin.conf DESTINATION ${CMAKE_INSTALL_DATADIR}/lightdm/lightdm.conf.d)

files/dde-lock-loader-wrapper

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/bin/bash
2+
# dde-lock wrapper for deepin-security-loader
3+
# Launches dde-lock through security loader to get authorization
4+
# for calling protected system services without polkit popup.
5+
6+
REAL_BINARY="/usr/libexec/deepin/dde-lock"
7+
LOADER="/usr/bin/deepin-security-loader"
8+
LOADER_EXEC="/usr/bin/deepin-security-loader-exec"
9+
10+
# Log to systemd journal with tag "dde-lock"
11+
log_to_journal() {
12+
logger -t dde-lock -p user.info "$1"
13+
}
14+
15+
# Log startup
16+
log_to_journal "dde-lock launched with args: $*"
17+
18+
# Check if loader is available and has proper capabilities
19+
if [ -x "$LOADER" ] && [ -x "$LOADER_EXEC" ]; then
20+
if getcap "$LOADER_EXEC" 2>/dev/null | grep -q cap_setgid; then
21+
# Launch via loader with authorization groups
22+
log_to_journal "Using deepin-security-loader with authorization groups"
23+
exec "$LOADER" --group deepin-daemon -- "$REAL_BINARY" "$@"
24+
fi
25+
fi
26+
27+
# Fallback: direct launch without loader (no polkit-free authorization)
28+
log_to_journal "Fallback: launching directly without security loader"
29+
exec "$REAL_BINARY" "$@"
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"DestList": [
3+
{
4+
"DbusName": "org.deepin.dde.Lastore1",
5+
"DbusPath": "/org/deepin/dde/Lastore1",
6+
"DbusInterface": "org.deepin.dde.Lastore1.Manager"
7+
},
8+
{
9+
"DbusName": "org.deepin.dde.Authenticate1",
10+
"DbusPath": "/org/deepin/dde/Authenticate1",
11+
"DbusInterface": "org.deepin.dde.Authenticate1"
12+
}
13+
]
14+
}

resources.qrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<RCC>
22
<qresource prefix="/">
3+
<file>files/permission-interfaces/auth.json</file>
34
<file>misc/images/caps_lock.svg</file>
45
<file>misc/images/login_check.svg</file>
56
<file>misc/images/login_lock.svg</file>

src/app/dde-lock.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// SPDX-FileCopyrightText: 2015 - 2022 UnionTech Software Technology Co., Ltd.
1+
// SPDX-FileCopyrightText: 2015 - 2026 UnionTech Software Technology Co., Ltd.
22
//
33
// SPDX-License-Identifier: GPL-3.0-or-later
44

@@ -16,6 +16,7 @@
1616
#include "sessionbasemodel.h"
1717
#include "warningcontent.h"
1818
#include "plugin_manager.h"
19+
#include "securityloaderhelper.h"
1920
#include "dbusconstant.h"
2021

2122
#include <DApplication>
@@ -109,9 +110,18 @@ int main(int argc, char *argv[])
109110
QCommandLineOption quickLoginProcess(QStringList() << "q" << "quicklogin", "show for quick login");
110111
cmdParser.addOption(quickLoginProcess);
111112

113+
QCommandLineOption fd1Opt("fd1", "fd1 from security loader", "fd1");
114+
cmdParser.addOption(fd1Opt);
115+
QCommandLineOption fd2Opt("fd2", "fd2 from security loader", "fd2");
116+
cmdParser.addOption(fd2Opt);
117+
112118
QStringList xddd = app->arguments();
113119
cmdParser.process(*app);
114120

121+
int fd1 = cmdParser.isSet(fd1Opt) ? cmdParser.value(fd1Opt).toInt() : -1;
122+
int fd2 = cmdParser.isSet(fd2Opt) ? cmdParser.value(fd2Opt).toInt() : -1;
123+
SecurityLoaderHelper::instance().doSecurityLoader(fd1, fd2);
124+
115125
bool runDaemon = cmdParser.isSet(backend);
116126
bool showUserList = cmdParser.isSet(switchUser);
117127
bool showShutdown = cmdParser.isSet(shutdown);
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd.
2+
//
3+
// SPDX-License-Identifier: GPL-3.0-or-later
4+
5+
#include "securityloaderhelper.h"
6+
#include "dbusconstant.h"
7+
8+
#include <QFile>
9+
#include <QJsonDocument>
10+
#include <QJsonObject>
11+
#include <QJsonParseError>
12+
#include <QLoggingCategory>
13+
#include <QDBusConnection>
14+
#include <QDBusConnectionInterface>
15+
#include <QDBusInterface>
16+
#include <QDBusReply>
17+
#include <unistd.h>
18+
19+
Q_LOGGING_CATEGORY(secLoader, "org.deepin.dde.lock.securityloader")
20+
21+
const QString SecurityLoaderHelper::DEFAULT_CONFIG_PATH = ":/files/permission-interfaces/auth.json";
22+
23+
SecurityLoaderHelper::SecurityLoaderHelper(QObject *parent)
24+
: QObject(parent)
25+
{
26+
}
27+
28+
SecurityLoaderHelper::~SecurityLoaderHelper() {}
29+
30+
SecurityLoaderHelper &SecurityLoaderHelper::instance()
31+
{
32+
static SecurityLoaderHelper instance;
33+
return instance;
34+
}
35+
36+
void SecurityLoaderHelper::doSecurityLoader(int fd1, int fd2)
37+
{
38+
if (fd1 < 0 || fd2 < 0) {
39+
qCWarning(secLoader) << "Not loaded by loader, skipping handshake";
40+
return;
41+
}
42+
43+
qCInfo(secLoader) << "Detected loader injection: fd1=" << fd1 << "fd2=" << fd2;
44+
45+
loadConfig();
46+
// appendCurrentUserAccountsUserDest();
47+
if (!performHandshake(fd1, fd2)) {
48+
qCWarning(secLoader) << "Security loader handshake failed";
49+
}
50+
}
51+
52+
void SecurityLoaderHelper::loadConfig(const QString &configPath)
53+
{
54+
QString path = configPath.isEmpty() ? DEFAULT_CONFIG_PATH : configPath;
55+
56+
qCInfo(secLoader) << "Loading permission config from:" << path;
57+
58+
m_destList = QJsonArray();
59+
parseJsonFile(path);
60+
61+
qCInfo(secLoader) << "Loaded" << m_destList.size() << "D-Bus interfaces to authorize";
62+
}
63+
64+
void SecurityLoaderHelper::parseJsonFile(const QString &filePath)
65+
{
66+
QFile file(filePath);
67+
if (!file.open(QIODevice::ReadOnly)) {
68+
qCWarning(secLoader) << "Cannot open file:" << filePath;
69+
return;
70+
}
71+
72+
QJsonParseError error;
73+
QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &error);
74+
file.close();
75+
76+
if (error.error != QJsonParseError::NoError) {
77+
qCWarning(secLoader) << "JSON parse error in" << filePath << ":" << error.errorString();
78+
return;
79+
}
80+
81+
QJsonObject root = doc.object();
82+
if (!root.contains("DestList") || !root["DestList"].isArray()) {
83+
qCWarning(secLoader) << "Invalid config format in" << filePath << ": missing DestList";
84+
return;
85+
}
86+
87+
for (const auto &item : root["DestList"].toArray()) {
88+
appendDest(item.toObject());
89+
}
90+
}
91+
92+
void SecurityLoaderHelper::appendDest(const QJsonObject &dest)
93+
{
94+
const QString dbusName = dest["DbusName"].toString();
95+
const QString dbusPath = dest["DbusPath"].toString();
96+
const QString dbusInterface = dest["DbusInterface"].toString();
97+
98+
if (dbusName.isEmpty() || dbusPath.isEmpty() || dbusInterface.isEmpty()) {
99+
qCWarning(secLoader) << "Skip invalid D-Bus destination:" << dest;
100+
return;
101+
}
102+
103+
for (const auto &existing : m_destList) {
104+
const QJsonObject current = existing.toObject();
105+
if (current["DbusName"] == dbusName &&
106+
current["DbusPath"] == dbusPath &&
107+
current["DbusInterface"] == dbusInterface) {
108+
return;
109+
}
110+
}
111+
112+
m_destList.append(dest);
113+
qCInfo(secLoader) << " Added:" << dbusName << dbusPath << dbusInterface;
114+
}
115+
116+
void SecurityLoaderHelper::appendCurrentUserAccountsUserDest()
117+
{
118+
const QString userPath = currentUserAccountsPath();
119+
if (userPath.isEmpty()) {
120+
qCWarning(secLoader) << "Cannot resolve current user's Accounts.User path";
121+
return;
122+
}
123+
124+
QJsonObject dest;
125+
dest["DbusName"] = DSS_DBUS::accountsService;
126+
dest["DbusPath"] = userPath;
127+
dest["DbusInterface"] = DSS_DBUS::accountsUserInterface;
128+
appendDest(dest);
129+
}
130+
131+
QString SecurityLoaderHelper::currentUserAccountsPath() const
132+
{
133+
QDBusConnection systemBus = QDBusConnection::systemBus();
134+
if (!systemBus.isConnected()) {
135+
qCWarning(secLoader) << "Cannot connect to system bus when resolving current user path";
136+
return {};
137+
}
138+
139+
QDBusInterface accountsInterface(DSS_DBUS::accountsService, DSS_DBUS::accountsPath, DSS_DBUS::accountsService, systemBus);
140+
if (!accountsInterface.isValid()) {
141+
qCWarning(secLoader) << "Accounts interface invalid when resolving current user path:"
142+
<< accountsInterface.lastError().message();
143+
return {};
144+
}
145+
146+
QDBusReply<QString> reply = accountsInterface.call(QStringLiteral("FindUserById"), QString::number(getuid()));
147+
if (!reply.isValid()) {
148+
qCWarning(secLoader) << "FindUserById failed when resolving current user path:"
149+
<< reply.error().message();
150+
return {};
151+
}
152+
153+
return reply.value();
154+
}
155+
156+
bool SecurityLoaderHelper::performHandshake(int fd1, int fd2)
157+
{
158+
if (m_destList.isEmpty()) {
159+
qCInfo(secLoader) << "No D-Bus interfaces loaded, skipping handshake";
160+
return true;
161+
}
162+
163+
qCInfo(secLoader) << "Performing loader handshake...";
164+
165+
QDBusConnection systemBus = QDBusConnection::systemBus();
166+
if (!systemBus.isConnected()) {
167+
qCWarning(secLoader) << "Cannot connect to system bus";
168+
return false;
169+
}
170+
// 偶现dbus的 unique name 发生变化,Qt的systemBus.baseService()实际上并未把dbus注册到总线上,要调用一下方法才行
171+
systemBus.interface()->isServiceRegistered("org.freedesktop.DBus");
172+
QString uniqueName = systemBus.baseService();
173+
qCInfo(secLoader) << "System Bus UniqueName:" << uniqueName;
174+
175+
QJsonObject request;
176+
request["UniqueName"] = uniqueName;
177+
request["DestList"] = m_destList;
178+
179+
QJsonDocument doc(request);
180+
QByteArray jsonData = doc.toJson(QJsonDocument::Compact);
181+
182+
qCInfo(secLoader) << "Sending request with" << m_destList.size() << "interfaces";
183+
184+
QFile fd1File;
185+
if (!fd1File.open(fd1, QIODevice::WriteOnly)) {
186+
qCWarning(secLoader) << "Cannot open fd1 for writing";
187+
return false;
188+
}
189+
fd1File.write(jsonData);
190+
fd1File.close();
191+
qCInfo(secLoader) << "Sent authorization request to loader";
192+
193+
QFile fd2File;
194+
if (!fd2File.open(fd2, QIODevice::ReadOnly)) {
195+
qCWarning(secLoader) << "Cannot open fd2 for reading";
196+
return false;
197+
}
198+
199+
QByteArray response = fd2File.readAll();
200+
fd2File.close();
201+
202+
QJsonParseError parseError;
203+
QJsonDocument responseDoc = QJsonDocument::fromJson(response, &parseError);
204+
if (parseError.error != QJsonParseError::NoError) {
205+
qCWarning(secLoader) << "Invalid JSON response from loader:" << parseError.errorString();
206+
return false;
207+
}
208+
209+
QJsonObject result = responseDoc.object();
210+
if (result["Result"].toBool()) {
211+
qCInfo(secLoader) << "Loader handshake completed successfully";
212+
return true;
213+
} else {
214+
qCWarning(secLoader) << "Loader authorization response:" << result["Message"].toString();
215+
return false;
216+
}
217+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd.
2+
//
3+
// SPDX-License-Identifier: GPL-3.0-or-later
4+
5+
#ifndef SECURITYLOADERHELPER_H
6+
#define SECURITYLOADERHELPER_H
7+
8+
#include <QObject>
9+
#include <QJsonArray>
10+
11+
class SecurityLoaderHelper : public QObject
12+
{
13+
Q_OBJECT
14+
15+
public:
16+
static SecurityLoaderHelper &instance();
17+
void doSecurityLoader(int fd1, int fd2);
18+
19+
private:
20+
explicit SecurityLoaderHelper(QObject *parent = nullptr);
21+
~SecurityLoaderHelper();
22+
23+
SecurityLoaderHelper(const SecurityLoaderHelper &) = delete;
24+
SecurityLoaderHelper &operator=(const SecurityLoaderHelper &) = delete;
25+
26+
void loadConfig(const QString &configPath = QString());
27+
void parseJsonFile(const QString &filePath);
28+
void appendDest(const QJsonObject &dest);
29+
void appendCurrentUserAccountsUserDest();
30+
QString currentUserAccountsPath() const;
31+
bool performHandshake(int fd1, int fd2);
32+
33+
private:
34+
QJsonArray m_destList;
35+
static const QString DEFAULT_CONFIG_PATH;
36+
};
37+
38+
#endif // SECURITYLOADERHELPER_H

0 commit comments

Comments
 (0)