Merge lp:~phablet-team/media-hub/introduce-apparmor-interfaces into lp:media-hub

Proposed by Ricardo Salveti
Status: Superseded
Proposed branch: lp:~phablet-team/media-hub/introduce-apparmor-interfaces
Merge into: lp:media-hub
Prerequisite: lp:~thomas-voss/media-hub/introduce-call-monitor-interface
Diff against target: 1303 lines (+686/-314)
15 files modified
src/core/media/CMakeLists.txt (+3/-0)
src/core/media/apparmor.h (+0/-93)
src/core/media/apparmor/context.cpp (+34/-0)
src/core/media/apparmor/context.h (+51/-0)
src/core/media/apparmor/dbus.h (+94/-0)
src/core/media/apparmor/ubuntu.cpp (+198/-0)
src/core/media/apparmor/ubuntu.h (+167/-0)
src/core/media/player.cpp (+0/-1)
src/core/media/player_configuration.h (+0/-3)
src/core/media/player_implementation.cpp (+2/-1)
src/core/media/player_implementation.h (+3/-1)
src/core/media/player_skeleton.cpp (+16/-93)
src/core/media/player_skeleton.h (+9/-3)
src/core/media/service_implementation.cpp (+10/-3)
src/core/media/service_skeleton.cpp (+99/-116)
To merge this branch: bzr merge lp:~phablet-team/media-hub/introduce-apparmor-interfaces
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing
Jim Hodapp code Pending
Review via email: mp+251800@code.launchpad.net

This proposal supersedes a proposal from 2014-11-26.

This proposal has been superseded by a proposal from 2015-03-04.

Commit message

Add an interface apparmor::ubuntu::RequestAuthenticator that is used to authenticate incoming open uri requests.
Add an interface apparmor::ubuntu::RequestContextResolver that is used to resolve a dbus name to an apparmor::ubuntu::Context.
Provide an implementation apparmor::ubuntu::ExistingAuthenticator that takes the impl. from player_skeleton.cpp and uses it to implement the interface.
Provide an implementation apparmor::ubuntu::RequestContextResolver that reaches out to the dbus daemon to resolve a given bus name to an apparmor profile.
Remove obsolete query for the apparmor profile in ServiceSkeleton.
Adjust the implementation in media::PlayerSkeleton to rely on Request{Authenticator, ContextResolver}.

Description of the change

Add an interface apparmor::ubuntu::RequestAuthenticator that is used to authenticate incoming open uri requests.
Add an interface apparmor::ubuntu::RequestContextResolver that is used to resolve a dbus name to an apparmor::ubuntu::Context.
Provide an implementation apparmor::ubuntu::ExistingAuthenticator that takes the impl. from player_skeleton.cpp and uses it to implement the interface.
Provide an implementation apparmor::ubuntu::RequestContextResolver that reaches out to the dbus daemon to resolve a given bus name to an apparmor profile.
Remove obsolete query for the apparmor profile in ServiceSkeleton.
Adjust the implementation in media::PlayerSkeleton to rely on Request{Authenticator, ContextResolver}.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Jim Hodapp (jhodapp) wrote : Posted in a previous version of this proposal

One simple comment below.

review: Needs Fixing (code)
Revision history for this message
Thomas Voß (thomas-voss) : Posted in a previous version of this proposal
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
121. By Ricardo Salveti

Merge prereq

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
122. By Thomas Voß

* debian/control:
  - Removing pre-depends that are not required
  - Bumping standards-version to 3.9.6
