policy: Add a deny-all policy as an example
[src/agl-compositor.git] / src / policy-deny.c
1 /*
2  * Copyright © 2020 Collabora, Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial
14  * portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25
26 #include "ivi-compositor.h"
27 #include "policy.h"
28
29 #ifdef HAVE_SMACK
30 #include <sys/smack.h>
31 #endif
32
33 #include <string.h>
34 #include "shared/helpers.h"
35
36
37 static const char *const applications_permitted[] = { "homescreen", "alexa-viewer",
38                                                      "launcher", "hvac",
39                                                      "navigation", "mediaplayer" };
40
41 /* helper start searches the applications_permitted for the
42  * app_id
43  */
44 static bool
45 ivi_policy_verify_permitted_app(const char *app_id)
46 {
47         for (size_t i = 0; i < ARRAY_LENGTH(applications_permitted); i++)
48                 if (strcmp(app_id, applications_permitted[i]) == 0)
49                         return true;
50
51         return false;
52 }
53
54 static bool
55 ivi_policy_verify_ivi_surface(struct ivi_surface *surf)
56 {
57         const char *app_id = weston_desktop_surface_get_app_id(surf->dsurface);
58         return ivi_policy_verify_permitted_app(app_id);
59 }
60
61 /*
62  * deny-all policy implementation allows every action to be denied
63  *
64  * This is an example, that implements the API
65  *
66  * For injecting rules back in the compositor one should use ivi_policy_add()
67  * - policy_rule_allow_to_add is required in order to add further policy rules
68  * - policy_rule_try_event will be callback executed when handling the state
69  *   change
70  */
71 static bool
72 ivi_policy_default_surface_create(struct ivi_surface *surf, void *user_data)
73 {
74         return ivi_policy_verify_ivi_surface(surf);
75 }
76
77 static bool
78 ivi_policy_default_surface_commmited(struct ivi_surface *surf, void *user_data)
79 {
80         return ivi_policy_verify_ivi_surface(surf);
81 }
82
83 static bool
84 ivi_policy_default_surface_activate(struct ivi_surface *surf, void *user_data)
85 {
86         return ivi_policy_verify_ivi_surface(surf);
87 }
88
89 static bool
90 ivi_policy_default_surface_deactivate(struct ivi_surface *surf, void *user_data)
91 {
92         return ivi_policy_verify_ivi_surface(surf);
93 }
94
95 static bool
96 ivi_policy_default_surface_activate_default(struct ivi_surface *surf, void *user_data)
97 {
98         return ivi_policy_verify_ivi_surface(surf);
99 }
100
101 static bool
102 ivi_policy_default_surface_advertise_state_change(struct ivi_surface *surf, void *user_data)
103 {
104         return ivi_policy_verify_ivi_surface(surf);
105 }
106
107 #ifdef HAVE_SMACK
108 static bool
109 ivi_policy_default_shell_bind_interface(void *client, void *interface)
110 {
111         struct wl_interface *shell_interface = interface;
112         struct wl_client *conn_client = client;
113
114         pid_t pid, uid, gid;
115         int client_fd;
116         char *label;
117         bool ret = false;
118
119         wl_client_get_credentials(conn_client, &pid, &uid, &gid);
120
121         client_fd = wl_client_get_fd(conn_client);
122         if (smack_new_label_from_socket(client_fd, &label) < 0) {
123                 return ret;
124         }
125
126         if (strcmp(shell_interface->name, "agl_shell") == 0)
127                 if (strcmp(label, "User::App::homescreen") == 0)
128                         ret = true;
129
130         if (strcmp(shell_interface->name, "agl_shell_desktop") == 0)
131                 if (strcmp(label, "User::App::launcher") == 0 ||
132                     strcmp(label, "User::App::alexa-viewer") == 0 ||
133                     strcmp(label, "User::App::tbtnavi") == 0 ||
134                     strcmp(label, "User::App::hvac") == 0)
135                         ret = true;
136
137         if (ret)
138                 weston_log("Client with pid %d, uid %d, gid %d, allowed "
139                                 "to bind to %s for label %s\n", pid, uid, gid,
140                                 shell_interface->name, label);
141
142         /* client responsible for free'ing */
143         free(label);
144         return ret;
145 }
146 #else
147 static bool
148 ivi_policy_default_shell_bind_interface(void *client, void *interface)
149 {
150         return false;
151 }
152 #endif
153
154 static bool
155 ivi_policy_default_allow_to_add(void *user_data)
156 {
157         /* verify that policy rules can be added with ivi_policy_add() */
158         return true;
159 }
160
161 /*
162  * Policy rules added by ivi_policy_add() will be handled by this callback, and
163  * should be treated depending on the event. Note this is just an example.
164  */
165 static void
166 ivi_policy_default_try_event(struct ivi_a_policy *a_policy)
167 {
168         uint32_t event = a_policy->event;
169
170         switch (event) {
171         case AGL_SHELL_POLICY_EVENT_SHOW:
172                 ivi_layout_activate(a_policy->output, a_policy->app_id);
173                 break;
174         case AGL_SHELL_POLICY_EVENT_HIDE:
175                 ivi_layout_deactivate(a_policy->policy->ivi, a_policy->app_id);
176         default:
177                 break;
178         }
179 }
180
181 static const struct ivi_policy_api policy_api = {
182         .struct_size = sizeof(policy_api),
183         .surface_create = ivi_policy_default_surface_create,
184         .surface_commited = ivi_policy_default_surface_commmited,
185         .surface_activate = ivi_policy_default_surface_activate,
186         .surface_deactivate = ivi_policy_default_surface_deactivate,
187         .surface_activate_by_default = ivi_policy_default_surface_activate_default,
188         .surface_advertise_state_change = ivi_policy_default_surface_advertise_state_change,
189         .shell_bind_interface = ivi_policy_default_shell_bind_interface,
190         .policy_rule_allow_to_add = ivi_policy_default_allow_to_add,
191         .policy_rule_try_event = ivi_policy_default_try_event,
192 };
193
194 int
195 ivi_policy_init(struct ivi_compositor *ivi)
196 {
197         ivi->policy = ivi_policy_create(ivi, &policy_api, ivi);
198         if (!ivi->policy)
199                 return -1;
200
201         weston_log("Installing 'deny-all' policy engine\n");
202         return 0;
203 }