Apply try-catch where exception can be occured
[platform/core/appfw/slp-pkgmgr.git] / installer / pkgmgr_installer_signal_agent.cc
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
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
18 #ifndef _GNU_SOURCE
19 #define _GNU_SOURCE
20 #endif
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <errno.h>
26 #include <sys/stat.h>
27 #include <sys/socket.h>
28 #include <sys/types.h>
29 #include <sys/un.h>
30 #include <linux/limits.h>
31 #include <pwd.h>
32
33 #include <glib.h>
34 #include <glib-unix.h>
35 #include <gio/gio.h>
36 #include <systemd/sd-daemon.h>
37
38 #include <aul_proc.h>
39 #include <dlog.h>
40
41 #include <memory>
42 #include <vector>
43
44 #include "src/pkgmgr_installer_type.h"
45 #include "src/PkgSignal.h"
46
47 #ifdef LOG_TAG
48 #undef LOG_TAG
49 #endif
50 #define LOG_TAG "PKGMGR_INSTALLER_SIGNAL_AGENT"
51
52 #define BUFMAX 4096
53 #define PWBUFSIZE sysconf(_SC_GETPW_R_SIZE_MAX)
54 #define APPFW_USERNAME "app_fw"
55 #define AGENT_APPID "signal_agent"
56
57 namespace pkg_group = rpc_port::PkgSignal::group;
58 namespace pkg_signal = rpc_port::PkgSignal;
59
60 static int server_fd = -1;
61 static GMainLoop* loop;
62 static guint sid;
63 static guint tid;
64 static std::unique_ptr<pkg_group::PkgSignal> signal_sender;
65
66 static int __create_server_socket(const char* path) {
67   int r;
68   int fd;
69   struct sockaddr_un sa;
70
71   fd = socket(AF_UNIX, SOCK_STREAM, 0);
72   if (fd == -1) {
73     LOGE("socket create failed: %d", errno);
74     return -1;
75   }
76
77   memset(&sa, 0, sizeof(sa));
78   sa.sun_family = AF_UNIX;
79   snprintf(sa.sun_path, sizeof(sa.sun_path), "%s", path);
80
81   r = unlink(sa.sun_path);
82   if (r == -1 && errno != ENOENT) {
83     LOGE("unlink(%s) failed: %d", sa.sun_path, errno);
84     close(fd);
85     return -1;
86   }
87
88   r = bind(fd, (struct sockaddr*)&sa, sizeof(sa));
89   if (r == -1) {
90     LOGE("bind(%s) failed: %d", sa.sun_path, errno);
91     close(fd);
92     return -1;
93   }
94
95   r = chmod(sa.sun_path, 0660);
96   if (r == -1)
97     LOGW("chmod(%s) failed: %d", sa.sun_path, errno);
98
99   r = listen(fd, SOMAXCONN);
100   if (r == -1) {
101     LOGE("listen(%s) failed: %d", sa.sun_path, errno);
102     close(fd);
103     return -1;
104   }
105
106   return fd;
107 }
108
109 static int __get_server_socket(const char* path) {
110   int i;
111   int n;
112   int r;
113   int fd = -1;
114
115   n = sd_listen_fds(0);
116   if (n < 0) {
117     LOGE("sd_listen_fds: %d", n);
118     return -1;
119   } else if (n == 0) {
120     return __create_server_socket(path);
121   }
122
123   for (i = SD_LISTEN_FDS_START; i < SD_LISTEN_FDS_START + n; i++) {
124     r = sd_is_socket_unix(i, SOCK_STREAM, -1, path, 0);
125     if (r > 0) {
126       fd = i;
127       break;
128     }
129   }
130
131   if (fd == -1) {
132     LOGE("socket is not passed, create server socket");
133     return __create_server_socket(path);
134   }
135
136   return fd;
137 }
138
139 static void __emit_signal_for_res_event(const char* signal, GVariant* gv) {
140   uid_t target_uid;
141   char* req_id;
142   char* pkgid = NULL;
143   char* status = NULL;
144   char* path = NULL;
145   int state;
146   int signal_type;
147   int error_code;
148   GVariant* extra_param = NULL;
149   GVariantIter* iter;
150
151   g_variant_get(gv, "(u&s&s&sv)", &target_uid, &req_id, &pkgid, &status, &extra_param);
152   if (!g_variant_type_equal(G_VARIANT_TYPE("(ia(si))"),
153       g_variant_get_type(extra_param))) {
154     LOGE("invalid extra parameter");
155     g_variant_unref(extra_param);
156     return;
157   }
158
159   std::vector<pkg_signal::PathInfo> path_info;
160
161   g_variant_get(extra_param, "(ia(si))", &error_code, &iter);
162   while (g_variant_iter_loop(iter, "(&si)", &path, &state))
163     path_info.emplace_back(path, state);
164   g_variant_unref(extra_param);
165   g_variant_iter_free(iter);
166
167   try {
168     signal_sender->AsyncResultForResource(signal, target_uid, req_id, pkgid,
169         status, pkg_signal::ExtraData(error_code, std::move(path_info)));
170   } catch (...) {
171     LOGE("Exception occured");
172   }
173 }
174
175 static void __emit_signal_for_pkg_event(GVariant* gv) {
176   uid_t target_uid;
177   char* req_id;
178   char* pkg_type = NULL;
179   char* appid = NULL;
180   char* pkgid = NULL;
181   char* key = NULL;
182   char* val = NULL;
183   GVariantIter* iter = NULL;
184   int signal_type;
185
186   g_variant_get(gv, "(u&sa(sss)&s&s)", &target_uid, &req_id, &iter,
187       &key, &val);
188   std::vector<pkg_signal::PkgInfo> pkgs;
189   while (g_variant_iter_loop(iter, "(&s&s&s)", &pkgid, &appid, &pkg_type))
190     pkgs.emplace_back(pkg_signal::PkgInfo(pkgid, appid, pkg_type));
191   g_variant_iter_free(iter);
192
193   try {
194     signal_sender->AsyncResult("", target_uid, req_id, std::move(pkgs), key, val);
195   } catch (...) {
196     LOGE("Exception occured");
197   }
198 }
199
200 static gboolean __quit(gpointer user_data) {
201   g_main_loop_quit(loop);
202   return FALSE;
203 }
204
205 static int __check_authority(int fd) {
206   int r;
207   struct ucred cr;
208   socklen_t len;
209   struct passwd pwd;
210   struct passwd* pwd_r;
211   char buf[PWBUFSIZE];
212
213   len = sizeof(struct ucred);
214   r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
215   if (r != 0) {
216     LOGE("getsockopt failed: %d", errno);
217     return -1;
218   }
219
220   /* allow root user */
221   if (cr.uid == 0)
222     return 0;
223
224   r = getpwuid_r(cr.uid, &pwd, buf, sizeof(buf), &pwd_r);
225   if (r != 0 || pwd_r == NULL) {
226     LOGE("getpwuid failed: %d", r);
227     return -1;
228   }
229
230   /* only app_fw user can send signal to agent */
231   if (strcmp(pwd_r->pw_name, APPFW_USERNAME) != 0) {
232     LOGE("unauthorized client");
233     return -1;
234   }
235
236   return 0;
237 }
238
239 /**
240  * packet format:
241  * +----------------+-------------+-----------+-------------------+
242  * |signal name size|GVariant size|signal name|serialized GVariant|
243  * +----------------+-------------+-----------+-------------------+
244  */
245 static gboolean __handle_signal(gint fd,
246     GIOCondition cond, gpointer user_data) {
247   int r;
248   unsigned char buf[BUFMAX];
249   int clifd;
250   struct sockaddr_un sa;
251   socklen_t s = sizeof(sa);
252   size_t type_len;
253   char* type_name;
254   gsize data_len;
255   gpointer data;
256   GVariant* gv;
257
258   clifd = accept(fd, (struct sockaddr*)&sa, &s);
259   if (clifd == -1) {
260     LOGE("accept failed: %d", errno);
261     return FALSE;
262   }
263
264   if (__check_authority(clifd)) {
265     close(clifd);
266     return TRUE;
267   }
268
269   r = recv(clifd, buf, sizeof(size_t) + sizeof(gsize), 0);
270   if (r < 0) {
271     LOGE("recv failed: %d", errno);
272     close(clifd);
273     return FALSE;
274   } else if (r == 0) {
275     LOGE("client fd already closed");
276     close(clifd);
277     return FALSE;
278   }
279
280   memcpy(&type_len, buf, sizeof(size_t));
281   memcpy(&data_len, buf + sizeof(size_t), sizeof(gsize));
282
283   if (type_len > BUFMAX || data_len > BUFMAX ||
284       (type_len + data_len) > BUFMAX) {
285     LOGE("received size is too large: %zu %zu", type_len, data_len);
286     close(clifd);
287     return FALSE;
288   }
289
290   r = recv(clifd, buf, type_len + data_len, 0);
291   if (r < 0) {
292     LOGE("recv failed: %d", errno);
293     close(clifd);
294     return FALSE;
295   } else if (r == 0) {
296     LOGE("client fd already closed");
297     close(clifd);
298     return FALSE;
299   }
300
301   if (type_len == 0) {
302     LOGE("invalid type_len");
303     close(clifd);
304     return FALSE;
305   }
306
307   /* get signal name (including terminating null byte) */
308   type_name = static_cast<char*>(malloc(type_len));
309   memcpy(type_name, buf, type_len);
310
311   /* get data */
312   data = malloc(data_len);
313   memcpy(data, buf + type_len, data_len);
314
315   /* floating type GVariant instance */
316   if (!strcmp(type_name, PKGMGR_INSTALLER_RES_COPY_EVENT_STR) ||
317     !strcmp(type_name, PKGMGR_INSTALLER_RES_CREATE_DIR_EVENT_STR) ||
318     !strcmp(type_name, PKGMGR_INSTALLER_RES_REMOVE_EVENT_STR) ||
319     !strcmp(type_name, PKGMGR_INSTALLER_RES_UNINSTALL_EVENT_STR)) {
320     gv = g_variant_new_from_data(G_VARIANT_TYPE("(usssv)"),
321         data, data_len, TRUE, NULL, NULL);
322     __emit_signal_for_res_event(type_name, gv);
323   } else {
324     gv = g_variant_new_from_data(G_VARIANT_TYPE("(usa(sss)ss)"),
325         data, data_len, TRUE, NULL, NULL);
326     __emit_signal_for_pkg_event(gv);
327   }
328   g_variant_unref(gv);
329
330   free(data);
331   free(type_name);
332   close(clifd);
333
334   /* renew timeout */
335   g_source_remove(tid);
336   tid = g_timeout_add_seconds(10, __quit, NULL);
337
338   return TRUE;
339 }
340
341 static int __init(void) {
342   char path[PATH_MAX];
343   GError* err = NULL;
344
345   snprintf(path, sizeof(path), "/run/pkgmgr/agent/%d", getuid());
346   server_fd = __get_server_socket(path);
347   if (server_fd < 0) {
348     LOGE("server init failed");
349     return -1;
350   }
351
352   if (aul_proc_register(AGENT_APPID, NULL) != AUL_R_OK) {
353     LOGE("aul_proc_register fail");
354     return -1;
355   }
356
357   try {
358     signal_sender = std::make_unique<pkg_group::PkgSignal>(AGENT_APPID, false);
359   } catch(...) {
360     LOGE("Exception occured");
361     return -1;
362   }
363
364   loop = g_main_loop_new(NULL, FALSE);
365   sid = g_unix_fd_add(server_fd, G_IO_IN, __handle_signal, NULL);
366   tid = g_timeout_add_seconds(10, __quit, NULL);
367
368   return 0;
369 }
370
371 static void __fini(void) {
372   if (sid > 0)
373     g_source_remove(sid);
374   if (loop)
375     g_main_loop_unref(loop);
376   if (server_fd > 0)
377     close(server_fd);
378   aul_proc_deregister();
379 }
380
381 int main(int argc, char* argv[]) {
382   int r;
383
384   r = __init();
385   if (r < 0)
386     return -1;
387
388   g_main_loop_run(loop);
389
390   __fini();
391
392   return 0;
393 }