2 * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
25 #include <sys/socket.h>
26 #include <sys/types.h>
28 #include <linux/limits.h>
32 #include <glib-unix.h>
34 #include <systemd/sd-daemon.h>
38 #include "pkgmgr_installer_config.h"
39 #include "pkgmgr_installer_type.h"
44 #define LOG_TAG "PKGMGR_INSTALLER_SIGNAL_AGENT"
47 #define PWBUFSIZE sysconf(_SC_GETPW_R_SIZE_MAX)
48 #define APPFW_USERNAME "app_fw"
50 static int server_fd = -1;
51 static GMainLoop *loop;
54 static GDBusConnection *conn;
56 static int __create_server_socket(const char *path)
60 struct sockaddr_un sa;
62 fd = socket(AF_UNIX, SOCK_STREAM, 0);
64 LOGE("socket create failed: %d", errno);
68 memset(&sa, 0, sizeof(sa));
69 sa.sun_family = AF_UNIX;
70 snprintf(sa.sun_path, sizeof(sa.sun_path), "%s", path);
72 r = unlink(sa.sun_path);
73 if (r == -1 && errno != ENOENT) {
74 LOGE("unlink(%s) failed: %d", sa.sun_path, errno);
79 r = bind(fd, (struct sockaddr *)&sa, sizeof(sa));
81 LOGE("bind(%s) failed: %d", sa.sun_path, errno);
86 r = chmod(sa.sun_path, 0660);
88 LOGW("chmod(%s) failed: %d", sa.sun_path, errno);
90 r = listen(fd, SOMAXCONN);
92 LOGE("listen(%s) failed: %d", sa.sun_path, errno);
100 static int __get_server_socket(const char *path)
107 n = sd_listen_fds(0);
109 LOGE("sd_listen_fds: %d", n);
112 return __create_server_socket(path);
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);
124 LOGE("socket is not passed, create server socket");
125 return __create_server_socket(path);
131 static void __emit_signal(const char *name, GVariant *gv)
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);
144 static gboolean __quit(gpointer user_data)
146 g_main_loop_quit(loop);
150 static int __check_authority(int fd)
156 struct passwd *pwd_r;
159 len = sizeof(struct ucred);
160 r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
162 LOGE("getsockopt failed: %d", errno);
166 /* allow root user */
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);
176 /* only app_fw user can send signal to agent */
177 if (strcmp(pwd_r->pw_name, APPFW_USERNAME) != 0) {
178 LOGE("unauthorized client");
187 * +----------------+-------------+-----------+-------------------+
188 * |signal name size|GVariant size|signal name|serialized GVariant|
189 * +----------------+-------------+-----------+-------------------+
191 static gboolean __handle_signal(gint fd, GIOCondition cond, gpointer user_data)
194 unsigned char buf[BUFMAX];
196 struct sockaddr_un sa;
197 socklen_t s = sizeof(sa);
204 clifd = accept(fd, (struct sockaddr *)&sa, &s);
206 LOGE("accept failed: %d", errno);
210 if (__check_authority(clifd)) {
215 r = recv(clifd, buf, sizeof(size_t) + sizeof(gsize), 0);
217 LOGE("recv failed: %d", errno);
221 LOGE("client fd already closed");
226 memcpy(&type_len, buf, sizeof(size_t));
227 memcpy(&data_len, buf + sizeof(size_t), sizeof(gsize));
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);
236 r = recv(clifd, buf, type_len + data_len, 0);
238 LOGE("recv failed: %d", errno);
242 LOGE("client fd already closed");
248 LOGE("invalid type_len");
253 /* get signal name (including terminating null byte) */
254 type_name = malloc(type_len);
255 memcpy(type_name, buf, type_len);
258 data = malloc(data_len);
259 memcpy(data, buf + type_len, data_len);
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);
269 gv = g_variant_new_from_data(G_VARIANT_TYPE("(usa(sss)ss)"),
270 data, data_len, TRUE, NULL, NULL);
272 __emit_signal(type_name, gv);
279 g_source_remove(tid);
280 tid = g_timeout_add_seconds(10, __quit, NULL);
285 static int __init(void)
290 snprintf(path, sizeof(path), "/run/pkgmgr/agent/%d", getuid());
291 server_fd = __get_server_socket(path);
293 LOGE("server init failed");
297 conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &err);
299 LOGE("g_bus_get_sync failed: %s", err->message);
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);
312 static void __fini(void)
315 g_source_remove(sid);
317 g_main_loop_unref(loop);
319 g_object_unref(conn);
324 int main(int argc, char *argv[])
332 g_main_loop_run(loop);