Merge lp:~thomas-voss/trust-store/add_convenience_function_for_processing_incoming_requests into lp:trust-store
- add_convenience_function_for_processing_incoming_requests
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Thomas Voß |
Approved revision: | 54 |
Merged at revision: | 19 |
Proposed branch: | lp:~thomas-voss/trust-store/add_convenience_function_for_processing_incoming_requests |
Merge into: | lp:trust-store |
Diff against target: |
2822 lines (+2097/-171) 26 files modified
CMakeLists.txt (+7/-1) debian/control (+19/-0) debian/libtrust-store0.install (+2/-0) debian/libtrust-store0.symbols (+41/-8) debian/trust-store-tests.install (+1/-0) include/core/trust/agent.h (+57/-0) include/core/trust/mir_agent.h (+48/-0) include/core/trust/request.h (+78/-1) include/core/trust/store.h (+25/-4) src/CMakeLists.txt (+62/-1) src/core/trust/dbus_interface.h (+2/-7) src/core/trust/expose.cpp (+46/-32) src/core/trust/impl/sqlite3/store.cpp (+10/-12) src/core/trust/mir/agent.cpp (+267/-0) src/core/trust/mir/agent.h (+196/-0) src/core/trust/mir/config.h.in (+41/-0) src/core/trust/mir/prompt_config.h.in (+39/-0) src/core/trust/mir/prompt_main.cpp (+191/-0) src/core/trust/mir/prompt_main.h (+65/-0) src/core/trust/mir/prompt_main.qml (+53/-0) src/core/trust/request.cpp (+49/-0) src/core/trust/resolve.cpp (+19/-13) tests/CMakeLists.txt (+66/-12) tests/mir_agent_test.cpp (+420/-0) tests/request_processor_test.cpp (+287/-0) tests/test_data.h.in (+6/-80) |
To merge this branch: | bzr merge lp:~thomas-voss/trust-store/add_convenience_function_for_processing_incoming_requests |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Seth Arnold (community) | Approve | ||
PS Jenkins bot | continuous-integration | Needs Fixing | |
Marcus Tomlinson (community) | Approve | ||
Review via email:
|
Commit message
Provide an agent implementation that leverages Mir's trusted prompting API.
Introduce a default prompt provider using Qt/QML.
Provide a test harness around the core::trust:
Add a convenience function for processing incoming requests.
Description of the change
Provide an agent implementation that leverages Mir's trusted prompting API.
Introduce a default prompt provider using Qt/QML.
Provide a test harness around the core::trust:
Add a convenience function for processing incoming requests.
- 19. By Thomas Voß
-
Add another set of tests.
- 20. By Thomas Voß
-
Make sure that trust-prompt executable is installed with libtrust-store0.
- 21. By Thomas Voß
-
Adjust symbols file.
- 22. By Thomas Voß
-
Replace manual env-var checking.
Add missing build dependencies. - 23. By Thomas Voß
-
Add build dependencies on qt.
- 24. By Thomas Voß
-
Add build-dependency on boost program options.
- 25. By Thomas Voß
-
Replace process with parse to prevent unexpected exits.
- 26. By Thomas Voß
-
Get rid of compile-time service name deduction.
- 27. By Thomas Voß
-
Temporarily alter the acceptance test to connect to mir's untrusted socket.
- 28. By Thomas Voß
-
Add missing build dependency on libjson-c-dev.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Seth Arnold (seth-arnold) wrote : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Marcus Tomlinson (marcustomlinson) wrote : | # |
Ok, so there's a fair amount of code here, I hope I haven't missed anything major.
Here are a few observations:
35 + qt5-default,
36 + qtbase5-dev,
AFAIK qtbase5-dev is included in qt5-default
202 + * @param app_id The application Id of the requesting application.
OCD I know, but the everywhere else you've used "id" instead of "Id" (Should be "application id").
320 + * issueing a prompt request via the given agent to the user. On return, the given trust-store is up-to-date.
Should be: "issuing a prompt..."
334 + * core::trust:
335 + * {
336 + * trust.agent,
337 + * trust.store,
338 + * app_id,
339 + * default_feature,
340 + * "Application " + app_id + " wants to access the example service."
341 + * };
You're missing "app_pid" (3rd param) between "trust.store" and "app_id".
362 + * std::shared_
Should be "std::shared_
(as it is for "core::
389 + * resources. For that, we severly limit an application's access to the system and
Should be "we severely limit..."
716 + static auto child_setup = []() {};
() not needed. Could just be: "static auto child_setup = []{};"
Just a personal style thing I guess.
854 +std::shared_
The implementation of this method (although impressively nested) is really hard to read. Just saying...
990 +// Abstracts common functionality required for runninging external helpers.
"runninging" ;)
1154 +inline QString appDirectory() {
1155 + if (isRunningInsta
1156 + return QString(
Is this not supposed to return "@CMAKE_
1174 + * This file is part of dialer-app.
Really? You have 3 references to "diaper-app" in this header comment.
1255 + if (!parser.
1256 + abort(); // We have to call abort here to make sure that we get signalled.
This app (trust-prompt) just aborts if the arguments are incorrect. Could you add a -h / --help handler to display the intended usage.
Also, when I run trust-prompt, the width of the window that appears seems to be too short (the left side of the "Deny" button is cut off a bit).
1879 + auto a_spinning_process = []()
Again, could just be: "auto a_spinning_process = []"
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Seth Arnold (seth-arnold) wrote : | # |
Actually, another question, this time about open file descriptors when the helper programs are executed.
- 29. By Thomas Voß
-
Fix some minor issues.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Marcus Tomlinson (marcustomlinson) wrote : | # |
545 + static const std::string& name()
const std::string? Should we not rather use static constexpr const char*?
- 30. By Thomas Voß
-
Adjust implementation of isRunningInstalled to correctly check for LIB_DIR as opposed to BIN_DIR.
- 31. By Thomas Voß
-
Add missing return.
- 32. By Thomas Voß
-
Remove obsolete synchronous addition of prompt provider pids.
- 33. By Thomas Voß
-
Fix installation of QML file for default trust prompt.
- 34. By Thomas Voß
-
Adjust installation of prompt_main.qml.
- 35. By Thomas Voß
-
Adjust naming of prompt application helper.
- 36. By Thomas Voß
-
Make extra sure that MIR_SOCKET is set.
- 37. By Thomas Voß
-
Correctly format helper invocation.
- 38. By Thomas Voß
-
Switch to boost::
program_ options for cli processing trust-prompt. - 39. By Thomas Voß
-
Fix crash at exit.
- 40. By Thomas Voß
-
Make sure that the event loop is cleaned up correctly.
- 41. By Thomas Voß
-
Refactor main prompt.
- 42. By Thomas Voß
-
Install custom message handler.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Marcus Tomlinson (marcustomlinson) wrote : | # |
> 545 + static const std::string& name()
>
> const std::string? Should we not rather use static constexpr const char*?
Ah, I see this name() trait is somewhat of a standard amongst your projects. Sorry, ignore that one.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Marcus Tomlinson (marcustomlinson) wrote : | # |
Symbols need updating again.
- 43. By Thomas Voß
-
Address reviewer comments.
- 44. By Thomas Voß
-
Remove symbol.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Thomas Voß (thomas-voss) wrote : | # |
> Ok, so there's a fair amount of code here, I hope I haven't missed anything
> major.
> Here are a few observations:
>
> 35 + qt5-default,
> 36 + qtbase5-dev,
>
> AFAIK qtbase5-dev is included in qt5-default
>
Hmmm, seems to be the usual approach, though.
> 202 + * @param app_id The application Id of the requesting
> application.
>
> OCD I know, but the everywhere else you've used "id" instead of "Id" (Should
> be "application id").
>
Fixed.
> 320 + * issueing a prompt request via the given agent to the user. On
> return, the given trust-store is up-to-date.
>
> Should be: "issuing a prompt..."
>
Fixed.
> 334 + * core::trust:
> 335 + * {
> 336 + * trust.agent,
> 337 + * trust.store,
> 338 + * app_id,
> 339 + * default_feature,
> 340 + * "Application " + app_id + " wants to access the
> example service."
> 341 + * };
>
> You're missing "app_pid" (3rd param) between "trust.store" and "app_id".
>
Fixed.
> 362 + * std::shared_
>
> Should be "std::shared_
> (as it is for "core::
>
> 389 + * resources. For that, we severly limit an application's access to
> the system and
>
> Should be "we severely limit..."
>
Fixed.
> 716 + static auto child_setup = []() {};
>
> () not needed. Could just be: "static auto child_setup = []{};"
> Just a personal style thing I guess.
>
Yup, personal style :) I like mine better :)
> 854 +std::shared_
> mir::create_
>
> The implementation of this method (although impressively nested) is really
> hard to read. Just saying...
>
Adjusted.
> 990 +// Abstracts common functionality required for runninging external
> helpers.
>
> "runninging" ;)
>
Fixed.
> 1154 +inline QString appDirectory() {
> 1155 + if (isRunningInsta
> 1156 + return QString(
>
> Is this not supposed to return "@CMAKE_
> as is validated in isRunningInstal
>
Fixed.
> 1174 + * This file is part of dialer-app.
>
> Really? You have 3 references to "diaper-app" in this header comment.
>
Fixed, like the typo, though :)
> 1255 + if (!parser.
> 1256 + abort(); // We have to call abort here to make sure that we
> get signalled.
>
> This app (trust-prompt) just aborts if the arguments are incorrect. Could you
> add a -h / --help handler to display the intended usage.
>
Hmmm, it's actually not meant for public consumption :) So I would like to keep its chattiness to a minimum.
> Also, when I run trust-prompt, the width of the window that appears seems to
> be too short (the left side of the "Deny" button is cut off a bit).
>
Yup, known and working on phone.
> 1879 + auto a_spinning_process = []()
>
> Again, could just be: "auto a_spinning_process ...
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Thomas Voß (thomas-voss) wrote : | # |
> Actually, another question, this time about open file descriptors when the
> helper programs are executed.
Right now, helper programs are by definition trusted by the helper and usually run unconfined. However, in a future iteration, whenever we start to allow confined applications to be added to trust sessions, we will likely leverage upstart to fire up the respective application. In that case, we would share the pre-authenticated mir socket via different means and would not share any fd with the helper app.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:44
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 45. By Thomas Voß
-
Adjust symbol files to account for architecture differences.
- 46. By Thomas Voß
-
i376 really should be i386.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:45
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 47. By Thomas Voß
-
Enable more architectures.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:46
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:47
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 48. By Thomas Voß
-
Adjust architecture.
- 49. By Thomas Voß
-
[ thomas-voss ]
* Remove obsolete data/session.conf and data/system.conf files. Adjust
directory creation default mode to 0755. (LP: #1338587)
[ Ubuntu daily release ]
* New rebuild forced
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:48
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 50. By Thomas Voß
-
Remove obsolete include.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:49
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 51. By Thomas Voß
-
Re-enable test_data.h.in for capturing paths used during mir_agent_tests.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:50
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 52. By Thomas Voß
-
Add a small sleep, evil but necessary.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:51
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:52
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 53. By Thomas Voß
-
Clean up application on test end.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:53
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Marcus Tomlinson (marcustomlinson) wrote : | # |
So I think this all looks pretty good, here are just a few more observations:
565 + static std::string s{"com.
I know it doesn't really matter but the "const" is missing here.
Should be: "static const std::string s{"com.
1493 + (core::
Missing a full-stop at the end of the string (doesn't match the others).
1530 + default:
1531 + break;
Redundant "break;"
2514 +std::shared_
2052 +std::function<
2062 +std::shared_
2080 +std::shared_
The above methods don't appear in your tests.
1426 === added file 'src/core/
2786 === added file 'tests/
These 2 files are pretty much doing the same thing. I get how one is a test version of the other but is it not a maintenance nightmare waiting to happen? If the app is used for internal use only, why not just check for something like a --testargs argument when running testing.
- 54. By Thomas Voß
-
Remove test_prompt executable and fold functionality into the trust-prompt executable.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Thomas Voß (thomas-voss) wrote : | # |
> So I think this all looks pretty good, here are just a few more observations:
>
> 565 + static std::string s{"com.
>
> I know it doesn't really matter but the "const" is missing here.
> Should be: "static const std::string s{"com.
>
Fixed.
> 1493 + (core::
> boost::
>
> Missing a full-stop at the end of the string (doesn't match the others).
>
Fixed.
> 1530 + default:
> 1531 + break;
>
> Redundant "break;"
But the compiler needs it :)
>
> 2514 +std::shared_
>
Keeping it for future convenience.
> 2052 +std::function<
> core::posix:
> std::shared_
>
Removed.
> 2062 +std::shared_
> a_prompt_
>
Removed.
> 2080 +std::shared_
> a_prompt_
>
Removed.
> The above methods don't appear in your tests.
>
> 1426 === added file 'src/core/
> 2786 === added file 'tests/
>
> These 2 files are pretty much doing the same thing. I get how one is a test
> version of the other but is it not a maintenance nightmare waiting to happen?
> If the app is used for internal use only, why not just check for something
> like a --testargs argument when running testing.
Fixed.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Marcus Tomlinson (marcustomlinson) wrote : | # |
> > 1530 + default:
> > 1531 + break;
> >
> > Redundant "break;"
>
> But the compiler needs it :)
Oh, haha, why did I think it wasn't needed? Or, I mean, I was just testing you ;)
Anyways, LGTM!
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:54
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Seth Arnold (seth-arnold) wrote : | # |
Thanks for the responses. Looks good to me.
- 55. By Thomas Voß
-
Add missing build dependency on libmirclient-dev.
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2013-12-20 10:38:58 +0000 |
3 | +++ CMakeLists.txt 2014-07-17 18:44:56 +0000 |
4 | @@ -28,8 +28,10 @@ |
5 | ENDIF(CMAKE_BUILD_TYPE MATCHES [cC][oO][vV][eE][rR][aA][gG][eE]) |
6 | |
7 | find_package(PkgConfig) |
8 | -find_package(Boost COMPONENTS system REQUIRED) |
9 | +find_package(Boost COMPONENTS program_options system REQUIRED) |
10 | |
11 | +pkg_check_modules(MIR_CLIENT mirclient REQUIRED) |
12 | +pkg_check_modules(MIR_COMMON mircommon REQUIRED) |
13 | pkg_check_modules(PROCESS_CPP process-cpp REQUIRED) |
14 | |
15 | set(TRUST_STORE_VERSION_MAJOR 0) |
16 | @@ -40,6 +42,10 @@ |
17 | |
18 | include_directories( |
19 | include/ |
20 | + |
21 | + ${MIR_CLIENT_INCLUDE_DIRS} |
22 | + ${MIR_COMMON_INCLUDE_DIRS} |
23 | + ${PROCESS_CPP_INCLUDE_DIRS} |
24 | ) |
25 | |
26 | add_subdirectory(doc) |
27 | |
28 | === modified file 'debian/control' |
29 | --- debian/control 2014-06-24 13:30:26 +0000 |
30 | +++ debian/control 2014-07-17 18:44:56 +0000 |
31 | @@ -7,13 +7,20 @@ |
32 | google-mock, |
33 | gcovr, |
34 | graphviz, |
35 | + libboost-program-options-dev, |
36 | libboost-system-dev, |
37 | libdbus-cpp-dev, |
38 | libdbus-1-dev, |
39 | libgtest-dev, |
40 | + libjson-c-dev, |
41 | + libmirclient-dev, |
42 | libprocess-cpp-dev, |
43 | libsqlite3-dev, |
44 | pkg-config, |
45 | + qt5-default, |
46 | + qtbase5-dev, |
47 | + qtdeclarative5-dev, |
48 | + qtquick1-5-dev, |
49 | Standards-Version: 3.9.5 |
50 | Section: libs |
51 | Homepage: https://launchpad.net/trust-store |
52 | @@ -49,6 +56,18 @@ |
53 | This package includes all the development headers and libraries for |
54 | trust-store. |
55 | |
56 | +Package: trust-store-tests |
57 | +Section: libdevel |
58 | +Architecture: any |
59 | +Depends: libtrust-store0 (= ${binary:Version}), |
60 | + ${misc:Depends}, |
61 | +Suggests: libtrust-store-dev, |
62 | +Description: Test files for libtrust-store0 |
63 | + Provides a common implementation of a trust store to be used by trusted |
64 | + helpers. |
65 | + . |
66 | + This package includes test executables packaged for post-build execution. |
67 | + |
68 | Package: libtrust-store-doc |
69 | Section: doc |
70 | Architecture: all |
71 | |
72 | === modified file 'debian/libtrust-store0.install' |
73 | --- debian/libtrust-store0.install 2013-12-18 11:58:52 +0000 |
74 | +++ debian/libtrust-store0.install 2014-07-17 18:44:56 +0000 |
75 | @@ -1,1 +1,3 @@ |
76 | usr/lib/*/lib*.so.* |
77 | +usr/lib/*/trust-prompt |
78 | +usr/share/core/trust/mir/* |
79 | |
80 | === modified file 'debian/libtrust-store0.symbols' |
81 | --- debian/libtrust-store0.symbols 2014-06-26 08:11:42 +0000 |
82 | +++ debian/libtrust-store0.symbols 2014-07-17 18:44:56 +0000 |
83 | @@ -1,29 +1,62 @@ |
84 | libtrust-store.so.0 libtrust-store0 #MINVER# |
85 | (c++)"core::trust::create_default_store(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.0.1+14.10.20140626.1 |
86 | + (c++)"core::trust::process_trust_request(core::trust::RequestParameters const&)@Base" 0replaceme |
87 | (c++)"core::trust::expose_store_to_bus_with_name(std::shared_ptr<core::trust::Store> const&, std::shared_ptr<core::dbus::Bus> const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.0.1+14.10.20140626.1 |
88 | (c++)"core::trust::resolve_store_on_bus_with_name(std::shared_ptr<core::dbus::Bus> const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.0.1+14.10.20140626.1 |
89 | (c++)"core::trust::expose_store_to_session_with_name(std::shared_ptr<core::trust::Store> const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.0.1+14.10.20140626.1 |
90 | (c++)"core::trust::resolve_store_in_session_with_name(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.0.1+14.10.20140626.1 |
91 | - (c++)"core::trust::Store::Query::Error::NoCurrentResult::~NoCurrentResult()@Base" 0.0.1+14.10.20140626.1 |
92 | - (c++)"core::trust::Store::Query::Error::QueryIsInErrorState::~QueryIsInErrorState()@Base" 0.0.1+14.10.20140626.1 |
93 | + (c++)"core::trust::mir::PromptProviderHelper::InvocationArguments::~InvocationArguments()@Base" 0replaceme |
94 | + (c++)"core::trust::mir::PromptProviderHelper::exec_prompt_provider_with_arguments(core::trust::mir::PromptProviderHelper::InvocationArguments const&)@Base" 0replaceme |
95 | + (c++)"core::trust::mir::PromptProviderHelper::PromptProviderHelper(core::trust::mir::PromptProviderHelper::CreationArguments const&)@Base" 0replaceme |
96 | + (c++)"core::trust::mir::ConnectionVirtualTable::create_prompt_session_sync(int, void (*)(MirPromptSession*, MirPromptSessionState, void*), void*)@Base" 0replaceme |
97 | + (c++)"core::trust::mir::ConnectionVirtualTable::ConnectionVirtualTable(MirConnection*)@Base" 0replaceme |
98 | + (c++)"core::trust::mir::PromptSessionVirtualTable::release_sync()@Base" 0replaceme |
99 | + (c++|arch=amd64 armhf64 ppc64el)"core::trust::mir::PromptSessionVirtualTable::mir_client_fd_callback(MirPromptSession*, unsigned long, int const*, void*)@Base" 0replaceme |
100 | + (c++|arch=armhf i386 powerpc)"core::trust::mir::PromptSessionVirtualTable::mir_client_fd_callback(MirPromptSession*, unsigned int, int const*, void*)@Base" 0replaceme |
101 | + (c++)"core::trust::mir::PromptSessionVirtualTable::new_fd_for_prompt_provider()@Base" 0replaceme |
102 | + (c++)"core::trust::mir::PromptSessionVirtualTable::PromptSessionVirtualTable(MirPromptSession*)@Base" 0replaceme |
103 | + (c++)"core::trust::mir::create_agent_for_mir_connection(MirConnection*)@Base" 0replaceme |
104 | + (c++)"core::trust::mir::Agent::prompt_user_for_request(int, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0replaceme |
105 | + (c++)"core::trust::mir::Agent::on_trust_session_changed_state(MirPromptSession*, MirPromptSessionState, void*)@Base" 0replaceme |
106 | + (c++)"core::trust::mir::Agent::translator_only_accepting_exit_status_success()@Base" 0replaceme |
107 | + (c++)"core::trust::mir::Agent::Agent(std::shared_ptr<core::trust::mir::ConnectionVirtualTable> const&, std::shared_ptr<core::trust::mir::PromptProviderHelper> const&, std::function<core::trust::Request::Answer (core::posix::wait::Result const&)> const&)@Base" 0replaceme |
108 | + (c++)"core::trust::mir::Agent::~Agent()@Base" 0replaceme |
109 | + (c++)"core::trust::mir::operator==(core::trust::mir::PromptProviderHelper::InvocationArguments const&, core::trust::mir::PromptProviderHelper::InvocationArguments const&)@Base" 0replaceme |
110 | + (c++)"core::trust::Store::Query::Errors::NoCurrentResult::~NoCurrentResult()@Base" 0replaceme |
111 | + (c++)"core::trust::Store::Query::Errors::QueryIsInErrorState::~QueryIsInErrorState()@Base" 0replaceme |
112 | (c++)"core::trust::Store::Errors::ErrorResettingStore::~ErrorResettingStore()@Base" 0.0.1+14.10.20140626.1 |
113 | (c++)"core::trust::operator==(core::trust::Request const&, core::trust::Request const&)@Base" 0.0.1+14.10.20140626.1 |
114 | (c++)"core::trust::operator<<(std::basic_ostream<char, std::char_traits<char> >&, core::trust::Request::Answer const&)@Base" 0.0.1+14.10.20140626.1 |
115 | (c++)"core::trust::operator<<(std::basic_ostream<char, std::char_traits<char> >&, core::trust::Request const&)@Base" 0.0.1+14.10.20140626.1 |
116 | - (c++)"typeinfo for core::trust::Store::Query::Error::NoCurrentResult@Base" 0.0.1+14.10.20140626.1 |
117 | - (c++)"typeinfo for core::trust::Store::Query::Error::QueryIsInErrorState@Base" 0.0.1+14.10.20140626.1 |
118 | + (c++)"typeinfo for core::trust::mir::PromptProviderHelper@Base" 0replaceme |
119 | + (c++)"typeinfo for core::trust::mir::ConnectionVirtualTable@Base" 0replaceme |
120 | + (c++)"typeinfo for core::trust::mir::PromptSessionVirtualTable@Base" 0replaceme |
121 | + (c++)"typeinfo for core::trust::mir::Agent@Base" 0replaceme |
122 | + (c++)"typeinfo for core::trust::Agent@Base" 0replaceme |
123 | + (c++)"typeinfo for core::trust::Store::Query::Errors::NoCurrentResult@Base" 0replaceme |
124 | + (c++)"typeinfo for core::trust::Store::Query::Errors::QueryIsInErrorState@Base" 0replaceme |
125 | (c++)"typeinfo for core::trust::Store::Query@Base" 0.0.1+14.10.20140626.1 |
126 | (c++)"typeinfo for core::trust::Store::Errors::ErrorResettingStore@Base" 0.0.1+14.10.20140626.1 |
127 | (c++)"typeinfo for core::trust::Store@Base" 0.0.1+14.10.20140626.1 |
128 | (c++)"typeinfo for core::trust::Token@Base" 0.0.1+14.10.20140626.1 |
129 | - (c++)"typeinfo name for core::trust::Store::Query::Error::NoCurrentResult@Base" 0.0.1+14.10.20140626.1 |
130 | - (c++)"typeinfo name for core::trust::Store::Query::Error::QueryIsInErrorState@Base" 0.0.1+14.10.20140626.1 |
131 | + (c++)"typeinfo name for core::trust::mir::PromptProviderHelper@Base" 0replaceme |
132 | + (c++)"typeinfo name for core::trust::mir::ConnectionVirtualTable@Base" 0replaceme |
133 | + (c++)"typeinfo name for core::trust::mir::PromptSessionVirtualTable@Base" 0replaceme |
134 | + (c++)"typeinfo name for core::trust::mir::Agent@Base" 0replaceme |
135 | + (c++)"typeinfo name for core::trust::Agent@Base" 0replaceme |
136 | + (c++)"typeinfo name for core::trust::Store::Query::Errors::NoCurrentResult@Base" 0replaceme |
137 | + (c++)"typeinfo name for core::trust::Store::Query::Errors::QueryIsInErrorState@Base" 0replaceme |
138 | (c++)"typeinfo name for core::trust::Store::Query@Base" 0.0.1+14.10.20140626.1 |
139 | (c++)"typeinfo name for core::trust::Store::Errors::ErrorResettingStore@Base" 0.0.1+14.10.20140626.1 |
140 | (c++)"typeinfo name for core::trust::Store@Base" 0.0.1+14.10.20140626.1 |
141 | (c++)"typeinfo name for core::trust::Token@Base" 0.0.1+14.10.20140626.1 |
142 | - (c++)"vtable for core::trust::Store::Query::Error::NoCurrentResult@Base" 0.0.1+14.10.20140626.1 |
143 | - (c++)"vtable for core::trust::Store::Query::Error::QueryIsInErrorState@Base" 0.0.1+14.10.20140626.1 |
144 | + (c++)"vtable for core::trust::mir::PromptProviderHelper@Base" 0replaceme |
145 | + (c++)"vtable for core::trust::mir::ConnectionVirtualTable@Base" 0replaceme |
146 | + (c++)"vtable for core::trust::mir::PromptSessionVirtualTable@Base" 0replaceme |
147 | + (c++)"vtable for core::trust::mir::Agent@Base" 0replaceme |
148 | + (c++)"vtable for core::trust::Agent@Base" 0replaceme |
149 | + (c++)"vtable for core::trust::Store::Query::Errors::NoCurrentResult@Base" 0replaceme |
150 | + (c++)"vtable for core::trust::Store::Query::Errors::QueryIsInErrorState@Base" 0replaceme |
151 | (c++)"vtable for core::trust::Store::Query@Base" 0.0.1+14.10.20140626.1 |
152 | (c++)"vtable for core::trust::Store::Errors::ErrorResettingStore@Base" 0.0.1+14.10.20140626.1 |
153 | (c++)"vtable for core::trust::Store@Base" 0.0.1+14.10.20140626.1 |
154 | |
155 | === added file 'debian/trust-store-tests.install' |
156 | --- debian/trust-store-tests.install 1970-01-01 00:00:00 +0000 |
157 | +++ debian/trust-store-tests.install 2014-07-17 18:44:56 +0000 |
158 | @@ -0,0 +1,1 @@ |
159 | +usr/bin/trust-store-tests/* |
160 | |
161 | === added file 'include/core/trust/agent.h' |
162 | --- include/core/trust/agent.h 1970-01-01 00:00:00 +0000 |
163 | +++ include/core/trust/agent.h 2014-07-17 18:44:56 +0000 |
164 | @@ -0,0 +1,57 @@ |
165 | +/* |
166 | + * Copyright © 2014 Canonical Ltd. |
167 | + * |
168 | + * This program is free software: you can redistribute it and/or modify it |
169 | + * under the terms of the GNU Lesser General Public License version 3, |
170 | + * as published by the Free Software Foundation. |
171 | + * |
172 | + * This program is distributed in the hope that it will be useful, |
173 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
174 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
175 | + * GNU Lesser General Public License for more details. |
176 | + * |
177 | + * You should have received a copy of the GNU Lesser General Public License |
178 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
179 | + * |
180 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
181 | + */ |
182 | + |
183 | +#ifndef CORE_TRUST_AGENT_H_ |
184 | +#define CORE_TRUST_AGENT_H_ |
185 | + |
186 | +#include <core/trust/request.h> |
187 | +#include <core/trust/visibility.h> |
188 | + |
189 | +namespace core |
190 | +{ |
191 | +namespace trust |
192 | +{ |
193 | +// Forward-declarations. |
194 | +struct RequestParameters; |
195 | + |
196 | +/** @brief Abstracts user-prompting functionality. */ |
197 | +class CORE_TRUST_DLL_PUBLIC Agent |
198 | +{ |
199 | +public: |
200 | + /** @cond */ |
201 | + Agent() = default; |
202 | + virtual ~Agent() = default; |
203 | + |
204 | + Agent(const Agent&) = delete; |
205 | + Agent(Agent&&) = delete; |
206 | + Agent& operator=(const Agent&) = delete; |
207 | + Agent& operator=(Agent&&) = delete; |
208 | + /** @endcond */ |
209 | + |
210 | + /** |
211 | + * @brief Presents the given request to the user, returning the user-provided answer. |
212 | + * @param app_pid The process id of the requesting application. |
213 | + * @param app_id The application id of the requesting application. |
214 | + * @param description Extended description of the trust request. |
215 | + */ |
216 | + virtual Request::Answer prompt_user_for_request(pid_t app_pid, const std::string& app_id, const std::string& description) = 0; |
217 | +}; |
218 | +} |
219 | +} |
220 | + |
221 | +#endif // CORE_TRUST_AGENT_H_ |
222 | |
223 | === added file 'include/core/trust/mir_agent.h' |
224 | --- include/core/trust/mir_agent.h 1970-01-01 00:00:00 +0000 |
225 | +++ include/core/trust/mir_agent.h 2014-07-17 18:44:56 +0000 |
226 | @@ -0,0 +1,48 @@ |
227 | +/* |
228 | + * Copyright © 2014 Canonical Ltd. |
229 | + * |
230 | + * This program is free software: you can redistribute it and/or modify it |
231 | + * under the terms of the GNU Lesser General Public License version 3, |
232 | + * as published by the Free Software Foundation. |
233 | + * |
234 | + * This program is distributed in the hope that it will be useful, |
235 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
236 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
237 | + * GNU Lesser General Public License for more details. |
238 | + * |
239 | + * You should have received a copy of the GNU Lesser General Public License |
240 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
241 | + * |
242 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
243 | + */ |
244 | + |
245 | +#ifndef CORE_TRUST_MIR_AGENT_H_ |
246 | +#define CORE_TRUST_MIR_AGENT_H_ |
247 | + |
248 | +#include <core/trust/visibility.h> |
249 | + |
250 | +#include <memory> |
251 | + |
252 | +// Forward declare the MirConnection type. |
253 | +struct MirConnection; |
254 | + |
255 | +namespace core |
256 | +{ |
257 | +namespace trust |
258 | +{ |
259 | +// Forward declare the Agent interface. |
260 | +class Agent; |
261 | + |
262 | +namespace mir |
263 | +{ |
264 | +/** |
265 | + * @brief create_agent_for_mir_connection creates a trust::Agent implementation leveraging Mir's trusted prompting API. |
266 | + * @param connection An existing connection to a Mir instance. |
267 | + * @throws std::logic_error if the connection object is NULL. |
268 | + */ |
269 | +CORE_TRUST_DLL_PUBLIC std::shared_ptr<core::trust::Agent> create_agent_for_mir_connection(MirConnection* connection); |
270 | +} |
271 | +} |
272 | +} |
273 | + |
274 | +#endif // CORE_TRUST_MIR_AGENT_H_ |
275 | |
276 | === modified file 'include/core/trust/request.h' |
277 | --- include/core/trust/request.h 2014-05-06 11:32:13 +0000 |
278 | +++ include/core/trust/request.h 2014-07-17 18:44:56 +0000 |
279 | @@ -24,6 +24,7 @@ |
280 | #include <cstdint> |
281 | |
282 | #include <chrono> |
283 | +#include <memory> |
284 | #include <ostream> |
285 | #include <string> |
286 | |
287 | @@ -31,6 +32,10 @@ |
288 | { |
289 | namespace trust |
290 | { |
291 | +// Forward declarations |
292 | +class Agent; |
293 | +class Store; |
294 | + |
295 | /** |
296 | * @brief The Request struct encapsulates information about a trust request answered by the user. |
297 | * |
298 | @@ -59,7 +64,7 @@ |
299 | enum class Answer |
300 | { |
301 | denied, ///< Nope, I do not trust this application. |
302 | - granted ///< Yup, I do trust this application. |
303 | + granted, ///< Yup, I do trust this application. |
304 | }; |
305 | |
306 | /** The application id of the application that resulted in the request. */ |
307 | @@ -94,6 +99,78 @@ |
308 | * @return The output stream. |
309 | */ |
310 | CORE_TRUST_DLL_PUBLIC std::ostream& operator<<(std::ostream& out, const Request& r); |
311 | + |
312 | +/** @brief Summarizes all parameters for processing a trust request. */ |
313 | +struct CORE_TRUST_DLL_PUBLIC RequestParameters |
314 | +{ |
315 | + /** @brief The Agent implementation to dispatch a request to the user. */ |
316 | + std::shared_ptr<Agent> agent; |
317 | + /** @brief The trust store to be used for caching purposes. */ |
318 | + std::shared_ptr<Store> store; |
319 | + /** @brief The process id of the requesting application. */ |
320 | + pid_t application_pid; |
321 | + /** @brief The id of the requesting application. */ |
322 | + std::string application_id; |
323 | + /** @brief The service-specific feature identifier. */ |
324 | + std::uint64_t feature; |
325 | + /** @brief An extended description that should be presented to the user on prompting. */ |
326 | + std::string description; |
327 | +}; |
328 | + |
329 | +/** |
330 | + * @brief Processes an incoming trust-request by an application, tries to lookup a previous reply before |
331 | + * issuing a prompt request via the given agent to the user. On return, the given trust-store is up-to-date. |
332 | + * |
333 | + * @throws std::exception To indicate that no conclusive answer could be resolved from either the store or |
334 | + * the user. In that case, the state of the store instance passed in to the function is not altered. |
335 | + * |
336 | + * The following code snippet illustrates how to use the function: |
337 | + * |
338 | + * @code |
339 | + * struct Service |
340 | + * { |
341 | + * static constexpr std::uint64_t default_feature = 0; |
342 | + * |
343 | + * void on_session_requested(pid_t app_pid, const std::string& app_id) |
344 | + * { |
345 | + * core::trust::RequestParameters params |
346 | + * { |
347 | + * trust.agent, |
348 | + * trust.store, |
349 | + * app_pid, |
350 | + * app_id, |
351 | + * default_feature, |
352 | + * "Application " + app_id + " wants to access the example service." |
353 | + * }; |
354 | + * |
355 | + * switch(process_trust_request(params)) |
356 | + * { |
357 | + * case core::trust::Request::Answer::granted: |
358 | + * // Create session and get back to application with session credentials. |
359 | + * break; |
360 | + * case core::trust::Request::Answer::denied: |
361 | + * // Deny session creation and inform application. |
362 | + * break; |
363 | + * } |
364 | + * } |
365 | + * |
366 | + * struct |
367 | + * { |
368 | + * // We use Mir's trust session support to request the prompting UI. |
369 | + * std::shared_ptr<core::trust::Agent> agent |
370 | + * { |
371 | + * core::trust::mir::make_agent_for_existing_connection(mir_connection) |
372 | + * }; |
373 | + * |
374 | + * std::shared_ptr<core::trust::Store> store |
375 | + * { |
376 | + * core::trust::create_default_store("my.example.service"); |
377 | + * }; |
378 | + * } trust; |
379 | + * }; |
380 | + * @endcode |
381 | + */ |
382 | +CORE_TRUST_DLL_PUBLIC Request::Answer process_trust_request(const RequestParameters& params); |
383 | } |
384 | } |
385 | |
386 | |
387 | === modified file 'include/core/trust/store.h' |
388 | --- include/core/trust/store.h 2014-05-06 11:32:13 +0000 |
389 | +++ include/core/trust/store.h 2014-07-17 18:44:56 +0000 |
390 | @@ -28,6 +28,18 @@ |
391 | |
392 | namespace core |
393 | { |
394 | +/** |
395 | + * @brief Contains functionality for implementing Ubuntu's trust model. |
396 | + * |
397 | + * Ubuntu's trust model extends upon a strict confinement approach implemented |
398 | + * on top of AppArmor. In this approach, applications are not trusted by default, and |
399 | + * we assume a very negative view of the app world. That is, we assume that all apps |
400 | + * are created with malicious intentions in mind, invading a user's privacy and wasting |
401 | + * resources. For that, we severely limit an application's access to the system and |
402 | + * provide trusted gates out of the confinement. These trusted gates, also called trusted helpers, |
403 | + * ensure that the user is prompted for granting or denying trust to a specific application. |
404 | + * |
405 | + */ |
406 | namespace trust |
407 | { |
408 | /** |
409 | @@ -36,9 +48,12 @@ |
410 | class CORE_TRUST_DLL_PUBLIC Store |
411 | { |
412 | public: |
413 | + /** @brief All Store-specific error/exception types go here. */ |
414 | struct Errors |
415 | { |
416 | + /** @cond */ |
417 | Errors() = delete; |
418 | + /** @endcond */ |
419 | |
420 | /** |
421 | * @brief Thrown if a store implementation could not access the persistence backend. |
422 | @@ -70,9 +85,12 @@ |
423 | class Query |
424 | { |
425 | public: |
426 | - struct Error |
427 | + /** @brief All Query-specific error/exception types go here. */ |
428 | + struct Errors |
429 | { |
430 | - Error() = delete; |
431 | + /** @cond */ |
432 | + Errors() = delete; |
433 | + /** @endcond */ |
434 | /** |
435 | * @brief Thrown if functionality of a query is accessed although the query is in error state. |
436 | */ |
437 | @@ -165,9 +183,12 @@ |
438 | Store() = default; |
439 | }; |
440 | |
441 | -struct Error |
442 | +/** @brief All core::trust-specific error/exception types go here. */ |
443 | +struct Errors |
444 | { |
445 | - Error() = delete; |
446 | + /** @cond */ |
447 | + Errors() = delete; |
448 | + /** @endcond */ |
449 | |
450 | /** |
451 | * @brief The ServiceNameMustNotBeEmpty is thrown if an empty service name |
452 | |
453 | === modified file 'src/CMakeLists.txt' |
454 | --- src/CMakeLists.txt 2014-05-06 11:52:46 +0000 |
455 | +++ src/CMakeLists.txt 2014-07-17 18:44:56 +0000 |
456 | @@ -14,6 +14,10 @@ |
457 | # |
458 | # Authored by: Thomas Voss <thomas.voss@canonical.com> |
459 | |
460 | +find_package(Qt5Core REQUIRED) |
461 | +find_package(Qt5Qml REQUIRED) |
462 | +find_package(Qt5Quick REQUIRED) |
463 | + |
464 | pkg_check_modules(DBUS_CPP dbus-cpp REQUIRED) |
465 | pkg_check_modules(DBUS dbus-1 REQUIRED) |
466 | pkg_check_modules(SQLITE3 sqlite3 REQUIRED) |
467 | @@ -24,14 +28,51 @@ |
468 | ${SQLITE3_INCLUDE_DIRS} |
469 | ) |
470 | |
471 | +# Make sure Qt does not inject evil macros like 'signals' and 'slots'. |
472 | +add_definitions(-DQT_NO_KEYWORDS) |
473 | +# We need this for building the Qt-based prompt UI |
474 | +set(CMAKE_AUTOMOC ON) |
475 | +set(CMAKE_INCLUDE_CURRENT_DIR ON) |
476 | + |
477 | add_library( |
478 | trust-store SHARED |
479 | |
480 | core/trust/expose.cpp |
481 | core/trust/request.cpp |
482 | core/trust/resolve.cpp |
483 | + |
484 | + # The default implementation leverages SQLite3 to persist |
485 | + # requests. |
486 | core/trust/impl/sqlite3/store.cpp |
487 | -) |
488 | + |
489 | + # An agent-implementation leveraging Mir's trusted prompting support |
490 | + # to prompt the user for trusting an application to access a trusted |
491 | + # system service. |
492 | + core/trust/mir/agent.cpp |
493 | +) |
494 | + |
495 | +configure_file( |
496 | + ${CMAKE_CURRENT_SOURCE_DIR}/core/trust/mir/config.h.in |
497 | + ${CMAKE_CURRENT_BINARY_DIR}/core/trust/mir/config.h @ONLY) |
498 | + |
499 | +configure_file( |
500 | + ${CMAKE_CURRENT_SOURCE_DIR}/core/trust/mir/prompt_config.h.in |
501 | + ${CMAKE_CURRENT_BINARY_DIR}/core/trust/mir/prompt_config.h @ONLY) |
502 | + |
503 | +include_directories(${CMAKE_CURRENT_BINARY_DIR}/core/trust/mir/) |
504 | + |
505 | +add_executable( |
506 | + trust-prompt |
507 | + |
508 | + core/trust/mir/prompt_main.cpp |
509 | +) |
510 | + |
511 | +set_target_properties( |
512 | + trust-prompt |
513 | + PROPERTIES INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR}/core/trust/mir |
514 | +) |
515 | + |
516 | +qt5_use_modules(trust-prompt Core Gui Qml Quick) |
517 | |
518 | target_link_libraries( |
519 | trust-store |
520 | @@ -40,9 +81,19 @@ |
521 | |
522 | ${Boost_LIBRARIES} |
523 | ${DBUS_LIBRARIES} |
524 | + ${MIR_CLIENT_LDFLAGS} |
525 | + ${MIR_COMMON_LDFLAGS} |
526 | + ${PROCESS_CPP_LDFLAGS} |
527 | ${SQLITE3_LIBRARIES} |
528 | ) |
529 | |
530 | +target_link_libraries( |
531 | + trust-prompt |
532 | + |
533 | + ${Boost_LIBRARIES} |
534 | + ${PROCESS_CPP_LDFLAGS} |
535 | +) |
536 | + |
537 | # We compile with all symbols visible by default. For the shipping library, we strip |
538 | # out all symbols that are not in core::dbus::* |
539 | set(symbol_map "${CMAKE_SOURCE_DIR}/symbols.map") |
540 | @@ -63,3 +114,13 @@ |
541 | TARGETS trust-store |
542 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} |
543 | ) |
544 | + |
545 | +install( |
546 | + TARGETS trust-prompt |
547 | + RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR} |
548 | +) |
549 | + |
550 | +install( |
551 | + FILES core/trust/mir/prompt_main.qml |
552 | + DESTINATION ${CMAKE_INSTALL_DATADIR}/core/trust/mir |
553 | +) |
554 | |
555 | === modified file 'src/core/trust/dbus_interface.h' |
556 | --- src/core/trust/dbus_interface.h 2013-12-21 08:05:08 +0000 |
557 | +++ src/core/trust/dbus_interface.h 2014-07-17 18:44:56 +0000 |
558 | @@ -63,17 +63,12 @@ |
559 | { |
560 | struct Store |
561 | { |
562 | - static std::string& mutable_name() |
563 | + static const std::string& name() |
564 | { |
565 | - static std::string s; |
566 | + static const std::string s{"com.ubuntu.trust.store"}; |
567 | return s; |
568 | } |
569 | |
570 | - static const std::string& name() |
571 | - { |
572 | - return mutable_name(); |
573 | - } |
574 | - |
575 | struct Error |
576 | { |
577 | struct AddingRequest |
578 | |
579 | === modified file 'src/core/trust/expose.cpp' |
580 | --- src/core/trust/expose.cpp 2014-05-06 11:32:13 +0000 |
581 | +++ src/core/trust/expose.cpp 2014-07-17 18:44:56 +0000 |
582 | @@ -69,13 +69,15 @@ |
583 | std::map<Key, Value> map; |
584 | }; |
585 | |
586 | -struct Token : public core::trust::Token, public dbus::Skeleton<core::trust::dbus::Store> |
587 | +struct Token : public core::trust::Token |
588 | { |
589 | - Token(const std::shared_ptr<dbus::Bus>& bus, |
590 | + Token(const std::string& service_name, |
591 | + const std::shared_ptr<dbus::Bus>& bus, |
592 | const std::shared_ptr<core::trust::Store>& store) |
593 | - : dbus::Skeleton<core::trust::dbus::Store>(bus), |
594 | - store(store), |
595 | - object(access_service()->add_object_for_path(dbus::types::ObjectPath::root())) |
596 | + : store(store), |
597 | + bus(bus), |
598 | + service(dbus::Service::add_service(bus, service_name)), |
599 | + object(service->add_object_for_path(dbus::types::ObjectPath::root())) |
600 | { |
601 | object->install_method_handler<core::trust::dbus::Store::Add>([this](const core::dbus::Message::Ptr& msg) |
602 | { |
603 | @@ -97,15 +99,18 @@ |
604 | handle_remove_query(msg); |
605 | }); |
606 | |
607 | - worker = std::move(std::thread([this](){access_bus()->run();})); |
608 | + worker = std::move(std::thread([this](){Token::bus->run();})); |
609 | } |
610 | |
611 | ~Token() |
612 | { |
613 | object->uninstall_method_handler<core::trust::dbus::Store::Add>(); |
614 | object->uninstall_method_handler<core::trust::dbus::Store::Reset>(); |
615 | - |
616 | - access_bus()->stop(); |
617 | + object->uninstall_method_handler<core::trust::dbus::Store::AddQuery>(); |
618 | + object->uninstall_method_handler<core::trust::dbus::Store::RemoveQuery>(); |
619 | + |
620 | + bus->stop(); |
621 | + |
622 | if (worker.joinable()) |
623 | worker.join(); |
624 | } |
625 | @@ -125,12 +130,12 @@ |
626 | core::trust::dbus::Store::Error::AddingRequest::name(), |
627 | e.what()); |
628 | |
629 | - access_bus()->send(error); |
630 | + bus->send(error); |
631 | return; |
632 | } |
633 | |
634 | auto reply = dbus::Message::make_method_return(msg); |
635 | - access_bus()->send(reply); |
636 | + bus->send(reply); |
637 | } |
638 | |
639 | void handle_reset(const core::dbus::Message::Ptr& msg) |
640 | @@ -145,11 +150,11 @@ |
641 | core::trust::dbus::Store::Error::ResettingStore::name(), |
642 | e.what()); |
643 | |
644 | - access_bus()->send(error); |
645 | + bus->send(error); |
646 | } |
647 | |
648 | auto reply = dbus::Message::make_method_return(msg); |
649 | - access_bus()->send(reply); |
650 | + bus->send(reply); |
651 | } |
652 | |
653 | void handle_add_query(const core::dbus::Message::Ptr& msg) |
654 | @@ -160,16 +165,16 @@ |
655 | { |
656 | core::dbus::types::ObjectPath path{"/queries/" + std::to_string(query_counter++)}; |
657 | auto query = store->query(); |
658 | - auto object = access_service()->add_object_for_path(path); |
659 | - auto bus = access_bus(); |
660 | - object->install_method_handler<core::trust::dbus::Store::Query::All>([bus, query](const core::dbus::Message::Ptr& msg) |
661 | + auto object = service->add_object_for_path(path); |
662 | + |
663 | + object->install_method_handler<core::trust::dbus::Store::Query::All>([this, query](const core::dbus::Message::Ptr& msg) |
664 | { |
665 | query->all(); |
666 | |
667 | auto reply = core::dbus::Message::make_method_return(msg); |
668 | bus->send(reply); |
669 | }); |
670 | - object->install_method_handler<core::trust::dbus::Store::Query::Current>([bus, query](const core::dbus::Message::Ptr& msg) |
671 | + object->install_method_handler<core::trust::dbus::Store::Query::Current>([this, query](const core::dbus::Message::Ptr& msg) |
672 | { |
673 | try |
674 | { |
675 | @@ -177,7 +182,7 @@ |
676 | auto reply = core::dbus::Message::make_method_return(msg); |
677 | reply->writer() << request; |
678 | bus->send(reply); |
679 | - } catch(const core::trust::Store::Query::Error::NoCurrentResult& e) |
680 | + } catch(const core::trust::Store::Query::Errors::NoCurrentResult& e) |
681 | { |
682 | auto error = core::dbus::Message::make_error( |
683 | msg, |
684 | @@ -187,21 +192,21 @@ |
685 | bus->send(error); |
686 | } |
687 | }); |
688 | - object->install_method_handler<core::trust::dbus::Store::Query::Erase>([bus, query](const core::dbus::Message::Ptr& msg) |
689 | + object->install_method_handler<core::trust::dbus::Store::Query::Erase>([this, query](const core::dbus::Message::Ptr& msg) |
690 | { |
691 | query->erase(); |
692 | |
693 | auto reply = core::dbus::Message::make_method_return(msg); |
694 | bus->send(reply); |
695 | }); |
696 | - object->install_method_handler<core::trust::dbus::Store::Query::Execute>([bus, query](const core::dbus::Message::Ptr& msg) |
697 | + object->install_method_handler<core::trust::dbus::Store::Query::Execute>([this, query](const core::dbus::Message::Ptr& msg) |
698 | { |
699 | query->execute(); |
700 | |
701 | auto reply = core::dbus::Message::make_method_return(msg); |
702 | bus->send(reply); |
703 | }); |
704 | - object->install_method_handler<core::trust::dbus::Store::Query::ForAnswer>([bus, query](const core::dbus::Message::Ptr& msg) |
705 | + object->install_method_handler<core::trust::dbus::Store::Query::ForAnswer>([this, query](const core::dbus::Message::Ptr& msg) |
706 | { |
707 | core::trust::Request::Answer a; msg->reader() >> a; |
708 | query->for_answer(a); |
709 | @@ -209,7 +214,7 @@ |
710 | auto reply = core::dbus::Message::make_method_return(msg); |
711 | bus->send(reply); |
712 | }); |
713 | - object->install_method_handler<core::trust::dbus::Store::Query::ForApplicationId>([bus, query](const core::dbus::Message::Ptr& msg) |
714 | + object->install_method_handler<core::trust::dbus::Store::Query::ForApplicationId>([this, query](const core::dbus::Message::Ptr& msg) |
715 | { |
716 | std::string app_id; msg->reader() >> app_id; |
717 | query->for_application_id(app_id); |
718 | @@ -217,7 +222,7 @@ |
719 | auto reply = core::dbus::Message::make_method_return(msg); |
720 | bus->send(reply); |
721 | }); |
722 | - object->install_method_handler<core::trust::dbus::Store::Query::ForFeature>([bus, query](const core::dbus::Message::Ptr& msg) |
723 | + object->install_method_handler<core::trust::dbus::Store::Query::ForFeature>([this, query](const core::dbus::Message::Ptr& msg) |
724 | { |
725 | std::uint64_t feature; msg->reader() >> feature; |
726 | query->for_feature(feature); |
727 | @@ -225,7 +230,7 @@ |
728 | auto reply = core::dbus::Message::make_method_return(msg); |
729 | bus->send(reply); |
730 | }); |
731 | - object->install_method_handler<core::trust::dbus::Store::Query::ForInterval>([bus, query](const core::dbus::Message::Ptr& msg) |
732 | + object->install_method_handler<core::trust::dbus::Store::Query::ForInterval>([this, query](const core::dbus::Message::Ptr& msg) |
733 | { |
734 | std::tuple<std::int64_t, std::int64_t> interval; msg->reader() >> interval; |
735 | |
736 | @@ -237,14 +242,14 @@ |
737 | auto reply = core::dbus::Message::make_method_return(msg); |
738 | bus->send(reply); |
739 | }); |
740 | - object->install_method_handler<core::trust::dbus::Store::Query::Next>([bus, query](const core::dbus::Message::Ptr& msg) |
741 | + object->install_method_handler<core::trust::dbus::Store::Query::Next>([this, query](const core::dbus::Message::Ptr& msg) |
742 | { |
743 | query->next(); |
744 | |
745 | auto reply = core::dbus::Message::make_method_return(msg); |
746 | bus->send(reply); |
747 | }); |
748 | - object->install_method_handler<core::trust::dbus::Store::Query::Status>([bus, query](const core::dbus::Message::Ptr& msg) |
749 | + object->install_method_handler<core::trust::dbus::Store::Query::Status>([this, query](const core::dbus::Message::Ptr& msg) |
750 | { |
751 | auto reply = core::dbus::Message::make_method_return(msg); |
752 | reply->writer() << query->status(); |
753 | @@ -255,7 +260,7 @@ |
754 | |
755 | auto reply = dbus::Message::make_method_return(msg); |
756 | reply->writer() << path; |
757 | - access_bus()->send(reply); |
758 | + bus->send(reply); |
759 | } catch(const std::runtime_error& e) |
760 | { |
761 | auto error = core::dbus::Message::make_error( |
762 | @@ -263,7 +268,7 @@ |
763 | core::trust::dbus::Store::Error::CreatingQuery::name(), |
764 | e.what()); |
765 | |
766 | - access_bus()->send(error); |
767 | + bus->send(error); |
768 | } |
769 | } |
770 | |
771 | @@ -275,17 +280,19 @@ |
772 | query_store.erase(path); |
773 | |
774 | auto reply = dbus::Message::make_method_return(msg); |
775 | - access_bus()->send(reply); |
776 | + bus->send(reply); |
777 | } catch(...) |
778 | { |
779 | } |
780 | |
781 | auto reply = dbus::Message::make_method_return(msg); |
782 | reply->writer(); |
783 | - access_bus()->send(reply); |
784 | + bus->send(reply); |
785 | } |
786 | |
787 | std::shared_ptr<core::trust::Store> store; |
788 | + std::shared_ptr<dbus::Bus> bus; |
789 | + std::shared_ptr<dbus::Service> service; |
790 | std::shared_ptr<dbus::Object> object; |
791 | std::thread worker; |
792 | |
793 | @@ -301,10 +308,17 @@ |
794 | const std::string& name) |
795 | { |
796 | if (name.empty()) |
797 | - throw Error::ServiceNameMustNotBeEmpty{}; |
798 | + throw Errors::ServiceNameMustNotBeEmpty{}; |
799 | |
800 | - core::trust::dbus::Store::mutable_name() = "com.ubuntu.trust.store." + name; |
801 | - return std::move(std::unique_ptr<core::trust::Token>(new detail::Token{bus, store})); |
802 | + return std::move(std::unique_ptr<core::trust::Token> |
803 | + { |
804 | + new detail::Token |
805 | + { |
806 | + "com.ubuntu.trust.store." + name, |
807 | + bus, |
808 | + store |
809 | + } |
810 | + }); |
811 | } |
812 | |
813 | std::unique_ptr<core::trust::Token> |
814 | |
815 | === modified file 'src/core/trust/impl/sqlite3/store.cpp' |
816 | --- src/core/trust/impl/sqlite3/store.cpp 2014-07-16 06:59:46 +0000 |
817 | +++ src/core/trust/impl/sqlite3/store.cpp 2014-07-17 18:44:56 +0000 |
818 | @@ -18,6 +18,8 @@ |
819 | |
820 | #include <core/trust/store.h> |
821 | |
822 | +#include <core/posix/this_process.h> |
823 | + |
824 | #include <sqlite3.h> |
825 | |
826 | #include <cstring> |
827 | @@ -32,18 +34,14 @@ |
828 | { |
829 | std::string home() |
830 | { |
831 | - return std::string{::getenv("HOME")}; |
832 | + return core::posix::this_process::env::get_or_throw("HOME"); |
833 | } |
834 | |
835 | std::string runtime_persistent_data_dir() |
836 | { |
837 | - char* value = ::getenv("XDG_DATA_HOME"); |
838 | - if (!value || value[0] == '0') |
839 | - { |
840 | - return std::string{home() + "/.local/share"}; |
841 | - } |
842 | - |
843 | - return std::string{value}; |
844 | + return core::posix::this_process::env::get( |
845 | + "XDG_DATA_HOME", |
846 | + home() + "/.local/share"); |
847 | } |
848 | |
849 | struct Directory |
850 | @@ -594,9 +592,9 @@ |
851 | { |
852 | switch(d.status) |
853 | { |
854 | - case Status::error: throw Error::QueryIsInErrorState{}; |
855 | - case Status::eor: throw Error::NoCurrentResult{}; |
856 | - case Status::armed: throw Error::NoCurrentResult{}; |
857 | + case Status::error: throw Errors::QueryIsInErrorState{}; |
858 | + case Status::eor: throw Errors::NoCurrentResult{}; |
859 | + case Status::armed: throw Errors::NoCurrentResult{}; |
860 | default: |
861 | { |
862 | trust::Request request |
863 | @@ -721,7 +719,7 @@ |
864 | std::shared_ptr<core::trust::Store> core::trust::create_default_store(const std::string& service_name) |
865 | { |
866 | if (service_name.empty()) |
867 | - throw core::trust::Error::ServiceNameMustNotBeEmpty(); |
868 | + throw core::trust::Errors::ServiceNameMustNotBeEmpty(); |
869 | |
870 | return std::shared_ptr<trust::Store>{new sqlite::Store(service_name)}; |
871 | } |
872 | |
873 | === added directory 'src/core/trust/mir' |
874 | === added file 'src/core/trust/mir/agent.cpp' |
875 | --- src/core/trust/mir/agent.cpp 1970-01-01 00:00:00 +0000 |
876 | +++ src/core/trust/mir/agent.cpp 2014-07-17 18:44:56 +0000 |
877 | @@ -0,0 +1,267 @@ |
878 | +/* |
879 | + * Copyright © 2014 Canonical Ltd. |
880 | + * |
881 | + * This program is free software: you can redistribute it and/or modify it |
882 | + * under the terms of the GNU Lesser General Public License version 3, |
883 | + * as published by the Free Software Foundation. |
884 | + * |
885 | + * This program is distributed in the hope that it will be useful, |
886 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
887 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
888 | + * GNU Lesser General Public License for more details. |
889 | + * |
890 | + * You should have received a copy of the GNU Lesser General Public License |
891 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
892 | + * |
893 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
894 | + */ |
895 | + |
896 | +#include "agent.h" |
897 | + |
898 | +#include "prompt_main.h" |
899 | + |
900 | +namespace mir = core::trust::mir; |
901 | + |
902 | +// Invoked whenever a request for creation of pre-authenticated fds succeeds. |
903 | +void mir::PromptSessionVirtualTable::mir_client_fd_callback(MirPromptSession */*prompt_session*/, size_t count, int const* fds, void* context) |
904 | +{ |
905 | + if (count == 0) |
906 | + return; |
907 | + |
908 | + auto ctxt = static_cast<mir::PromptSessionVirtualTable::Context*>(context); |
909 | + |
910 | + if (not ctxt) |
911 | + return; |
912 | + |
913 | + ctxt->fd = fds[0]; |
914 | +} |
915 | + |
916 | +mir::PromptSessionVirtualTable::PromptSessionVirtualTable(MirPromptSession* prompt_session) |
917 | + : prompt_session(prompt_session) |
918 | +{ |
919 | +} |
920 | + |
921 | +int mir::PromptSessionVirtualTable::new_fd_for_prompt_provider() |
922 | +{ |
923 | + static const unsigned int fd_count = 1; |
924 | + |
925 | + mir::PromptSessionVirtualTable::Context context; |
926 | + |
927 | + mir_wait_for(mir_prompt_session_new_fds_for_prompt_providers( |
928 | + prompt_session, |
929 | + fd_count, |
930 | + PromptSessionVirtualTable::mir_client_fd_callback, |
931 | + &context)); |
932 | + |
933 | + if (context.fd == Context::invalid_fd) throw std::runtime_error |
934 | + { |
935 | + "Could not acquire pre-authenticated file descriptors for Mir prompt session." |
936 | + }; |
937 | + |
938 | + return context.fd; |
939 | +} |
940 | + |
941 | +void mir::PromptSessionVirtualTable::release_sync() |
942 | +{ |
943 | + mir_prompt_session_release_sync(prompt_session); |
944 | +} |
945 | + |
946 | +mir::ConnectionVirtualTable::ConnectionVirtualTable(MirConnection* connection) |
947 | + : connection{connection} |
948 | +{ |
949 | +} |
950 | + |
951 | +mir::PromptSessionVirtualTable::Ptr mir::ConnectionVirtualTable::create_prompt_session_sync( |
952 | + // The process id of the requesting app/service |
953 | + pid_t app_pid, |
954 | + // Callback handling prompt session state changes. |
955 | + mir_prompt_session_state_change_callback cb, |
956 | + // Callback context |
957 | + void* context) |
958 | +{ |
959 | + return PromptSessionVirtualTable::Ptr |
960 | + { |
961 | + new PromptSessionVirtualTable |
962 | + { |
963 | + mir_connection_create_prompt_session_sync(connection, app_pid, cb, context) |
964 | + } |
965 | + }; |
966 | +} |
967 | + |
968 | +mir::PromptProviderHelper::PromptProviderHelper( |
969 | + const mir::PromptProviderHelper::CreationArguments& args) : creation_arguments(args) |
970 | +{ |
971 | +} |
972 | + |
973 | +core::posix::ChildProcess mir::PromptProviderHelper::exec_prompt_provider_with_arguments( |
974 | + const mir::PromptProviderHelper::InvocationArguments& args) |
975 | +{ |
976 | + static auto child_setup = []() {}; |
977 | + |
978 | + std::vector<std::string> argv |
979 | + { |
980 | + "--" + std::string{core::trust::mir::cli::option_server_socket}, "fd://" + std::to_string(args.fd), |
981 | + "--" + std::string{core::trust::mir::cli::option_title}, args.application_id, |
982 | + "--" + std::string{core::trust::mir::cli::option_description}, args.description |
983 | + }; |
984 | + |
985 | + // We just copy the environment |
986 | + std::map<std::string, std::string> env; |
987 | + core::posix::this_process::env::for_each([&env](const std::string& key, const std::string& value) |
988 | + { |
989 | + env.insert(std::make_pair(key, value)); |
990 | + }); |
991 | + |
992 | + |
993 | + auto result = core::posix::exec(creation_arguments.path_to_helper_executable, |
994 | + argv, |
995 | + env, |
996 | + core::posix::StandardStream::empty, |
997 | + child_setup); |
998 | + |
999 | + return result; |
1000 | +} |
1001 | + |
1002 | +void mir::Agent::on_trust_session_changed_state( |
1003 | + // The prompt session instance that just changed state. |
1004 | + MirPromptSession* /*prompt_provider*/, |
1005 | + // The new state of the prompt session instance. |
1006 | + MirPromptSessionState state, |
1007 | + // The context of type context. |
1008 | + void* context) |
1009 | +{ |
1010 | + if (mir_prompt_session_state_stopped != state) |
1011 | + return; |
1012 | + |
1013 | + auto ctxt = static_cast<mir::Agent::OnTrustSessionStateChangedCallbackContext*>(context); |
1014 | + |
1015 | + if (not ctxt) |
1016 | + return; |
1017 | + |
1018 | + std::error_code ec; |
1019 | + // If the trust session ended (for whatever reason), we send a SIG_KILL to the |
1020 | + // prompt provider process. We hereby ensure that we never return Answer::granted |
1021 | + // unless the prompt provider cleanly exited prior to the trust session stopping. |
1022 | + ctxt->prompt_provider_process.send_signal(core::posix::Signal::sig_kill, ec); |
1023 | + // The required wait for the child process happens in prompt_user_for_request(...). |
1024 | + // TODO(tvoss): We should log ec in case of errors. |
1025 | +} |
1026 | + |
1027 | +std::function<core::trust::Request::Answer(const core::posix::wait::Result&)> mir::Agent::translator_only_accepting_exit_status_success() |
1028 | +{ |
1029 | + return [](const core::posix::wait::Result& result) -> core::trust::Request::Answer |
1030 | + { |
1031 | + // We now analyze the result of the process execution. |
1032 | + if (core::posix::wait::Result::Status::exited != result.status) throw std::logic_error |
1033 | + { |
1034 | + "The prompt provider process was signaled or stopped, " |
1035 | + "unable to determine a conclusive answer from the user" |
1036 | + }; |
1037 | + |
1038 | + // If the child process did not exit cleanly, we deny access to the resource. |
1039 | + if (core::posix::exit::Status::failure == result.detail.if_exited.status) |
1040 | + return core::trust::Request::Answer::denied; |
1041 | + |
1042 | + return core::trust::Request::Answer::granted; |
1043 | + }; |
1044 | +} |
1045 | + |
1046 | +mir::Agent::Agent( |
1047 | + // VTable object providing access to Mir's trusted prompting functionality. |
1048 | + const mir::ConnectionVirtualTable::Ptr& connection_vtable, |
1049 | + // Exec helper for starting up prompt provider child processes with the correct setup |
1050 | + // of command line arguments and environment variables. |
1051 | + const mir::PromptProviderHelper::Ptr& exec_helper, |
1052 | + // A translator function for mapping child process exit states to trust::Request answers. |
1053 | + const std::function<core::trust::Request::Answer(const core::posix::wait::Result&)>& translator) |
1054 | + : connection_vtable(connection_vtable), |
1055 | + exec_helper(exec_helper), |
1056 | + translator(translator) |
1057 | +{ |
1058 | +} |
1059 | + |
1060 | +// From core::trust::Agent: |
1061 | +core::trust::Request::Answer mir::Agent::prompt_user_for_request(pid_t app_pid, const std::string& app_id, const std::string& description) |
1062 | +{ |
1063 | + // We initialize our callback context with an invalid child-process for setup |
1064 | + // purposes. Later on, once we have acquired a pre-authenticated fd for the |
1065 | + // prompt provider, we exec the actual provider in a child process and replace the |
1066 | + // instance here. |
1067 | + mir::Agent::OnTrustSessionStateChangedCallbackContext cb_context |
1068 | + { |
1069 | + core::posix::ChildProcess::invalid() |
1070 | + }; |
1071 | + |
1072 | + // We ensure that the prompt session is always released cleanly, either on return or on throw. |
1073 | + struct Scope |
1074 | + { |
1075 | + ~Scope() { prompt_session->release_sync(); } |
1076 | + mir::PromptSessionVirtualTable::Ptr prompt_session; |
1077 | + } scope |
1078 | + { |
1079 | + // We setup the prompt session and wire up to our own internal callback helper. |
1080 | + connection_vtable->create_prompt_session_sync( |
1081 | + app_pid, |
1082 | + Agent::on_trust_session_changed_state, |
1083 | + &cb_context) |
1084 | + }; |
1085 | + |
1086 | + // Acquire a new fd for the prompt provider. |
1087 | + auto fd = scope.prompt_session->new_fd_for_prompt_provider(); |
1088 | + |
1089 | + // And prepare the actual execution in a child process. |
1090 | + mir::PromptProviderHelper::InvocationArguments args |
1091 | + { |
1092 | + fd, |
1093 | + app_id, |
1094 | + description |
1095 | + }; |
1096 | + |
1097 | + // Ask the helper to fire up the prompt provider. |
1098 | + cb_context.prompt_provider_process = exec_helper->exec_prompt_provider_with_arguments(args); |
1099 | + // And subsequently wait for it to finish. |
1100 | + auto result = cb_context.prompt_provider_process.wait_for(core::posix::wait::Flags::untraced); |
1101 | + |
1102 | + return translator(result); |
1103 | +} |
1104 | + |
1105 | +bool mir::operator==(const mir::PromptProviderHelper::InvocationArguments& lhs, const mir::PromptProviderHelper::InvocationArguments& rhs) |
1106 | +{ |
1107 | + return std::tie(lhs.application_id, lhs.description, lhs.fd) == std::tie(rhs.application_id, rhs.description, rhs.fd); |
1108 | +} |
1109 | + |
1110 | +#include <core/trust/mir_agent.h> |
1111 | + |
1112 | +#include "config.h" |
1113 | + |
1114 | +std::shared_ptr<core::trust::Agent> mir::create_agent_for_mir_connection(MirConnection* connection) |
1115 | +{ |
1116 | + mir::ConnectionVirtualTable::Ptr cvt |
1117 | + { |
1118 | + new mir::ConnectionVirtualTable |
1119 | + { |
1120 | + connection |
1121 | + } |
1122 | + }; |
1123 | + |
1124 | + mir::PromptProviderHelper::Ptr pph |
1125 | + { |
1126 | + new mir::PromptProviderHelper |
1127 | + { |
1128 | + mir::PromptProviderHelper::CreationArguments |
1129 | + { |
1130 | + core::trust::mir::trust_prompt_executable_in_lib_dir |
1131 | + } |
1132 | + } |
1133 | + }; |
1134 | + |
1135 | + return mir::Agent::Ptr |
1136 | + { |
1137 | + new mir::Agent |
1138 | + { |
1139 | + cvt, |
1140 | + pph, |
1141 | + mir::Agent::translator_only_accepting_exit_status_success() |
1142 | + } |
1143 | + }; |
1144 | +} |
1145 | |
1146 | === added file 'src/core/trust/mir/agent.h' |
1147 | --- src/core/trust/mir/agent.h 1970-01-01 00:00:00 +0000 |
1148 | +++ src/core/trust/mir/agent.h 2014-07-17 18:44:56 +0000 |
1149 | @@ -0,0 +1,196 @@ |
1150 | +/* |
1151 | + * Copyright © 2014 Canonical Ltd. |
1152 | + * |
1153 | + * This program is free software: you can redistribute it and/or modify it |
1154 | + * under the terms of the GNU Lesser General Public License version 3, |
1155 | + * as published by the Free Software Foundation. |
1156 | + * |
1157 | + * This program is distributed in the hope that it will be useful, |
1158 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1159 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1160 | + * GNU Lesser General Public License for more details. |
1161 | + * |
1162 | + * You should have received a copy of the GNU Lesser General Public License |
1163 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1164 | + * |
1165 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
1166 | + */ |
1167 | + |
1168 | +#ifndef CORE_TRUST_MIR_MIR_AGENT_H_ |
1169 | +#define CORE_TRUST_MIR_MIR_AGENT_H_ |
1170 | + |
1171 | +#include <core/trust/agent.h> |
1172 | + |
1173 | +#include <core/posix/child_process.h> |
1174 | +#include <core/posix/exec.h> |
1175 | + |
1176 | +#include <mirclient/mir_toolkit/mir_client_library.h> |
1177 | +#include <mirclient/mir_toolkit/mir_prompt_session.h> |
1178 | + |
1179 | +#include <condition_variable> |
1180 | +#include <functional> |
1181 | +#include <mutex> |
1182 | + |
1183 | +namespace core |
1184 | +{ |
1185 | +namespace trust |
1186 | +{ |
1187 | +namespace mir |
1188 | +{ |
1189 | +// We wrap the Mir prompt session API into a struct to |
1190 | +// ease with testing and mocking. |
1191 | +struct CORE_TRUST_DLL_PUBLIC PromptSessionVirtualTable |
1192 | +{ |
1193 | + // Just a convenience typedef |
1194 | + typedef std::shared_ptr<PromptSessionVirtualTable> Ptr; |
1195 | + |
1196 | + // Just a helper struct to be passed to client_fd_callbacks. |
1197 | + struct Context |
1198 | + { |
1199 | + // Marks the value of an invalid fd. |
1200 | + static constexpr const int invalid_fd{-1}; |
1201 | + // The fd contained within this context instance. |
1202 | + int fd{invalid_fd}; |
1203 | + }; |
1204 | + |
1205 | + // Invoked whenever a request for creation of pre-authenticated fds succeeds. |
1206 | + static void mir_client_fd_callback(MirPromptSession */*prompt_session*/, size_t count, int const* fds, void* context); |
1207 | + |
1208 | + // Create a MirPromptSessionVirtualTable for a given prompt session instance. |
1209 | + // Please note that no change of ownwership is happening here. Instead, we expect |
1210 | + // the calling code to handle object lifetimes. |
1211 | + PromptSessionVirtualTable(MirPromptSession* prompt_session); |
1212 | + virtual ~PromptSessionVirtualTable() = default; |
1213 | + |
1214 | + // Requests a new, pre-authenticated fd for associating prompt providers. |
1215 | + // Returns the fd or throws std::runtime_error. |
1216 | + virtual int new_fd_for_prompt_provider(); |
1217 | + |
1218 | + // Finalizes and releases the given prompt session instance. |
1219 | + virtual void release_sync(); |
1220 | + |
1221 | + // The underlying prompt session instance. |
1222 | + MirPromptSession* prompt_session; |
1223 | +}; |
1224 | + |
1225 | +struct CORE_TRUST_DLL_PUBLIC ConnectionVirtualTable |
1226 | +{ |
1227 | + // Just a convenience typedef |
1228 | + typedef std::shared_ptr<ConnectionVirtualTable> Ptr; |
1229 | + |
1230 | + // Create a new instance of MirConnectionVirtualTable |
1231 | + // using a pre-existing connection to Mir. Please note |
1232 | + // that we do not take ownership of the MirConnection but |
1233 | + // expect the calling code to coordinate object lifetimes. |
1234 | + ConnectionVirtualTable(MirConnection* connection); |
1235 | + virtual ~ConnectionVirtualTable() = default; |
1236 | + |
1237 | + // Creates a new trusted prompt session instance synchronously. |
1238 | + virtual PromptSessionVirtualTable::Ptr create_prompt_session_sync( |
1239 | + // The process id of the requesting app/service |
1240 | + pid_t app_pid, |
1241 | + // Callback handling prompt session state changes. |
1242 | + mir_prompt_session_state_change_callback cb, |
1243 | + // Callback context |
1244 | + void* context); |
1245 | + |
1246 | + // We do not take over ownership of the connection object. |
1247 | + MirConnection* connection; |
1248 | +}; |
1249 | + |
1250 | +// Abstracts common functionality required for running external helpers. |
1251 | +struct CORE_TRUST_DLL_PUBLIC PromptProviderHelper |
1252 | +{ |
1253 | + // Just a convenience typedef. |
1254 | + typedef std::shared_ptr<PromptProviderHelper> Ptr; |
1255 | + |
1256 | + // Creation-time arguments. |
1257 | + struct CreationArguments |
1258 | + { |
1259 | + // Path to the helper executable that provides the prompting UI. |
1260 | + std::string path_to_helper_executable; |
1261 | + }; |
1262 | + |
1263 | + // Invocation arguments for exec_prompt_provider_with_arguments |
1264 | + struct InvocationArguments |
1265 | + { |
1266 | + // The pre-authenticated fd that the helper |
1267 | + // should use for connecting to Mir. |
1268 | + int fd; |
1269 | + // The application id of the requesting app. |
1270 | + std::string application_id; |
1271 | + // The extended description that should be presented to the user. |
1272 | + std::string description; |
1273 | + }; |
1274 | + |
1275 | + PromptProviderHelper(const CreationArguments& args); |
1276 | + virtual ~PromptProviderHelper() = default; |
1277 | + |
1278 | + // Execs the executable provided at construction time for the arguments and |
1279 | + // returns the corresponding child process. |
1280 | + virtual core::posix::ChildProcess exec_prompt_provider_with_arguments(const InvocationArguments& args); |
1281 | + |
1282 | + // We store all arguments passed at construction. |
1283 | + CreationArguments creation_arguments; |
1284 | +}; |
1285 | + |
1286 | +// Implements the trust::Agent interface and dispatches calls to a helper |
1287 | +// prompt provider, tying it together with the requesting service and app |
1288 | +// by leveraging Mir's trusted session/prompting support. |
1289 | +struct CORE_TRUST_DLL_PUBLIC Agent : public core::trust::Agent |
1290 | +{ |
1291 | + // Convenience typedef |
1292 | + typedef std::shared_ptr<Agent> Ptr; |
1293 | + |
1294 | + // Helper struct for injecting state into on_trust_changed_state_state callbacks. |
1295 | + // Used in prompt_user_for_request to wait for the trust session to be stopped. |
1296 | + struct OnTrustSessionStateChangedCallbackContext |
1297 | + { |
1298 | + // The process that provides the prompting UI. |
1299 | + core::posix::ChildProcess prompt_provider_process; |
1300 | + }; |
1301 | + |
1302 | + // Handles state changes of trust sessions and sigkills the child process |
1303 | + // provided in context (of type OnTrustSessionStateChangedCallbackContext). |
1304 | + static void on_trust_session_changed_state( |
1305 | + // The prompt session instance that just changed state. |
1306 | + MirPromptSession* prompt_provider, |
1307 | + // The new state of the prompt session instance. |
1308 | + MirPromptSessionState state, |
1309 | + // The context of type context. |
1310 | + void* context); |
1311 | + |
1312 | + // Returns a wait result -> trust::Request::Answer translator that only returns Answer::granted if |
1313 | + // the prompt provider child process exits cleanly with status success. |
1314 | + // Throws std::logic_error if the process did not exit but was signaled. |
1315 | + static std::function<core::trust::Request::Answer(const core::posix::wait::Result&)> translator_only_accepting_exit_status_success(); |
1316 | + |
1317 | + // Creates a new MirAgent instance with the given MirConnectionVirtualTable instance. |
1318 | + Agent( |
1319 | + // VTable object providing access to Mir's trusted prompting functionality. |
1320 | + const ConnectionVirtualTable::Ptr& connection_vtable, |
1321 | + // Exec helper for starting up prompt provider child processes with the correct setup |
1322 | + // of command line arguments and environment variables. |
1323 | + const PromptProviderHelper::Ptr& exec_helper, |
1324 | + // A translator function for mapping child process exit states to trust::Request answers. |
1325 | + const std::function<core::trust::Request::Answer(const core::posix::wait::Result&)>& translator); |
1326 | + |
1327 | + // From core::trust::Agent: |
1328 | + // Throws a std::logic_error if anything unforeseen happens during execution, thus |
1329 | + // indicating that no conclusive answer could be obtained from the user. |
1330 | + core::trust::Request::Answer prompt_user_for_request(pid_t app_pid, const std::string& app_id, const std::string& description) override; |
1331 | + |
1332 | + // The connection VTable used for creating trusted prompting sessions. |
1333 | + ConnectionVirtualTable::Ptr connection_vtable; |
1334 | + // Execution helper for firing up prompt provider executables. |
1335 | + PromptProviderHelper::Ptr exec_helper; |
1336 | + // Translator instance. |
1337 | + std::function<core::trust::Request::Answer(const core::posix::wait::Result&)> translator; |
1338 | +}; |
1339 | + |
1340 | +CORE_TRUST_DLL_PUBLIC bool operator==(const PromptProviderHelper::InvocationArguments&, const PromptProviderHelper::InvocationArguments&); |
1341 | +} |
1342 | +} |
1343 | +} |
1344 | + |
1345 | +#endif // CORE_TRUST_MIR_MIR_AGENT_H_ |
1346 | |
1347 | === added file 'src/core/trust/mir/config.h.in' |
1348 | --- src/core/trust/mir/config.h.in 1970-01-01 00:00:00 +0000 |
1349 | +++ src/core/trust/mir/config.h.in 2014-07-17 18:44:56 +0000 |
1350 | @@ -0,0 +1,41 @@ |
1351 | +/* |
1352 | + * Copyright © 2014 Canonical Ltd. |
1353 | + * |
1354 | + * This program is free software: you can redistribute it and/or modify it |
1355 | + * under the terms of the GNU Lesser General Public License version 3, |
1356 | + * as published by the Free Software Foundation. |
1357 | + * |
1358 | + * This program is distributed in the hope that it will be useful, |
1359 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1360 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1361 | + * GNU Lesser General Public License for more details. |
1362 | + * |
1363 | + * You should have received a copy of the GNU Lesser General Public License |
1364 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1365 | + * |
1366 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
1367 | + */ |
1368 | + |
1369 | +#ifndef CORE_TRUST_MIR_CONFIG_H_ |
1370 | +#define CORE_TRUST_MIR_CONFIG_H_ |
1371 | + |
1372 | +namespace core |
1373 | +{ |
1374 | +namespace trust |
1375 | +{ |
1376 | +namespace mir |
1377 | +{ |
1378 | +static constexpr const char* trust_prompt_executable_in_build_dir |
1379 | +{ |
1380 | + "@CMAKE_BINARY_DIR@/src/trust-prompt" |
1381 | +}; |
1382 | + |
1383 | +static constexpr const char* trust_prompt_executable_in_lib_dir |
1384 | +{ |
1385 | + "@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@/trust-prompt" |
1386 | +}; |
1387 | +} |
1388 | +} |
1389 | +} |
1390 | + |
1391 | +#endif // CORE_TRUST_MIR_CONFIG_H_ |
1392 | |
1393 | === added file 'src/core/trust/mir/prompt_config.h.in' |
1394 | --- src/core/trust/mir/prompt_config.h.in 1970-01-01 00:00:00 +0000 |
1395 | +++ src/core/trust/mir/prompt_config.h.in 2014-07-17 18:44:56 +0000 |
1396 | @@ -0,0 +1,39 @@ |
1397 | +/* |
1398 | + * Copyright © 2014 Canonical Ltd. |
1399 | + * |
1400 | + * This program is free software: you can redistribute it and/or modify it |
1401 | + * under the terms of the GNU Lesser General Public License version 3, |
1402 | + * as published by the Free Software Foundation. |
1403 | + * |
1404 | + * This program is distributed in the hope that it will be useful, |
1405 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1406 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1407 | + * GNU Lesser General Public License for more details. |
1408 | + * |
1409 | + * You should have received a copy of the GNU Lesser General Public License |
1410 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1411 | + * |
1412 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
1413 | + */ |
1414 | + |
1415 | +#include <QtCore/QCoreApplication> |
1416 | +#include <QtCore/QDir> |
1417 | + |
1418 | +// Returns true if the application is called from its installed location. |
1419 | +inline bool isRunningInstalled() |
1420 | +{ |
1421 | + static bool installed |
1422 | + { |
1423 | + QCoreApplication::applicationDirPath() == |
1424 | + QDir(("@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@")).canonicalPath() |
1425 | + }; |
1426 | + |
1427 | + return installed; |
1428 | +} |
1429 | + |
1430 | +inline QString appDirectory() |
1431 | +{ |
1432 | + return isRunningInstalled() ? |
1433 | + QString("@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_DATADIR@/core/trust/mir/") : |
1434 | + QString("@CMAKE_SOURCE_DIR@/src/core/trust/mir/"); |
1435 | +} |
1436 | |
1437 | === added file 'src/core/trust/mir/prompt_main.cpp' |
1438 | --- src/core/trust/mir/prompt_main.cpp 1970-01-01 00:00:00 +0000 |
1439 | +++ src/core/trust/mir/prompt_main.cpp 2014-07-17 18:44:56 +0000 |
1440 | @@ -0,0 +1,191 @@ |
1441 | +/* |
1442 | + * Copyright © 2014 Canonical Ltd. |
1443 | + * |
1444 | + * This program is free software: you can redistribute it and/or modify it |
1445 | + * under the terms of the GNU Lesser General Public License version 3, |
1446 | + * as published by the Free Software Foundation. |
1447 | + * |
1448 | + * This program is distributed in the hope that it will be useful, |
1449 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1450 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1451 | + * GNU Lesser General Public License for more details. |
1452 | + * |
1453 | + * You should have received a copy of the GNU Lesser General Public License |
1454 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1455 | + * |
1456 | + * Authors: |
1457 | + * Olivier Tilloy <olivier.tilloy@canonical.com> |
1458 | + * Nick Dedekind <nick.dedekind@canonical.com> |
1459 | + * Thomas Voß <thomas.voss@canonical.com> |
1460 | + */ |
1461 | + |
1462 | +// Qt |
1463 | +#include <QCommandLineParser> |
1464 | +#include <QGuiApplication> |
1465 | + |
1466 | +#include <QQuickView> |
1467 | +#include <QQuickItem> |
1468 | +#include <QQmlContext> |
1469 | +#include <QQmlEngine> |
1470 | + |
1471 | +#include <boost/program_options.hpp> |
1472 | +#include <boost/program_options/environment_iterator.hpp> |
1473 | + |
1474 | +#include <core/posix/this_process.h> |
1475 | + |
1476 | +#include "prompt_config.h" |
1477 | +#include "prompt_main.h" |
1478 | + |
1479 | +namespace core |
1480 | +{ |
1481 | +namespace trust |
1482 | +{ |
1483 | +namespace mir |
1484 | +{ |
1485 | +class SignalTrap : public QObject |
1486 | +{ |
1487 | + Q_OBJECT |
1488 | + |
1489 | +public Q_SLOTS: |
1490 | + void quit(int code) |
1491 | + { |
1492 | + QCoreApplication::exit(code); |
1493 | + } |
1494 | +}; |
1495 | +} |
1496 | +} |
1497 | +} |
1498 | + |
1499 | +namespace |
1500 | +{ |
1501 | +namespace testing |
1502 | +{ |
1503 | +void validate_command_line_arguments(const boost::program_options::variables_map& vm) |
1504 | +{ |
1505 | + // We are throwing exceptions here, which immediately calls abort and still gives a |
1506 | + // helpful error message on the terminal. |
1507 | + if (vm.count(core::trust::mir::cli::option_title) == 0) throw std::logic_error |
1508 | + { |
1509 | + "Missing option title." |
1510 | + }; |
1511 | + |
1512 | + if (vm.count(core::trust::mir::cli::option_description) == 0) throw std::logic_error |
1513 | + { |
1514 | + "Missing option description" |
1515 | + }; |
1516 | + |
1517 | + if (vm.count(core::trust::mir::cli::option_server_socket) == 0) throw std::logic_error |
1518 | + { |
1519 | + "Missing option mir_server_socket" |
1520 | + }; |
1521 | + |
1522 | + std::string mir_server_socket = vm[core::trust::mir::cli::option_server_socket].as<std::string>(); |
1523 | + |
1524 | + if (mir_server_socket.find("fd://") != 0) throw std::logic_error |
1525 | + { |
1526 | + "mir_server_socket does not being with fd://" |
1527 | + }; |
1528 | +} |
1529 | +} |
1530 | +} |
1531 | + |
1532 | + |
1533 | +int main(int argc, char** argv) |
1534 | +{ |
1535 | + boost::program_options::options_description options; |
1536 | + options.add_options() |
1537 | + (core::trust::mir::cli::option_server_socket, boost::program_options::value<std::string>(), "Mir server socket to connect to.") |
1538 | + (core::trust::mir::cli::option_description, boost::program_options::value<std::string>(), "Extended description of the prompt.") |
1539 | + (core::trust::mir::cli::option_title, boost::program_options::value<std::string>(), "Title of the prompt.") |
1540 | + (core::trust::mir::cli::option_testing, "Only checks command-line parameters and does not execute any actions."); |
1541 | + |
1542 | + auto parsed_options = boost::program_options::command_line_parser{argc, argv} |
1543 | + .options(options) |
1544 | + .allow_unregistered() |
1545 | + .run(); |
1546 | + |
1547 | + // Consider the command line. |
1548 | + boost::program_options::variables_map vm; |
1549 | + boost::program_options::store(parsed_options, vm); |
1550 | + boost::program_options::notify(vm); |
1551 | + |
1552 | + // And the environment for option passing. |
1553 | + parsed_options = boost::program_options::parse_environment(options, "CORE_TRUST_MIR_PROMPT_"); |
1554 | + boost::program_options::store(parsed_options, vm); |
1555 | + boost::program_options::notify(vm); |
1556 | + |
1557 | + // We just verify command line arguments in testing and immediately return. |
1558 | + if (vm.count(core::trust::mir::cli::option_testing) > 0) |
1559 | + { |
1560 | + testing::validate_command_line_arguments(vm); return 0; |
1561 | + } |
1562 | + |
1563 | + // Let's validate the arguments. |
1564 | + if (vm.count(core::trust::mir::cli::option_title) == 0) |
1565 | + abort(); // We have to call abort here to make sure that we get signalled. |
1566 | + |
1567 | + std::string title = vm[core::trust::mir::cli::option_title].as<std::string>(); |
1568 | + |
1569 | + std::string description; |
1570 | + if (vm.count(core::trust::mir::cli::option_description) > 0) |
1571 | + description = vm[core::trust::mir::cli::option_description].as<std::string>(); |
1572 | + |
1573 | + if (vm.count(core::trust::mir::cli::option_server_socket) > 0) |
1574 | + core::posix::this_process::env::set_or_throw( |
1575 | + core::trust::mir::env::option_mir_socket, |
1576 | + vm[core::trust::mir::cli::option_server_socket].as<std::string>()); |
1577 | + |
1578 | + // We install a custom message handler to silence Qt's chattiness |
1579 | + qInstallMessageHandler([](QtMsgType type, const QMessageLogContext&, const QString& msg) |
1580 | + { |
1581 | + switch (type) |
1582 | + { |
1583 | + // We only handle critical and fatal messages. |
1584 | + case QtCriticalMsg: |
1585 | + case QtFatalMsg: |
1586 | + std::cerr << qPrintable(msg) << std::endl; |
1587 | + break; |
1588 | + // And just drop the rest. |
1589 | + default: |
1590 | + break; |
1591 | + } |
1592 | + }); |
1593 | + |
1594 | + // We already parsed the command line arguments and do not parse them |
1595 | + // to the application. |
1596 | + QGuiApplication app{argc, argv}; |
1597 | + |
1598 | + core::trust::mir::SignalTrap signal_trap; |
1599 | + |
1600 | + QQuickView* view = new QQuickView(); |
1601 | + view->setResizeMode(QQuickView::SizeRootObjectToView); |
1602 | + view->setTitle(QGuiApplication::applicationName()); |
1603 | + |
1604 | + // Make some properties known to the root context. |
1605 | + // The title of the dialog. |
1606 | + view->rootContext()->setContextProperty( |
1607 | + core::trust::mir::cli::option_title, |
1608 | + title.c_str()); |
1609 | + // The description of the dialog. |
1610 | + view->rootContext()->setContextProperty( |
1611 | + core::trust::mir::cli::option_description, |
1612 | + description.c_str()); |
1613 | + |
1614 | + // Point the engine to the right directory. Please note that |
1615 | + // the respective value changes with the installation state. |
1616 | + view->engine()->setBaseUrl(QUrl::fromLocalFile(appDirectory())); |
1617 | + |
1618 | + view->setSource(QUrl::fromLocalFile("prompt_main.qml")); |
1619 | + view->show(); |
1620 | + |
1621 | + QObject::connect( |
1622 | + view->rootObject(), |
1623 | + SIGNAL(quit(int)), |
1624 | + &signal_trap, |
1625 | + SLOT(quit(int))); |
1626 | + |
1627 | + return app.exec(); |
1628 | +} |
1629 | + |
1630 | +#include "prompt_main.moc" |
1631 | + |
1632 | |
1633 | === added file 'src/core/trust/mir/prompt_main.h' |
1634 | --- src/core/trust/mir/prompt_main.h 1970-01-01 00:00:00 +0000 |
1635 | +++ src/core/trust/mir/prompt_main.h 2014-07-17 18:44:56 +0000 |
1636 | @@ -0,0 +1,65 @@ |
1637 | +/* |
1638 | + * Copyright © 2014 Canonical Ltd. |
1639 | + * |
1640 | + * This program is free software: you can redistribute it and/or modify it |
1641 | + * under the terms of the GNU Lesser General Public License version 3, |
1642 | + * as published by the Free Software Foundation. |
1643 | + * |
1644 | + * This program is distributed in the hope that it will be useful, |
1645 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1646 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1647 | + * GNU Lesser General Public License for more details. |
1648 | + * |
1649 | + * You should have received a copy of the GNU Lesser General Public License |
1650 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1651 | + * |
1652 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
1653 | + */ |
1654 | + |
1655 | +#ifndef CORE_TRUST_MIR_PROMPT_MAIN_H_ |
1656 | +#define CORE_TRUST_MIR_PROMPT_MAIN_H_ |
1657 | + |
1658 | +namespace core |
1659 | +{ |
1660 | +namespace trust |
1661 | +{ |
1662 | +namespace mir |
1663 | +{ |
1664 | +namespace env |
1665 | +{ |
1666 | +static constexpr const char* option_mir_socket |
1667 | +{ |
1668 | + "MIR_SOCKET" |
1669 | +}; |
1670 | +} |
1671 | +namespace cli |
1672 | +{ |
1673 | +/** @brief Mir server socket to connect to. */ |
1674 | +static constexpr const char* option_server_socket |
1675 | +{ |
1676 | + "mir_server_socket" |
1677 | +}; |
1678 | + |
1679 | +/** @brief Title of the prompt. */ |
1680 | +static constexpr const char* option_title |
1681 | +{ |
1682 | + "title" |
1683 | +}; |
1684 | + |
1685 | +/** @brief Extended description of the prompt. */ |
1686 | +static constexpr const char* option_description |
1687 | +{ |
1688 | + "description" |
1689 | +}; |
1690 | + |
1691 | +/** @brief Only checks command-line parameters and does not execute any actions. */ |
1692 | +static constexpr const char* option_testing |
1693 | +{ |
1694 | + "testing" |
1695 | +}; |
1696 | +} |
1697 | +} |
1698 | +} |
1699 | +} |
1700 | + |
1701 | +#endif // CORE_TRUST_MIR_PROMPT_MAIN_H_ |
1702 | |
1703 | === added file 'src/core/trust/mir/prompt_main.qml' |
1704 | --- src/core/trust/mir/prompt_main.qml 1970-01-01 00:00:00 +0000 |
1705 | +++ src/core/trust/mir/prompt_main.qml 2014-07-17 18:44:56 +0000 |
1706 | @@ -0,0 +1,53 @@ |
1707 | +import QtQuick 2.0 |
1708 | +import Ubuntu.Components 0.1 |
1709 | +import QtQuick.Layouts 1.1 |
1710 | + |
1711 | +Rectangle { |
1712 | + anchors.fill: parent |
1713 | + |
1714 | + signal quit(int code) |
1715 | + |
1716 | + ColumnLayout { |
1717 | + anchors.fill: parent |
1718 | + anchors.margins: units.gu(2) |
1719 | + spacing: units.gu(2) |
1720 | + |
1721 | + Label { |
1722 | + anchors.horizontalCenter: parent.horizontalCenter |
1723 | + |
1724 | + text: title |
1725 | + font.family: "Ubuntu" |
1726 | + fontSize: "large" |
1727 | + |
1728 | + maximumLineCount: 1 |
1729 | + elide: Text.ElideRight |
1730 | + } |
1731 | + |
1732 | + Label { |
1733 | + |
1734 | + text: description |
1735 | + font.family: "Ubuntu" |
1736 | + fontSize: "medium" |
1737 | + Layout.maximumWidth: parent.width |
1738 | + Layout.fillHeight: true |
1739 | + |
1740 | + wrapMode: Text.WordWrap |
1741 | + } |
1742 | + |
1743 | + RowLayout { |
1744 | + spacing: units.gu(1) |
1745 | + height: units.gu(3) |
1746 | + anchors.right: parent.right |
1747 | + |
1748 | + Button { |
1749 | + text: "Deny" |
1750 | + onClicked: quit(1) |
1751 | + } |
1752 | + Button { |
1753 | + text: "Grant" |
1754 | + onClicked: quit(0) |
1755 | + } |
1756 | + } |
1757 | + } |
1758 | +} |
1759 | + |
1760 | |
1761 | === modified file 'src/core/trust/request.cpp' |
1762 | --- src/core/trust/request.cpp 2014-05-06 11:32:13 +0000 |
1763 | +++ src/core/trust/request.cpp 2014-07-17 18:44:56 +0000 |
1764 | @@ -18,6 +18,55 @@ |
1765 | |
1766 | #include <core/trust/request.h> |
1767 | |
1768 | +#include <core/trust/agent.h> |
1769 | +#include <core/trust/store.h> |
1770 | + |
1771 | +core::trust::Request::Answer core::trust::process_trust_request(const core::trust::RequestParameters& params) |
1772 | +{ |
1773 | + // We verify parameters first: |
1774 | + if (not params.agent) throw std::logic_error |
1775 | + { |
1776 | + "Cannot operate without an agent implementation." |
1777 | + }; |
1778 | + |
1779 | + if (not params.store) throw std::logic_error |
1780 | + { |
1781 | + "Cannot operate without a store implementation." |
1782 | + }; |
1783 | + |
1784 | + // Let's see if the store has an answer for app-id and feature. |
1785 | + auto query = params.store->query(); |
1786 | + |
1787 | + // Narrow it down to the specific app and the specific feature |
1788 | + query->for_application_id(params.application_id); |
1789 | + query->for_feature(params.feature); |
1790 | + |
1791 | + query->execute(); |
1792 | + |
1793 | + // We have got results and we take the most recent one as the most appropriate. |
1794 | + if (query->status() == core::trust::Store::Query::Status::has_more_results) |
1795 | + { |
1796 | + // And we are returning early. |
1797 | + return query->current().answer; |
1798 | + } |
1799 | + |
1800 | + // We do not have results available in the store, prompting the user |
1801 | + auto answer = params.agent->prompt_user_for_request( |
1802 | + params.application_pid, |
1803 | + params.application_id, |
1804 | + params.description); |
1805 | + |
1806 | + params.store->add(core::trust::Request |
1807 | + { |
1808 | + params.application_id, |
1809 | + params.feature, |
1810 | + std::chrono::system_clock::now(), |
1811 | + answer |
1812 | + }); |
1813 | + |
1814 | + return answer; |
1815 | +} |
1816 | + |
1817 | bool core::trust::operator==(const core::trust::Request& lhs, const core::trust::Request& rhs) |
1818 | { |
1819 | return lhs.from == rhs.from && |
1820 | |
1821 | === modified file 'src/core/trust/resolve.cpp' |
1822 | --- src/core/trust/resolve.cpp 2014-05-06 11:32:13 +0000 |
1823 | +++ src/core/trust/resolve.cpp 2014-07-17 18:44:56 +0000 |
1824 | @@ -41,15 +41,14 @@ |
1825 | }; |
1826 | } |
1827 | |
1828 | -struct Store : |
1829 | - public core::trust::Store, |
1830 | - public dbus::Stub<core::trust::dbus::Store> |
1831 | +struct Store : public core::trust::Store |
1832 | { |
1833 | - Store(const std::shared_ptr<core::dbus::Bus>& bus) |
1834 | - : dbus::Stub<core::trust::dbus::Store>(bus), |
1835 | - bus(bus), |
1836 | - worker{[this]() { this->bus->run(); }}, |
1837 | - proxy(access_service()->object_for_path(dbus::types::ObjectPath::root())) |
1838 | + Store(const std::shared_ptr<dbus::Service>& service, |
1839 | + const std::shared_ptr<core::dbus::Bus>& bus) |
1840 | + : bus(bus), |
1841 | + worker{[this]() { Store::bus->run(); }}, |
1842 | + service(service), |
1843 | + proxy(service->object_for_path(dbus::types::ObjectPath::root())) |
1844 | { |
1845 | } |
1846 | |
1847 | @@ -99,7 +98,7 @@ |
1848 | |
1849 | if (result.is_error()) |
1850 | { |
1851 | - throw core::trust::Store::Query::Error::NoCurrentResult{}; |
1852 | + throw core::trust::Store::Query::Errors::NoCurrentResult{}; |
1853 | } |
1854 | |
1855 | return result.value(); |
1856 | @@ -224,7 +223,7 @@ |
1857 | { |
1858 | path, |
1859 | proxy, |
1860 | - access_service()->object_for_path(path) |
1861 | + service->object_for_path(path) |
1862 | }); |
1863 | |
1864 | return query; |
1865 | @@ -232,6 +231,7 @@ |
1866 | |
1867 | std::shared_ptr<core::dbus::Bus> bus; |
1868 | std::thread worker; |
1869 | + std::shared_ptr<dbus::Service> service; |
1870 | std::shared_ptr<dbus::Object> proxy; |
1871 | }; |
1872 | } |
1873 | @@ -242,10 +242,16 @@ |
1874 | const std::string& name) |
1875 | { |
1876 | if (name.empty()) |
1877 | - throw Error::ServiceNameMustNotBeEmpty{}; |
1878 | + throw Errors::ServiceNameMustNotBeEmpty{}; |
1879 | |
1880 | - core::trust::dbus::Store::mutable_name() = "com.ubuntu.trust.store." + name; |
1881 | - return std::shared_ptr<core::trust::Store>{new detail::Store(bus)}; |
1882 | + return std::shared_ptr<core::trust::Store> |
1883 | + { |
1884 | + new detail::Store |
1885 | + { |
1886 | + core::dbus::Service::use_service(bus, "com.ubuntu.trust.store." + name), |
1887 | + bus |
1888 | + } |
1889 | + }; |
1890 | } |
1891 | |
1892 | std::shared_ptr<core::trust::Store> core::trust::resolve_store_in_session_with_name( |
1893 | |
1894 | === modified file 'tests/CMakeLists.txt' |
1895 | --- tests/CMakeLists.txt 2014-07-16 06:59:46 +0000 |
1896 | +++ tests/CMakeLists.txt 2014-07-17 18:44:56 +0000 |
1897 | @@ -1,20 +1,24 @@ |
1898 | -set (OLD_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) |
1899 | -# Don't treat warnings as errors in 3rd_party/{gmock,cucumber-cpp} |
1900 | -string (REPLACE " -Werror " " " CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) |
1901 | -find_package(Gtest REQUIRED) |
1902 | -include_directories( |
1903 | - ${GMOCK_INCLUDE_DIR} |
1904 | - ${GTEST_INCLUDE_DIR} |
1905 | -) |
1906 | -set (CMAKE_CXX_FLAGS ${OLD_CMAKE_CXX_FLAGS}) |
1907 | +include_directories(${CMAKE_BINARY_DIR}/src) |
1908 | + |
1909 | +# Build with system gmock and embedded gtest |
1910 | +set (GMOCK_INCLUDE_DIR "/usr/include/gmock/include" CACHE PATH "gmock source include directory") |
1911 | +set (GMOCK_SOURCE_DIR "/usr/src/gmock" CACHE PATH "gmock source directory") |
1912 | +set (GTEST_INCLUDE_DIR "${GMOCK_SOURCE_DIR}/gtest/include" CACHE PATH "gtest source include directory") |
1913 | + |
1914 | +add_subdirectory(${GMOCK_SOURCE_DIR} "${CMAKE_CURRENT_BINARY_DIR}/gmock") |
1915 | |
1916 | pkg_check_modules(DBUS dbus-1) |
1917 | |
1918 | add_definitions(-DCORE_DBUS_ENABLE_GOOGLE_TEST_FIXTURE) |
1919 | |
1920 | +configure_file(test_data.h.in test_data.h @ONLY) |
1921 | + |
1922 | include_directories( |
1923 | + ${CMAKE_SOURCE_DIR}/src |
1924 | + |
1925 | ${CMAKE_CURRENT_BINARY_DIR} |
1926 | - ${GTEST_INCLUDE_DIRS} |
1927 | + ${GMOCK_INCLUDE_DIR} |
1928 | + ${GTEST_INCLUDE_DIR} |
1929 | ${PROCESS_CPP_INCLUDE_DIRS} |
1930 | ${DBUS_INCLUDE_DIRS} |
1931 | ) |
1932 | @@ -29,12 +33,25 @@ |
1933 | remote_trust_store_test.cpp |
1934 | ) |
1935 | |
1936 | +add_executable( |
1937 | + request_processor_test |
1938 | + request_processor_test.cpp |
1939 | +) |
1940 | + |
1941 | +add_executable( |
1942 | + mir_agent_test |
1943 | + mir_agent_test.cpp |
1944 | +) |
1945 | + |
1946 | target_link_libraries( |
1947 | trust_store_test |
1948 | |
1949 | trust-store |
1950 | |
1951 | - ${GTEST_BOTH_LIBRARIES} |
1952 | + gmock |
1953 | + |
1954 | + gtest |
1955 | + gtest_main |
1956 | ) |
1957 | |
1958 | target_link_libraries( |
1959 | @@ -42,9 +59,46 @@ |
1960 | |
1961 | trust-store |
1962 | |
1963 | - ${GTEST_BOTH_LIBRARIES} |
1964 | + gmock |
1965 | + |
1966 | + gtest |
1967 | + gtest_main |
1968 | + |
1969 | + ${PROCESS_CPP_LIBRARIES} |
1970 | +) |
1971 | + |
1972 | +target_link_libraries( |
1973 | + request_processor_test |
1974 | + |
1975 | + trust-store |
1976 | + |
1977 | + gmock |
1978 | + |
1979 | + gtest |
1980 | + gtest_main |
1981 | + |
1982 | + ${PROCESS_CPP_LIBRARIES} |
1983 | +) |
1984 | + |
1985 | +target_link_libraries( |
1986 | + mir_agent_test |
1987 | + |
1988 | + trust-store |
1989 | + |
1990 | + gmock |
1991 | + |
1992 | + gtest |
1993 | + gtest_main |
1994 | + |
1995 | ${PROCESS_CPP_LIBRARIES} |
1996 | ) |
1997 | |
1998 | add_test(trust_store_test ${CMAKE_CURRENT_BINARY_DIR}/trust_store_test) |
1999 | add_test(remote_trust_store_test ${CMAKE_CURRENT_BINARY_DIR}/remote_trust_store_test) |
2000 | +add_test(request_processor_test ${CMAKE_CURRENT_BINARY_DIR}/request_processor_test) |
2001 | +add_test(mir_agent_test ${CMAKE_CURRENT_BINARY_DIR}/mir_agent_test --gtest_filter=*-*requires_mir) |
2002 | + |
2003 | +install( |
2004 | + TARGETS trust_store_test remote_trust_store_test request_processor_test mir_agent_test |
2005 | + RUNTIME DESTINATION bin/trust-store-tests |
2006 | +) |
2007 | |
2008 | === added file 'tests/mir_agent_test.cpp' |
2009 | --- tests/mir_agent_test.cpp 1970-01-01 00:00:00 +0000 |
2010 | +++ tests/mir_agent_test.cpp 2014-07-17 18:44:56 +0000 |
2011 | @@ -0,0 +1,420 @@ |
2012 | +/* |
2013 | + * Copyright © 2013 Canonical Ltd. |
2014 | + * |
2015 | + * This program is free software: you can redistribute it and/or modify it |
2016 | + * under the terms of the GNU Lesser General Public License version 3, |
2017 | + * as published by the Free Software Foundation. |
2018 | + * |
2019 | + * This program is distributed in the hope that it will be useful, |
2020 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2021 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2022 | + * GNU Lesser General Public License for more details. |
2023 | + * |
2024 | + * You should have received a copy of the GNU Lesser General Public License |
2025 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2026 | + * |
2027 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
2028 | + */ |
2029 | + |
2030 | +// Implementation-specific header |
2031 | +#include <core/trust/mir/agent.h> |
2032 | +#include <core/trust/mir/config.h> |
2033 | + |
2034 | +#include <core/trust/agent.h> |
2035 | +#include <core/trust/request.h> |
2036 | +#include <core/trust/store.h> |
2037 | + |
2038 | +#include "test_data.h" |
2039 | + |
2040 | +#include <core/posix/fork.h> |
2041 | + |
2042 | +#include <gmock/gmock.h> |
2043 | +#include <gtest/gtest.h> |
2044 | + |
2045 | +#include <random> |
2046 | +#include <thread> |
2047 | + |
2048 | +namespace |
2049 | +{ |
2050 | +struct MockPromptSessionVirtualTable : public core::trust::mir::PromptSessionVirtualTable |
2051 | +{ |
2052 | + MockPromptSessionVirtualTable() : core::trust::mir::PromptSessionVirtualTable{nullptr} |
2053 | + { |
2054 | + } |
2055 | + |
2056 | + // Requests a new, pre-authenticated fd for associating prompt providers. |
2057 | + // Returns the fd or throws std::runtime_error. |
2058 | + MOCK_METHOD0(new_fd_for_prompt_provider, int()); |
2059 | + |
2060 | + // Adds a prompt provider process to the prompting session, identified by its PID. |
2061 | + // Returns true if addition of the prompt provider succeeded. |
2062 | + MOCK_METHOD1(add_prompt_provider_sync, bool(pid_t)); |
2063 | + |
2064 | + // Finalizes and releases the given prompt session instance. |
2065 | + MOCK_METHOD0(release_sync, void()); |
2066 | +}; |
2067 | + |
2068 | +struct MockConnectionVirtualTable : public core::trust::mir::ConnectionVirtualTable |
2069 | +{ |
2070 | + MockConnectionVirtualTable() : core::trust::mir::ConnectionVirtualTable{nullptr} |
2071 | + { |
2072 | + } |
2073 | + |
2074 | + // Creates a new trusted prompt session instance synchronously. |
2075 | + MOCK_METHOD3(create_prompt_session_sync, |
2076 | + core::trust::mir::PromptSessionVirtualTable::Ptr( |
2077 | + // The process id of the requesting app/service |
2078 | + pid_t app_pid, |
2079 | + // Callback handling prompt session state changes. |
2080 | + mir_prompt_session_state_change_callback, |
2081 | + // Callback context |
2082 | + void*)); |
2083 | +}; |
2084 | + |
2085 | +struct MockPromptProviderHelper : public core::trust::mir::PromptProviderHelper |
2086 | +{ |
2087 | + MockPromptProviderHelper(const core::trust::mir::PromptProviderHelper::CreationArguments& args) |
2088 | + : core::trust::mir::PromptProviderHelper{args} |
2089 | + { |
2090 | + using namespace ::testing; |
2091 | + ON_CALL(*this, exec_prompt_provider_with_arguments(_)) |
2092 | + .WillByDefault( |
2093 | + Invoke(this, &MockPromptProviderHelper::super_exec_prompt_provider_with_arguments)); |
2094 | + } |
2095 | + |
2096 | + // Execs the executable provided at construction time for the arguments and |
2097 | + // returns the corresponding child process. |
2098 | + MOCK_METHOD1(exec_prompt_provider_with_arguments, |
2099 | + core::posix::ChildProcess( |
2100 | + const core::trust::mir::PromptProviderHelper::InvocationArguments&)); |
2101 | + |
2102 | + core::posix::ChildProcess super_exec_prompt_provider_with_arguments(const core::trust::mir::PromptProviderHelper::InvocationArguments& args) |
2103 | + { |
2104 | + return core::trust::mir::PromptProviderHelper::exec_prompt_provider_with_arguments(args); |
2105 | + } |
2106 | +}; |
2107 | + |
2108 | +struct MockTranslator |
2109 | +{ |
2110 | + MOCK_METHOD1(translate, core::trust::Request::Answer(const core::posix::wait::Result&)); |
2111 | +}; |
2112 | + |
2113 | +std::shared_ptr<MockPromptSessionVirtualTable> a_mocked_prompt_session_vtable() |
2114 | +{ |
2115 | + return std::make_shared<testing::NiceMock<MockPromptSessionVirtualTable>>(); |
2116 | +} |
2117 | + |
2118 | +std::shared_ptr<MockPromptProviderHelper> a_mocked_prompt_provider_calling_bin_false() |
2119 | +{ |
2120 | + return std::make_shared<MockPromptProviderHelper>( |
2121 | + core::trust::mir::PromptProviderHelper::CreationArguments |
2122 | + { |
2123 | + "/bin/false" |
2124 | + }); |
2125 | +} |
2126 | +} |
2127 | + |
2128 | +TEST(DefaultProcessStateTranslator, throws_for_signalled_process) |
2129 | +{ |
2130 | + core::posix::wait::Result result; |
2131 | + result.status = core::posix::wait::Result::Status::signaled; |
2132 | + result.detail.if_signaled.signal = core::posix::Signal::sig_kill; |
2133 | + result.detail.if_signaled.core_dumped = true; |
2134 | + |
2135 | + auto translator = core::trust::mir::Agent::translator_only_accepting_exit_status_success(); |
2136 | + EXPECT_THROW(translator(result), std::logic_error); |
2137 | +} |
2138 | + |
2139 | +TEST(DefaultProcessStateTranslator, throws_for_stopped_process) |
2140 | +{ |
2141 | + core::posix::wait::Result result; |
2142 | + result.status = core::posix::wait::Result::Status::stopped; |
2143 | + result.detail.if_stopped.signal = core::posix::Signal::sig_stop; |
2144 | + |
2145 | + auto translator = core::trust::mir::Agent::translator_only_accepting_exit_status_success(); |
2146 | + EXPECT_THROW(translator(result), std::logic_error); |
2147 | +} |
2148 | + |
2149 | +TEST(DefaultProcessStateTranslator, returns_denied_for_process_exiting_with_failure) |
2150 | +{ |
2151 | + core::posix::wait::Result result; |
2152 | + result.status = core::posix::wait::Result::Status::exited; |
2153 | + result.detail.if_exited.status = core::posix::exit::Status::failure; |
2154 | + |
2155 | + auto translator = core::trust::mir::Agent::translator_only_accepting_exit_status_success(); |
2156 | + EXPECT_EQ(core::trust::Request::Answer::denied, translator(result)); |
2157 | +} |
2158 | + |
2159 | +TEST(DefaultProcessStateTranslator, returns_granted_for_process_exiting_successfully) |
2160 | +{ |
2161 | + core::posix::wait::Result result; |
2162 | + result.status = core::posix::wait::Result::Status::exited; |
2163 | + result.detail.if_exited.status = core::posix::exit::Status::success; |
2164 | + |
2165 | + auto translator = core::trust::mir::Agent::translator_only_accepting_exit_status_success(); |
2166 | + EXPECT_EQ(core::trust::Request::Answer::granted, translator(result)); |
2167 | +} |
2168 | + |
2169 | +TEST(DefaultPromptProviderHelper, correctly_passes_arguments_to_prompt_executable) |
2170 | +{ |
2171 | + core::posix::this_process::env::set_or_throw("CORE_TRUST_MIR_PROMPT_TESTING", "1"); |
2172 | + |
2173 | + core::trust::mir::PromptProviderHelper::CreationArguments cargs |
2174 | + { |
2175 | + core::trust::mir::trust_prompt_executable_in_build_dir |
2176 | + }; |
2177 | + |
2178 | + core::trust::mir::PromptProviderHelper::InvocationArguments iargs |
2179 | + { |
2180 | + 42, |
2181 | + "does.not.exist.application", |
2182 | + "Just an extended description" |
2183 | + }; |
2184 | + |
2185 | + core::trust::mir::PromptProviderHelper helper{cargs}; |
2186 | + auto child = helper.exec_prompt_provider_with_arguments(iargs); |
2187 | + |
2188 | + auto result = child.wait_for(core::posix::wait::Flags::untraced); |
2189 | + |
2190 | + EXPECT_EQ(core::posix::wait::Result::Status::exited, result.status); |
2191 | + EXPECT_EQ(core::posix::exit::Status::success, result.detail.if_exited.status); |
2192 | + |
2193 | + // And clean up. |
2194 | + core::posix::this_process::env::unset_or_throw("CORE_TRUST_MIR_PROMPT_TESTING"); |
2195 | +} |
2196 | + |
2197 | +TEST(MirAgent, creates_prompt_session_and_execs_helper_with_preauthenticated_fd) |
2198 | +{ |
2199 | + using namespace ::testing; |
2200 | + |
2201 | + const pid_t app_pid {21}; |
2202 | + const std::string app_id {"does.not.exist.application"}; |
2203 | + const std::string app_description {"This is just an extended description"}; |
2204 | + const int pre_authenticated_fd {42}; |
2205 | + |
2206 | + const core::trust::mir::PromptProviderHelper::InvocationArguments reference_invocation_args |
2207 | + { |
2208 | + pre_authenticated_fd, |
2209 | + app_id, |
2210 | + app_description |
2211 | + }; |
2212 | + |
2213 | + auto connection_vtable = std::make_shared<MockConnectionVirtualTable>(); |
2214 | + auto prompt_session_vtable = a_mocked_prompt_session_vtable(); |
2215 | + |
2216 | + auto prompt_provider_exec_helper = a_mocked_prompt_provider_calling_bin_false(); |
2217 | + |
2218 | + ON_CALL(*connection_vtable, create_prompt_session_sync(_, _, _)) |
2219 | + .WillByDefault(Return(prompt_session_vtable)); |
2220 | + |
2221 | + ON_CALL(*prompt_session_vtable, new_fd_for_prompt_provider()) |
2222 | + .WillByDefault(Return(pre_authenticated_fd)); |
2223 | + |
2224 | + ON_CALL(*prompt_session_vtable, add_prompt_provider_sync(_)) |
2225 | + .WillByDefault(Return(true)); |
2226 | + |
2227 | + EXPECT_CALL(*connection_vtable, create_prompt_session_sync(app_pid, _, _)).Times(1); |
2228 | + EXPECT_CALL(*prompt_session_vtable, new_fd_for_prompt_provider()).Times(1); |
2229 | + EXPECT_CALL(*prompt_provider_exec_helper, |
2230 | + exec_prompt_provider_with_arguments( |
2231 | + reference_invocation_args)).Times(1); |
2232 | + |
2233 | + core::trust::mir::Agent agent |
2234 | + { |
2235 | + connection_vtable, |
2236 | + prompt_provider_exec_helper, |
2237 | + core::trust::mir::Agent::translator_only_accepting_exit_status_success() |
2238 | + }; |
2239 | + |
2240 | + EXPECT_EQ(core::trust::Request::Answer::denied, // /bin/false exits with failure. |
2241 | + agent.prompt_user_for_request(app_pid, app_id, app_description)); |
2242 | +} |
2243 | + |
2244 | +TEST(MirAgent, sig_kills_prompt_provider_process_on_status_change) |
2245 | +{ |
2246 | + using namespace ::testing; |
2247 | + |
2248 | + const pid_t app_pid {21}; |
2249 | + const std::string app_id {"does.not.exist.application"}; |
2250 | + const std::string app_description {"This is just an extended description"}; |
2251 | + const int pre_authenticated_fd {42}; |
2252 | + |
2253 | + auto a_spinning_process = []() |
2254 | + { |
2255 | + while (true) |
2256 | + { |
2257 | + std::this_thread::sleep_for(std::chrono::milliseconds{20}); |
2258 | + } |
2259 | + return core::posix::exit::Status::success; |
2260 | + }; |
2261 | + |
2262 | + auto connection_vtable = std::make_shared<MockConnectionVirtualTable>(); |
2263 | + auto prompt_session_vtable = a_mocked_prompt_session_vtable(); |
2264 | + |
2265 | + auto prompt_provider_helper = std::make_shared<MockPromptProviderHelper>( |
2266 | + core::trust::mir::PromptProviderHelper::CreationArguments{"/bin/false"}); |
2267 | + |
2268 | + void* prompt_session_state_callback_context{nullptr}; |
2269 | + |
2270 | + ON_CALL(*prompt_provider_helper, exec_prompt_provider_with_arguments(_)) |
2271 | + .WillByDefault( |
2272 | + Return( |
2273 | + core::posix::fork( |
2274 | + a_spinning_process, |
2275 | + core::posix::StandardStream::empty))); |
2276 | + |
2277 | + ON_CALL(*prompt_session_vtable, new_fd_for_prompt_provider()) |
2278 | + .WillByDefault( |
2279 | + Return( |
2280 | + pre_authenticated_fd)); |
2281 | + |
2282 | + ON_CALL(*prompt_session_vtable, add_prompt_provider_sync(_)) |
2283 | + .WillByDefault( |
2284 | + Return( |
2285 | + true)); |
2286 | + |
2287 | + // An invocation results in a session being created. In addition, |
2288 | + // we store pointers to callback and context provided by the implementation |
2289 | + // for being able to later trigger the callback. |
2290 | + ON_CALL(*connection_vtable, create_prompt_session_sync(app_pid, _, _)) |
2291 | + .WillByDefault( |
2292 | + DoAll( |
2293 | + SaveArg<2>(&prompt_session_state_callback_context), |
2294 | + Return(prompt_session_vtable))); |
2295 | + |
2296 | + core::trust::mir::Agent agent |
2297 | + { |
2298 | + connection_vtable, |
2299 | + prompt_provider_helper, |
2300 | + core::trust::mir::Agent::translator_only_accepting_exit_status_success() |
2301 | + }; |
2302 | + |
2303 | + std::thread asynchronously_stop_the_prompting_session |
2304 | + { |
2305 | + [&prompt_session_state_callback_context]() |
2306 | + { |
2307 | + std::this_thread::sleep_for(std::chrono::seconds{1}); |
2308 | + |
2309 | + core::trust::mir::Agent::on_trust_session_changed_state( |
2310 | + nullptr, |
2311 | + mir_prompt_session_state_stopped, |
2312 | + prompt_session_state_callback_context); |
2313 | + } |
2314 | + }; |
2315 | + |
2316 | + // The spinning prompt provider should get signalled if the prompting session is stopped. |
2317 | + // If that does not happen, the prompt provider returns success and we would have a result |
2318 | + // granted. |
2319 | + EXPECT_THROW(agent.prompt_user_for_request(app_pid, app_id, app_description), |
2320 | + std::logic_error); |
2321 | + |
2322 | + // And some clean up. |
2323 | + if (asynchronously_stop_the_prompting_session.joinable()) |
2324 | + asynchronously_stop_the_prompting_session.join(); |
2325 | +} |
2326 | + |
2327 | +TEST(TrustPrompt, aborts_for_missing_title) |
2328 | +{ |
2329 | + // And we pass in an empty argument vector |
2330 | + std::vector<std::string> argv; |
2331 | + |
2332 | + // We pass in the empty env |
2333 | + std::map<std::string, std::string> env; |
2334 | + |
2335 | + auto child = core::posix::exec( |
2336 | + core::trust::testing::trust_prompt_executable_in_build_dir, |
2337 | + argv, |
2338 | + env, |
2339 | + core::posix::StandardStream::empty); |
2340 | + |
2341 | + auto result = child.wait_for(core::posix::wait::Flags::untraced); |
2342 | + |
2343 | + EXPECT_EQ(core::posix::wait::Result::Status::signaled, result.status); |
2344 | + EXPECT_EQ(core::posix::Signal::sig_abrt, result.detail.if_signaled.signal); |
2345 | +} |
2346 | + |
2347 | +/*********************************************************************** |
2348 | +* All tests requiring a running Mir instance go here. * |
2349 | +* They are tagged with _requires_mir and taken out of the * |
2350 | +* automatic build and test cycle. * |
2351 | +***********************************************************************/ |
2352 | + |
2353 | +#include <core/trust/mir_agent.h> |
2354 | + |
2355 | +#include <core/trust/mir/config.h> |
2356 | +#include <core/trust/mir/prompt_main.h> |
2357 | + |
2358 | +namespace |
2359 | +{ |
2360 | +std::map<std::string, std::string> a_copy_of_the_env() |
2361 | +{ |
2362 | + std::map<std::string, std::string> result; |
2363 | + core::posix::this_process::env::for_each([&result](const std::string& key, const std::string& value) |
2364 | + { |
2365 | + result.insert(std::make_pair(key, value)) ; |
2366 | + }); |
2367 | + return result; |
2368 | +} |
2369 | + |
2370 | +std::string mir_socket() |
2371 | +{ |
2372 | + // We either take the XDG_RUNTIME_DIR or fall back to /tmp if XDG_RUNTIME_DIR is not set. |
2373 | + std::string dir = core::posix::this_process::env::get("XDG_RUNTIME_DIR", "/tmp"); |
2374 | + return dir + "/mir_socket"; |
2375 | +} |
2376 | + |
2377 | +std::string trusted_mir_socket() |
2378 | +{ |
2379 | + // We either take the XDG_RUNTIME_DIR or fall back to /tmp if XDG_RUNTIME_DIR is not set. |
2380 | + std::string dir = core::posix::this_process::env::get("XDG_RUNTIME_DIR", "/tmp"); |
2381 | + return dir + "/mir_socket_trusted"; |
2382 | +} |
2383 | +} |
2384 | + |
2385 | +TEST(MirAgent, default_agent_works_correctly_against_running_mir_instance_requires_mir) |
2386 | +{ |
2387 | + std::string pretty_function{__PRETTY_FUNCTION__}; |
2388 | + |
2389 | + // We start up an application in a child process and simulate that it is requesting access |
2390 | + // to a trusted system service/resource. |
2391 | + std::vector<std::string> argv |
2392 | + { |
2393 | + "--" + std::string{core::trust::mir::cli::option_server_socket} + "=" + mir_socket(), |
2394 | + "--" + std::string{core::trust::mir::cli::option_title} + "=" + pretty_function, |
2395 | + "--" + std::string{core::trust::mir::cli::option_description} + "=" + pretty_function, |
2396 | + // We have to circumvent unity8's authentication mechanism and just provide |
2397 | + // the desktop_file_hint as part of the command line. |
2398 | + "--desktop_file_hint=/usr/share/applications/webbrowser-app.desktop" |
2399 | + }; |
2400 | + |
2401 | + core::posix::ChildProcess app = core::posix::exec( |
2402 | + core::trust::mir::trust_prompt_executable_in_lib_dir, |
2403 | + argv, |
2404 | + a_copy_of_the_env(), |
2405 | + core::posix::StandardStream::empty); |
2406 | + |
2407 | + // We give the app some time to come up. |
2408 | + std::this_thread::sleep_for(std::chrono::seconds{5}); |
2409 | + |
2410 | + // We pretend to be a trusted helper and connect to mir via its trusted socket. |
2411 | + auto mir_connection = mir_connect_sync(trusted_mir_socket().c_str(), pretty_function.c_str()); |
2412 | + |
2413 | + // Based on the mir connection, we create a prompting agent. |
2414 | + auto mir_agent = core::trust::mir::create_agent_for_mir_connection(mir_connection); |
2415 | + |
2416 | + // And issue a prompt request. As a result, the user is presented with a prompting dialog. |
2417 | + auto answer = mir_agent->prompt_user_for_request(app.pid(), "embedded prompt", "embedded prompt"); |
2418 | + |
2419 | + // And we cross-check with the user: |
2420 | + std::cout << "You answered the trust prompt with: " << answer << "." |
2421 | + << "Is that correct? [y/n]:"; |
2422 | + |
2423 | + char y_or_n{'n'}; std::cin >> y_or_n; |
2424 | + EXPECT_EQ('y', y_or_n); |
2425 | + |
2426 | + // We are bit rude here, but we have no more use for the app. |
2427 | + app.send_signal_or_throw(core::posix::Signal::sig_kill); |
2428 | + |
2429 | + // And wait for the app to complete to avoid zombies. |
2430 | + app.wait_for(core::posix::wait::Flags::untraced); |
2431 | +} |
2432 | |
2433 | === added file 'tests/request_processor_test.cpp' |
2434 | --- tests/request_processor_test.cpp 1970-01-01 00:00:00 +0000 |
2435 | +++ tests/request_processor_test.cpp 2014-07-17 18:44:56 +0000 |
2436 | @@ -0,0 +1,287 @@ |
2437 | +/* |
2438 | + * Copyright © 2013 Canonical Ltd. |
2439 | + * |
2440 | + * This program is free software: you can redistribute it and/or modify it |
2441 | + * under the terms of the GNU Lesser General Public License version 3, |
2442 | + * as published by the Free Software Foundation. |
2443 | + * |
2444 | + * This program is distributed in the hope that it will be useful, |
2445 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2446 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2447 | + * GNU Lesser General Public License for more details. |
2448 | + * |
2449 | + * You should have received a copy of the GNU Lesser General Public License |
2450 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2451 | + * |
2452 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
2453 | + */ |
2454 | + |
2455 | +#include <core/trust/agent.h> |
2456 | +#include <core/trust/request.h> |
2457 | +#include <core/trust/store.h> |
2458 | + |
2459 | +#include <gmock/gmock.h> |
2460 | +#include <gtest/gtest.h> |
2461 | + |
2462 | +#include <random> |
2463 | + |
2464 | +namespace |
2465 | +{ |
2466 | +struct MockAgent : public core::trust::Agent |
2467 | +{ |
2468 | + /** |
2469 | + * @brief Presents the given request to the user, returning the user-provided answer. |
2470 | + * @param request The trust request that a user has to answer. |
2471 | + * @param description Extended description of the trust request. |
2472 | + */ |
2473 | + MOCK_METHOD3(prompt_user_for_request, core::trust::Request::Answer(pid_t, const std::string&, const std::string&)); |
2474 | +}; |
2475 | + |
2476 | +struct MockStore : public core::trust::Store |
2477 | +{ |
2478 | + struct MockQuery : public core::trust::Store::Query |
2479 | + { |
2480 | + /** @brief Access the status of the query. */ |
2481 | + MOCK_CONST_METHOD0(status, core::trust::Store::Query::Status()); |
2482 | + |
2483 | + /** @brief Limit the query to a specific application Id. */ |
2484 | + MOCK_METHOD1(for_application_id, void(const std::string&)); |
2485 | + |
2486 | + /** @brief Limit the query to a service-specific feature. */ |
2487 | + MOCK_METHOD1(for_feature, void(std::uint64_t)); |
2488 | + |
2489 | + /** @brief Limit the query to the specified time interval. */ |
2490 | + MOCK_METHOD2(for_interval, void(const core::trust::Request::Timestamp&, const core::trust::Request::Timestamp&)); |
2491 | + |
2492 | + /** @brief Limit the query for a specific answer. */ |
2493 | + MOCK_METHOD1(for_answer, void(core::trust::Request::Answer)); |
2494 | + |
2495 | + /** @brief Query all stored requests. */ |
2496 | + MOCK_METHOD0(all, void()); |
2497 | + |
2498 | + /** @brief Execute the query against the store. */ |
2499 | + MOCK_METHOD0(execute, void()); |
2500 | + |
2501 | + /** @brief After successful execution, advance to the next request. */ |
2502 | + MOCK_METHOD0(next, void()); |
2503 | + |
2504 | + /** @brief After successful execution, erase the current element and advance to the next request. */ |
2505 | + MOCK_METHOD0(erase, void()); |
2506 | + |
2507 | + /** @brief Access the request the query currently points to. */ |
2508 | + MOCK_METHOD0(current, core::trust::Request()); |
2509 | + }; |
2510 | + |
2511 | + /** @brief Resets the state of the store, implementations should discard |
2512 | + * all persistent and non-persistent state. |
2513 | + */ |
2514 | + MOCK_METHOD0(reset, void()); |
2515 | + |
2516 | + /** @brief Add the provided request to the store. When this function returns true, |
2517 | + * the request has been persisted by the implementation. |
2518 | + */ |
2519 | + MOCK_METHOD1(add, void(const core::trust::Request&)); |
2520 | + |
2521 | + /** |
2522 | + * @brief Create a query for this store. |
2523 | + */ |
2524 | + MOCK_METHOD0(query, std::shared_ptr<core::trust::Store::Query>()); |
2525 | +}; |
2526 | + |
2527 | +pid_t the_default_pid_for_testing() |
2528 | +{ |
2529 | + return 42; |
2530 | +} |
2531 | + |
2532 | +std::uint64_t the_default_feature_for_testing() |
2533 | +{ |
2534 | + return 0; |
2535 | +} |
2536 | + |
2537 | +std::shared_ptr<core::trust::Agent> a_null_agent() |
2538 | +{ |
2539 | + return std::shared_ptr<core::trust::Agent>{}; |
2540 | +} |
2541 | + |
2542 | +std::shared_ptr<testing::NiceMock<MockAgent>> a_mocked_agent() |
2543 | +{ |
2544 | + return std::make_shared<testing::NiceMock<MockAgent>>(); |
2545 | +} |
2546 | + |
2547 | +std::shared_ptr<core::trust::Store> a_null_store() |
2548 | +{ |
2549 | + return std::shared_ptr<core::trust::Store>{}; |
2550 | +} |
2551 | + |
2552 | +std::shared_ptr<testing::NiceMock<MockStore>> a_mocked_store() |
2553 | +{ |
2554 | + return std::make_shared<testing::NiceMock<MockStore>>(); |
2555 | +} |
2556 | + |
2557 | +std::shared_ptr<core::trust::Store::Query> a_null_query() |
2558 | +{ |
2559 | + return std::shared_ptr<core::trust::Store::Query>{}; |
2560 | +} |
2561 | + |
2562 | +std::shared_ptr<testing::NiceMock<MockStore::MockQuery>> a_mocked_query() |
2563 | +{ |
2564 | + return std::make_shared<testing::NiceMock<MockStore::MockQuery>>(); |
2565 | +} |
2566 | + |
2567 | +core::trust::RequestParameters default_request_parameters_for_testing() |
2568 | +{ |
2569 | + return core::trust::RequestParameters |
2570 | + { |
2571 | + a_null_agent(), |
2572 | + a_null_store(), |
2573 | + the_default_pid_for_testing(), |
2574 | + "this.is.just.for.testing.purposes", |
2575 | + the_default_feature_for_testing(), |
2576 | + "Someone wants to access all your credentials and steal your identity." |
2577 | + }; |
2578 | +} |
2579 | + |
2580 | +core::trust::Request::Answer throw_a_dice() |
2581 | +{ |
2582 | + // We seed the rng with the current time to ensure randomness across test runs. |
2583 | + static std::default_random_engine generator |
2584 | + { |
2585 | + static_cast<long unsigned int>(std::chrono::system_clock::now().time_since_epoch().count()) |
2586 | + }; |
2587 | + // Our dice :) |
2588 | + static std::uniform_int_distribution<int> distribution |
2589 | + { |
2590 | + 1, |
2591 | + 6 |
2592 | + }; |
2593 | + |
2594 | + return distribution(generator) <= 3 ? |
2595 | + core::trust::Request::Answer::denied : |
2596 | + core::trust::Request::Answer::granted; |
2597 | +} |
2598 | + |
2599 | +} |
2600 | + |
2601 | +TEST(RequestProcessing, throws_for_missing_agent_implementation) |
2602 | +{ |
2603 | + auto params = default_request_parameters_for_testing(); |
2604 | + |
2605 | + params.store = a_mocked_store(); |
2606 | + |
2607 | + EXPECT_THROW(core::trust::process_trust_request(params), std::logic_error); |
2608 | +} |
2609 | + |
2610 | +TEST(RequestProcessing, throws_for_missing_store_implementation) |
2611 | +{ |
2612 | + auto params = default_request_parameters_for_testing(); |
2613 | + |
2614 | + params.agent = a_mocked_agent(); |
2615 | + |
2616 | + EXPECT_THROW(core::trust::process_trust_request(params), std::logic_error); |
2617 | +} |
2618 | + |
2619 | +TEST(RequestProcessing, queries_store_for_cached_results_and_returns_cached_value) |
2620 | +{ |
2621 | + using namespace ::testing; |
2622 | + |
2623 | + auto answer = throw_a_dice(); |
2624 | + |
2625 | + auto params = default_request_parameters_for_testing(); |
2626 | + |
2627 | + core::trust::Request request |
2628 | + { |
2629 | + params.application_id, |
2630 | + params.feature, |
2631 | + std::chrono::system_clock::now(), |
2632 | + answer |
2633 | + }; |
2634 | + |
2635 | + auto mocked_agent = a_mocked_agent(); |
2636 | + auto mocked_query = a_mocked_query(); |
2637 | + auto mocked_store = a_mocked_store(); |
2638 | + |
2639 | + ON_CALL(*mocked_query, status()) |
2640 | + .WillByDefault( |
2641 | + Return( |
2642 | + core::trust::Store::Query::Status::has_more_results)); |
2643 | + |
2644 | + ON_CALL(*mocked_query, current()) |
2645 | + .WillByDefault( |
2646 | + Return( |
2647 | + request)); |
2648 | + |
2649 | + ON_CALL(*mocked_store, query()) |
2650 | + .WillByDefault( |
2651 | + Return( |
2652 | + mocked_query)); |
2653 | + |
2654 | + EXPECT_CALL(*mocked_store, query()).Times(1); |
2655 | + // We expect the processor to limit the query to the respective application id |
2656 | + // and to the respective feature. |
2657 | + EXPECT_CALL(*mocked_query, for_application_id(params.application_id)).Times(1); |
2658 | + EXPECT_CALL(*mocked_query, for_feature(params.feature)).Times(1); |
2659 | + // The setup ensures that a previously stored answer is available in the store. |
2660 | + // For that, the agent should not be queried. |
2661 | + EXPECT_CALL(*mocked_agent, prompt_user_for_request(_, _, _)).Times(0); |
2662 | + |
2663 | + params.agent = mocked_agent; |
2664 | + params.store = mocked_store; |
2665 | + |
2666 | + EXPECT_EQ(answer, core::trust::process_trust_request(params)); |
2667 | +} |
2668 | + |
2669 | +TEST(RequestProcessing, queries_agent_if_no_cached_results_and_returns_users_answer) |
2670 | +{ |
2671 | + using namespace ::testing; |
2672 | + |
2673 | + auto answer = throw_a_dice(); |
2674 | + |
2675 | + auto params = default_request_parameters_for_testing(); |
2676 | + |
2677 | + core::trust::Request request |
2678 | + { |
2679 | + params.application_id, |
2680 | + params.feature, |
2681 | + std::chrono::system_clock::now(), |
2682 | + answer |
2683 | + }; |
2684 | + |
2685 | + auto mocked_agent = a_mocked_agent(); |
2686 | + auto mocked_query = a_mocked_query(); |
2687 | + auto mocked_store = a_mocked_store(); |
2688 | + |
2689 | + ON_CALL(*mocked_agent, prompt_user_for_request(params.application_pid, params.application_id, params.description)) |
2690 | + .WillByDefault( |
2691 | + Return( |
2692 | + answer)); |
2693 | + |
2694 | + // We return EndOfRecord for queries, and expect the request processor |
2695 | + // to subsequently ask the user for his answer. |
2696 | + ON_CALL(*mocked_query, status()) |
2697 | + .WillByDefault( |
2698 | + Return( |
2699 | + core::trust::Store::Query::Status::eor)); |
2700 | + |
2701 | + ON_CALL(*mocked_store, query()) |
2702 | + .WillByDefault( |
2703 | + Return( |
2704 | + mocked_query)); |
2705 | + |
2706 | + EXPECT_CALL(*mocked_query, current()).Times(0); |
2707 | + EXPECT_CALL(*mocked_store, query()).Times(1); |
2708 | + // We expect the processor to limit the query to the respective application id |
2709 | + // and to the respective feature. |
2710 | + EXPECT_CALL(*mocked_query, for_application_id(params.application_id)).Times(1); |
2711 | + EXPECT_CALL(*mocked_query, for_feature(params.feature)).Times(1); |
2712 | + // The setup ensures that a previously stored answer is available in the store. |
2713 | + // For that, the agent should not be queried. |
2714 | + EXPECT_CALL(*mocked_agent, prompt_user_for_request(params.application_pid, params.application_id, params.description)).Times(1); |
2715 | + |
2716 | + params.agent = mocked_agent; |
2717 | + params.store = mocked_store; |
2718 | + |
2719 | + EXPECT_EQ(answer, core::trust::process_trust_request(params)); |
2720 | +} |
2721 | + |
2722 | + |
2723 | + |
2724 | |
2725 | === modified file 'tests/test_data.h.in' |
2726 | --- tests/test_data.h.in 2014-05-06 11:32:13 +0000 |
2727 | +++ tests/test_data.h.in 2014-07-17 18:44:56 +0000 |
2728 | @@ -21,88 +21,14 @@ |
2729 | |
2730 | namespace core |
2731 | { |
2732 | +namespace trust |
2733 | +{ |
2734 | namespace testing |
2735 | { |
2736 | - |
2737 | -const char* session_bus_configuration_file() |
2738 | -{ |
2739 | - return "@CMAKE_SOURCE_DIR@/data/session.conf"; |
2740 | -} |
2741 | - |
2742 | -const char* system_bus_configuration_file() |
2743 | -{ |
2744 | - return "@CMAKE_SOURCE_DIR@/data/system.conf"; |
2745 | -} |
2746 | - |
2747 | -namespace com |
2748 | -{ |
2749 | -namespace canonical |
2750 | -{ |
2751 | -const char* user_metrics_introspection_file() |
2752 | -{ |
2753 | - return "@CMAKE_CURRENT_SOURCE_DIR@/data/com.canonical.UserMetrics.xml"; |
2754 | -} |
2755 | - |
2756 | -const char* url_dispatcher_introspection_file() |
2757 | -{ |
2758 | - return "@CMAKE_CURRENT_SOURCE_DIR@/data/com.canonical.URLDispatcher.xml"; |
2759 | -} |
2760 | -} |
2761 | -} |
2762 | - |
2763 | -namespace org |
2764 | -{ |
2765 | -namespace freedesktop |
2766 | -{ |
2767 | -namespace modem_manager |
2768 | -{ |
2769 | -namespace modem |
2770 | -{ |
2771 | -constexpr const char* cdma_introspection_file() |
2772 | -{ |
2773 | - return "@CMAKE_CURRENT_SOURCE_DIR@/data/org.freedesktop.ModemManager.Modem.Cdma.xml"; |
2774 | -} |
2775 | - |
2776 | -constexpr const char* firmware_introspection_file() |
2777 | -{ |
2778 | - return "@CMAKE_CURRENT_SOURCE_DIR@/data/org.freedesktop.ModemManager.Modem.Firmware.xml"; |
2779 | -} |
2780 | - |
2781 | -namespace gsm |
2782 | -{ |
2783 | -constexpr const char* card_introspection_file() |
2784 | -{ |
2785 | - return "@CMAKE_CURRENT_SOURCE_DIR@/data/org.freedesktop.ModemManager.Modem.Gsm.Card.xml"; |
2786 | -} |
2787 | - |
2788 | -constexpr const char* contact_introspection_file() |
2789 | -{ |
2790 | - return "@CMAKE_CURRENT_SOURCE_DIR@/data/org.freedesktop.ModemManager.Modem.Gsm.Contacts.xml"; |
2791 | -} |
2792 | - |
2793 | -constexpr const char* hso_introspection_file() |
2794 | -{ |
2795 | - return "@CMAKE_CURRENT_SOURCE_DIR@/data/org.freedesktop.ModemManager.Modem.Gsm.Hso.xml"; |
2796 | -} |
2797 | - |
2798 | -constexpr const char* network_introspection_file() |
2799 | -{ |
2800 | - return "@CMAKE_CURRENT_SOURCE_DIR@/data/org.freedesktop.ModemManager.Modem.Gsm.Network.xml"; |
2801 | -} |
2802 | - |
2803 | -constexpr const char* sms_introspection_file() |
2804 | -{ |
2805 | - return "@CMAKE_CURRENT_SOURCE_DIR@/data/org.freedesktop.ModemManager.Modem.Gsm.SMS.xml"; |
2806 | -} |
2807 | - |
2808 | -constexpr const char* ussd_introspection_file() |
2809 | -{ |
2810 | - return "@CMAKE_CURRENT_SOURCE_DIR@/data/org.freedesktop.ModemManager.Modem.Gsm.Ussd.xml"; |
2811 | -} |
2812 | -} |
2813 | -} |
2814 | -} |
2815 | -} |
2816 | +static constexpr const char* trust_prompt_executable_in_build_dir |
2817 | +{ |
2818 | + "@CMAKE_BINARY_DIR@/src/trust-prompt" |
2819 | +}; |
2820 | } |
2821 | } |
2822 | } |
Looks good to me, one comment inline. Thanks