28 namespace ubuntu = apparmor::ubuntu;
35 std::string authority;
43 Uri parse_uri(
const std::string& s)
48 const std::size_t scheme{2};
49 const std::size_t authority{4};
50 const std::size_t path{5};
51 const std::size_t query{7};
52 const std::size_t fragment{9};
55 static const std::regex regex{R
"delim(^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?)delim"};
58 if (not std::regex_match(s, match, regex))
throw std::runtime_error
60 "Not a valid URI: " + s
65 match.str(index.scheme),
66 match.str(index.authority),
67 match.str(index.path),
68 match.str(index.query),
69 match.str(index.fragment)
73 static constexpr std::size_t index_package{1};
74 static constexpr std::size_t index_app{2};
78 bool process_context_name(
const std::string& s, std::smatch& out)
81 static const std::regex short_re{
"(.*)_(.*)"};
82 static const std::regex full_re{
"(.*)_(.*)_(.*)"};
84 if (std::regex_match(s, out, full_re))
87 if (std::regex_match(s, out, short_re))
94 apparmor::ubuntu::Context::Context(
const std::string& name)
96 unconfined_{str() == ubuntu::unconfined},
97 has_package_name_{process_context_name(str(), match_)}
99 if (not is_unconfined() && not has_package_name())
throw std::logic_error
101 "apparmor::ubuntu::Context: Invalid profile name " + str()
112 return has_package_name_;
118 return std::string{match_[index_package]};
126 const std::string& name,
129 dbus_daemon.get_connection_app_armor_security_async(name, [cb](
const std::string& context_name)
138 return Result{
true,
"Client allowed access since it's unconfined"};
140 Uri parsed_uri = parse_uri(uri);
143 if (parsed_uri.path.find(std::string(
".local/share/" + context.
package_name() +
"/")) != std::string::npos ||
144 parsed_uri.path.find(std::string(
".cache/" + context.
package_name() +
"/")) != std::string::npos)
152 else if (parsed_uri.path.find(std::string(
"opt/click.ubuntu.com/")) != std::string::npos &&
153 parsed_uri.path.find(context.
package_name()) != std::string::npos)
155 return Result{
true,
"Client can access content in own opt directory"};
157 else if ((parsed_uri.path.find(std::string(
"/system/media/audio/ui/")) != std::string::npos ||
158 parsed_uri.path.find(std::string(
"/android/system/media/audio/ui/")) != std::string::npos) &&
161 return Result{
true,
"Camera app can access ui sounds"};
170 (parsed_uri.path.find(std::string(
"Music/")) != std::string::npos ||
171 parsed_uri.path.find(std::string(
"Videos/")) != std::string::npos ||
172 parsed_uri.path.find(std::string(
"/media")) != std::string::npos))
174 return Result{
true,
"Client can access content in ~/Music or ~/Videos"};
176 else if (parsed_uri.path.find(std::string(
"/usr/share/sounds")) != std::string::npos)
178 return Result{
true,
"Client can access content in /usr/share/sounds"};
180 else if (parsed_uri.scheme ==
"http" ||
181 parsed_uri.scheme ==
"https" ||
182 parsed_uri.scheme ==
"rtsp")
184 return Result{
true,
"Client can access streaming content"};
187 return Result{
false,
"Client is not allowed to access: " + uri};
193 return std::make_shared<apparmor::ubuntu::DBusDaemonRequestContextResolver>(es.
session);
199 return std::make_shared<apparmor::ubuntu::ExistingAuthenticator>();
DBusDaemonRequestContextResolver(const core::dbus::Bus::Ptr &)
virtual bool has_package_name() const
std::shared_ptr< RequestContextResolver > Ptr
virtual bool is_unconfined() const
void resolve_context_for_dbus_name_async(const std::string &name, ResolveCallback) override
std::function< void(const Context &)> ResolveCallback
virtual std::string package_name() const