2 * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
18 * @file privacy_privilege_manager.c
19 * @author Piotr Sawicki <p.sawicki2@partner.samsung.com>
21 * @brief This file contains test of CAPI for Privacy Privilege Manager
32 #include <attributes/attributes.h>
33 #include <askuser-notification/ask-user-client-channel.h>
34 #include <askuser-notification/ask-user-server-channel.h>
35 #include <askuser-notification/ask-user-types.h>
36 #include <privacy_privilege_manager.h>
38 using namespace AskUser::Protocol;
40 struct ServerPrivilegeRequest {
42 ServerPrivilegeRequest(RequestId reqId)
46 ServerPrivilegeRequest(RequestId reqId, const Privilege &privilege)
48 , m_privilege(privilege)
51 bool operator<(const ServerPrivilegeRequest &other) const {
52 return m_id < other.m_id;
56 Privilege m_privilege;
59 typedef std::set<ServerPrivilegeRequest> PrivilegeRequestSet;
61 struct ClientRequest {
63 Privilege m_privilege;
68 GIOChannel *gio_channel;
69 GIOCondition condition;
79 const GIOCondition GIO_ERROR_CONDITION = static_cast<GIOCondition>(G_IO_ERR | G_IO_HUP | G_IO_NVAL);
81 GIOCondition maskToGIOCondition(int mask)
83 int ret = (mask & FdMask::READ ? G_IO_IN : 0) |
84 (mask & FdMask::WRITE ? G_IO_OUT : 0);
85 return static_cast<GIOCondition>(ret);
88 GIOCondition makeCondition(GIOCondition condition)
90 return static_cast<GIOCondition>(condition | GIO_ERROR_CONDITION);
93 bool isErrorCondition(GIOCondition condition)
95 return !!(GIO_ERROR_CONDITION & condition);
98 void print_prompt(Mode mode)
116 struct ServerSimulator : public IServerCallbacks {
123 virtual void newConnection(ConnectionFd fd, const Credentials &creds) {
124 printf("\nnew connection fd: %d credentials = { label: \"%s\" uid: %s }",
125 fd, creds.label.c_str(), creds.uid.c_str());
128 static gboolean server_gio_cb(GIOChannel *src, GIOCondition cond, gpointer data)
130 ServerSimulator *handle = static_cast<ServerSimulator *>(data);
132 int fd = g_io_channel_unix_get_fd(src);
133 int events = (cond & G_IO_IN ? FdMask::READ : 0) |
134 (cond & G_IO_OUT ? FdMask::WRITE : 0);
136 handle->m_channel->process(fd, isErrorCondition(cond) ? 0 : events);
141 virtual void updateConnection(ConnectionFd fd, int mask) {
143 printf("ERROR: updateConnection() called with fd == -1\n");
147 GIOCondition gio_condition = maskToGIOCondition(mask);
149 auto it = m_connections.find(fd);
152 if (it == m_connections.end())
155 auto &connection = it->second;
157 g_source_remove(connection.watch_id);
158 g_io_channel_unref(connection.gio_channel);
160 m_connections.erase(fd);
161 m_requests.erase(fd);
163 printf("Connection for fd: %d has been closed\n", fd);
164 print_prompt(Mode::SERVER);
168 if (it == m_connections.end()) {
169 GIOChannel *gio_channel = g_io_channel_unix_new(fd);
171 g_io_channel_set_encoding (gio_channel, nullptr, nullptr);
172 g_io_channel_set_close_on_unref(gio_channel, FALSE);
174 guint watch_id = g_io_add_watch(gio_channel,
175 makeCondition(gio_condition),
179 m_connections.insert({ fd, Connection{gio_channel, gio_condition, watch_id }});
184 auto &connection = it->second;
186 if (connection.condition != gio_condition) {
187 connection.condition = gio_condition;
188 g_source_remove(connection.watch_id);
189 connection.watch_id = g_io_add_watch(connection.gio_channel,
190 makeCondition(connection.condition),
196 virtual void popup(ConnectionFd fd, RequestId id, Privilege &&privilege) {
197 printf("\npopup request fd: %d requestId: %d privilege: \"%s\"\n", fd, id, privilege.c_str());
198 addRequest(fd, id, privilege);
199 print_prompt(Mode::SERVER);
202 void addRequest(ConnectionFd fd, RequestId id, const Privilege &privilege) {
203 auto fdIt = m_requests.find(fd);
204 if (fdIt == m_requests.end()) {
205 m_requests.insert({ fd, PrivilegeRequestSet() });
208 auto &s = m_requests[fd];
210 auto reqIt = s.find(id);
211 if (reqIt != s.end()) {
212 printf("ERROR: We already have request id: %d for fd: %d\n", id, fd);
216 s.insert(ServerPrivilegeRequest(id, privilege));
219 void sendResponse(ConnectionFd fd, RequestId id, int response) {
220 auto fdIt = m_requests.find(fd);
221 if (fdIt == m_requests.end()) {
222 printf("ERROR: Connection for fd: %d doesn't exist!\n", fd);
226 auto &s = fdIt->second;
228 auto reqIt = s.find(id);
229 if (reqIt == s.end()) {
230 printf("ERROR: Request %d doesn't exist for fd: %d\n", id, fd);
235 m_channel->popupResponse(fd, id, response);
240 m_requests.erase(fdIt);
245 void showPrivilegeRequests() {
246 printf("fd requestId privilege\n");
247 for (const auto &con : m_requests) {
248 for (const auto &req : con.second) {
249 printf("%-11d %-11d %-20s\n", con.first, req.m_id, req.m_privilege.c_str());
254 void closeConnection(int fd) {
255 auto it = m_connections.find(fd);
256 if (it == m_connections.end()) {
257 printf("ERROR: Connection fd: %d not found\n", fd);
258 print_prompt(Mode::SERVER);
262 m_requests.erase(fd);
263 m_channel->process(fd, 0);
266 void showConnections() {
268 for (const auto &con : m_connections) {
269 printf("%d\n", con.first);
273 void setServerChannel(ServerChannel *ptr) {
278 ServerChannel *m_channel;
279 std::map<ConnectionFd, Connection> m_connections;
280 std::map<ConnectionFd, PrivilegeRequestSet> m_requests;
285 : m_serverSimulator(nullptr)
287 , m_mode(Mode::UNKNOWN)
291 if (m_channel != nullptr) {
297 if (m_mode == Mode::SERVER) {
298 m_serverSimulator = new ServerSimulator();
299 m_channel = new ServerChannel(ServerCallbacksPtr(m_serverSimulator));
300 m_serverSimulator->setServerChannel(m_channel);
304 ServerSimulator *m_serverSimulator;
305 ServerChannel *m_channel;
309 const char *popup_result_to_str(ppm_popup_result_e result)
312 case PRIVACY_PRIVILEGE_MANAGER_POPUP_RESULT_ALLOW_FOREVER:
313 return "ALLOW_FOREVER";
314 case PRIVACY_PRIVILEGE_MANAGER_POPUP_RESULT_DENY_FOREVER:
315 return "DENY_FOREVER";
316 case PRIVACY_PRIVILEGE_MANAGER_POPUP_RESULT_DENY_ONCE:
323 void popup_response_cb(ppm_call_cause_e cause, ppm_popup_result_e result, void *user_data)
325 ClientRequest *request = static_cast<ClientRequest *>(user_data);
326 if (request == nullptr) {
327 printf("ERROR: User data is nullptr\n");
331 printf("localId: %d privilege: \"%s\" ", request->m_id, request->m_privilege.c_str());
334 case PRIVACY_PRIVILEGE_MANAGER_CALL_CAUSE_ANSWER:
335 printf("popup response ANSWER: %s\n", popup_result_to_str(result));
337 case PRIVACY_PRIVILEGE_MANAGER_CALL_CAUSE_ERROR:
338 printf("popup response ERROR cause: PRIVACY_PRIVILEGE_MANAGER_CALL_CAUSE_ERROR\n");
344 print_prompt(Mode::CLIENT);
347 void print_client_help()
349 printf("c <privilege> check privilege status\n");
350 printf("r <privilege> send popup request\n");
351 printf("h print help\n");
353 print_prompt(Mode::CLIENT);
356 void print_client_error(ppm_error_e error)
359 case PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE:
361 case PRIVACY_PRIVILEGE_MANAGER_ERROR_IO_ERROR:
362 printf("I/O error\n");
364 case PRIVACY_PRIVILEGE_MANAGER_ERROR_INVALID_PARAMETER:
365 printf("Invalid parameters\n");
367 case PRIVACY_PRIVILEGE_MANAGER_ERROR_OUT_OF_MEMORY:
368 printf("Out of memory\n");
370 case PRIVACY_PRIVILEGE_MANAGER_ERROR_UNKNOWN:
371 printf("Unknown error\n");
376 static void print_client_check_result(ppm_check_result_e result)
381 case PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_ALLOW:
384 case PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_DENY:
387 case PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_ASK:
392 print_prompt(Mode::CLIENT);
395 void handle_client(char *buffer)
397 ppm_check_result_e result;
398 ppm_error_e err = PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE;
399 ClientRequest *request = nullptr;
400 char *privilege = nullptr;
401 static RequestId clientRequestId;
405 if (strlen(buffer) < 3) {
409 err = static_cast<ppm_error_e>(ppm_check_privilege(&buffer[2], &result));
410 if (err == PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE) {
411 print_client_check_result(result);
415 if (strlen(buffer) < 3) {
420 buffer[strlen(buffer)] = '\0'; // erase new line
421 privilege = &buffer[2];
423 printf("sending localId: %d privilege: \"%s\"\n", clientRequestId, privilege);
425 request = new ClientRequest{ clientRequestId++, privilege };
426 err = static_cast<ppm_error_e>(ppm_popup_request(privilege, popup_response_cb, request));
427 if (err != PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE) {
440 print_client_error(err);
441 print_prompt(Mode::CLIENT);
444 void print_server_help()
446 printf("l list all connections\n");
447 printf("s list all requests\n");
448 printf("ra <fd> <request id> send ALLOW FOREVER response\n");
449 printf("rd <fd> <request id> send DENY FOREVER response\n");
450 printf("ro <fd> <request id> send DENY ONCE response\n");
451 printf("c <fd> close connection\n");
452 printf("h print help\n");
454 print_prompt(Mode::SERVER);
457 void handle_server(const char *buffer, ServerSimulator *serverSimulator)
465 serverSimulator->showConnections();
468 serverSimulator->showPrivilegeRequests();
471 res = sscanf(&buffer[2], "%d %d", &fd, &requestId);
478 serverSimulator->sendResponse(fd, requestId, ASKUSER_ALLOW_FOREVER);
481 serverSimulator->sendResponse(fd, requestId, ASKUSER_DENY_FOREVER);
484 serverSimulator->sendResponse(fd, requestId, ASKUSER_DENY_ONCE);
492 res = sscanf(&buffer[1], "%d", &fd);
497 serverSimulator->closeConnection(fd);
506 print_prompt(Mode::SERVER);
509 gboolean main_loop_cb(UNUSED GIOChannel *channel, UNUSED GIOCondition cond, gpointer user_data)
513 int ret = read(0, buffer, sizeof(buffer));
515 printf("read from stdin failed\n");
519 buffer[ret - 1] = '\0';
521 AppContext *ctx = static_cast<AppContext *>(user_data);
522 switch (ctx->m_mode) {
524 handle_client(buffer);
527 handle_server(buffer, ctx->m_serverSimulator);
531 printf("Mode not set, exiting.\n");
538 void print_help(const char *programName)
540 printf("Usage: %s [OPTIONS]\n", programName);
541 printf("Allows to test CAPI for Privacy Privilege Manager.\n");
542 printf("This program can run in two modes: as a client and as a server.\n");
543 printf("You can use it in two scenarios:\n");
544 printf("1. Run as a client (%s -c) to trigger popups in the askuser-notification daemon.\n", programName);
545 printf("2. Run one part as a client (%s -c) and other one as a server (%s -s).\n",
546 programName, programName);
547 printf("If you want to run this program as a root you need to create /var/run/user_ext/0 folder.\n");
548 printf("To run this program in context of some Tizen's application, type in the console:\n");
549 printf("#echo <SMACK label of the application> > /proc/self/attr/current\n");
550 printf("#su - <user name>\n\n");
551 printf("Options:\n");
552 printf("-s run as a server\n");
553 printf("-c run as a client (uses CAPI)\n");
554 printf("-h display this help end exit\n");
557 int main(int argc, char **argv)
563 while ((c = getopt (argc, argv, "sch")) != -1) {
566 ctx.m_mode = Mode::SERVER;
570 ctx.m_mode = Mode::CLIENT;
579 if (ctx.m_mode == Mode::UNKNOWN) {
588 printf("Unknwon exception occured, exiting.\n");
592 GMainLoop *mainloop = g_main_loop_new(nullptr, FALSE);
594 GIOChannel *gio_channel = g_io_channel_unix_new(0);
595 g_io_add_watch(gio_channel, static_cast<GIOCondition>(G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL),
598 g_main_loop_run(mainloop);