Check signal agent's operation success
[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(const char* signal, 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(signal, target_uid, req_id,
195         std::move(pkgs), key, val);
196   } catch (...) {
197     LOGE("Exception occured");
198   }
199 }
200
201 static gboolean __quit(gpointer user_data) {
202   g_main_loop_quit(loop);
203   return FALSE;
204 }
205
206 static int __check_authority(int fd) {
207   int r;
208   struct ucred cr;
209   socklen_t len;
210   struct passwd pwd;
211   struct passwd* pwd_r;
212   char buf[PWBUFSIZE];
213
214   len = sizeof(struct ucred);
215   r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
216   if (r != 0) {
217     LOGE("getsockopt failed: %d", errno);
218     return -1;
219   }
220
221   /* allow root user */
222   if (cr.uid == 0)
223     return 0;
224
225   r = getpwuid_r(cr.uid, &pwd, buf, sizeof(buf), &pwd_r);
226   if (r != 0 || pwd_r == NULL) {
227     LOGE("getpwuid failed: %d", r);
228     return -1;
229   }
230
231   /* only app_fw user can send signal to agent */
232   if (strcmp(pwd_r->pw_name, APPFW_USERNAME) != 0) {
233     LOGE("unauthorized client");
234     return -1;
235   }
236
237   return 0;
238 }
239
240 /**
241  * packet format:
242  * +----------------+-------------+-----------+-------------------+
243  * |signal name size|GVariant size|signal name|serialized GVariant|
244  * +----------------+-------------+-----------+-------------------+
245  */
246 static gboolean __handle_signal(gint fd,
247     GIOCondition cond, gpointer user_data) {
248   int r;
249   unsigned char buf[BUFMAX];
250   int clifd;
251   struct sockaddr_un sa;
252   socklen_t s = sizeof(sa);
253   size_t type_len;
254   char* type_name;
255   gsize data_len;
256   gpointer data;
257   GVariant* gv;
258
259   clifd = accept(fd, (struct sockaddr*)&sa, &s);
260   if (clifd == -1) {
261     LOGE("accept failed: %d", errno);
262     return FALSE;
263   }
264
265   if (__check_authority(clifd)) {
266     close(clifd);
267     return TRUE;
268   }
269
270   r = recv(clifd, buf, sizeof(size_t) + sizeof(gsize), 0);
271   if (r < 0) {
272     LOGE("recv failed: %d", errno);
273     close(clifd);
274     return FALSE;
275   } else if (r == 0) {
276     LOGE("client fd already closed");
277     close(clifd);
278     return FALSE;
279   }
280
281   memcpy(&type_len, buf, sizeof(size_t));
282   memcpy(&data_len, buf + sizeof(size_t), sizeof(gsize));
283
284   if (type_len > BUFMAX || data_len > BUFMAX ||
285       (type_len + data_len) > BUFMAX) {
286     LOGE("received size is too large: %zu %zu", type_len, data_len);
287     close(clifd);
288     return FALSE;
289   }
290
291   r = recv(clifd, buf, type_len + data_len, 0);
292   if (r < 0) {
293     LOGE("recv failed: %d", errno);
294     close(clifd);
295     return FALSE;
296   } else if (r == 0) {
297     LOGE("client fd already closed");
298     close(clifd);
299     return FALSE;
300   }
301
302   if (type_len == 0) {
303     LOGE("invalid type_len");
304     close(clifd);
305     return FALSE;
306   }
307
308   /* get signal name (including terminating null byte) */
309   type_name = static_cast<char*>(malloc(type_len));
310   memcpy(type_name, buf, type_len);
311
312   /* get data */
313   data = malloc(data_len);
314   memcpy(data, buf + type_len, data_len);
315
316   /* floating type GVariant instance */
317   if (!strcmp(type_name, PKGMGR_INSTALLER_RES_COPY_EVENT_STR) ||
318     !strcmp(type_name, PKGMGR_INSTALLER_RES_CREATE_DIR_EVENT_STR) ||
319     !strcmp(type_name, PKGMGR_INSTALLER_RES_REMOVE_EVENT_STR) ||
320     !strcmp(type_name, PKGMGR_INSTALLER_RES_UNINSTALL_EVENT_STR)) {
321     gv = g_variant_new_from_data(G_VARIANT_TYPE("(usssv)"),
322         data, data_len, TRUE, NULL, NULL);
323     __emit_signal_for_res_event(type_name, gv);
324   } else {
325     gv = g_variant_new_from_data(G_VARIANT_TYPE("(usa(sss)ss)"),
326         data, data_len, TRUE, NULL, NULL);
327     __emit_signal_for_pkg_event(type_name, gv);
328   }
329   g_variant_unref(gv);
330
331   free(data);
332   free(type_name);
333
334   int ret = 0;
335   ssize_t send_byte = send(clifd, &ret, sizeof(ret), MSG_NOSIGNAL);
336   if (send_byte < 0)
337     LOGE("send() is failed. fd: %d, errno: %d", fd, errno);
338
339   close(clifd);
340
341   /* renew timeout */
342   g_source_remove(tid);
343   tid = g_timeout_add_seconds(10, __quit, NULL);
344
345   return TRUE;
346 }
347
348 static int __init(void) {
349   char path[PATH_MAX];
350   GError* err = NULL;
351
352   snprintf(path, sizeof(path), "/run/pkgmgr/agent/%d", getuid());
353   server_fd = __get_server_socket(path);
354   if (server_fd < 0) {
355     LOGE("server init failed");
356     return -1;
357   }
358
359   if (aul_proc_register(AGENT_APPID, NULL) != AUL_R_OK) {
360     LOGE("aul_proc_register fail");
361     return -1;
362   }
363
364   try {
365     signal_sender = std::make_unique<pkg_group::PkgSignal>(AGENT_APPID, false);
366   } catch(...) {
367     LOGE("Exception occured");
368     return -1;
369   }
370
371   loop = g_main_loop_new(NULL, FALSE);
372   sid = g_unix_fd_add(server_fd, G_IO_IN, __handle_signal, NULL);
373   tid = g_timeout_add_seconds(10, __quit, NULL);
374
375   return 0;
376 }
377
378 static void __fini(void) {
379   if (sid > 0)
380     g_source_remove(sid);
381   if (loop)
382     g_main_loop_unref(loop);
383   if (server_fd > 0)
384     close(server_fd);
385   aul_proc_deregister();
386 }
387
388 int main(int argc, char* argv[]) {
389   int r;
390
391   r = __init();
392   if (r < 0)
393     return -1;
394
395   LOGW("signal agent start");
396
397   g_main_loop_run(loop);
398
399   __fini();
400
401   return 0;
402 }