1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <cerrno>
17#include <cstdlib>
18#include <cstdio>
19#include <cstdint>
20#include <getopt.h>
21#include <iostream>
22#include <map>
23#include <securec.h>
24#include <string>
25#include <unistd.h>
26#include <vector>
27
28#ifdef ENABLE_ENTER_APPSPAWN_SANDBOX
29#include "appspawn.h"
30#endif
31#include "begetctl.h"
32#include "control_fd.h"
33#include "init_utils.h"
34#include "sandbox.h"
35#include "sandbox_namespace.h"
36#include "string_ex.h"
37
38using namespace OHOS;
39struct option g_options[] = {
40    { "service_name", required_argument, nullptr, 's' },
41    { "namespace_name", required_argument, nullptr, 'n' },
42    { "process_name", required_argument, nullptr, 'p' },
43    { "process_pid", required_argument, nullptr, 'b' },
44    { "help", no_argument, nullptr, 'h' },
45    { nullptr, 0, nullptr, 0 },
46};
47
48static void Usage()
49{
50    std::cout << "sandbox -s | -n [-p] | -p | -b | -h" << std::endl;
51    std::cout << "sandbox -s, --service_name=sandbox service \"enter service sandbox\"" << std::endl;
52    std::cout << "sandbox -n, --namespace_name=namespace name \"namespace name, system, chipset etc.\"" << std::endl;
53    std::cout << "sandbox -p, --process=process name \"sh, hdcd, hdf_devhost, etc.\"" << std::endl;
54    std::cout << "sandbox -b, --process_pid=process pid \"sh, enter native app sandbox, etc.\"" << std::endl;
55    std::cout << "sandbox -h, --help \"Show help\"" << std::endl;
56#ifndef STARTUP_INIT_TEST
57    exit(0);
58#endif
59}
60
61static void RunSandbox(const std::string &sandboxName)
62{
63    InitDefaultNamespace();
64    if (!InitSandboxWithName(sandboxName.c_str())) {
65        std::cout << "Init sandbox failed." << std::endl;
66        return;
67    }
68
69    DumpSandboxByName(sandboxName.c_str());
70    if (PrepareSandbox(sandboxName.c_str()) != 0) {
71        std::cout << "Prepare sandbox failed." << std::endl;
72        return;
73    }
74    EnterDefaultNamespace();
75    CloseDefaultNamespace();
76    EnterSandbox(sandboxName.c_str());
77    return;
78}
79
80static void EnterShell()
81{
82    char *argv[] = { const_cast<char *>("sh"), nullptr };
83    char *envp[] = { nullptr };
84    if (execve("/system/bin/sh", argv, envp) != 0) {
85        std::cout << "execve sh failed! err = "<< errno << std::endl;
86    }
87    return;
88}
89
90static const int MAX_PROCESS_ARGC = 8;
91static void EnterExec(const std::string &processName)
92{
93    std::string tmpName = processName;
94    std::vector<std::string> vtr;
95    const std::string sep = " ";
96    OHOS::SplitStr(tmpName, sep, vtr, true, false);
97
98    if ((vtr.size() > MAX_PROCESS_ARGC) || (vtr.size() == 0)) {
99        std::cout << "Service parameters is error." << std::endl;
100        return;
101    }
102    char *argv[MAX_PROCESS_ARGC] = {};
103    std::vector<std::string>::iterator it;
104    int i = 0;
105    for (it = vtr.begin(); it != vtr.end(); ++it) {
106        argv[i] = (char *)(*it).c_str();
107        std::cout << std::string(argv[i]) << std::endl;
108        i++;
109    }
110    argv[i] = NULL;
111    char *envp[] = { NULL };
112    if (execve(argv[0], argv, envp) != 0) {
113        std::cout << "execve:" << argv[0] << "failed! err = "<< errno << std::endl;
114    }
115    return;
116}
117
118static int SendAppspawnCmdMessage(const CmdAgent *agent, uint16_t type, const char *cmd, const char *ptyName)
119{
120#ifdef ENABLE_ENTER_APPSPAWN_SANDBOX
121    if ((agent == NULL) || (cmd == NULL) || (ptyName == NULL)) {
122        BEGET_LOGE("Invalid parameter");
123        return -1;
124    }
125
126    AppSpawnClientHandle clientHandle;
127    int ret = AppSpawnClientInit("AppSpawn", &clientHandle);
128    BEGET_ERROR_CHECK(ret == 0,  return -1, "AppSpawnClientInit error, errno = %d", errno);
129    AppSpawnReqMsgHandle reqHandle;
130    ret = AppSpawnReqMsgCreate(AppSpawnMsgType::MSG_BEGET_CMD, cmd, &reqHandle);
131    BEGET_ERROR_CHECK(ret == 0, AppSpawnClientDestroy(clientHandle); return -1, "AppSpawnReqMsgCreate error");
132    ret = AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_BEGETCTL_BOOT);
133    BEGET_ERROR_CHECK(ret == 0, AppSpawnClientDestroy(clientHandle); return -1, "AppSpawnReqMsgSetAppFlag error");
134    ret = AppSpawnReqMsgAddStringInfo(reqHandle, MSG_EXT_NAME_BEGET_PID, cmd);
135    BEGET_ERROR_CHECK(ret == 0, AppSpawnClientDestroy(clientHandle); return -1, "add %s request message error", cmd);
136    ret = AppSpawnReqMsgAddStringInfo(reqHandle, MSG_EXT_NAME_BEGET_PTY_NAME, ptyName);
137    BEGET_ERROR_CHECK(ret == 0, AppSpawnClientDestroy(clientHandle);
138        return -1, "add %s request message error", ptyName);
139    AppSpawnResult result = {};
140    ret = AppSpawnClientSendMsg(clientHandle, reqHandle, &result);
141    if (ret != 0 || result.result != 0) {
142        AppSpawnClientDestroy(clientHandle);
143        return -1;
144    }
145    AppSpawnClientDestroy(clientHandle);
146    return 0;
147#endif
148    return -1;
149}
150
151static void CmdAppspawnClientInit(const char *cmd, CallbackSendMsgProcess sendMsg)
152{
153    if (cmd == nullptr) {
154        BEGET_LOGE("[control_fd] Invalid parameter");
155        return;
156    }
157
158    CmdAgent agent;
159    int ret = InitPtyInterface(&agent, ACTION_APP_SANDBOX, cmd, sendMsg);
160    if (ret != 0) {
161        BEGET_LOGE("App with pid=%s does not support entering sandbox environment", cmd);
162        return;
163    }
164    LE_RunLoop(LE_GetDefaultLoop());
165    LE_CloseLoop(LE_GetDefaultLoop());
166    BEGET_LOGI("Cmd Client exit ");
167}
168
169static void RunCmd(const std::string &serviceName, const std::string &namespaceName, const std::string &processName,
170    const std::string &pid)
171{
172    bool isNamespaceOnly = !namespaceName.empty() && processName.empty() && serviceName.empty() && pid.empty();
173    bool isNamespaceAndProcess = !namespaceName.empty() && !processName.empty() && serviceName.empty() && pid.empty();
174    bool isProcessOnly = namespaceName.empty() && !processName.empty() && serviceName.empty() && pid.empty();
175    bool isServiceOnly = namespaceName.empty() && processName.empty() && !serviceName.empty() && pid.empty();
176    bool isPidOnly = namespaceName.empty() && processName.empty() && serviceName.empty() && !pid.empty();
177    if (isNamespaceOnly) {
178        RunSandbox(namespaceName);
179        EnterShell();
180    } else if (isNamespaceAndProcess) {
181        RunSandbox(namespaceName);
182        EnterExec(processName);
183    } else if (isProcessOnly) {
184        std::cout << "process name:" << processName << std::endl;
185        RunSandbox(std::string("system"));
186        EnterExec(processName);
187    } else if (isServiceOnly) {
188        std::cout << "enter sandbox service name " << serviceName << std::endl;
189        CmdClientInit(INIT_CONTROL_FD_SOCKET_PATH, ACTION_SANDBOX, serviceName.c_str(), nullptr);
190    } else if (isPidOnly) {
191        CmdAppspawnClientInit(pid.c_str(), SendAppspawnCmdMessage);
192    } else {
193        Usage();
194    }
195}
196
197static int main_cmd(BShellHandle shell, int argc, char **argv)
198{
199    int rc = -1;
200    int optIndex = -1;
201    std::string serviceName {};
202    std::string namespaceName {};
203    std::string processName {};
204    std::string pid {};
205    while ((rc = getopt_long(argc, argv, "s:n:p:h:b:",  g_options, &optIndex)) != -1) {
206        switch (rc) {
207            case 0: {
208                std::string optionName = g_options[optIndex].name;
209                if (optionName == "service_name") {
210                    serviceName = optarg;
211                } else if (optionName == "help") {
212                    Usage();
213                } else if (optionName == "namespace_name") {
214                    namespaceName = optarg;
215                } else if (optionName == "process_name") {
216                    processName = optarg;
217                } else if (optionName == "process_pid") {
218                    pid = optarg;
219                }
220                break;
221            }
222            case 's':
223                serviceName = optarg;
224                break;
225            case 'h':
226                Usage();
227                break;
228            case 'n':
229                namespaceName = optarg;
230                break;
231            case 'p':
232                processName = optarg;
233                break;
234            case 'b':
235                pid = optarg;
236                break;
237            case '?':
238                std::cout << "Invalid argument\n";
239                break;
240            default:
241                std::cout << "Invalid argument\n";
242                break;
243        }
244    }
245    RunCmd(serviceName, namespaceName, processName, pid);
246    return 0;
247}
248
249MODULE_CONSTRUCTOR(void)
250{
251    const CmdInfo infos[] = {
252        {
253            const_cast<char *>("sandbox"), main_cmd, const_cast<char *>("enter service sandbox"),
254            const_cast<char *>("sandbox -s service_name"),
255            NULL
256        },
257        {
258            const_cast<char *>("sandbox"), main_cmd, const_cast<char *>("enter namespace, system, chipset etc."),
259            const_cast<char *>("sandbox -n namespace_name [-p]"),
260            NULL
261        },
262        {
263            const_cast<char *>("sandbox"), main_cmd, const_cast<char *>("enter namespace and exec process"),
264            const_cast<char *>("sandbox -p process_name"),
265            NULL
266        },
267        {
268            const_cast<char *>("sandbox"), main_cmd, const_cast<char *>("enter native app sandbox namespace"),
269            const_cast<char *>("sandbox -b pid"),
270            NULL
271        }
272    };
273    for (size_t i = 0; i < ARRAY_LENGTH(infos); i++) {
274        BShellEnvRegisterCmd(GetShellHandle(), &infos[i]);
275    }
276}
277