1d9f0492fSopenharmony_ci/*
2d9f0492fSopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd.
3d9f0492fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4d9f0492fSopenharmony_ci * you may not use this file except in compliance with the License.
5d9f0492fSopenharmony_ci * You may obtain a copy of the License at
6d9f0492fSopenharmony_ci *
7d9f0492fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8d9f0492fSopenharmony_ci *
9d9f0492fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10d9f0492fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11d9f0492fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12d9f0492fSopenharmony_ci * See the License for the specific language governing permissions and
13d9f0492fSopenharmony_ci * limitations under the License.
14d9f0492fSopenharmony_ci */
15d9f0492fSopenharmony_ci
16d9f0492fSopenharmony_ci#include <fcntl.h>
17d9f0492fSopenharmony_ci#include <unistd.h>
18d9f0492fSopenharmony_ci#include <sys/types.h>
19d9f0492fSopenharmony_ci#include <sys/socket.h>
20d9f0492fSopenharmony_ci
21d9f0492fSopenharmony_ci#include "beget_ext.h"
22d9f0492fSopenharmony_ci#include "control_fd.h"
23d9f0492fSopenharmony_ci#include "init_utils.h"
24d9f0492fSopenharmony_ci#include "securec.h"
25d9f0492fSopenharmony_ci
26d9f0492fSopenharmony_cistatic CmdService g_cmdService;
27d9f0492fSopenharmony_cistatic LoopHandle g_controlFdLoop = NULL;
28d9f0492fSopenharmony_ci
29d9f0492fSopenharmony_ciCallbackControlFdProcess g_controlFdFunc = NULL;
30d9f0492fSopenharmony_ci
31d9f0492fSopenharmony_cistatic void OnClose(const TaskHandle task)
32d9f0492fSopenharmony_ci{
33d9f0492fSopenharmony_ci    CmdTask *agent = (CmdTask *)LE_GetUserData(task);
34d9f0492fSopenharmony_ci    BEGET_ERROR_CHECK(agent != NULL, return, "[control_fd] Can not get agent");
35d9f0492fSopenharmony_ci    OH_ListRemove(&agent->item);
36d9f0492fSopenharmony_ci    OH_ListInit(&agent->item);
37d9f0492fSopenharmony_ci}
38d9f0492fSopenharmony_ci
39d9f0492fSopenharmony_ciCONTROL_FD_STATIC int CheckSocketPermission(const TaskHandle task)
40d9f0492fSopenharmony_ci{
41d9f0492fSopenharmony_ci    struct ucred uc = {-1, -1, -1};
42d9f0492fSopenharmony_ci    socklen_t len = sizeof(uc);
43d9f0492fSopenharmony_ci    if (getsockopt(LE_GetSocketFd(task), SOL_SOCKET, SO_PEERCRED, &uc, &len) < 0) {
44d9f0492fSopenharmony_ci        BEGET_LOGE("Failed to get socket option. err = %d", errno);
45d9f0492fSopenharmony_ci        return -1;
46d9f0492fSopenharmony_ci    }
47d9f0492fSopenharmony_ci    // Only root is permitted to use control fd of init.
48d9f0492fSopenharmony_ci    if (uc.uid != 0) { // non-root user
49d9f0492fSopenharmony_ci        errno = EPERM;
50d9f0492fSopenharmony_ci        return -1;
51d9f0492fSopenharmony_ci    }
52d9f0492fSopenharmony_ci    return 0;
53d9f0492fSopenharmony_ci}
54d9f0492fSopenharmony_ci
55d9f0492fSopenharmony_ciCONTROL_FD_STATIC void CmdOnRecvMessage(const TaskHandle task, const uint8_t *buffer, uint32_t buffLen)
56d9f0492fSopenharmony_ci{
57d9f0492fSopenharmony_ci    if (buffer == NULL) {
58d9f0492fSopenharmony_ci        return;
59d9f0492fSopenharmony_ci    }
60d9f0492fSopenharmony_ci    CmdTask *agent = (CmdTask *)LE_GetUserData(task);
61d9f0492fSopenharmony_ci    BEGET_ERROR_CHECK(agent != NULL, return, "[control_fd] Can not get agent");
62d9f0492fSopenharmony_ci
63d9f0492fSopenharmony_ci    // parse msg to exec
64d9f0492fSopenharmony_ci    CmdMessage *msg = (CmdMessage *)buffer;
65d9f0492fSopenharmony_ci    if ((msg->type >= ACTION_MAX) || (msg->cmd[0] == '\0') || (msg->ptyName[0] == '\0')) {
66d9f0492fSopenharmony_ci        BEGET_LOGE("[control_fd] Received msg is invalid");
67d9f0492fSopenharmony_ci        return;
68d9f0492fSopenharmony_ci    }
69d9f0492fSopenharmony_ci
70d9f0492fSopenharmony_ci    BEGET_ERROR_CHECK(CheckSocketPermission(task) >= 0, return, "Check socket permission failed, err = %d", errno);
71d9f0492fSopenharmony_ci
72d9f0492fSopenharmony_ci#ifndef STARTUP_INIT_TEST
73d9f0492fSopenharmony_ci    agent->pid = fork();
74d9f0492fSopenharmony_ci    if (agent->pid == 0) {
75d9f0492fSopenharmony_ci        OpenConsole();
76d9f0492fSopenharmony_ci        char *realPath = GetRealPath(msg->ptyName);
77d9f0492fSopenharmony_ci        BEGET_ERROR_CHECK(realPath != NULL, _exit(1), "Failed get realpath, err=%d", errno);
78d9f0492fSopenharmony_ci        int n = strncmp(realPath, "/dev/pts/", strlen("/dev/pts/"));
79d9f0492fSopenharmony_ci        BEGET_ERROR_CHECK(n == 0, free(realPath); _exit(1), "pts path %s is invaild", realPath);
80d9f0492fSopenharmony_ci        int fd = open(realPath, O_RDWR);
81d9f0492fSopenharmony_ci        free(realPath);
82d9f0492fSopenharmony_ci        BEGET_ERROR_CHECK(fd >= 0, _exit(1), "Failed open %s, err=%d", msg->ptyName, errno);
83d9f0492fSopenharmony_ci        (void)dup2(fd, STDIN_FILENO);
84d9f0492fSopenharmony_ci        (void)dup2(fd, STDOUT_FILENO);
85d9f0492fSopenharmony_ci        (void)dup2(fd, STDERR_FILENO); // Redirect fd to 0, 1, 2
86d9f0492fSopenharmony_ci        (void)close(fd);
87d9f0492fSopenharmony_ci        if (g_controlFdFunc != NULL) {
88d9f0492fSopenharmony_ci            g_controlFdFunc(msg->type, msg->cmd, NULL);
89d9f0492fSopenharmony_ci        }
90d9f0492fSopenharmony_ci        _exit(0);
91d9f0492fSopenharmony_ci    } else if (agent->pid < 0) {
92d9f0492fSopenharmony_ci        BEGET_LOGE("[control_fd] Failed to fork child process, err = %d", errno);
93d9f0492fSopenharmony_ci    }
94d9f0492fSopenharmony_ci#endif
95d9f0492fSopenharmony_ci    return;
96d9f0492fSopenharmony_ci}
97d9f0492fSopenharmony_ci
98d9f0492fSopenharmony_ciCONTROL_FD_STATIC int SendMessage(LoopHandle loop, TaskHandle task, const char *message)
99d9f0492fSopenharmony_ci{
100d9f0492fSopenharmony_ci    if (message == NULL) {
101d9f0492fSopenharmony_ci        BEGET_LOGE("[control_fd] Invalid parameter");
102d9f0492fSopenharmony_ci        return -1;
103d9f0492fSopenharmony_ci    }
104d9f0492fSopenharmony_ci    BufferHandle handle = NULL;
105d9f0492fSopenharmony_ci    uint32_t bufferSize = strlen(message) + 1;
106d9f0492fSopenharmony_ci    handle = LE_CreateBuffer(loop, bufferSize);
107d9f0492fSopenharmony_ci    char *buff = (char *)LE_GetBufferInfo(handle, NULL, &bufferSize);
108d9f0492fSopenharmony_ci    BEGET_ERROR_CHECK(buff != NULL, return -1, "[control_fd] Failed get buffer info");
109d9f0492fSopenharmony_ci    int ret = memcpy_s(buff, bufferSize, message, strlen(message) + 1);
110d9f0492fSopenharmony_ci    BEGET_ERROR_CHECK(ret == 0, LE_FreeBuffer(g_controlFdLoop, task, handle);
111d9f0492fSopenharmony_ci        return -1, "[control_fd] Failed memcpy_s err=%d", errno);
112d9f0492fSopenharmony_ci    LE_STATUS status = LE_Send(loop, task, handle, strlen(message) + 1);
113d9f0492fSopenharmony_ci    BEGET_ERROR_CHECK(status == LE_SUCCESS, return -1, "[control_fd] Failed le send msg");
114d9f0492fSopenharmony_ci    return 0;
115d9f0492fSopenharmony_ci}
116d9f0492fSopenharmony_ci
117d9f0492fSopenharmony_ciCONTROL_FD_STATIC int CmdOnIncommingConnect(const LoopHandle loop, const TaskHandle server)
118d9f0492fSopenharmony_ci{
119d9f0492fSopenharmony_ci    TaskHandle client = NULL;
120d9f0492fSopenharmony_ci    LE_StreamInfo info = {};
121d9f0492fSopenharmony_ci#ifndef STARTUP_INIT_TEST
122d9f0492fSopenharmony_ci    info.baseInfo.flags = TASK_STREAM | TASK_PIPE | TASK_CONNECT;
123d9f0492fSopenharmony_ci#else
124d9f0492fSopenharmony_ci    info.baseInfo.flags = TASK_STREAM | TASK_PIPE | TASK_CONNECT | TASK_TEST;
125d9f0492fSopenharmony_ci#endif
126d9f0492fSopenharmony_ci    info.baseInfo.close = OnClose;
127d9f0492fSopenharmony_ci    info.baseInfo.userDataSize = sizeof(CmdTask);
128d9f0492fSopenharmony_ci    info.disConnectComplete = NULL;
129d9f0492fSopenharmony_ci    info.sendMessageComplete = NULL;
130d9f0492fSopenharmony_ci    info.recvMessage = CmdOnRecvMessage;
131d9f0492fSopenharmony_ci    int ret = LE_AcceptStreamClient(g_controlFdLoop, server, &client, &info);
132d9f0492fSopenharmony_ci    BEGET_ERROR_CHECK(ret == 0, return -1, "[control_fd] Failed accept stream")
133d9f0492fSopenharmony_ci    CmdTask *agent = (CmdTask *)LE_GetUserData(client);
134d9f0492fSopenharmony_ci    BEGET_ERROR_CHECK(agent != NULL, return -1, "[control_fd] Invalid agent");
135d9f0492fSopenharmony_ci    agent->task = client;
136d9f0492fSopenharmony_ci    OH_ListInit(&agent->item);
137d9f0492fSopenharmony_ci    ret = SendMessage(g_controlFdLoop, agent->task, "connect success.");
138d9f0492fSopenharmony_ci    BEGET_ERROR_CHECK(ret == 0, return -1, "[control_fd] Failed send msg");
139d9f0492fSopenharmony_ci    OH_ListAddTail(&g_cmdService.head, &agent->item);
140d9f0492fSopenharmony_ci    return 0;
141d9f0492fSopenharmony_ci}
142d9f0492fSopenharmony_ci
143d9f0492fSopenharmony_civoid CmdServiceInit(const char *socketPath, CallbackControlFdProcess func, LoopHandle loop)
144d9f0492fSopenharmony_ci{
145d9f0492fSopenharmony_ci    if ((socketPath == NULL) || (func == NULL) || (loop == NULL)) {
146d9f0492fSopenharmony_ci        BEGET_LOGE("[control_fd] Invalid parameter");
147d9f0492fSopenharmony_ci        return;
148d9f0492fSopenharmony_ci    }
149d9f0492fSopenharmony_ci    OH_ListInit(&g_cmdService.head);
150d9f0492fSopenharmony_ci    LE_StreamServerInfo info = {};
151d9f0492fSopenharmony_ci    info.baseInfo.flags = TASK_STREAM | TASK_SERVER | TASK_PIPE;
152d9f0492fSopenharmony_ci    info.server = (char *)socketPath;
153d9f0492fSopenharmony_ci    info.socketId = -1;
154d9f0492fSopenharmony_ci    info.baseInfo.close = NULL;
155d9f0492fSopenharmony_ci    info.disConnectComplete = NULL;
156d9f0492fSopenharmony_ci    info.incommingConnect = CmdOnIncommingConnect;
157d9f0492fSopenharmony_ci    info.sendMessageComplete = NULL;
158d9f0492fSopenharmony_ci    info.recvMessage = NULL;
159d9f0492fSopenharmony_ci    g_controlFdFunc = func;
160d9f0492fSopenharmony_ci    if (g_controlFdLoop == NULL) {
161d9f0492fSopenharmony_ci        g_controlFdLoop = loop;
162d9f0492fSopenharmony_ci    }
163d9f0492fSopenharmony_ci    (void)LE_CreateStreamServer(g_controlFdLoop, &g_cmdService.serverTask, &info);
164d9f0492fSopenharmony_ci}
165d9f0492fSopenharmony_ci
166d9f0492fSopenharmony_cistatic int ClientTraversalProc(ListNode *node, void *data)
167d9f0492fSopenharmony_ci{
168d9f0492fSopenharmony_ci    CmdTask *info = ListEntry(node, CmdTask, item);
169d9f0492fSopenharmony_ci    int pid = *(int *)data;
170d9f0492fSopenharmony_ci    return pid - info->pid;
171d9f0492fSopenharmony_ci}
172d9f0492fSopenharmony_ci
173d9f0492fSopenharmony_civoid CmdServiceProcessDelClient(pid_t pid)
174d9f0492fSopenharmony_ci{
175d9f0492fSopenharmony_ci    ListNode *node = OH_ListFind(&g_cmdService.head, (void *)&pid, ClientTraversalProc);
176d9f0492fSopenharmony_ci    if (node != NULL) {
177d9f0492fSopenharmony_ci        CmdTask *agent = ListEntry(node, CmdTask, item);
178d9f0492fSopenharmony_ci        OH_ListRemove(&agent->item);
179d9f0492fSopenharmony_ci        OH_ListInit(&agent->item);
180d9f0492fSopenharmony_ci        LE_CloseTask(g_controlFdLoop, agent->task);
181d9f0492fSopenharmony_ci    }
182d9f0492fSopenharmony_ci}
183d9f0492fSopenharmony_ci
184d9f0492fSopenharmony_cistatic void CmdServiceDestroyProc(ListNode *node)
185d9f0492fSopenharmony_ci{
186d9f0492fSopenharmony_ci    if (node == NULL) {
187d9f0492fSopenharmony_ci        return;
188d9f0492fSopenharmony_ci    }
189d9f0492fSopenharmony_ci    CmdTask *agent = ListEntry(node, CmdTask, item);
190d9f0492fSopenharmony_ci    OH_ListRemove(&agent->item);
191d9f0492fSopenharmony_ci    OH_ListInit(&agent->item);
192d9f0492fSopenharmony_ci    LE_CloseTask(g_controlFdLoop, agent->task);
193d9f0492fSopenharmony_ci}
194d9f0492fSopenharmony_ci
195d9f0492fSopenharmony_civoid CmdServiceProcessDestroyClient(void)
196d9f0492fSopenharmony_ci{
197d9f0492fSopenharmony_ci    OH_ListRemoveAll(&g_cmdService.head, CmdServiceDestroyProc);
198d9f0492fSopenharmony_ci    LE_StopLoop(g_controlFdLoop);
199d9f0492fSopenharmony_ci}
200