[Merge] lp:~thomas-voss/media-hub/introduce-apparmor-interfaces into lp:media-hub
Thomas Voß
thomas.voss at canonical.com
Mon Dec 15 14:05:56 UTC 2014
Diff comments:
> === modified file 'src/core/media/CMakeLists.txt'
> --- src/core/media/CMakeLists.txt 2014-11-26 16:28:50 +0000
> +++ src/core/media/CMakeLists.txt 2014-11-26 16:28:50 +0000
> @@ -91,6 +91,9 @@
> cover_art_resolver.cpp
> engine.cpp
>
> + apparmor/context.cpp
> + apparmor/ubuntu.cpp
> +
> audio/pulse_audio_output_observer.cpp
> audio/output_observer.cpp
>
>
> === 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 @@
> -/*
> - * Copyright (C) 2013-2014 Canonical Ltd
> - *
> - * This program is free software: you can redistribute it and/or modify
> - * it under the terms of the GNU Lesser General Public License version 3 as
> - * published by the Free Software Foundation.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU Lesser General Public License for more details.
> - *
> - * You should have received a copy of the GNU Lesser General Public License
> - * along with this program. If not, see <http://www.gnu.org/licenses/>.
> - *
> - * Author: Jim Hodapp <jim.hodapp at canonical.com>
> - */
> -
> -#ifndef APPARMOR_DBUS_H_
> -#define APPARMOR_DBUS_H_
> -
> -#include <core/dbus/macros.h>
> -#include <core/dbus/object.h>
> -#include <core/dbus/service.h>
> -
> -#include <string>
> -#include <chrono>
> -
> -// TODO(tvoss): This really should live in trust-store, providing a straightforward
> -// way for parties involved in managing trust relationships to query peers' apparmor
> -// profiles. Please see https://bugs.launchpad.net/trust-store/+bug/1350736 for the
> -// related bug
> -namespace org
> -{
> -namespace freedesktop
> -{
> -namespace dbus
> -{
> -struct DBus
> -{
> - static const std::string& name()
> - {
> - static const std::string s = "org.freedesktop.DBus";
> - return s;
> - }
> -
> - // Gets the AppArmor confinement string associated with the unique connection name. If
> - // D-Bus is not performing AppArmor mediation, the
> - // org.freedesktop.DBus.Error.AppArmorSecurityContextUnknown error is returned.
> - DBUS_CPP_METHOD_DEF(GetConnectionAppArmorSecurityContext, DBus)
> -
> - struct Stub
> - {
> - // Creates a new stub instance for the given object to access
> - // DBus functionality.
> - Stub(const core::dbus::Object::Ptr& object) : object{object}
> - {
> - }
> -
> - // Creates a new stub instance for the given bus connection
> - Stub(const core::dbus::Bus::Ptr& bus)
> - : object
> - {
> - core::dbus::Service::use_service<org::freedesktop::dbus::DBus>(bus)
> - ->object_for_path(core::dbus::types::ObjectPath{"/org/freedesktop/DBus"})
> - }
> - {
> - }
> -
> - // Gets the AppArmor confinement string associated with the unique connection name. If
> - // D-Bus is not performing AppArmor mediation, the
> - // org.freedesktop.DBus.Error.AppArmorSecurityContextUnknown error is returned.
> - //
> - // Invokes the given handler on completion.
> - void get_connection_app_armor_security_async(
> - const std::string& name,
> - std::function<void(const std::string&)> handler)
> - {
> - object->invoke_method_asynchronously_with_callback<GetConnectionAppArmorSecurityContext, std::string>(
> - [handler](const core::dbus::Result<std::string>& result)
> - {
> - if (not result.is_error()) handler(result.value());
> - }, name);
> - }
> -
> - core::dbus::Object::Ptr object;
> - };
> -};
> -}
> -}
> -}
> -
> -#endif // APPARMOR_DBUS_H_
>
> === 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 2014-11-26 16:28:50 +0000
> @@ -0,0 +1,34 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +
> +#include <core/media/apparmor/context.h>
> +
> +namespace apparmor = core::ubuntu::media::apparmor;
> +
> +apparmor::Context::Context(const std::string& name) : name{name}
> +{
> + if (name.empty()) throw std::runtime_error
> + {
> + "apparmor::Context cannot be created for empty name."
> + };
> +}
> +
> +const std::string& apparmor::Context::str() const
> +{
> + return name;
> +}
>
> === 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 2014-11-26 16:28:50 +0000
> @@ -0,0 +1,51 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +#ifndef CORE_UBUNTU_MEDIA_APPARMOR_AUTHENTICATOR_H_
> +#define CORE_UBUNTU_MEDIA_APPARMOR_AUTHENTICATOR_H_
> +
> +#include <memory>
> +#include <string>
> +
> +namespace core
> +{
> +namespace ubuntu
> +{
> +namespace media
> +{
> +namespace apparmor
> +{
> +// Models an apparmor context name, and provides convenience functionality
> +// on top of it.
> +class Context
> +{
> +public:
> + // Constructs a new Context instance for the given raw name.
> + // Throws std::logic_error for empty names.
> + explicit Context(const std::string& name);
> + virtual ~Context() = default;
> + // Returns the raw string describing the context.
> + const std::string& str() const;
> +
> +private:
> + const std::string name;
> +};
> +}
> +}
> +}
> +}
> +#endif // CORE_UBUNTU_MEDIA_APPARMOR_AUTHENTICATOR_H_
>
> === 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 2014-11-26 16:28:50 +0000
> @@ -0,0 +1,94 @@
> +/*
> + * Copyright (C) 2013-2014 Canonical Ltd
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU Lesser General Public License version 3 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Author: Jim Hodapp <jim.hodapp at canonical.com>
> + */
> +
> +#ifndef CORE_UBUNTU_MEDIA_APPARMOR_DBUS_H_
> +#define CORE_UBUNTU_MEDIA_APPARMOR_DBUS_H_
> +
> +#include <core/dbus/bus.h>
> +#include <core/dbus/macros.h>
> +#include <core/dbus/object.h>
> +#include <core/dbus/service.h>
> +
> +#include <string>
> +#include <chrono>
> +
> +// TODO(tvoss): This really should live in trust-store, providing a straightforward
> +// way for parties involved in managing trust relationships to query peers' apparmor
> +// profiles. Please see https://bugs.launchpad.net/trust-store/+bug/1350736 for the
> +// related bug
> +namespace org
> +{
> +namespace freedesktop
> +{
> +namespace dbus
> +{
> +struct DBus
> +{
> + static const std::string& name()
> + {
> + static const std::string s = "org.freedesktop.DBus";
> + return s;
> + }
> +
> + // Gets the AppArmor confinement string associated with the unique connection name. If
> + // D-Bus is not performing AppArmor mediation, the
> + // org.freedesktop.DBus.Error.AppArmorSecurityContextUnknown error is returned.
> + DBUS_CPP_METHOD_DEF(GetConnectionAppArmorSecurityContext, DBus)
> +
> + struct Stub
> + {
> + // Creates a new stub instance for the given object to access
> + // DBus functionality.
> + Stub(const core::dbus::Object::Ptr& object) : object{object}
> + {
> + }
> +
> + // Creates a new stub instance for the given bus connection
> + Stub(const core::dbus::Bus::Ptr& bus)
> + : object
> + {
> + core::dbus::Service::use_service<org::freedesktop::dbus::DBus>(bus)
> + ->object_for_path(core::dbus::types::ObjectPath{"/org/freedesktop/DBus"})
> + }
> + {
> + }
> +
> + // Gets the AppArmor confinement string associated with the unique connection name. If
> + // D-Bus is not performing AppArmor mediation, the
> + // org.freedesktop.DBus.Error.AppArmorSecurityContextUnknown error is returned.
> + //
> + // Invokes the given handler on completion.
> + void get_connection_app_armor_security_async(
> + const std::string& name,
> + std::function<void(const std::string&)> handler)
> + {
> + object->invoke_method_asynchronously_with_callback<GetConnectionAppArmorSecurityContext, std::string>(
> + [handler](const core::dbus::Result<std::string>& result)
> + {
> + if (not result.is_error()) handler(result.value());
> + }, name);
> + }
> +
> + core::dbus::Object::Ptr object;
> + };
> +};
> +}
> +}
> +}
> +
> +#endif // CORE_UBUNTU_MEDIA_APPARMOR_DBUS_H_
>
> === 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 2014-11-26 16:28:50 +0000
> @@ -0,0 +1,198 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +
> +#include <core/media/apparmor/ubuntu.h>
> +
> +#include <core/media/external_services.h>
> +
> +#include <iostream>
> +#include <regex>
> +
> +namespace apparmor = core::ubuntu::media::apparmor;
> +namespace media = core::ubuntu::media;
> +namespace ubuntu = apparmor::ubuntu;
> +
> +namespace
> +{
> +struct Uri
> +{
> + std::string scheme;
> + std::string authority;
> + std::string path;
> + std::string query;
> + std::string fragment;
> +};
> +
> +// Poor mans version of a uri parser.
> +// See https://tools.ietf.org/html/rfc3986#appendix-B
> +Uri parse_uri(const std::string& s)
> +{
> + // Indices into the regex match go here.
> + struct Index
> + {
> + const std::size_t scheme{2};
> + const std::size_t authority{4};
> + const std::size_t path{5};
> + const std::size_t query{7};
> + const std::size_t fragment{9};
> + } static index;
> +
> + static const std::regex regex{R"delim(^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?)delim"};
> + std::smatch match;
> +
> + if (not std::regex_match(s, match, regex)) throw std::runtime_error
> + {
> + "Not a valid URI: " + s
> + };
> +
> + return Uri
> + {
> + match.str(index.scheme),
> + match.str(index.authority),
> + match.str(index.path),
> + match.str(index.query),
> + match.str(index.fragment)
> + };
> +}
> +
> +static constexpr std::size_t index_package{1};
> +static constexpr std::size_t index_app{2};
> +
> +// Returns true if the context name is a valid Ubuntu app id.
> +// If it is, out is populated with the package and app name.
> +bool process_context_name(const std::string& s, std::smatch& out)
> +{
> + // See https://wiki.ubuntu.com/AppStore/Interfaces/ApplicationId.
> + static const std::regex short_re{"(.*)_(.*)"};
> + static const std::regex full_re{"(.*)_(.*)_(.*)"};
> +
> + if (std::regex_match(s, out, full_re))
> + return true;
> +
> + if (std::regex_match(s, out, short_re))
> + return true;
> +
> + return false;
> +}
> +}
> +
> +apparmor::ubuntu::Context::Context(const std::string& name)
> + : apparmor::Context{name},
> + unconfined_{str() == ubuntu::unconfined},
> + has_package_name_{process_context_name(str(), match_)}
> +{
> + if (not is_unconfined() && not has_package_name()) throw std::logic_error
> + {
> + "apparmor::ubuntu::Context: Invalid profile name " + str()
> + };
> +}
> +
> +bool apparmor::ubuntu::Context::is_unconfined() const
> +{
> + return unconfined_;
> +}
> +
> +bool apparmor::ubuntu::Context::has_package_name() const
> +{
> + return has_package_name_;
> +}
> +
> +
> +std::string apparmor::ubuntu::Context::package_name() const
> +{
> + return std::string{match_[index_package]};
> +}
> +
> +apparmor::ubuntu::DBusDaemonRequestContextResolver::DBusDaemonRequestContextResolver(const core::dbus::Bus::Ptr& bus) : dbus_daemon{bus}
> +{
> +}
> +
> +void apparmor::ubuntu::DBusDaemonRequestContextResolver::resolve_context_for_dbus_name_async(
> + const std::string& name,
> + apparmor::ubuntu::RequestContextResolver::ResolveCallback cb)
> +{
> + dbus_daemon.get_connection_app_armor_security_async(name, [cb](const std::string& context_name)
> + {
> + cb(apparmor::ubuntu::Context{context_name});
> + });
> +}
> +
> +apparmor::ubuntu::RequestAuthenticator::Result apparmor::ubuntu::ExistingAuthenticator::authenticate_open_uri_request(const apparmor::ubuntu::Context& context, const std::string& uri)
> +{
> + if (context.is_unconfined())
> + return Result{true, "Client allowed access since it's unconfined"};
> +
> + Uri parsed_uri = parse_uri(uri);
> +
> + // All confined apps can access their own files
> + if (parsed_uri.path.find(std::string(".local/share/" + context.package_name() + "/")) != std::string::npos ||
> + parsed_uri.path.find(std::string(".cache/" + context.package_name() + "/")) != std::string::npos)
> + {
> + return Result
> + {
> + true,
> + "Client can access content in ~/.local/share/" + context.package_name() + " or ~/.cache/" + context.package_name()
> + };
> + }
> + else if (parsed_uri.path.find(std::string("opt/click.ubuntu.com/")) != std::string::npos &&
> + parsed_uri.path.find(context.package_name()) != std::string::npos)
> + {
> + return Result{true, "Client can access content in own opt directory"};
> + }
> + else if ((parsed_uri.path.find(std::string("/system/media/audio/ui/")) != std::string::npos ||
> + parsed_uri.path.find(std::string("/android/system/media/audio/ui/")) != std::string::npos) &&
> + context.package_name() == "com.ubuntu.camera")
> + {
> + return Result{true, "Camera app can access ui sounds"};
> + }
> +
> + // TODO: Check if the trust store previously allowed direct access to uri
> +
> + // Check in ~/Music and ~/Videos
> + // TODO: when the trust store lands, check it to see if this app can access the dirs and
> + // then remove the explicit whitelist of the music-app, and gallery-app
> + else if ((context.package_name() == "com.ubuntu.music" || context.package_name() == "com.ubuntu.gallery") &&
> + (parsed_uri.path.find(std::string("Music/")) != std::string::npos ||
> + parsed_uri.path.find(std::string("Videos/")) != std::string::npos ||
> + parsed_uri.path.find(std::string("/media")) != std::string::npos))
> + {
> + return Result{true, "Client can access content in ~/Music or ~/Videos"};
> + }
> + else if (parsed_uri.path.find(std::string("/usr/share/sounds")) != std::string::npos)
> + {
> + return Result{true, "Client can access content in /usr/share/sounds"};
> + }
> + else if (parsed_uri.scheme == "http" || parsed_uri.scheme == "rtsp")
> + {
> + return Result{true, "Client can access streaming content"};
> + }
> +
> + return Result{false, "Client is not allowed to access: " + uri};
> +}
> +
> +// Returns the platform-default implementation of RequestContextResolver.
> +apparmor::ubuntu::RequestContextResolver::Ptr apparmor::ubuntu::make_platform_default_request_context_resolver(media::helper::ExternalServices& es)
> +{
> + return std::make_shared<apparmor::ubuntu::DBusDaemonRequestContextResolver>(es.session);
> +}
> +
> +// Returns the platform-default implementation of RequestAuthenticator.
> +apparmor::ubuntu::RequestAuthenticator::Ptr apparmor::ubuntu::make_platform_default_request_authenticator()
> +{
> + return std::make_shared<apparmor::ubuntu::ExistingAuthenticator>();
> +}
>
> === 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 2014-11-26 16:28:50 +0000
> @@ -0,0 +1,166 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +#ifndef CORE_UBUNTU_MEDIA_APPARMOR_UBUNTU_H_
> +#define CORE_UBUNTU_MEDIA_APPARMOR_UBUNTU_H_
> +
> +#include <core/media/apparmor/context.h>
> +#include <core/media/apparmor/dbus.h>
> +
> +#include <functional>
> +#include <memory>
> +#include <regex>
> +#include <string>
> +#include <vector>
> +
> +namespace core
> +{
> +namespace dbus
> +{
> +class Bus;
> +}
> +namespace ubuntu
Yup, done :)
> +{
> +namespace media
> +{
> +namespace helper
> +{
> +struct ExternalServices;
> +}
> +namespace apparmor
> +{
> +// Collects Ubuntu-specific apparmor conventions, e.g., format
> +// of short and full package names as well as convenience functionality
> +// to inspect apparmor::Context instances.
> +namespace ubuntu
> +{
> +// The unconfined profile, unconditionally trusted
> +// by the system.
> +static constexpr const char* unconfined
> +{
> + "unconfined"
> +};
> +
> +class Context : public apparmor::Context
> +{
> +public:
> + // Constructs a new Context instance for the given raw name.
> + // Throws std::logic_error for empty names or for names not
> + // complying to Ubuntu conventions.
> + Context(const std::string& name);
> +
> + // Returns true iff the context is unconfined.
> + virtual bool is_unconfined() const;
> +
> + // Returns true iff the context contains a package name.
> + virtual bool has_package_name() const;
> +
> + // Returns the package name or throws if no package name can be found.
> + virtual std::string package_name() const;
> +
> +private:
> + std::smatch match_;
> + const bool unconfined_;
> + const bool has_package_name_;
> +};
> +
> +// Abstracts query for the apparmor context of an incoming request
> +class RequestContextResolver
> +{
> +public:
> + // To save us some typing.
> + typedef std::shared_ptr<RequestContextResolver> Ptr;
> +
> + // Callback for resolve context operations.
> + typedef std::function<void(const Context&)> ResolveCallback;
> +
> + // Resolves the given name (of a dbus participant) to its apparmor context,
> + // invoking the callback whenever a result is available.
> + virtual void resolve_context_for_dbus_name_async(const std::string& name, ResolveCallback cb) = 0;
> +
> +protected:
> + RequestContextResolver() = default;
> + RequestContextResolver(const RequestContextResolver&) = delete;
> + virtual ~RequestContextResolver() = default;
> + RequestContextResolver& operator=(const RequestContextResolver&) = delete;
> +};
> +
> +// An implementation of RequestContextResolver that queries the dbus
> +// daemon to resolve the apparmor context.
> +class DBusDaemonRequestContextResolver : public RequestContextResolver
> +{
> +public:
> + // To save us some typing.
> + typedef std::shared_ptr<DBusDaemonRequestContextResolver> Ptr;
> +
> + // Constructs a new instance for the given bus connection.
> + DBusDaemonRequestContextResolver(const core::dbus::Bus::Ptr &);
> +
> + // From RequestContextResolver
> + void resolve_context_for_dbus_name_async(const std::string& name, ResolveCallback) override;
> +
> +private:
> + org::freedesktop::dbus::DBus::Stub dbus_daemon;
> +};
> +
> +// Abstracts an apparmor-based authentication of
> +// incoming requests from clients.
> +class RequestAuthenticator
> +{
> +public:
> + // To save us some typing.
> + typedef std::shared_ptr<RequestAuthenticator> Ptr;
> +
> + // Return type of an authentication call.
> + typedef std::tuple
> + <
> + bool, // True if authenticated, false if not.
> + std::string // Reason for the result.
> + > Result;
> +
> + virtual ~RequestAuthenticator() = default;
> +
> + // Returns true iff the client identified by the given apparmor::Context is allowed
> + // to access the given uri, false otherwise.
> + virtual Result authenticate_open_uri_request(const Context&, const std::string& uri) = 0;
> +
> +protected:
> + RequestAuthenticator() = default;
> + RequestAuthenticator(const RequestAuthenticator&) = default;
> + RequestAuthenticator& operator=(const RequestAuthenticator&) = default;
> +};
> +
> +// Takes the existing logic and exposes it as an implementation
> +// of the RequestAuthenticator interface.
> +struct ExistingAuthenticator : public RequestAuthenticator
> +{
> + ExistingAuthenticator() = default;
> + // From RequestAuthenticator
> + Result authenticate_open_uri_request(const Context&, const std::string& uri) override;
> +};
> +
> +// Returns the platform-default implementation of RequestContextResolver.
> +RequestContextResolver::Ptr make_platform_default_request_context_resolver(helper::ExternalServices& es);
> +// Returns the platform-default implementation of RequestAuthenticator.
> +RequestAuthenticator::Ptr make_platform_default_request_authenticator();
> +}
> +}
> +}
> +}
> +}
> +
> +#endif // CORE_UBUNTU_MEDIA_APPARMOR_UBUNTU_H_
>
> === modified file 'src/core/media/player.cpp'
> --- src/core/media/player.cpp 2014-11-26 16:28:50 +0000
> +++ src/core/media/player.cpp 2014-11-26 16:28:50 +0000
> @@ -31,7 +31,6 @@
> {
> static const media::Player::Configuration config
> {
> - std::string{""},
> 0,
> nullptr,
> nullptr
>
> === 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 2014-11-26 16:28:50 +0000
> @@ -27,9 +27,6 @@
> // to the implementation in a way that is opaque to the client.
> struct core::ubuntu::media::Player::Configuration
> {
> - // An identifier that is helpful in referencing the player instance
> - // across multiple services.
> - std::string identity;
> // Unique key for identifying the session.
> core::ubuntu::media::Player::PlayerKey key;
> // The bus connection to expose objects on.
>
> === modified file 'src/core/media/player_implementation.cpp'
> --- src/core/media/player_implementation.cpp 2014-11-26 16:28:50 +0000
> +++ src/core/media/player_implementation.cpp 2014-11-26 16:28:50 +0000
> @@ -260,7 +260,8 @@
> {
> config.bus,
> config.session,
> - config.identity
> + config.request_context_resolver,
> + config.request_authenticator
> }
> },
> d{std::make_shared<Private>(this, config)}
>
> === modified file 'src/core/media/player_implementation.h'
> --- src/core/media/player_implementation.h 2014-11-26 16:28:50 +0000
> +++ src/core/media/player_implementation.h 2014-11-26 16:28:50 +0000
> @@ -21,6 +21,7 @@
>
> #include "player_skeleton.h"
>
> +#include "apparmor/ubuntu.h"
> #include "client_death_observer.h"
> #include "power/state_controller.h"
>
> @@ -41,13 +42,14 @@
> // All creation time arguments go here
> struct Configuration
> {
> - std::string identity;
> std::shared_ptr<core::dbus::Bus> bus;
> std::shared_ptr<core::dbus::Object> session;
> std::shared_ptr<Service> service;
> PlayerKey key;
>
> // Functional dependencies
> + apparmor::ubuntu::RequestContextResolver::Ptr request_context_resolver;
> + apparmor::ubuntu::RequestAuthenticator::Ptr request_authenticator;
> ClientDeathObserver::Ptr client_death_observer;
> power::StateController::Ptr power_state_controller;
> };
>
> === modified file 'src/core/media/player_skeleton.cpp'
> --- src/core/media/player_skeleton.cpp 2014-11-26 16:28:50 +0000
> +++ src/core/media/player_skeleton.cpp 2014-11-26 16:28:50 +0000
> @@ -17,15 +17,16 @@
> * Jim Hodapp <jim.hodapp at canonical.com>
> */
>
> -#include "apparmor.h"
> #include "codec.h"
> #include "engine.h"
> +#include "external_services.h"
> #include "player_skeleton.h"
> #include "player_traits.h"
> #include "property_stub.h"
> #include "the_session_bus.h"
> #include "xesam.h"
>
> +#include "apparmor/ubuntu.h"
> #include "mpris/media_player2.h"
> #include "mpris/metadata.h"
> #include "mpris/player.h"
> @@ -44,15 +45,15 @@
> struct media::PlayerSkeleton::Private
> {
> Private(media::PlayerSkeleton* player,
> - const std::string& identity,
> const std::shared_ptr<core::dbus::Bus>& bus,
> - const std::shared_ptr<core::dbus::Object>& session)
> + const std::shared_ptr<core::dbus::Object>& session,
> + const apparmor::ubuntu::RequestContextResolver::Ptr& request_context_resolver,
> + const apparmor::ubuntu::RequestAuthenticator::Ptr& request_authenticator)
> : impl(player),
> - identity(identity),
> bus(bus),
> object(session),
> - apparmor_session(nullptr),
> - dbus_stub{bus},
> + request_context_resolver{request_context_resolver},
> + request_authenticator{request_authenticator},
> skeleton{mpris::Player::Skeleton::Configuration{bus, session, mpris::Player::Skeleton::Configuration::Defaults{}}},
> signals
> {
> @@ -162,82 +163,6 @@
> bus->send(reply);
> }
>
> - bool does_client_have_access(const std::string& context, const std::string& uri)
> - {
> - if (context.empty() || uri.empty())
> - {
> - std::cout << "Client denied access since context or uri are empty" << std::endl;
> - return false;
> - }
> -
> - if (context == "unconfined")
> - {
> - std::cout << "Client allowed access since it's unconfined" << std::endl;
> - return true;
> - }
> -
> - size_t pos = context.find_first_of('_');
> - if (pos == std::string::npos)
> - {
> - std::cout << "Client denied access since it's an invalid apparmor security context" << std::endl;
> - return false;
> - }
> -
> - const std::string pkgname = context.substr(0, pos);
> - std::cout << "client pkgname: " << pkgname << std::endl;
> - std::cout << "uri: " << uri << std::endl;
> -
> - // All confined apps can access their own files
> - if (uri.find(std::string(".local/share/" + pkgname + "/")) != std::string::npos
> - || uri.find(std::string(".cache/" + pkgname + "/")) != std::string::npos)
> - {
> - std::cout << "Client can access content in ~/.local/share/" << pkgname << " or ~/.cache/" << pkgname << std::endl;
> - return true;
> - }
> - else if (uri.find(std::string("opt/click.ubuntu.com/")) != std::string::npos
> - && uri.find(pkgname) != std::string::npos)
> - {
> - std::cout << "Client can access content in own opt directory" << std::endl;
> - return true;
> - }
> - else if ((uri.find(std::string("/system/media/audio/ui/")) != std::string::npos
> - || uri.find(std::string("/android/system/media/audio/ui/")) != std::string::npos)
> - && pkgname == "com.ubuntu.camera")
> - {
> - std::cout << "Camera app can access ui sounds" << std::endl;
> - return true;
> - }
> - // TODO: Check if the trust store previously allowed direct access to uri
> -
> - // Check in ~/Music and ~/Videos
> - // TODO: when the trust store lands, check it to see if this app can access the dirs and
> - // then remove the explicit whitelist of the music-app, and gallery-app
> - else if ((pkgname == "com.ubuntu.music" || pkgname == "com.ubuntu.gallery") &&
> - (uri.find(std::string("Music/")) != std::string::npos
> - || uri.find(std::string("Videos/")) != std::string::npos
> - || uri.find(std::string("/media")) != std::string::npos))
> - {
> - std::cout << "Client can access content in ~/Music or ~/Videos" << std::endl;
> - return true;
> - }
> - else if (uri.find(std::string("/usr/share/sounds")) != std::string::npos)
> - {
> - std::cout << "Client can access content in /usr/share/sounds" << std::endl;
> - return true;
> - }
> - else if (uri.find(std::string("http://")) != std::string::npos
> - || uri.find(std::string("rtsp://")) != std::string::npos)
> - {
> - std::cout << "Client can access streaming content" << std::endl;
> - return true;
> - }
> - else
> - {
> - std::cout << "Client denied access to open_uri()" << std::endl;
> - return false;
> - }
> - }
> -
> void handle_key(const core::dbus::Message::Ptr& in)
> {
> auto reply = dbus::Message::make_method_return(in);
> @@ -247,15 +172,15 @@
>
> void handle_open_uri(const core::dbus::Message::Ptr& in)
> {
> - dbus_stub.get_connection_app_armor_security_async(in->sender(), [this, in](const std::string& profile)
> + request_context_resolver->resolve_context_for_dbus_name_async(in->sender(), [this, in](const media::apparmor::ubuntu::Context& context)
> {
> Track::UriType uri;
> in->reader() >> uri;
>
> - bool have_access = does_client_have_access(profile, uri);
> + auto result = request_authenticator->authenticate_open_uri_request(context, uri);
>
> auto reply = dbus::Message::make_method_return(in);
> - reply->writer() << (have_access ? impl->open_uri(uri) : false);
> + reply->writer() << (std::get<0>(result) ? impl->open_uri(uri) : false);
>
> bus->send(reply);
> });
> @@ -283,12 +208,10 @@
> }
>
> media::PlayerSkeleton* impl;
> - std::string identity;
> dbus::Bus::Ptr bus;
> dbus::Object::Ptr object;
> - dbus::Object::Ptr apparmor_session;
> -
> - org::freedesktop::dbus::DBus::Stub dbus_stub;
> + media::apparmor::ubuntu::RequestContextResolver::Ptr request_context_resolver;
> + media::apparmor::ubuntu::RequestAuthenticator::Ptr request_authenticator;
>
> mpris::Player::Skeleton skeleton;
>
> @@ -334,7 +257,7 @@
> };
>
> media::PlayerSkeleton::PlayerSkeleton(const media::PlayerSkeleton::Configuration& config)
> - : d(new Private{this, config.identity, config.bus, config.session})
> + : d(new Private{this, config.bus, config.session, config.request_context_resolver, config.request_authenticator})
> {
> // Setup method handlers for mpris::Player methods.
> auto next = std::bind(&Private::handle_next, d, std::placeholders::_1);
>
> === modified file 'src/core/media/player_skeleton.h'
> --- src/core/media/player_skeleton.h 2014-11-26 16:28:50 +0000
> +++ src/core/media/player_skeleton.h 2014-11-26 16:28:50 +0000
> @@ -24,6 +24,7 @@
>
> #include "player_traits.h"
>
> +#include "apparmor/ubuntu.h"
> #include "mpris/player.h"
>
> #include <core/dbus/skeleton.h>
> @@ -37,6 +38,11 @@
> {
> namespace media
> {
> +namespace helper
> +{
> +struct ExternalServices;
> +}
> +
> class Service;
>
> class PlayerSkeleton : public core::ubuntu::media::Player
> @@ -83,9 +89,9 @@
> std::shared_ptr<core::dbus::Bus> bus;
> // The session object that we want to expose the skeleton upon.
> std::shared_ptr<core::dbus::Object> session;
> - // Our identity, an identifier we pass out to other parts of the system.
> - // Defaults to the short app id (${PKG_NAME}_${APP}).
> - std::string identity;
> + // Our functional dependencies.
> + apparmor::ubuntu::RequestContextResolver::Ptr request_context_resolver;
> + apparmor::ubuntu::RequestAuthenticator::Ptr request_authenticator;
> };
>
> PlayerSkeleton(const Configuration& configuration);
>
> === modified file 'src/core/media/service_implementation.cpp'
> --- src/core/media/service_implementation.cpp 2014-11-26 16:28:50 +0000
> +++ src/core/media/service_implementation.cpp 2014-11-26 16:28:50 +0000
> @@ -22,6 +22,7 @@
>
> #include "service_implementation.h"
>
> +#include "apparmor/ubuntu.h"
> #include "audio/output_observer.h"
> #include "client_death_observer.h"
> #include "player_configuration.h"
> @@ -59,6 +60,8 @@
> client_death_observer(media::platform_default_client_death_observer()),
> recorder_observer(media::make_platform_default_recorder_observer()),
> audio_output_observer(media::audio::make_platform_default_output_observer()),
> + request_context_resolver(media::apparmor::ubuntu::make_platform_default_request_context_resolver(configuration.external_services)),
> + request_authenticator(media::apparmor::ubuntu::make_platform_default_request_authenticator()),
> call_monitor(media::telephony::make_platform_default_call_monitor())
> {
> }
> @@ -81,12 +84,14 @@
> media::ClientDeathObserver::Ptr client_death_observer;
> media::RecorderObserver::Ptr recorder_observer;
> media::audio::OutputObserver::Ptr audio_output_observer;
> -
> + media::apparmor::ubuntu::RequestContextResolver::Ptr request_context_resolver;
> + media::apparmor::ubuntu::RequestAuthenticator::Ptr request_authenticator;
> media::telephony::CallMonitor::Ptr call_monitor;
> std::list<media::Player::PlayerKey> paused_sessions;
> };
>
> -media::ServiceImplementation::ServiceImplementation(const Configuration& configuration) : d(new Private(configuration))
> +media::ServiceImplementation::ServiceImplementation(const Configuration& configuration)
> + : d(new Private(configuration))
> {
> d->battery_observer->level().changed().connect([this](const media::power::Level& level)
> {
> @@ -145,11 +150,12 @@
> {
> auto player = std::make_shared<media::PlayerImplementation>(media::PlayerImplementation::Configuration
> {
> - conf.identity,
> conf.bus,
> conf.session,
> shared_from_this(),
> conf.key,
> + d->request_context_resolver,
> + d->request_authenticator,
> d->client_death_observer,
> d->power_state_controller
> });
>
> === modified file 'src/core/media/service_skeleton.cpp'
> --- src/core/media/service_skeleton.cpp 2014-11-07 15:49:20 +0000
> +++ src/core/media/service_skeleton.cpp 2014-11-26 16:28:50 +0000
> @@ -19,8 +19,6 @@
>
> #include "service_skeleton.h"
>
> -#include "apparmor.h"
> -
> #include "mpris/media_player2.h"
> #include "mpris/metadata.h"
> #include "mpris/player.h"
> @@ -55,7 +53,6 @@
> : impl(impl),
> object(impl->access_service()->add_object_for_path(
> dbus::traits::Service<media::Service>::object_path())),
> - dbus_stub(impl->access_bus()),
> exported(impl->access_bus(), resolver)
> {
> object->install_method_handler<mpris::Service::CreateSession>(
> @@ -80,40 +77,36 @@
> dbus::types::ObjectPath op{ss.str()};
> media::Player::PlayerKey key{session_counter};
>
> - dbus_stub.get_connection_app_armor_security_async(msg->sender(), [this, msg, op, key](const std::string& profile)
> - {
> - media::Player::Configuration config
> - {
> - profile,
> - key,
> - impl->access_bus(),
> - impl->access_service()->add_object_for_path(op)
> - };
> -
> - try
> - {
> - auto session = impl->create_session(config);
> -
> - bool inserted = false;
> - std::tie(std::ignore, inserted)
> - = session_store.insert(std::make_pair(key, session));
> -
> - if (!inserted)
> - throw std::runtime_error("Problem persisting session in session store.");
> -
> - auto reply = dbus::Message::make_method_return(msg);
> - reply->writer() << op;
> -
> - impl->access_bus()->send(reply);
> - } catch(const std::runtime_error& e)
> - {
> - auto reply = dbus::Message::make_error(
> - msg,
> - mpris::Service::Errors::CreatingSession::name(),
> - e.what());
> - impl->access_bus()->send(reply);
> - }
> - });
> + media::Player::Configuration config
> + {
> + key,
> + impl->access_bus(),
> + impl->access_service()->add_object_for_path(op)
> + };
> +
> + try
> + {
> + auto session = impl->create_session(config);
> +
> + bool inserted = false;
> + std::tie(std::ignore, inserted)
> + = session_store.insert(std::make_pair(key, session));
> +
> + if (!inserted)
> + throw std::runtime_error("Problem persisting session in session store.");
> +
> + auto reply = dbus::Message::make_method_return(msg);
> + reply->writer() << op;
> +
> + impl->access_bus()->send(reply);
> + } catch(const std::runtime_error& e)
> + {
> + auto reply = dbus::Message::make_error(
> + msg,
> + mpris::Service::Errors::CreatingSession::name(),
> + e.what());
> + impl->access_bus()->send(reply);
> + }
> }
>
> void handle_pause_other_sessions(const core::dbus::Message::Ptr& msg)
> @@ -130,8 +123,6 @@
> media::ServiceSkeleton* impl;
> dbus::Object::Ptr object;
>
> - // We query the apparmor profile to obtain an identity for players.
> - org::freedesktop::dbus::DBus::Stub dbus_stub;
> // We track all running player instances.
> std::map<media::Player::PlayerKey, std::shared_ptr<media::Player>> session_store;
> // We expose the entire service as an MPRIS player.
>
--
https://code.launchpad.net/~thomas-voss/media-hub/introduce-apparmor-interfaces/+merge/242943
Your team Ubuntu Phablet Team is subscribed to branch lp:media-hub.
More information about the Ubuntu-reviews
mailing list