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