26 #include <QDBusMessage>
27 #include <QDBusPendingCall>
28 #include <QDBusPendingCallWatcher>
33 #include <QVariantList>
34 #include <QVariantMap>
39 #include <sys/apparmor.h>
44 namespace MediaHubService = apparmor::lomiri;
49 static constexpr std::size_t index_package{0};
50 static constexpr std::size_t index_app{1};
54 bool process_context_name(
const QString &s, QStringList &out,
59 if (s ==
"messaging-app")
67 if (out.count() == 2 || out.count() == 3)
69 pkg_name = out[index_package];
77 apparmor::lomiri::Context::Context(
const QString &name)
79 unconfined_{str() == lomiri::unconfined},
80 has_package_name_{process_context_name(str(), app_id_parts, pkg_name_)}
82 MH_DEBUG(
"apparmor profile name: %s", qUtf8Printable(name));
83 MH_DEBUG(
"is_unconfined(): %s", (is_unconfined() ?
"true" :
"false"));
84 MH_DEBUG(
"has_package_name(): %s", (has_package_name() ?
"true" :
"false"));
85 if (not is_unconfined() and not has_package_name()) {
86 MH_FATAL(
"apparmor::lomiri::Context: Invalid profile name %s", qUtf8Printable(str()));
97 return has_package_name_;
107 switch (app_id_parts.count()) {
109 return app_id_parts[2];
111 return app_id_parts[1];
119 return app_id_parts.isEmpty() ?
120 str() : (app_id_parts[index_package] +
"-" + app_id_parts[index_app]);
124 m_connection(QDBusConnection::sessionBus())
132 const QString dbusServiceName =
133 qEnvironmentVariable(
"MEDIA_HUB_MOCKED_DBUS",
"org.freedesktop.DBus");
135 QDBusMessage::createMethodCall(dbusServiceName,
136 "/org/freedesktop/DBus",
137 "org.freedesktop.DBus",
138 "GetConnectionCredentials");
139 msg.setArguments({ name });
140 QDBusPendingCall call = QDBusConnection::sessionBus().asyncCall(msg);
141 QDBusPendingCallWatcher *callWatcher =
new QDBusPendingCallWatcher(call);
142 QObject::connect(callWatcher, &QDBusPendingCallWatcher::finished,
143 [cb](QDBusPendingCallWatcher *callWatcher) {
144 QDBusReply<QVariantMap> reply(*callWatcher);
146 if (reply.isValid()) {
147 QVariantMap map = reply.value();
148 QByteArray context = map.value(
"LinuxSecurityLabel").toByteArray();
149 if (!context.isEmpty()) {
150 aa_splitcon(context.data(), NULL);
151 appId = QString::fromUtf8(context);
154 QDBusError error = reply.error();
155 qWarning() <<
"Error getting app ID:" << error.name() <<
159 callWatcher->deleteLater();
163 bool apparmor::lomiri::ExistingAuthenticator::is_click_package_path(
const apparmor::lomiri::Context& context,
const QString &path)
165 g_autoptr(ClickDB) db = 0;
166 g_autoptr(GError) error = 0;
167 g_autofree gchar *click_path = 0;
168 QString
package = context.package_name();
173 qWarning() <<
"Failed to create ClickDB";
176 click_db_read(db, 0, &error);
178 qWarning() <<
"Error reading click DB:" << error->message;
181 click_path = click_db_get_path(db, package.toUtf8(), version.toUtf8(), &error);
183 MH_DEBUG(
"click package path could not be determined for %s: %s", qUtf8Printable(context.
package_name()), error->message);
187 return path.startsWith(QString(click_path));
193 return Result{
true,
"Client allowed access since it's unconfined"};
195 QString path = uri.path();
197 MH_DEBUG(
"parsed_uri.path: %s", qUtf8Printable(path));
200 if (path.contains(
".local/share/" + context.
package_name() +
"/") ||
201 path.contains(
".cache/" + context.
package_name() +
"/") ||
202 path.contains(
"/run/user/" + QString::number(geteuid()) +
"/confined/" + context.
package_name()))
213 (path.contains(
".local/share/" + context.
profile_name() +
".ubports/") ||
214 path.contains(
".cache/" + context.
profile_name() +
".ubports/")))
222 else if (is_click_package_path(context, path))
224 return Result{
true,
"Client can access content in own opt directory"};
226 else if ((path.contains(
"/system/media/audio/ui/") ||
227 path.contains(
"/android/system/media/audio/ui/")) &&
230 return Result{
true,
"Camera app can access ui sounds"};
239 (path.contains(
"Music/") ||
240 path.contains(
"Videos/") ||
241 path.contains(
"/media")))
243 return Result{
true,
"Client can access content in ~/Music or ~/Videos"};
245 else if (path.contains(
"/usr/share/sounds"))
247 return Result{
true,
"Client can access content in /usr/share/sounds"};
249 else if (uri.scheme() ==
"http" ||
250 uri.scheme() ==
"https" ||
251 uri.scheme() ==
"rtsp")
253 return Result{
true,
"Client can access streaming content"};
256 return Result{
false,
"Client is not allowed to access: " + uri.toString()};