[ Ricardo Salveti de Araujo ]
* Migrating tests to use ogg instead of mp3/avi removed:
  tests/h264.avi tests/test.mp3 added: tests/test-audio-1.ogg
  tests/test-video.ogg tests/test.mp3 renamed: tests/test.ogg =>
  tests/test-audio.ogg

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/core/media/CMakeLists.txt'
--- src/core/media/CMakeLists.txt 2015-03-04 18:32:01 +0000
+++ src/core/media/CMakeLists.txt 2015-03-04 18:32:01 +0000
@@ -91,6 +91,9 @@
91 cover_art_resolver.cpp91 cover_art_resolver.cpp
92 engine.cpp92 engine.cpp
9393
94 apparmor/context.cpp
95 apparmor/ubuntu.cpp
96
94 audio/pulse_audio_output_observer.cpp97 audio/pulse_audio_output_observer.cpp
95 audio/ostream_reporter.cpp98 audio/ostream_reporter.cpp
96 audio/output_observer.cpp99 audio/output_observer.cpp
97100
=== added directory 'src/core/media/apparmor'
=== removed file 'src/core/media/apparmor.h'
--- src/core/media/apparmor.h 2014-09-01 07:49:45 +0000
+++ src/core/media/apparmor.h 1970-01-01 00:00:00 +0000
@@ -1,93 +0,0 @@
1/*
2 * Copyright (C) 2013-2014 Canonical Ltd
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 3 as
6 * 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 * Author: Jim Hodapp <jim.hodapp@canonical.com>
17 */
18
19#ifndef APPARMOR_DBUS_H_
20#define APPARMOR_DBUS_H_
21
22#include <core/dbus/macros.h>
23#include <core/dbus/object.h>
24#include <core/dbus/service.h>
25
26#include <string>
27#include <chrono>
28
29// TODO(tvoss): This really should live in trust-store, providing a straightforward
30// way for parties involved in managing trust relationships to query peers' apparmor
31// profiles. Please see https://bugs.launchpad.net/trust-store/+bug/1350736 for the
32// related bug
33namespace org
34{
35namespace freedesktop
36{
37namespace dbus
38{
39struct DBus
40{
41 static const std::string& name()
42 {
43 static const std::string s = "org.freedesktop.DBus";
44 return s;
45 }
46
47 // Gets the AppArmor confinement string associated with the unique connection name. If
48 // D-Bus is not performing AppArmor mediation, the
49 // org.freedesktop.DBus.Error.AppArmorSecurityContextUnknown error is returned.
50 DBUS_CPP_METHOD_DEF(GetConnectionAppArmorSecurityContext, DBus)
51
52 struct Stub
53 {
54 // Creates a new stub instance for the given object to access
55 // DBus functionality.
56 Stub(const core::dbus::Object::Ptr& object) : object{object}
57 {
58 }
59
60 // Creates a new stub instance for the given bus connection
61 Stub(const core::dbus::Bus::Ptr& bus)
62 : object
63 {
64 core::dbus::Service::use_service<org::freedesktop::dbus::DBus>(bus)
65 ->object_for_path(core::dbus::types::ObjectPath{"/org/freedesktop/DBus"})
66 }
67 {
68 }
69
70 // Gets the AppArmor confinement string associated with the unique connection name. If
71 // D-Bus is not performing AppArmor mediation, the
72 // org.freedesktop.DBus.Error.AppArmorSecurityContextUnknown error is returned.
73 //
74 // Invokes the given handler on completion.
75 void get_connection_app_armor_security_async(
76 const std::string& name,
77 std::function<void(const std::string&)> handler)
78 {
79 object->invoke_method_asynchronously_with_callback<GetConnectionAppArmorSecurityContext, std::string>(
80 [handler](const core::dbus::Result<std::string>& result)
81 {
82 if (not result.is_error()) handler(result.value());
83 }, name);
84 }
85
86 core::dbus::Object::Ptr object;
87 };
88};
89}
90}
91}
92
93#endif // APPARMOR_DBUS_H_
940
=== added file 'src/core/media/apparmor/context.cpp'
--- src/core/media/apparmor/context.cpp 1970-01-01 00:00:00 +0000
+++ src/core/media/apparmor/context.cpp 2015-03-04 18:32:01 +0000
@@ -0,0 +1,34 @@
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
19#include <core/media/apparmor/context.h>
20
21namespace apparmor = core::ubuntu::media::apparmor;
22
23apparmor::Context::Context(const std::string& name) : name{name}
24{
25 if (name.empty()) throw std::runtime_error
26 {
27 "apparmor::Context cannot be created for empty name."
28 };
29}
30
31const std::string& apparmor::Context::str() const
32{
33 return name;
34}
035
=== added file 'src/core/media/apparmor/context.h'
--- src/core/media/apparmor/context.h 1970-01-01 00:00:00 +0000
+++ src/core/media/apparmor/context.h 2015-03-04 18:32:01 +0000
@@ -0,0 +1,51 @@
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#ifndef CORE_UBUNTU_MEDIA_APPARMOR_AUTHENTICATOR_H_
19#define CORE_UBUNTU_MEDIA_APPARMOR_AUTHENTICATOR_H_
20
21#include <memory>
22#include <string>
23
24namespace core
25{
26namespace ubuntu
27{
28namespace media
29{
30namespace apparmor
31{
32// Models an apparmor context name, and provides convenience functionality
33// on top of it.
34class Context
35{
36public:
37 // Constructs a new Context instance for the given raw name.
38 // Throws std::logic_error for empty names.
39 explicit Context(const std::string& name);
40 virtual ~Context() = default;
41 // Returns the raw string describing the context.
42 const std::string& str() const;
43
44private:
45 const std::string name;
46};
47}
48}
49}
50}
51#endif // CORE_UBUNTU_MEDIA_APPARMOR_AUTHENTICATOR_H_
052
=== added file 'src/core/media/apparmor/dbus.h'
--- src/core/media/apparmor/dbus.h 1970-01-01 00:00:00 +0000
+++ src/core/media/apparmor/dbus.h 2015-03-04 18:32:01 +0000
@@ -0,0 +1,94 @@
1/*
2 * Copyright (C) 2013-2014 Canonical Ltd
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 3 as
6 * 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 * Author: Jim Hodapp <jim.hodapp@canonical.com>
17 */
18
19#ifndef CORE_UBUNTU_MEDIA_APPARMOR_DBUS_H_
20#define CORE_UBUNTU_MEDIA_APPARMOR_DBUS_H_
21
22#include <core/dbus/bus.h>
23#include <core/dbus/macros.h>
24#include <core/dbus/object.h>
25#include <core/dbus/service.h>
26
27#include <string>
28#include <chrono>
29
30// TODO(tvoss): This really should live in trust-store, providing a straightforward
31// way for parties involved in managing trust relationships to query peers' apparmor
32// profiles. Please see https://bugs.launchpad.net/trust-store/+bug/1350736 for the
33// related bug
34namespace org
35{
36namespace freedesktop
37{
38namespace dbus
39{
40struct DBus
41{
42 static const std::string& name()
43 {
44 static const std::string s = "org.freedesktop.DBus";
45 return s;
46 }
47
48 // Gets the AppArmor confinement string associated with the unique connection name. If
49 // D-Bus is not performing AppArmor mediation, the
50 // org.freedesktop.DBus.Error.AppArmorSecurityContextUnknown error is returned.
51 DBUS_CPP_METHOD_DEF(GetConnectionAppArmorSecurityContext, DBus)
52
53 struct Stub
54 {
55 // Creates a new stub instance for the given object to access
56 // DBus functionality.
57 Stub(const core::dbus::Object::Ptr& object) : object{object}
58 {
59 }
60
61 // Creates a new stub instance for the given bus connection
62 Stub(const core::dbus::Bus::Ptr& bus)
63 : object
64 {
65 core::dbus::Service::use_service<org::freedesktop::dbus::DBus>(bus)
66 ->object_for_path(core::dbus::types::ObjectPath{"/org/freedesktop/DBus"})
67 }
68 {
69 }
70
71 // Gets the AppArmor confinement string associated with the unique connection name. If
72 // D-Bus is not performing AppArmor mediation, the
73 // org.freedesktop.DBus.Error.AppArmorSecurityContextUnknown error is returned.
74 //
75 // Invokes the given handler on completion.
76 void get_connection_app_armor_security_async(
77 const std::string& name,
78 std::function<void(const std::string&)> handler)
79 {
80 object->invoke_method_asynchronously_with_callback<GetConnectionAppArmorSecurityContext, std::string>(
81 [handler](const core::dbus::Result<std::string>& result)
82 {
83 if (not result.is_error()) handler(result.value());
84 }, name);
85 }
86
87 core::dbus::Object::Ptr object;
88 };
89};
90}
91}
92}
93
94#endif // CORE_UBUNTU_MEDIA_APPARMOR_DBUS_H_
095
=== added file 'src/core/media/apparmor/ubuntu.cpp'
--- src/core/media/apparmor/ubuntu.cpp 1970-01-01 00:00:00 +0000
+++ src/core/media/apparmor/ubuntu.cpp 2015-03-04 18:32:01 +0000
@@ -0,0 +1,198 @@
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
19#include <core/media/apparmor/ubuntu.h>
20
21#include <core/media/external_services.h>
22
23#include <iostream>
24#include <regex>
25
26namespace apparmor = core::ubuntu::media::apparmor;
27namespace media = core::ubuntu::media;
28namespace ubuntu = apparmor::ubuntu;
29
30namespace
31{
32struct 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
43Uri 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
73static constexpr std::size_t index_package{1};
74static 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.
78bool 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
94apparmor::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
105bool apparmor::ubuntu::Context::is_unconfined() const
106{
107 return unconfined_;
108}
109
110bool apparmor::ubuntu::Context::has_package_name() const
111{
112 return has_package_name_;
113}
114
115
116std::string apparmor::ubuntu::Context::package_name() const
117{
118 return std::string{match_[index_package]};
119}
120
121apparmor::ubuntu::DBusDaemonRequestContextResolver::DBusDaemonRequestContextResolver(const core::dbus::Bus::Ptr& bus) : dbus_daemon{bus}
122{
123}
124
125void apparmor::ubuntu::DBusDaemonRequestContextResolver::resolve_context_for_dbus_name_async(
126 const std::string& name,
127 apparmor::ubuntu::RequestContextResolver::ResolveCallback cb)
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
135apparmor::ubuntu::RequestAuthenticator::Result apparmor::ubuntu::ExistingAuthenticator::authenticate_open_uri_request(const apparmor::ubuntu::Context& context, const std::string& uri)
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.
189apparmor::ubuntu::RequestContextResolver::Ptr apparmor::ubuntu::make_platform_default_request_context_resolver(media::helper::ExternalServices& es)
190{
191 return std::make_shared<apparmor::ubuntu::DBusDaemonRequestContextResolver>(es.session);
192}
193
194// Returns the platform-default implementation of RequestAuthenticator.
195apparmor::ubuntu::RequestAuthenticator::Ptr apparmor::ubuntu::make_platform_default_request_authenticator()
196{
197 return std::make_shared<apparmor::ubuntu::ExistingAuthenticator>();
198}
0199
=== added file 'src/core/media/apparmor/ubuntu.h'
--- src/core/media/apparmor/ubuntu.h 1970-01-01 00:00:00 +0000
+++ src/core/media/apparmor/ubuntu.h 2015-03-04 18:32:01 +0000
@@ -0,0 +1,167 @@
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#ifndef CORE_UBUNTU_MEDIA_APPARMOR_UBUNTU_H_
19#define CORE_UBUNTU_MEDIA_APPARMOR_UBUNTU_H_
20
21#include <core/media/apparmor/context.h>
22#include <core/media/apparmor/dbus.h>
23
24#include <functional>
25#include <memory>
26#include <regex>
27#include <string>
28#include <vector>
29
30namespace core
31{
32namespace dbus
33{
34class Bus;
35}
36
37namespace ubuntu
38{
39namespace media
40{
41namespace helper
42{
43struct ExternalServices;
44}
45namespace apparmor
46{
47// Collects Ubuntu-specific apparmor conventions, e.g., format
48// of short and full package names as well as convenience functionality
49// to inspect apparmor::Context instances.
50namespace ubuntu
51{
52// The unconfined profile, unconditionally trusted
53// by the system.
54static constexpr const char* unconfined
55{
56 "unconfined"
57};
58
59class Context : public apparmor::Context
60{
61public:
62 // Constructs a new Context instance for the given raw name.
63 // Throws std::logic_error for empty names or for names not
64 // complying to Ubuntu conventions.
65 Context(const std::string& name);
66
67 // Returns true iff the context is unconfined.
68 virtual bool is_unconfined() const;
69
70 // Returns true iff the context contains a package name.
71 virtual bool has_package_name() const;
72
73 // Returns the package name or throws if no package name can be found.
74 virtual std::string package_name() const;
75
76private:
77 std::smatch match_;
78 const bool unconfined_;
79 const bool has_package_name_;
80};
81
82// Abstracts query for the apparmor context of an incoming request
83class RequestContextResolver
84{
85public:
86 // To save us some typing.
87 typedef std::shared_ptr<RequestContextResolver> Ptr;
88
89 // Callback for resolve context operations.
90 typedef std::function<void(const Context&)> ResolveCallback;
91
92 // Resolves the given name (of a dbus participant) to its apparmor context,
93 // invoking the callback whenever a result is available.
94 virtual void resolve_context_for_dbus_name_async(const std::string& name, ResolveCallback cb) = 0;
95
96protected:
97 RequestContextResolver() = default;
98 RequestContextResolver(const RequestContextResolver&) = delete;
99 virtual ~RequestContextResolver() = default;
100 RequestContextResolver& operator=(const RequestContextResolver&) = delete;
101};
102
103// An implementation of RequestContextResolver that queries the dbus
104// daemon to resolve the apparmor context.
105class DBusDaemonRequestContextResolver : public RequestContextResolver
106{
107public:
108 // To save us some typing.
109 typedef std::shared_ptr<DBusDaemonRequestContextResolver> Ptr;
110
111 // Constructs a new instance for the given bus connection.
112 DBusDaemonRequestContextResolver(const core::dbus::Bus::Ptr &);
113
114 // From RequestContextResolver
115 void resolve_context_for_dbus_name_async(const std::string& name, ResolveCallback) override;
116
117private:
118 org::freedesktop::dbus::DBus::Stub dbus_daemon;
119};
120
121// Abstracts an apparmor-based authentication of
122// incoming requests from clients.
123class RequestAuthenticator
124{
125public:
126 // To save us some typing.
127 typedef std::shared_ptr<RequestAuthenticator> Ptr;
128
129 // Return type of an authentication call.
130 typedef std::tuple
131 <
132 bool, // True if authenticated, false if not.
133 std::string // Reason for the result.
134 > Result;
135
136 virtual ~RequestAuthenticator() = default;
137
138 // Returns true iff the client identified by the given apparmor::Context is allowed
139 // to access the given uri, false otherwise.
140 virtual Result authenticate_open_uri_request(const Context&, const std::string& uri) = 0;
141
142protected:
143 RequestAuthenticator() = default;
144 RequestAuthenticator(const RequestAuthenticator&) = default;
145 RequestAuthenticator& operator=(const RequestAuthenticator&) = default;
146};
147
148// Takes the existing logic and exposes it as an implementation
149// of the RequestAuthenticator interface.
150struct ExistingAuthenticator : public RequestAuthenticator
151{
152 ExistingAuthenticator() = default;
153 // From RequestAuthenticator
154 Result authenticate_open_uri_request(const Context&, const std::string& uri) override;
155};
156
157// Returns the platform-default implementation of RequestContextResolver.
158RequestContextResolver::Ptr make_platform_default_request_context_resolver(helper::ExternalServices& es);
159// Returns the platform-default implementation of RequestAuthenticator.
160RequestAuthenticator::Ptr make_platform_default_request_authenticator();
161}
162}
163}
164}
165}
166
167#endif // CORE_UBUNTU_MEDIA_APPARMOR_UBUNTU_H_
0168
=== modified file 'src/core/media/player.cpp'
--- src/core/media/player.cpp 2015-03-04 18:32:01 +0000
+++ src/core/media/player.cpp 2015-03-04 18:32:01 +0000
@@ -31,7 +31,6 @@
31{31{
32 static const media::Player::Configuration config32 static const media::Player::Configuration config
33 {33 {
34 std::string{""},
35 0,34 0,
36 nullptr,35 nullptr,
37 nullptr36 nullptr
3837
=== modified file 'src/core/media/player_configuration.h'
--- src/core/media/player_configuration.h 2014-09-09 10:28:32 +0000
+++ src/core/media/player_configuration.h 2015-03-04 18:32:01 +0000
@@ -27,9 +27,6 @@
27// to the implementation in a way that is opaque to the client.27// to the implementation in a way that is opaque to the client.
28struct core::ubuntu::media::Player::Configuration28struct core::ubuntu::media::Player::Configuration
29{29{
30 // An identifier that is helpful in referencing the player instance
31 // across multiple services.
32 std::string identity;
33 // Unique key for identifying the session.30 // Unique key for identifying the session.
34 core::ubuntu::media::Player::PlayerKey key;31 core::ubuntu::media::Player::PlayerKey key;
35 // The bus connection to expose objects on.32 // The bus connection to expose objects on.
3633
=== modified file 'src/core/media/player_implementation.cpp'
--- src/core/media/player_implementation.cpp 2015-03-04 18:32:01 +0000
+++ src/core/media/player_implementation.cpp 2015-03-04 18:32:01 +0000
@@ -293,7 +293,8 @@
293 {293 {
294 config.bus,294 config.bus,
295 config.session,295 config.session,
296 config.identity296 config.request_context_resolver,
297 config.request_authenticator
297 }298 }
298 },299 },
299 d{std::make_shared<Private>(this, config)}300 d{std::make_shared<Private>(this, config)}
300301
=== modified file 'src/core/media/player_implementation.h'
--- src/core/media/player_implementation.h 2015-03-04 18:32:01 +0000
+++ src/core/media/player_implementation.h 2015-03-04 18:32:01 +0000
@@ -21,6 +21,7 @@
2121
22#include "player_skeleton.h"22#include "player_skeleton.h"
2323
24#include "apparmor/ubuntu.h"
24#include "client_death_observer.h"25#include "client_death_observer.h"
25#include "power/state_controller.h"26#include "power/state_controller.h"
2627
@@ -41,13 +42,14 @@
41 // All creation time arguments go here42 // All creation time arguments go here
42 struct Configuration43 struct Configuration
43 {44 {
44 std::string identity;
45 std::shared_ptr<core::dbus::Bus> bus;45 std::shared_ptr<core::dbus::Bus> bus;
46 std::shared_ptr<core::dbus::Object> session;46 std::shared_ptr<core::dbus::Object> session;
47 std::shared_ptr<Service> service;47 std::shared_ptr<Service> service;
48 PlayerKey key;48 PlayerKey key;
4949
50 // Functional dependencies50 // Functional dependencies
51 apparmor::ubuntu::RequestContextResolver::Ptr request_context_resolver;
52 apparmor::ubuntu::RequestAuthenticator::Ptr request_authenticator;
51 ClientDeathObserver::Ptr client_death_observer;53 ClientDeathObserver::Ptr client_death_observer;
52 power::StateController::Ptr power_state_controller;54 power::StateController::Ptr power_state_controller;
53 };55 };
5456
=== modified file 'src/core/media/player_skeleton.cpp'
--- src/core/media/player_skeleton.cpp 2015-03-04 18:32:01 +0000
+++ src/core/media/player_skeleton.cpp 2015-03-04 18:32:01 +0000
@@ -17,15 +17,16 @@
17 * Jim Hodapp <jim.hodapp@canonical.com>17 * Jim Hodapp <jim.hodapp@canonical.com>
18 */18 */
1919
20#include "apparmor.h"
21#include "codec.h"20#include "codec.h"
22#include "engine.h"21#include "engine.h"
22#include "external_services.h"
23#include "player_skeleton.h"23#include "player_skeleton.h"
24#include "player_traits.h"24#include "player_traits.h"
25#include "property_stub.h"25#include "property_stub.h"
26#include "the_session_bus.h"26#include "the_session_bus.h"
27#include "xesam.h"27#include "xesam.h"
2828
29#include "apparmor/ubuntu.h"
29#include "mpris/media_player2.h"30#include "mpris/media_player2.h"
30#include "mpris/metadata.h"31#include "mpris/metadata.h"
31#include "mpris/player.h"32#include "mpris/player.h"
@@ -44,15 +45,15 @@
44struct media::PlayerSkeleton::Private45struct media::PlayerSkeleton::Private
45{46{
46 Private(media::PlayerSkeleton* player,47 Private(media::PlayerSkeleton* player,
47 const std::string& identity,
48 const std::shared_ptr<core::dbus::Bus>& bus,48 const std::shared_ptr<core::dbus::Bus>& bus,
49 const std::shared_ptr<core::dbus::Object>& session)49 const std::shared_ptr<core::dbus::Object>& session,
50 const apparmor::ubuntu::RequestContextResolver::Ptr& request_context_resolver,
51 const apparmor::ubuntu::RequestAuthenticator::Ptr& request_authenticator)
50 : impl(player),52 : impl(player),
51 identity(identity),
52 bus(bus),53 bus(bus),
53 object(session),54 object(session),
54 apparmor_session(nullptr),55 request_context_resolver{request_context_resolver},
55 dbus_stub{bus},56 request_authenticator{request_authenticator},
56 skeleton{mpris::Player::Skeleton::Configuration{bus, session, mpris::Player::Skeleton::Configuration::Defaults{}}},57 skeleton{mpris::Player::Skeleton::Configuration{bus, session, mpris::Player::Skeleton::Configuration::Defaults{}}},
57 signals58 signals
58 {59 {
@@ -163,82 +164,6 @@
163 bus->send(reply);164 bus->send(reply);
164 }165 }
165166
166 bool does_client_have_access(const std::string& context, const std::string& uri)
167 {
168 if (context.empty() || uri.empty())
169 {
170 std::cout << "Client denied access since context or uri are empty" << std::endl;
171 return false;
172 }
173
174 if (context == "unconfined")
175 {
176 std::cout << "Client allowed access since it's unconfined" << std::endl;
177 return true;
178 }
179
180 size_t pos = context.find_first_of('_');
181 if (pos == std::string::npos)
182 {
183 std::cout << "Client denied access since it's an invalid apparmor security context" << std::endl;
184 return false;
185 }
186
187 const std::string pkgname = context.substr(0, pos);
188 std::cout << "client pkgname: " << pkgname << std::endl;
189 std::cout << "uri: " << uri << std::endl;
190
191 // All confined apps can access their own files
192 if (uri.find(std::string(".local/share/" + pkgname + "/")) != std::string::npos
193 || uri.find(std::string(".cache/" + pkgname + "/")) != std::string::npos)
194 {
195 std::cout << "Client can access content in ~/.local/share/" << pkgname << " or ~/.cache/" << pkgname << std::endl;
196 return true;
197 }
198 else if (uri.find(std::string("opt/click.ubuntu.com/")) != std::string::npos
199 && uri.find(pkgname) != std::string::npos)
200 {
201 std::cout << "Client can access content in own opt directory" << std::endl;
202 return true;
203 }
204 else if ((uri.find(std::string("/system/media/audio/ui/")) != std::string::npos
205 || uri.find(std::string("/android/system/media/audio/ui/")) != std::string::npos)
206 && pkgname == "com.ubuntu.camera")
207 {
208 std::cout << "Camera app can access ui sounds" << std::endl;
209 return true;
210 }
211 // TODO: Check if the trust store previously allowed direct access to uri
212
213 // Check in ~/Music and ~/Videos
214 // TODO: when the trust store lands, check it to see if this app can access the dirs and
215 // then remove the explicit whitelist of the music-app, and gallery-app
216 else if ((pkgname == "com.ubuntu.music" || pkgname == "com.ubuntu.gallery") &&
217 (uri.find(std::string("Music/")) != std::string::npos
218 || uri.find(std::string("Videos/")) != std::string::npos
219 || uri.find(std::string("/media")) != std::string::npos))
220 {
221 std::cout << "Client can access content in ~/Music or ~/Videos" << std::endl;
222 return true;
223 }
224 else if (uri.find(std::string("/usr/share/sounds")) != std::string::npos)
225 {
226 std::cout << "Client can access content in /usr/share/sounds" << std::endl;
227 return true;
228 }
229 else if (uri.find(std::string("http://")) != std::string::npos
230 || uri.find(std::string("rtsp://")) != std::string::npos)
231 {
232 std::cout << "Client can access streaming content" << std::endl;
233 return true;
234 }
235 else
236 {
237 std::cout << "Client denied access to open_uri()" << std::endl;
238 return false;
239 }
240 }
241
242 void handle_key(const core::dbus::Message::Ptr& in)167 void handle_key(const core::dbus::Message::Ptr& in)
243 {168 {
244 auto reply = dbus::Message::make_method_return(in);169 auto reply = dbus::Message::make_method_return(in);
@@ -248,15 +173,15 @@
248173
249 void handle_open_uri(const core::dbus::Message::Ptr& in)174 void handle_open_uri(const core::dbus::Message::Ptr& in)
250 {175 {
251 dbus_stub.get_connection_app_armor_security_async(in->sender(), [this, in](const std::string& profile)176 request_context_resolver->resolve_context_for_dbus_name_async(in->sender(), [this, in](const media::apparmor::ubuntu::Context& context)
252 {177 {
253 Track::UriType uri;178 Track::UriType uri;
254 in->reader() >> uri;179 in->reader() >> uri;
255180
256 bool have_access = does_client_have_access(profile, uri);181 auto result = request_authenticator->authenticate_open_uri_request(context, uri);
257182
258 auto reply = dbus::Message::make_method_return(in);183 auto reply = dbus::Message::make_method_return(in);
259 reply->writer() << (have_access ? impl->open_uri(uri) : false);184 reply->writer() << (std::get<0>(result) ? impl->open_uri(uri) : false);
260185
261 bus->send(reply);186 bus->send(reply);
262 });187 });
@@ -264,16 +189,16 @@
264189
265 void handle_open_uri_extended(const core::dbus::Message::Ptr& in)190 void handle_open_uri_extended(const core::dbus::Message::Ptr& in)
266 {191 {
267 dbus_stub.get_connection_app_armor_security_async(in->sender(), [this, in](const std::string& profile)192 request_context_resolver->resolve_context_for_dbus_name_async(in->sender(), [this, in](const media::apparmor::ubuntu::Context& context)
268 {193 {
269 Track::UriType uri;194 Track::UriType uri;
270 Player::HeadersType headers;195 Player::HeadersType headers;
271196
272 in->reader() >> uri >> headers;197 in->reader() >> uri >> headers;
273198
274 bool have_access = does_client_have_access(profile, uri);199 auto result = request_authenticator->authenticate_open_uri_request(context, uri);
275 auto reply = dbus::Message::make_method_return(in);200 auto reply = dbus::Message::make_method_return(in);
276 reply->writer() << (have_access ? impl->open_uri(uri, headers) : false);201 reply->writer() << (std::get<0>(result) ? impl->open_uri(uri, headers) : false);
277202
278 bus->send(reply);203 bus->send(reply);
279 });204 });
@@ -301,12 +226,10 @@
301 }226 }
302227
303 media::PlayerSkeleton* impl;228 media::PlayerSkeleton* impl;
304 std::string identity;
305 dbus::Bus::Ptr bus;229 dbus::Bus::Ptr bus;
306 dbus::Object::Ptr object;230 dbus::Object::Ptr object;
307 dbus::Object::Ptr apparmor_session;231 media::apparmor::ubuntu::RequestContextResolver::Ptr request_context_resolver;
308232 media::apparmor::ubuntu::RequestAuthenticator::Ptr request_authenticator;
309 org::freedesktop::dbus::DBus::Stub dbus_stub;
310233
311 mpris::Player::Skeleton skeleton;234 mpris::Player::Skeleton skeleton;
312235
@@ -360,7 +283,7 @@
360};283};
361284
362media::PlayerSkeleton::PlayerSkeleton(const media::PlayerSkeleton::Configuration& config)285media::PlayerSkeleton::PlayerSkeleton(const media::PlayerSkeleton::Configuration& config)
363 : d(new Private{this, config.identity, config.bus, config.session})286 : d(new Private{this, config.bus, config.session, config.request_context_resolver, config.request_authenticator})
364{287{
365 // Setup method handlers for mpris::Player methods.288 // Setup method handlers for mpris::Player methods.
366 auto next = std::bind(&Private::handle_next, d, std::placeholders::_1);289 auto next = std::bind(&Private::handle_next, d, std::placeholders::_1);
367290
=== modified file 'src/core/media/player_skeleton.h'
--- src/core/media/player_skeleton.h 2015-03-04 18:32:01 +0000
+++ src/core/media/player_skeleton.h 2015-03-04 18:32:01 +0000
@@ -24,6 +24,7 @@
2424
25#include "player_traits.h"25#include "player_traits.h"
2626
27#include "apparmor/ubuntu.h"
27#include "mpris/player.h"28#include "mpris/player.h"
2829
29#include <core/dbus/skeleton.h>30#include <core/dbus/skeleton.h>
@@ -37,6 +38,11 @@
37{38{
38namespace media39namespace media
39{40{
41namespace helper
42{
43struct ExternalServices;
44}
45
40class Service;46class Service;
4147
42class PlayerSkeleton : public core::ubuntu::media::Player48class PlayerSkeleton : public core::ubuntu::media::Player
@@ -86,9 +92,9 @@
86 std::shared_ptr<core::dbus::Bus> bus;92 std::shared_ptr<core::dbus::Bus> bus;
87 // The session object that we want to expose the skeleton upon.93 // The session object that we want to expose the skeleton upon.
88 std::shared_ptr<core::dbus::Object> session;94 std::shared_ptr<core::dbus::Object> session;
89 // Our identity, an identifier we pass out to other parts of the system.95 // Our functional dependencies.
90 // Defaults to the short app id (${PKG_NAME}_${APP}).96 apparmor::ubuntu::RequestContextResolver::Ptr request_context_resolver;
91 std::string identity;97 apparmor::ubuntu::RequestAuthenticator::Ptr request_authenticator;
92 };98 };
9399
94 PlayerSkeleton(const Configuration& configuration);100 PlayerSkeleton(const Configuration& configuration);
95101
=== modified file 'src/core/media/service_implementation.cpp'
--- src/core/media/service_implementation.cpp 2015-03-04 18:32:01 +0000
+++ src/core/media/service_implementation.cpp 2015-03-04 18:32:01 +0000
@@ -22,6 +22,7 @@
2222
23#include "service_implementation.h"23#include "service_implementation.h"
2424
25#include "apparmor/ubuntu.h"
25#include "audio/output_observer.h"26#include "audio/output_observer.h"
26#include "client_death_observer.h"27#include "client_death_observer.h"
27#include "player_configuration.h"28#include "player_configuration.h"
@@ -59,6 +60,8 @@
59 client_death_observer(media::platform_default_client_death_observer()),60 client_death_observer(media::platform_default_client_death_observer()),
60 recorder_observer(media::make_platform_default_recorder_observer()),61 recorder_observer(media::make_platform_default_recorder_observer()),
61 audio_output_observer(media::audio::make_platform_default_output_observer()),62 audio_output_observer(media::audio::make_platform_default_output_observer()),
63 request_context_resolver(media::apparmor::ubuntu::make_platform_default_request_context_resolver(configuration.external_services)),
64 request_authenticator(media::apparmor::ubuntu::make_platform_default_request_authenticator()),
62 audio_output_state(media::audio::OutputState::Speaker),65 audio_output_state(media::audio::OutputState::Speaker),
63 call_monitor(media::telephony::make_platform_default_call_monitor())66 call_monitor(media::telephony::make_platform_default_call_monitor())
64 {67 {
@@ -74,13 +77,16 @@
74 media::ClientDeathObserver::Ptr client_death_observer;77 media::ClientDeathObserver::Ptr client_death_observer;
75 media::RecorderObserver::Ptr recorder_observer;78 media::RecorderObserver::Ptr recorder_observer;
76 media::audio::OutputObserver::Ptr audio_output_observer;79 media::audio::OutputObserver::Ptr audio_output_observer;
77 media::audio::OutputObserver audio_output_state;80 media::apparmor::ubuntu::RequestContextResolver::Ptr request_context_resolver;
81 media::apparmor::ubuntu::RequestAuthenticator::Ptr request_authenticator;
82 media::audio::OutputState audio_output_state;
7883
79 media::telephony::CallMonitor::Ptr call_monitor;84 media::telephony::CallMonitor::Ptr call_monitor;
80 std::list<media::Player::PlayerKey> paused_sessions;85 std::list<media::Player::PlayerKey> paused_sessions;
81};86};
8287
83media::ServiceImplementation::ServiceImplementation(const Configuration& configuration) : d(new Private(configuration))88media::ServiceImplementation::ServiceImplementation(const Configuration& configuration)
89 : d(new Private(configuration))
84{90{
85 d->battery_observer->level().changed().connect([this](const media::power::Level& level)91 d->battery_observer->level().changed().connect([this](const media::power::Level& level)
86 {92 {
@@ -162,11 +168,12 @@
162{168{
163 auto player = std::make_shared<media::PlayerImplementation>(media::PlayerImplementation::Configuration169 auto player = std::make_shared<media::PlayerImplementation>(media::PlayerImplementation::Configuration
164 {170 {
165 conf.identity,
166 conf.bus,171 conf.bus,
167 conf.session,172 conf.session,
168 shared_from_this(),173 shared_from_this(),
169 conf.key,174 conf.key,
175 d->request_context_resolver,
176 d->request_authenticator,
170 d->client_death_observer,177 d->client_death_observer,
171 d->power_state_controller178 d->power_state_controller
172 });179 });
173180
=== modified file 'src/core/media/service_skeleton.cpp'
--- src/core/media/service_skeleton.cpp 2014-11-18 20:29:26 +0000
+++ src/core/media/service_skeleton.cpp 2015-03-04 18:32:01 +0000
@@ -19,8 +19,6 @@
1919
20#include "service_skeleton.h"20#include "service_skeleton.h"
2121
22#include "apparmor.h"
23
24#include "mpris/media_player2.h"22#include "mpris/media_player2.h"
25#include "mpris/metadata.h"23#include "mpris/metadata.h"
26#include "mpris/player.h"24#include "mpris/player.h"
@@ -55,7 +53,6 @@
55 : impl(impl),53 : impl(impl),
56 object(impl->access_service()->add_object_for_path(54 object(impl->access_service()->add_object_for_path(
57 dbus::traits::Service<media::Service>::object_path())),55 dbus::traits::Service<media::Service>::object_path())),
58 dbus_stub(impl->access_bus()),
59 exported(impl->access_bus(), resolver)56 exported(impl->access_bus(), resolver)
60 {57 {
61 object->install_method_handler<mpris::Service::CreateSession>(58 object->install_method_handler<mpris::Service::CreateSession>(
@@ -99,19 +96,61 @@
99 dbus::types::ObjectPath op{session_info.first};96 dbus::types::ObjectPath op{session_info.first};
100 media::Player::PlayerKey key{session_info.second};97 media::Player::PlayerKey key{session_info.second};
10198
102 dbus_stub.get_connection_app_armor_security_async(msg->sender(), [this, msg, op, key](const std::string& profile)99 media::Player::Configuration config
103 {100 {
104 media::Player::Configuration config101 key,
105 {102 impl->access_bus(),
106 profile,103 impl->access_service()->add_object_for_path(op)
107 key,104 };
108 impl->access_bus(),105
109 impl->access_service()->add_object_for_path(op)106 try
110 };107 {
111108 auto session = impl->create_session(config);
112 try109
113 {110 bool inserted = false;
111 std::tie(std::ignore, inserted)
112 = session_store.insert(std::make_pair(key, session));
113
114 if (!inserted)
115 throw std::runtime_error("Problem persisting session in session store.");
116
117 auto reply = dbus::Message::make_method_return(msg);
118 reply->writer() << op;
119
120 impl->access_bus()->send(reply);
121 } catch(const std::runtime_error& e)
122 {
123 auto reply = dbus::Message::make_error(
124 msg,
125 mpris::Service::Errors::CreatingSession::name(),
126 e.what());
127 impl->access_bus()->send(reply);
128 }
129 }
130
131 void handle_create_fixed_session(const core::dbus::Message::Ptr& msg)
132 {
133 try
134 {
135 std::string name;
136 msg->reader() >> name;
137
138 if (fixed_session_store.count(name) == 0) {
139 // Create new session
140 auto session_info = create_session_info();
141
142 dbus::types::ObjectPath op{session_info.first};
143 media::Player::PlayerKey key{session_info.second};
144
145 media::Player::Configuration config
146 {
147 key,
148 impl->access_bus(),
149 impl->access_service()->add_object_for_path(op)
150 };
151
114 auto session = impl->create_session(config);152 auto session = impl->create_session(config);
153 session->lifetime().set(media::Player::Lifetime::resumable);
115154
116 bool inserted = false;155 bool inserted = false;
117 std::tie(std::ignore, inserted)156 std::tie(std::ignore, inserted)
@@ -120,108 +159,20 @@
120 if (!inserted)159 if (!inserted)
121 throw std::runtime_error("Problem persisting session in session store.");160 throw std::runtime_error("Problem persisting session in session store.");
122161
162 fixed_session_store.insert(std::make_pair(name, key));
123163
124 auto reply = dbus::Message::make_method_return(msg);164 auto reply = dbus::Message::make_method_return(msg);
125 reply->writer() << op;165 reply->writer() << op;
126166
127 impl->access_bus()->send(reply);167 impl->access_bus()->send(reply);
128 } catch(const std::runtime_error& e)168 }
129 {169 else {
130 auto reply = dbus::Message::make_error(170 // Resume previous session
131 msg,171 auto key = fixed_session_store[name];
132 mpris::Service::Errors::CreatingSession::name(),
133 e.what());
134 impl->access_bus()->send(reply);
135 }
136 });
137 }
138
139 void handle_create_fixed_session(const core::dbus::Message::Ptr& msg)
140 {
141 dbus_stub.get_connection_app_armor_security_async(msg->sender(), [this, msg](const std::string& profile)
142 {
143 try
144 {
145 std::string name;
146 msg->reader() >> name;
147
148 if (fixed_session_store.count(name) == 0) {
149 // Create new session
150 auto session_info = create_session_info();
151
152 dbus::types::ObjectPath op{session_info.first};
153 media::Player::PlayerKey key{session_info.second};
154
155 media::Player::Configuration config
156 {
157 profile,
158 key,
159 impl->access_bus(),
160 impl->access_service()->add_object_for_path(op)
161 };
162
163 auto session = impl->create_session(config);
164 session->lifetime().set(media::Player::Lifetime::resumable);
165
166 bool inserted = false;
167 std::tie(std::ignore, inserted)
168 = session_store.insert(std::make_pair(key, session));
169
170 if (!inserted)
171 throw std::runtime_error("Problem persisting session in session store.");
172
173 fixed_session_store.insert(std::make_pair(name, key));
174
175 auto reply = dbus::Message::make_method_return(msg);
176 reply->writer() << op;
177
178 impl->access_bus()->send(reply);
179 }
180 else {
181 // Resume previous session
182 auto key = fixed_session_store[name];
183 if (session_store.count(key) == 0) {
184 auto reply = dbus::Message::make_error(
185 msg,
186 mpris::Service::Errors::CreatingFixedSession::name(),
187 "Unable to locate player session");
188 impl->access_bus()->send(reply);
189 return;
190 }
191
192 std::stringstream ss;
193 ss << "/core/ubuntu/media/Service/sessions/" << key;
194 dbus::types::ObjectPath op{ss.str()};
195
196 auto reply = dbus::Message::make_method_return(msg);
197 reply->writer() << op;
198
199 impl->access_bus()->send(reply);
200 }
201 } catch(const std::runtime_error& e)
202 {
203 auto reply = dbus::Message::make_error(
204 msg,
205 mpris::Service::Errors::CreatingSession::name(),
206 e.what());
207 impl->access_bus()->send(reply);
208 }
209 });
210 }
211
212 void handle_resume_session(const core::dbus::Message::Ptr& msg)
213 {
214 dbus_stub.get_connection_app_armor_security_async(msg->sender(), [this, msg](const std::string&)
215 {
216 try
217 {
218 Player::PlayerKey key;
219 msg->reader() >> key;
220
221 if (session_store.count(key) == 0) {172 if (session_store.count(key) == 0) {
222 auto reply = dbus::Message::make_error(173 auto reply = dbus::Message::make_error(
223 msg,174 msg,
224 mpris::Service::Errors::ResumingSession::name(),175 mpris::Service::Errors::CreatingFixedSession::name(),
225 "Unable to locate player session");176 "Unable to locate player session");
226 impl->access_bus()->send(reply);177 impl->access_bus()->send(reply);
227 return;178 return;
@@ -235,15 +186,49 @@
235 reply->writer() << op;186 reply->writer() << op;
236187
237 impl->access_bus()->send(reply);188 impl->access_bus()->send(reply);
238 } catch(const std::runtime_error& e)189 }
239 {190 } catch(const std::runtime_error& e)
191 {
192 auto reply = dbus::Message::make_error(
193 msg,
194 mpris::Service::Errors::CreatingSession::name(),
195 e.what());
196 impl->access_bus()->send(reply);
197 }
198 }
199
200 void handle_resume_session(const core::dbus::Message::Ptr& msg)
201 {
202 try
203 {
204 Player::PlayerKey key;
205 msg->reader() >> key;
206
207 if (session_store.count(key) == 0) {
240 auto reply = dbus::Message::make_error(208 auto reply = dbus::Message::make_error(
241 msg,209 msg,
242 mpris::Service::Errors::CreatingSession::name(),210 mpris::Service::Errors::ResumingSession::name(),
243 e.what());211 "Unable to locate player session");
244 impl->access_bus()->send(reply);212 impl->access_bus()->send(reply);
213 return;
245 }214 }
246 });215
216 std::stringstream ss;
217 ss << "/core/ubuntu/media/Service/sessions/" << key;
218 dbus::types::ObjectPath op{ss.str()};
219
220 auto reply = dbus::Message::make_method_return(msg);
221 reply->writer() << op;
222
223 impl->access_bus()->send(reply);
224 } catch(const std::runtime_error& e)
225 {
226 auto reply = dbus::Message::make_error(
227 msg,
228 mpris::Service::Errors::CreatingSession::name(),
229 e.what());
230 impl->access_bus()->send(reply);
231 }
247 }232 }
248233
249 void handle_pause_other_sessions(const core::dbus::Message::Ptr& msg)234 void handle_pause_other_sessions(const core::dbus::Message::Ptr& msg)
@@ -260,8 +245,6 @@
260 media::ServiceSkeleton* impl;245 media::ServiceSkeleton* impl;
261 dbus::Object::Ptr object;246 dbus::Object::Ptr object;
262247
263 // We query the apparmor profile to obtain an identity for players.
264 org::freedesktop::dbus::DBus::Stub dbus_stub;
265 // We track all running player instances.248 // We track all running player instances.
266 std::map<media::Player::PlayerKey, std::shared_ptr<media::Player>> session_store;249 std::map<media::Player::PlayerKey, std::shared_ptr<media::Player>> session_store;
267 std::map<std::string, media::Player::PlayerKey> fixed_session_store;250 std::map<std::string, media::Player::PlayerKey> fixed_session_store;

Subscribers

People subscribed via source and target branches

to all changes: