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);
164 g_variant_unref(extra_param);
165 g_variant_iter_free(iter);
168 signal_sender->AsyncResultForResource(signal, target_uid, req_id, pkgid,
169 status, pkg_signal::ExtraData(error_code, std::move(path_info)));
171 LOGE("Exception occured");
175 static void __emit_signal_for_pkg_event(const char* signal, GVariant* gv) {
178 char* pkg_type = NULL;
183 GVariantIter* iter = NULL;
186 g_variant_get(gv, "(u&sa(sss)&s&s)", &target_uid, &req_id, &iter,
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);
194 signal_sender->AsyncResult(signal, target_uid, req_id,
195 std::move(pkgs), key, val);
197 LOGE("Exception occured");
201 static gboolean __quit(gpointer user_data) {
202 g_main_loop_quit(loop);
206 static int __check_authority(int fd) {
211 struct passwd* pwd_r;
214 len = sizeof(struct ucred);
215 r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
217 LOGE("getsockopt failed: %d", errno);
221 /* allow root user */
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);
231 /* only app_fw user can send signal to agent */
232 if (strcmp(pwd_r->pw_name, APPFW_USERNAME) != 0) {
233 LOGE("unauthorized client");
242 * +----------------+-------------+-----------+-------------------+
243 * |signal name size|GVariant size|signal name|serialized GVariant|
244 * +----------------+-------------+-----------+-------------------+
246 static gboolean __handle_signal(gint fd,
247 GIOCondition cond, gpointer user_data) {
249 unsigned char buf[BUFMAX];
251 struct sockaddr_un sa;
252 socklen_t s = sizeof(sa);
259 clifd = accept(fd, (struct sockaddr*)&sa, &s);
261 LOGE("accept failed: %d", errno);
265 if (__check_authority(clifd)) {
270 r = recv(clifd, buf, sizeof(size_t) + sizeof(gsize), 0);
272 LOGE("recv failed: %d", errno);
276 LOGE("client fd already closed");
281 memcpy(&type_len, buf, sizeof(size_t));
282 memcpy(&data_len, buf + sizeof(size_t), sizeof(gsize));
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);
291 r = recv(clifd, buf, type_len + data_len, 0);
293 LOGE("recv failed: %d", errno);
297 LOGE("client fd already closed");
303 LOGE("invalid type_len");
308 /* get signal name (including terminating null byte) */
309 type_name = static_cast<char*>(malloc(type_len));
310 memcpy(type_name, buf, type_len);
313 data = malloc(data_len);
314 memcpy(data, buf + type_len, data_len);
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);
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);
335 ssize_t send_byte = send(clifd, &ret, sizeof(ret), MSG_NOSIGNAL);
337 LOGE("send() is failed. fd: %d, errno: %d", fd, errno);
342 g_source_remove(tid);
343 tid = g_timeout_add_seconds(10, __quit, NULL);
348 static int __init(void) {
352 snprintf(path, sizeof(path), "/run/pkgmgr/agent/%d", getuid());
353 server_fd = __get_server_socket(path);
355 LOGE("server init failed");
359 if (aul_proc_register(AGENT_APPID, NULL) != AUL_R_OK) {
360 LOGE("aul_proc_register fail");
365 signal_sender = std::make_unique<pkg_group::PkgSignal>(AGENT_APPID, false);
367 LOGE("Exception occured");
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);
378 static void __fini(void) {
380 g_source_remove(sid);
382 g_main_loop_unref(loop);
385 aul_proc_deregister();
388 int main(int argc, char* argv[]) {
395 LOGW("signal agent start");
397 g_main_loop_run(loop);