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.
27 #include <sys/socket.h>
28 #include <sys/types.h>
30 #include <linux/limits.h>
34 #include <glib-unix.h>
36 #include <systemd/sd-daemon.h>
44 #include "src/pkgmgr_installer_type.h"
45 #include "src/PkgSignal.h"
50 #define LOG_TAG "PKGMGR_INSTALLER_SIGNAL_AGENT"
53 #define PWBUFSIZE sysconf(_SC_GETPW_R_SIZE_MAX)
54 #define APPFW_USERNAME "app_fw"
55 #define AGENT_APPID "signal_agent"
57 namespace pkg_group = rpc_port::PkgSignal::group;
58 namespace pkg_signal = rpc_port::PkgSignal;
60 static int server_fd = -1;
61 static GMainLoop* loop;
64 static std::unique_ptr<pkg_group::PkgSignal> signal_sender;
66 static int __create_server_socket(const char* path) {
69 struct sockaddr_un sa;
71 fd = socket(AF_UNIX, SOCK_STREAM, 0);
73 LOGE("socket create failed: %d", errno);
77 memset(&sa, 0, sizeof(sa));
78 sa.sun_family = AF_UNIX;
79 snprintf(sa.sun_path, sizeof(sa.sun_path), "%s", path);
81 r = unlink(sa.sun_path);
82 if (r == -1 && errno != ENOENT) {
83 LOGE("unlink(%s) failed: %d", sa.sun_path, errno);
88 r = bind(fd, (struct sockaddr*)&sa, sizeof(sa));
90 LOGE("bind(%s) failed: %d", sa.sun_path, errno);
95 r = chmod(sa.sun_path, 0660);
97 LOGW("chmod(%s) failed: %d", sa.sun_path, errno);
99 r = listen(fd, SOMAXCONN);
101 LOGE("listen(%s) failed: %d", sa.sun_path, errno);
109 static int __get_server_socket(const char* path) {
115 n = sd_listen_fds(0);
117 LOGE("sd_listen_fds: %d", n);
120 return __create_server_socket(path);
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);
132 LOGE("socket is not passed, create server socket");
133 return __create_server_socket(path);
139 static void __emit_signal_for_res_event(const char* signal, GVariant* gv) {
148 GVariant* extra_param = NULL;
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);
159 std::vector<pkg_signal::PathInfo> path_info;
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);
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);
171 static void __emit_signal_for_pkg_event(GVariant* gv) {
174 char* pkg_type = NULL;
179 GVariantIter* iter = NULL;
182 g_variant_get(gv, "(u&sa(sss)&s&s)", &target_uid, &req_id, &iter,
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);
191 static gboolean __quit(gpointer user_data) {
192 g_main_loop_quit(loop);
196 static int __check_authority(int fd) {
201 struct passwd* pwd_r;
204 len = sizeof(struct ucred);
205 r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
207 LOGE("getsockopt failed: %d", errno);
211 /* allow root user */
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);
221 /* only app_fw user can send signal to agent */
222 if (strcmp(pwd_r->pw_name, APPFW_USERNAME) != 0) {
223 LOGE("unauthorized client");
232 * +----------------+-------------+-----------+-------------------+
233 * |signal name size|GVariant size|signal name|serialized GVariant|
234 * +----------------+-------------+-----------+-------------------+
236 static gboolean __handle_signal(gint fd,
237 GIOCondition cond, gpointer user_data) {
239 unsigned char buf[BUFMAX];
241 struct sockaddr_un sa;
242 socklen_t s = sizeof(sa);
249 clifd = accept(fd, (struct sockaddr*)&sa, &s);
251 LOGE("accept failed: %d", errno);
255 if (__check_authority(clifd)) {
260 r = recv(clifd, buf, sizeof(size_t) + sizeof(gsize), 0);
262 LOGE("recv failed: %d", errno);
266 LOGE("client fd already closed");
271 memcpy(&type_len, buf, sizeof(size_t));
272 memcpy(&data_len, buf + sizeof(size_t), sizeof(gsize));
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);
281 r = recv(clifd, buf, type_len + data_len, 0);
283 LOGE("recv failed: %d", errno);
287 LOGE("client fd already closed");
293 LOGE("invalid type_len");
298 /* get signal name (including terminating null byte) */
299 type_name = static_cast<char*>(malloc(type_len));
300 memcpy(type_name, buf, type_len);
303 data = malloc(data_len);
304 memcpy(data, buf + type_len, data_len);
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);
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);
326 g_source_remove(tid);
327 tid = g_timeout_add_seconds(10, __quit, NULL);
332 static int __init(void) {
336 snprintf(path, sizeof(path), "/run/pkgmgr/agent/%d", getuid());
337 server_fd = __get_server_socket(path);
339 LOGE("server init failed");
343 if (aul_proc_register(AGENT_APPID, NULL) != AUL_R_OK) {
344 LOGE("aul_proc_register fail");
349 signal_sender = std::make_unique<pkg_group::PkgSignal>(AGENT_APPID, false);
351 LOGE("Exception occured");
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);
362 static void __fini(void) {
364 g_source_remove(sid);
366 g_main_loop_unref(loop);
369 aul_proc_deregister();
372 int main(int argc, char* argv[]) {
379 g_main_loop_run(loop);