Check priv_id of item_info when update
[platform/core/api/notification.git] / notification-ex / dbus_event_listener.cc
1 /*
2  * Copyright (c) 2019 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <dlog.h>
18 #include <glib.h>
19 #include <unistd.h>
20
21 #include <string>
22 #include <list>
23
24 #include "notification-ex/dbus_connection_manager.h"
25 #include "notification-ex/dbus_event_listener.h"
26 #include "notification-ex/dbus_event_listener_implementation.h"
27 #include "notification-ex/exception.h"
28 #include "notification-ex/ex_util.h"
29 #include "notification-ex/event_info_internal.h"
30
31 #ifdef LOG_TAG
32 #undef LOG_TAG
33 #endif
34
35 #define LOG_TAG "NOTIFICATION_EX"
36 #define MAX_PACKAGE_STR_SIZE 512
37 #define NORMAL_UID_BASE 5000
38
39 #define DBUS_NAME "org.freedesktop.DBus"
40 #define DBUS_OBJECT_PATH "/org/freedesktop/DBus"
41 #define DBUS_INTERFACE_NAME "org.freedesktop.DBus"
42
43 using namespace std;
44 using namespace tizen_base;
45
46 namespace notification {
47
48 DBusEventListener::DBusEventListener(string path)
49     : impl_(new Impl(this, path)) {
50   LOGW("Created (%s)", path.c_str());
51 }
52
53 DBusEventListener::~DBusEventListener() {
54   LOGW("Destroyed");
55 }
56
57 DBusEventListener::Impl::~Impl() = default;
58
59 DBusEventListener::Impl::Impl(DBusEventListener* parent, string path)
60     : subscribe_id_(0), registration_id_(0), path_(path), parent_(parent) {
61   LOGI("Dbus_event_listener impl created");
62 }
63
64 uid_t DBusEventListener::Impl::GetSenderUid(GDBusConnection* connection,
65                 const char* sender_name) {
66   GDBusMessage* msg = nullptr;
67   GDBusMessage* reply = nullptr;
68   GError* err = nullptr;
69   GVariant* body;
70   uid_t uid = 0;
71
72   msg = g_dbus_message_new_method_call(DBUS_NAME, DBUS_OBJECT_PATH,
73       DBUS_INTERFACE_NAME, "GetConnectionUnixUser");
74   if (!msg) {
75     LOGE("Failed to alloc new method call");
76     goto out;
77   }
78
79   g_dbus_message_set_body(msg, g_variant_new("(s)", sender_name));
80   reply = g_dbus_connection_send_message_with_reply_sync(connection, msg,
81       G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, nullptr, nullptr, &err);
82
83   if (!reply) {
84     if (err != nullptr) {
85       LOGE("Failed to get uid [%s]", err->message);
86       g_error_free(err);
87     }
88     goto out;
89   }
90
91   body = g_dbus_message_get_body(reply);
92   g_variant_get(body, "(u)", &uid);
93
94 out:
95   if (msg)
96     g_object_unref(msg);
97   if (reply)
98     g_object_unref(reply);
99
100   return uid;
101 }
102
103 pid_t DBusEventListener::Impl::GetSenderPid(GDBusConnection* connection,
104                const char* sender_name) {
105   GDBusMessage* msg = nullptr;
106   GDBusMessage* reply = nullptr;
107   GError* err = nullptr;
108   GVariant* body;
109   pid_t pid = 0;
110
111   msg = g_dbus_message_new_method_call(DBUS_NAME, DBUS_OBJECT_PATH,
112       DBUS_INTERFACE_NAME, "GetConnectionUnixProcessID");
113   if (!msg) {
114     LOGE("Failed to alloc new method call");
115     goto out;
116   }
117
118   g_dbus_message_set_body(msg, g_variant_new("(s)", sender_name));
119   reply = g_dbus_connection_send_message_with_reply_sync(connection, msg,
120       G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, nullptr, nullptr, &err);
121
122   if (!reply) {
123     if (err != nullptr) {
124       LOGE("Failed to get uid [%s]", err->message);
125       g_error_free(err);
126     }
127     goto out;
128   }
129
130   body = g_dbus_message_get_body(reply);
131   g_variant_get(body, "(u)", &pid);
132
133 out:
134   if (msg)
135     g_object_unref(msg);
136   if (reply)
137     g_object_unref(reply);
138
139   return pid;
140 }
141
142 void DBusEventListener::Impl::SignalCb(GDBusConnection* connection,
143                       const gchar* sender_name,
144                       const gchar* object_path,
145                       const gchar* interface_name,
146                       const gchar* signal_name,
147                       GVariant* parameters,
148                       void* user_data) {
149   DBusEventListener::Impl* dl = static_cast<DBusEventListener::Impl*>(user_data);
150   char* appid = nullptr;
151   GVariantIter *iter = nullptr;
152   char* event_info_raw = nullptr;
153   g_variant_get(parameters, "(ssa(s))", &appid, &event_info_raw, &iter);
154
155   LOGI("signal callback!! (%s)", appid);
156   string sender_appid = string(appid);
157   string cur_appid = util::GetAppId();
158   if (sender_appid == cur_appid)
159     return;
160   if ((!DBusConnectionManager::GetInst().IsDataProviderMaster(cur_appid)
161     && !DBusConnectionManager::GetInst().IsDataProviderMaster(sender_appid))
162     || (cur_appid == sender_appid))
163     return;
164
165   LOGD("%s : %s", cur_appid.c_str(), sender_appid.c_str());
166
167   try {
168     char* raw = nullptr;
169     list<Bundle> ret_list;
170     while (g_variant_iter_loop(iter, "(s)", &raw) && raw != nullptr) {
171       Bundle ret(raw);
172       ret_list.emplace_back(ret);
173     }
174
175     Bundle b(event_info_raw);
176     EventInfo info(b);
177     if (info.GetEventType() == EventInfo::Post
178            || info.GetEventType() == EventInfo::Update) {
179       uid_t uid = GetSenderUid(connection, sender_name);
180       if (uid >= NORMAL_UID_BASE) {
181         pid_t pid = GetSenderPid(connection, sender_name);
182         info.SetValidatedOwner(util::GetAppId(pid));
183         info.SetValidatedUid(uid);
184       }
185     }
186     dl->parent_->NotifyObserver(info, ret_list);
187   } catch(Exception &ex) {
188     LOGE("%s %d", ex.what(), ex.GetErrorCode());
189   }
190 }
191
192 void DBusEventListener::Impl::OnMethodCall(
193     GDBusConnection *conn, const gchar *sender, const gchar *object_path,
194     const gchar *iface_name, const gchar *method_name,
195     GVariant *parameters, GDBusMethodInvocation *invocation,
196     gpointer user_data) {
197   LOGI("method_name[%s] sender[%s]", method_name, sender);
198   DBusEventListener::Impl* dl = static_cast<DBusEventListener::Impl*>(user_data);
199   GVariant *reply_body = NULL;
200   try {
201     char* appid = NULL;
202     char* serialized = NULL;
203     if (g_strcmp0(method_name, "Get") == 0) {
204       g_variant_get(parameters, "(&s&s)", &appid, &serialized);
205
206       Bundle b(serialized);
207       EventInfo info(b);
208       list<Bundle> result = dl->parent_->NotifyObserver(info);
209       GVariantBuilder* builder = g_variant_builder_new(G_VARIANT_TYPE("a(s)"));
210       for (auto& i : result) {
211         g_variant_builder_add(builder, "(s)",
212           reinterpret_cast<char*>(i.ToRaw().first.get()));
213       }
214       reply_body = g_variant_new("(a(s))", builder);
215       g_variant_builder_unref(builder);
216     } else if (g_strcmp0(method_name, "Count") == 0) {
217       g_variant_get(parameters, "(&s&s)", &appid, &serialized);
218
219       Bundle b(serialized);
220       EventInfo info(b);
221       int num = dl->parent_->NotifyNumberRequest(info);
222       reply_body = g_variant_new("(i)", num);
223     }
224     g_dbus_method_invocation_return_value(invocation, reply_body);
225   } catch (Exception &ex) {
226     LOGE("%s %d", ex.what(), ex.GetErrorCode());
227     g_dbus_method_invocation_return_error(invocation, noti_ex_error_quark(),
228             ERROR_IO_ERROR, "OnMethodCall fail");
229   }
230 }
231
232 int DBusEventListener::Impl::RegisterGDBusInterface() {
233   static const GDBusInterfaceVTable interface_vtable = {
234     OnMethodCall,
235     nullptr,
236     nullptr
237   };
238   static gchar introspection_xml[] =
239     "  <node>"
240     "  <interface name='org.tizen.notification_ex'>"
241     "        <method name='Get'>"
242     "          <arg type='s' name='appid' direction='in'/>"
243     "          <arg type='s' name='serialized' direction='in'/>"
244     "          <arg type='a(s)' name='noti_arr' direction='out'/>"
245     "        </method>"
246     "        <method name='Count'>"
247     "          <arg type='s' name='appid' direction='in'/>"
248     "          <arg type='s' name='serialized' direction='in'/>"
249     "          <arg type='i' name='num' direction='out'/>"
250     "        </method>"
251     "  </interface>"
252     "  </node>";
253   GError *error = NULL;
254   GDBusNodeInfo *introspection_data =
255       g_dbus_node_info_new_for_xml(introspection_xml, &error);
256   if (!introspection_data) {
257     LOGE("g_dbus_node_info_new_for_xml is failed.");
258     if (error != NULL) {
259       LOGE("g_dbus_node_info_new_for_xml err [%s]", error->message);
260       g_error_free(error);
261     }
262     return ERROR_IO_ERROR;
263   }
264
265   registration_id_ = g_dbus_connection_register_object(
266       DBusConnectionManager::GetInst().GetConnection(),
267       path_.c_str(), introspection_data->interfaces[0],
268       &interface_vtable, this, NULL, NULL);
269   g_dbus_node_info_unref(introspection_data);
270   if (registration_id_ == 0) {
271     LOGE("register object fail");
272     return ERROR_IO_ERROR;
273   }
274
275   LOGI("RegisterGDBusInterface success");
276   return ERROR_NONE;
277 }
278
279 void DBusEventListener::Impl::UnRegisterGDBusInterface() {
280   g_dbus_connection_unregister_object(
281         DBusConnectionManager::GetInst().GetConnection(),
282         registration_id_);
283 }
284
285 bool DBusEventListener::Impl::SubscribeSignal() {
286   subscribe_id_ = g_dbus_connection_signal_subscribe(
287                     DBusConnectionManager::GetInst().GetConnection(),
288                     NULL,
289                     DBusConnectionManager::GetInst().GetInterfaceName().c_str(),
290                     NULL,
291                     path_.c_str(),
292                     NULL,
293                     G_DBUS_SIGNAL_FLAGS_NONE,
294                     SignalCb,
295                     this,
296                     NULL);
297   return subscribe_id_ > 0;
298 }
299
300 void DBusEventListener::Impl::UnSubscribeSignal() {
301   g_dbus_connection_signal_unsubscribe(
302       DBusConnectionManager::GetInst().GetConnection(), subscribe_id_);
303   subscribe_id_ = 0;
304 }
305
306 void DBusEventListener::RegisterObserver(IEventObserver* observer) {
307   if (impl_->subscribe_id_ == 0) {
308     impl_->SubscribeSignal();
309   } else {
310     impl_->UnSubscribeSignal();
311     impl_->SubscribeSignal();
312   }
313
314   if (impl_->registration_id_ == 0) {
315     impl_->RegisterGDBusInterface();
316   } else {
317     impl_->UnRegisterGDBusInterface();
318     impl_->RegisterGDBusInterface();
319   }
320   impl_->observer_ = observer;
321 }
322
323 void DBusEventListener::UnRegisterObserver(IEventObserver* observer) {
324   impl_->UnSubscribeSignal();
325   impl_->observer_ = NULL;
326 }
327
328 void DBusEventListener::NotifyObserver(
329     const IEventInfo& info, list<Bundle> serialized) {
330   impl_->observer_->OnEvent(info, serialized);
331 }
332
333 list<Bundle> DBusEventListener::NotifyObserver(const IEventInfo& info) {
334   return impl_->observer_->OnRequest(info);
335 }
336
337 int DBusEventListener::NotifyNumberRequest(const IEventInfo& info) {
338   return impl_->observer_->OnRequestNumber(info);
339 }
340
341 }  // namespace notification