2
* Copyright (C) 2015 Canonical, Ltd.
4
* This library is free software; you can redistribute it and/or modify it under
5
* the terms of version 3 of the GNU General Public License as published
6
* by the Free Software Foundation.
8
* This library is distributed in the hope that it will be useful, but WITHOUT
9
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13
* You should have received a copy of the GNU General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17
* James Henstridge <james.henstridge@canonical.com>
20
#include "credentialscache.h"
22
#include <QDBusPendingCallWatcher>
26
#include <sys/apparmor.h>
32
char const DBUS_BUS_NAME[] = "org.freedesktop.DBus";
33
char const DBUS_BUS_PATH[] = "/org/freedesktop/DBus";
35
char const UNIX_USER_ID[] = "UnixUserID";
36
char const LINUX_SECURITY_LABEL[] = "LinuxSecurityLabel";
38
int const MAX_CACHE_SIZE = 50;
51
struct CredentialsCache::Request
53
QDBusPendingCallWatcher watcher;
54
std::vector<CredentialsCache::Callback> callbacks;
56
Request(QDBusPendingReply<QVariantMap> call) : watcher(call) {}
59
CredentialsCache::CredentialsCache(QDBusConnection const& bus)
60
: bus_daemon_(DBUS_BUS_NAME, DBUS_BUS_PATH, bus)
61
, apparmor_enabled_(aa_is_enabled())
65
CredentialsCache::~CredentialsCache() = default;
67
void CredentialsCache::get(QString const& peer, Callback callback)
69
// Return the credentials directly if they are cached
72
Credentials const& credentials = cache_.at(peer);
73
callback(credentials);
76
catch (std::out_of_range const &)
81
// If the credentials exist in the previous generation of the
82
// cache, move them to the current generation.
85
Credentials& credentials = old_cache_.at(peer);
86
cache_.emplace(peer, std::move(credentials));
87
old_cache_.erase(peer);
88
callback(cache_.at(peer));
91
catch (std::out_of_range const &)
96
// If the credentials are already being requested, add ourselves
97
// to the callback list.
100
unique_ptr<Request>& request = pending_.at(peer);
101
request->callbacks.push_back(callback);
104
catch (std::out_of_range const &)
109
// Ask the bus daemon for the peer's credentials
110
unique_ptr<Request> request(
111
new Request(bus_daemon_.GetConnectionCredentials(peer)));
112
QObject::connect(&request->watcher, &QDBusPendingCallWatcher::finished,
113
[this, peer](QDBusPendingCallWatcher *watcher)
115
this->received_credentials(peer, *watcher);
117
request->callbacks.push_back(callback);
118
pending_.emplace(peer, std::move(request));
121
void CredentialsCache::received_credentials(QString const& peer, QDBusPendingReply<QVariantMap> reply)
123
Credentials credentials;
126
qWarning() << "CredentialsCache::received_credentials(): "
127
"error retrieving credentials for" << peer <<
128
":" << reply.error().message();
132
credentials.valid = true;
133
// The contents of this map are described in the specification here:
134
// http://dbus.freedesktop.org/doc/dbus-specification.html#bus-messages-get-connection-credentials
135
credentials.user = reply.value().value(UNIX_USER_ID).value<uint32_t>();
136
if (apparmor_enabled_)
138
QByteArray label = reply.value().value(LINUX_SECURITY_LABEL).value<QByteArray>();
139
if (label.size() > 0) {
140
// The label is null terminated.
141
assert(label[label.size()-1] == '\0');
142
label.truncate(label.size() - 1);
143
// Trim the mode off the end of the label.
144
int pos = label.lastIndexOf(' ');
145
if (pos > 0 && label.endsWith(')') && label[pos+1] == '(')
149
credentials.label = string(label.constData(), label.size());
154
// If AppArmor is not enabled, treat peer as unconfined.
155
credentials.label = "unconfined";
159
// If we've hit our maximum cache size, start a new generation.
160
if (cache_.size() >= MAX_CACHE_SIZE)
162
old_cache_ = std::move(cache_);
165
cache_.emplace(peer, credentials);
167
// Notify anyone waiting on the request and remove it from the map:
168
for (auto& callback : pending_.at(peer)->callbacks)
170
callback(credentials);
172
pending_.erase(peer);
175
} // namespace service
177
} // namespace thumbnailer