Music Hub  ..
A session-wide music playback service
ubuntu.cpp
Go to the documentation of this file.
1 /*
2  * Copyright © 2014 Canonical Ltd.
3  *
4  * This program is free software: you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License version 3,
6  * as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  *
16  * Authored by: Thomas Voß <thomas.voss@canonical.com>
17  */
18 
20 
22 
23 #include <iostream>
24 #include <regex>
25 
27 namespace media = core::ubuntu::media;
28 namespace ubuntu = apparmor::ubuntu;
29 
30 namespace
31 {
32 struct Uri
33 {
34  std::string scheme;
35  std::string authority;
36  std::string path;
37  std::string query;
38  std::string fragment;
39 };
40 
41 // Poor mans version of a uri parser.
42 // See https://tools.ietf.org/html/rfc3986#appendix-B
43 Uri parse_uri(const std::string& s)
44 {
45  // Indices into the regex match go here.
46  struct Index
47  {
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};
53  } static index;
54 
55  static const std::regex regex{R"delim(^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?)delim"};
56  std::smatch match;
57 
58  if (not std::regex_match(s, match, regex)) throw std::runtime_error
59  {
60  "Not a valid URI: " + s
61  };
62 
63  return Uri
64  {
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)
70  };
71 }
72 
73 static constexpr std::size_t index_package{1};
74 static constexpr std::size_t index_app{2};
75 
76 // Returns true if the context name is a valid Ubuntu app id.
77 // If it is, out is populated with the package and app name.
78 bool process_context_name(const std::string& s, std::smatch& out)
79 {
80  // See https://wiki.ubuntu.com/AppStore/Interfaces/ApplicationId.
81  static const std::regex short_re{"(.*)_(.*)"};
82  static const std::regex full_re{"(.*)_(.*)_(.*)"};
83 
84  if (std::regex_match(s, out, full_re))
85  return true;
86 
87  if (std::regex_match(s, out, short_re))
88  return true;
89 
90  return false;
91 }
92 }
93 
94 apparmor::ubuntu::Context::Context(const std::string& name)
95  : apparmor::Context{name},
96  unconfined_{str() == ubuntu::unconfined},
97  has_package_name_{process_context_name(str(), match_)}
98 {
99  if (not is_unconfined() && not has_package_name()) throw std::logic_error
100  {
101  "apparmor::ubuntu::Context: Invalid profile name " + str()
102  };
103 }
104 
106 {
107  return unconfined_;
108 }
109 
111 {
112  return has_package_name_;
113 }
114 
115 
117 {
118  return std::string{match_[index_package]};
119 }
120 
122 {
123 }
124 
126  const std::string& name,
128 {
129  dbus_daemon.get_connection_app_armor_security_async(name, [cb](const std::string& context_name)
130  {
131  cb(apparmor::ubuntu::Context{context_name});
132  });
133 }
134 
136 {
137  if (context.is_unconfined())
138  return Result{true, "Client allowed access since it's unconfined"};
139 
140  Uri parsed_uri = parse_uri(uri);
141 
142  // All confined apps can access their own files
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)
145  {
146  return Result
147  {
148  true,
149  "Client can access content in ~/.local/share/" + context.package_name() + " or ~/.cache/" + context.package_name()
150  };
151  }
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)
154  {
155  return Result{true, "Client can access content in own opt directory"};
156  }
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) &&
159  context.package_name() == "com.ubuntu.camera")
160  {
161  return Result{true, "Camera app can access ui sounds"};
162  }
163 
164  // TODO: Check if the trust store previously allowed direct access to uri
165 
166  // Check in ~/Music and ~/Videos
167  // TODO: when the trust store lands, check it to see if this app can access the dirs and
168  // then remove the explicit whitelist of the music-app, and gallery-app
169  else if ((context.package_name() == "com.ubuntu.music" || context.package_name() == "com.ubuntu.gallery") &&
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))
173  {
174  return Result{true, "Client can access content in ~/Music or ~/Videos"};
175  }
176  else if (parsed_uri.path.find(std::string("/usr/share/sounds")) != std::string::npos)
177  {
178  return Result{true, "Client can access content in /usr/share/sounds"};
179  }
180  else if (parsed_uri.scheme == "http" || parsed_uri.scheme == "rtsp")
181  {
182  return Result{true, "Client can access streaming content"};
183  }
184 
185  return Result{false, "Client is not allowed to access: " + uri};
186 }
187 
188 // Returns the platform-default implementation of RequestContextResolver.
190 {
191  return std::make_shared<apparmor::ubuntu::DBusDaemonRequestContextResolver>(es.session);
192 }
193 
194 // Returns the platform-default implementation of RequestAuthenticator.
196 {
197  return std::make_shared<apparmor::ubuntu::ExistingAuthenticator>();
198 }
RequestAuthenticator::Ptr make_platform_default_request_authenticator()
std::shared_ptr< RequestContextResolver > Ptr
Definition: ubuntu.h:87
RequestContextResolver::Ptr make_platform_default_request_context_resolver(helper::ExternalServices &es)
void resolve_context_for_dbus_name_async(const std::string &name, ResolveCallback) override
Definition: ubuntu.cpp:125
std::function< void(const Context &)> ResolveCallback
Definition: ubuntu.h:90
Result authenticate_open_uri_request(const Context &, const std::string &uri) override
Definition: ubuntu.cpp:135
virtual std::string package_name() const
Definition: ubuntu.cpp:116
std::shared_ptr< RequestAuthenticator > Ptr
Definition: ubuntu.h:127