Release version 0.15.0
[platform/core/appfw/slp-pkgmgr.git] / installer / pkgmgr_installer_signal_agent.c
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 #define _GNU_SOURCE
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <errno.h>
24 #include <sys/stat.h>
25 #include <sys/socket.h>
26 #include <sys/types.h>
27 #include <sys/un.h>
28 #include <linux/limits.h>
29 #include <pwd.h>
30
31 #include <glib.h>
32 #include <glib-unix.h>
33 #include <gio/gio.h>
34 #include <systemd/sd-daemon.h>
35
36 #include <dlog.h>
37
38 #include "pkgmgr_installer_config.h"
39 #include "pkgmgr_installer_type.h"
40
41 #ifdef LOG_TAG
42 #undef LOG_TAG
43 #endif
44 #define LOG_TAG "PKGMGR_INSTALLER_SIGNAL_AGENT"
45
46 #define BUFMAX 4096
47 #define PWBUFSIZE sysconf(_SC_GETPW_R_SIZE_MAX)
48 #define APPFW_USERNAME "app_fw"
49
50 static int server_fd = -1;
51 static GMainLoop *loop;
52 static guint sid;
53 static guint tid;
54 static GDBusConnection *conn;
55
56 static int __create_server_socket(const char *path)
57 {
58         int r;
59         int fd;
60         struct sockaddr_un sa;
61
62         fd = socket(AF_UNIX, SOCK_STREAM, 0);
63         if (fd == -1) {
64                 LOGE("socket create failed: %d", errno);
65                 return -1;
66         }
67
68         memset(&sa, 0, sizeof(sa));
69         sa.sun_family = AF_UNIX;
70         snprintf(sa.sun_path, sizeof(sa.sun_path), "%s", path);
71
72         r = unlink(sa.sun_path);
73         if (r == -1 && errno != ENOENT) {
74                 LOGE("unlink(%s) failed: %d", sa.sun_path, errno);
75                 close(fd);
76                 return -1;
77         }
78
79         r = bind(fd, (struct sockaddr *)&sa, sizeof(sa));
80         if (r == -1) {
81                 LOGE("bind(%s) failed: %d", sa.sun_path, errno);
82                 close(fd);
83                 return -1;
84         }
85
86         r = chmod(sa.sun_path, 0660);
87         if (r == -1)
88                 LOGW("chmod(%s) failed: %d", sa.sun_path, errno);
89
90         r = listen(fd, SOMAXCONN);
91         if (r == -1) {
92                 LOGE("listen(%s) failed: %d", sa.sun_path, errno);
93                 close(fd);
94                 return -1;
95         }
96
97         return fd;
98 }
99
100 static int __get_server_socket(const char *path)
101 {
102         int i;
103         int n;
104         int r;
105         int fd = -1;
106
107         n = sd_listen_fds(0);
108         if (n < 0) {
109                 LOGE("sd_listen_fds: %d", n);
110                 return -1;
111         } else if (n == 0) {
112                 return __create_server_socket(path);
113         }
114
115         for (i = SD_LISTEN_FDS_START; i < SD_LISTEN_FDS_START + n; i++) {
116                 r = sd_is_socket_unix(i, SOCK_STREAM, -1, path, 0);
117                 if (r > 0) {
118                         fd = i;
119                         break;
120                 }
121         }
122
123         if (fd == -1) {
124                 LOGE("socket is not passed, create server socket");
125                 return __create_server_socket(path);
126         }
127
128         return fd;
129 }
130
131 static void __emit_signal(const char *name, GVariant *gv)
132 {
133         GError *err = NULL;
134
135         if (g_dbus_connection_emit_signal(conn, NULL,
136                                 PKGMGR_INSTALLER_DBUS_OBJECT_PATH,
137                                 PKGMGR_INSTALLER_DBUS_INTERFACE,
138                                 name, gv, &err) != TRUE) {
139                 LOGE("g_dbus_connection_emit_signal failed: %s", err->message);
140                 g_error_free(err);
141         }
142 }
143
144 static gboolean __quit(gpointer user_data)
145 {
146         g_main_loop_quit(loop);
147         return FALSE;
148 }
149
150 static int __check_authority(int fd)
151 {
152         int r;
153         struct ucred cr;
154         socklen_t len;
155         struct passwd pwd;
156         struct passwd *pwd_r;
157         char buf[PWBUFSIZE];
158
159         len = sizeof(struct ucred);
160         r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
161         if (r != 0) {
162                 LOGE("getsockopt failed: %d", errno);
163                 return -1;
164         }
165
166         /* allow root user */
167         if (cr.uid == 0)
168                 return 0;
169
170         r = getpwuid_r(cr.uid, &pwd, buf, sizeof(buf), &pwd_r);
171         if (r != 0 || pwd_r == NULL) {
172                 LOGE("getpwuid failed: %d", r);
173                 return -1;
174         }
175
176         /* only app_fw user can send signal to agent */
177         if (strcmp(pwd_r->pw_name, APPFW_USERNAME) != 0) {
178                 LOGE("unauthorized client");
179                 return -1;
180         }
181
182         return 0;
183 }
184
185 /**
186  * packet format:
187  * +----------------+-------------+-----------+-------------------+
188  * |signal name size|GVariant size|signal name|serialized GVariant|
189  * +----------------+-------------+-----------+-------------------+
190  */
191 static gboolean __handle_signal(gint fd, GIOCondition cond, gpointer user_data)
192 {
193         int r;
194         unsigned char buf[BUFMAX];
195         int clifd;
196         struct sockaddr_un sa;
197         socklen_t s = sizeof(sa);
198         size_t type_len;
199         char *type_name;
200         gsize data_len;
201         gpointer data;
202         GVariant *gv;
203
204         clifd = accept(fd, (struct sockaddr *)&sa, &s);
205         if (clifd == -1) {
206                 LOGE("accept failed: %d", errno);
207                 return FALSE;
208         }
209
210         if (__check_authority(clifd)) {
211                 close(clifd);
212                 return TRUE;
213         }
214
215         r = recv(clifd, buf, sizeof(size_t) + sizeof(gsize), 0);
216         if (r < 0) {
217                 LOGE("recv failed: %d", errno);
218                 close(clifd);
219                 return FALSE;
220         } else if (r == 0) {
221                 LOGE("client fd already closed");
222                 close(clifd);
223                 return FALSE;
224         }
225
226         memcpy(&type_len, buf, sizeof(size_t));
227         memcpy(&data_len, buf + sizeof(size_t), sizeof(gsize));
228
229         if (type_len > BUFMAX || data_len > BUFMAX ||
230                         (type_len + data_len) > BUFMAX) {
231                 LOGE("received size is too large: %zu %zu", type_len, data_len);
232                 close(clifd);
233                 return FALSE;
234         }
235
236         r = recv(clifd, buf, type_len + data_len, 0);
237         if (r < 0) {
238                 LOGE("recv failed: %d", errno);
239                 close(clifd);
240                 return FALSE;
241         } else if (r == 0) {
242                 LOGE("client fd already closed");
243                 close(clifd);
244                 return FALSE;
245         }
246
247         if (type_len == 0) {
248                 LOGE("invalid type_len");
249                 close(clifd);
250                 return FALSE;
251         }
252
253         /* get signal name (including terminating null byte) */
254         type_name = malloc(type_len);
255         memcpy(type_name, buf, type_len);
256
257         /* get data */
258         data = malloc(data_len);
259         memcpy(data, buf + type_len, data_len);
260
261         /* floating type GVariant instance */
262         if (!strcmp(type_name, PKGMGR_INSTALLER_RES_COPY_EVENT_STR) ||
263                 !strcmp(type_name, PKGMGR_INSTALLER_RES_CREATE_DIR_EVENT_STR) ||
264                 !strcmp(type_name, PKGMGR_INSTALLER_RES_REMOVE_EVENT_STR) ||
265                 !strcmp(type_name, PKGMGR_INSTALLER_RES_UNINSTALL_EVENT_STR)) {
266                 gv = g_variant_new_from_data(G_VARIANT_TYPE("(usssv)"),
267                                 data, data_len, TRUE, NULL, NULL);
268         } else {
269                 gv = g_variant_new_from_data(G_VARIANT_TYPE("(usa(sss)ss)"),
270                                 data, data_len, TRUE, NULL, NULL);
271         }
272         __emit_signal(type_name, gv);
273
274         free(data);
275         free(type_name);
276         close(clifd);
277
278         /* renew timeout */
279         g_source_remove(tid);
280         tid = g_timeout_add_seconds(10, __quit, NULL);
281
282         return TRUE;
283 }
284
285 static int __init(void)
286 {
287         char path[PATH_MAX];
288         GError *err = NULL;
289
290         snprintf(path, sizeof(path), "/run/pkgmgr/agent/%d", getuid());
291         server_fd = __get_server_socket(path);
292         if (server_fd < 0) {
293                 LOGE("server init failed");
294                 return -1;
295         }
296
297         conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &err);
298         if (conn == NULL) {
299                 LOGE("g_bus_get_sync failed: %s", err->message);
300                 g_error_free(err);
301                 close(server_fd);
302                 return -1;
303         }
304
305         loop = g_main_loop_new(NULL, FALSE);
306         sid = g_unix_fd_add(server_fd, G_IO_IN, __handle_signal, NULL);
307         tid = g_timeout_add_seconds(10, __quit, NULL);
308
309         return 0;
310 }
311
312 static void __fini(void)
313 {
314         if (sid > 0)
315                 g_source_remove(sid);
316         if (loop)
317                 g_main_loop_unref(loop);
318         if (conn)
319                 g_object_unref(conn);
320         if (server_fd > 0)
321                 close(server_fd);
322 }
323
324 int main(int argc, char *argv[])
325 {
326         int r;
327
328         r = __init();
329         if (r < 0)
330                 return -1;
331
332         g_main_loop_run(loop);
333
334         __fini();
335
336         return 0;
337 }