1/*
2 * Copyright (C) 2021 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#include "daemon.h"
16
17#include <openssl/sha.h>
18#include "daemon_updater.h"
19#include "flashd_define.h"
20#include "serial_struct.h"
21
22namespace Hdc {
23HdcDaemon::HdcDaemon(bool serverOrDaemonIn)
24    : HdcSessionBase(serverOrDaemonIn)
25{
26    clsTCPServ = nullptr;
27    clsUSBServ = nullptr;
28    clsJdwp = nullptr;
29    enableSecure = false;
30}
31
32HdcDaemon::~HdcDaemon()
33{
34    WRITE_LOG(LOG_DEBUG, "~HdcDaemon");
35}
36
37void HdcDaemon::ClearInstanceResource()
38{
39    TryStopInstance();
40    Base::TryCloseLoop(&loopMain, "HdcDaemon::~HdcDaemon");
41    if (clsTCPServ) {
42        delete (HdcDaemonTCP *)clsTCPServ;
43        clsTCPServ = nullptr;
44    }
45    if (clsUSBServ) {
46        delete (HdcDaemonUSB *)clsUSBServ;
47        clsUSBServ = nullptr;
48    }
49    if (clsJdwp) {
50        delete (HdcJdwp *)clsJdwp;
51        clsJdwp = nullptr;
52    }
53    WRITE_LOG(LOG_DEBUG, "~HdcDaemon finish");
54}
55
56void HdcDaemon::TryStopInstance()
57{
58    ClearSessions();
59    if (clsTCPServ) {
60        WRITE_LOG(LOG_DEBUG, "Stop TCP");
61        ((HdcDaemonTCP *)clsTCPServ)->Stop();
62    }
63    if (clsUSBServ) {
64        WRITE_LOG(LOG_DEBUG, "Stop USB");
65        ((HdcDaemonUSB *)clsUSBServ)->Stop();
66    }
67    ((HdcJdwp *)clsJdwp)->Stop();
68    // workaround temply remove MainLoop instance clear
69    ReMainLoopForInstanceClear();
70    WRITE_LOG(LOG_DEBUG, "Stop loopmain");
71}
72
73void HdcDaemon::InitMod(bool bEnableTCP, bool bEnableUSB)
74{
75    WRITE_LOG(LOG_DEBUG, "HdcDaemon InitMod");
76    if (bEnableTCP) {
77        // tcp
78        clsTCPServ = new HdcDaemonTCP(false, this);
79        ((HdcDaemonTCP *)clsTCPServ)->Initial();
80    }
81    if (bEnableUSB) {
82        // usb
83        clsUSBServ = new HdcDaemonUSB(false, this);
84        ((HdcDaemonUSB *)clsUSBServ)->Initial();
85    }
86
87    clsJdwp = new HdcJdwp(&loopMain);
88    ((HdcJdwp *)clsJdwp)->Initial();
89
90    // enable security
91    string secure;
92    SystemDepend::GetDevItem("ro.hdc.secure", secure);
93    enableSecure = (Base::Trim(secure) == "1");
94}
95
96// clang-format off
97bool HdcDaemon::RedirectToTask(HTaskInfo hTaskInfo, HSession hSession, const uint32_t channelId,
98    const uint16_t command, uint8_t *payload, const int payloadSize)
99{
100    bool ret = true;
101    hTaskInfo->ownerSessionClass = this;
102    WRITE_LOG(LOG_DEBUG, "RedirectToTask command %d", command);
103    switch (command) {
104#ifndef UPDATER_BUILD_VARIANT_USER
105        case CMD_UNITY_EXECUTE:
106            ret = TaskCommandDispatch<HdcDaemonUnity>(hTaskInfo, TYPE_UNITY, command, payload, payloadSize);
107            break;
108        case CMD_SHELL_INIT:
109        case CMD_SHELL_DATA:
110            ret = TaskCommandDispatch<HdcShell>(hTaskInfo, TYPE_SHELL, command, payload, payloadSize);
111            break;
112        case CMD_FILE_CHECK:
113        case CMD_FILE_DATA:
114        case CMD_FILE_FINISH:
115        case CMD_FILE_INIT:
116        case CMD_FILE_BEGIN:
117            ret = TaskCommandDispatch<HdcFile>(hTaskInfo, TASK_FILE, command, payload, payloadSize);
118            break;
119#endif
120        case CMD_UNITY_REBOOT:
121        case CMD_UNITY_HILOG:
122            ret = TaskCommandDispatch<HdcDaemonUnity>(hTaskInfo, TYPE_UNITY, command, payload, payloadSize);
123            break;
124        // One-way function, so fewer options
125        case CMD_UPDATER_UPDATE_INIT:
126        case CMD_UPDATER_FLASH_INIT:
127        case CMD_UPDATER_CHECK:
128        case CMD_UPDATER_BEGIN:
129        case CMD_UPDATER_DATA:
130        case CMD_UPDATER_FINISH:
131        case CMD_UPDATER_ERASE:
132        case CMD_UPDATER_FORMAT:
133        case CMD_UPDATER_PROGRESS:
134            ret = TaskCommandDispatch<DaemonUpdater>(hTaskInfo, TASK_UPDATER, command, payload, payloadSize);
135            break;
136        case CMD_UNITY_REMOUNT:
137        case CMD_UNITY_RUNMODE:
138        case CMD_UNITY_ROOTRUN:
139        case CMD_UNITY_BUGREPORT_INIT:
140        case CMD_JDWP_LIST:
141        case CMD_JDWP_TRACK:
142            ret = TaskCommandDispatch<InvalidDaemon>(hTaskInfo, TASK_FAKE, command, payload, payloadSize);
143            break;
144        default:
145            break;
146    }
147    return ret;
148}
149
150bool HdcDaemon::HandDaemonAuth(HSession hSession, const uint32_t channelId, SessionHandShake &handshake)
151{
152    bool ret = false;
153    switch (handshake.authType) {
154        case AUTH_NONE: {  // AUTH_NONE -> AUTH
155            hSession->tokenRSA = Base::GetRandomString(SHA_DIGEST_LENGTH);
156            handshake.authType = AUTH_TOKEN;
157            handshake.buf = hSession->tokenRSA;
158            string bufString = SerialStruct::SerializeToString(handshake);
159            Send(hSession->sessionId, channelId, CMD_KERNEL_HANDSHAKE, (uint8_t *)bufString.c_str(), bufString.size());
160            ret = true;
161            break;
162        }
163        case AUTH_SIGNATURE: {
164            // When Host is first connected to the device, the signature authentication is inevitable, and the
165            // certificate verification must be triggered.
166            //
167            // When the certificate is verified, the client sends a public key to the device, triggered the system UI
168            // jump out dialog, and click the system, the system will store the Host public key certificate in the
169            // device locally, and the signature authentication will be correct when the subsequent connection is
170            // connected.
171            if (!HdcAuth::AuthVerify((uint8_t *)hSession->tokenRSA.c_str(),
172                (uint8_t *)handshake.buf.c_str(), handshake.buf.size())) {
173                // Next auth
174                handshake.authType = AUTH_TOKEN;
175                handshake.buf = hSession->tokenRSA;
176                string bufString = SerialStruct::SerializeToString(handshake);
177                Send(hSession->sessionId, channelId, CMD_KERNEL_HANDSHAKE, (uint8_t *)bufString.c_str(),
178                     bufString.size());
179                break;
180            }
181            ret = true;
182            break;
183        }
184        case AUTH_PUBLICKEY: {
185            ret = HdcAuth::PostUIConfirm(handshake.buf);
186            WRITE_LOG(LOG_DEBUG, "Auth host OK, postUIConfirm");
187            break;
188        }
189        default:
190            break;
191    }
192    return ret;
193}
194
195bool HdcDaemon::DaemonSessionHandshake(HSession hSession, const uint32_t channelId, uint8_t *payload, int payloadSize)
196{
197    // session handshake step2
198    string s = string((char *)payload, payloadSize);
199    SessionHandShake handshake;
200    string err;
201    SerialStruct::ParseFromString(handshake, s);
202    // banner to check is parse ok...
203    if (handshake.banner != HANDSHAKE_MESSAGE) {
204        hSession->availTailIndex = 0;
205        WRITE_LOG(LOG_FATAL, "Recv server-hello failed");
206        return false;
207    }
208    if (handshake.authType == AUTH_NONE) {
209        // daemon handshake 1st packet
210        uint32_t unOld = hSession->sessionId;
211        hSession->sessionId = handshake.sessionId;
212        hSession->connectKey = handshake.connectKey;
213        AdminSession(OP_UPDATE, unOld, hSession);
214        if (clsUSBServ != nullptr) {
215            (reinterpret_cast<HdcDaemonUSB *>(clsUSBServ))->OnNewHandshakeOK(hSession->sessionId);
216        }
217
218        handshake.sessionId = 0;
219        handshake.connectKey = "";
220    }
221    if (enableSecure && !HandDaemonAuth(hSession, channelId, handshake)) {
222        return false;
223    }
224    // handshake auth OK.Can append the sending device information to HOST
225    char hostName[BUF_SIZE_MEDIUM] = "";
226    size_t len = sizeof(hostName);
227    uv_os_gethostname(hostName, &len);
228    handshake.authType = AUTH_OK;
229    handshake.buf = hostName;
230    string bufString = SerialStruct::SerializeToString(handshake);
231    Send(hSession->sessionId, channelId, CMD_KERNEL_HANDSHAKE, (uint8_t *)bufString.c_str(), bufString.size());
232    hSession->handshakeOK = true;
233    return true;
234}
235
236bool HdcDaemon::FetchCommand(HSession hSession, const uint32_t channelId, const uint16_t command, uint8_t *payload,
237                             int payloadSize)
238{
239    WRITE_LOG(LOG_DEBUG, "FetchCommand command %d", command);
240    bool ret = true;
241    if (!hSession->handshakeOK && command != CMD_KERNEL_HANDSHAKE) {
242        ret = false;
243        return ret;
244    }
245    switch (command) {
246        case CMD_KERNEL_HANDSHAKE: {
247            // session handshake step2
248            ret = DaemonSessionHandshake(hSession, channelId, payload, payloadSize);
249            break;
250        }
251        case CMD_KERNEL_CHANNEL_CLOSE: {  // Daemon is only cleaning up the Channel task
252            ClearOwnTasks(hSession, channelId);
253            if (*payload != 0) {
254                --(*payload);
255                Send(hSession->sessionId, channelId, CMD_KERNEL_CHANNEL_CLOSE, payload, 1);
256            }
257            ret = true;
258            break;
259        }
260        default:
261            ret = DispatchTaskData(hSession, channelId, command, payload, payloadSize);
262            break;
263    }
264    return ret;
265}
266
267bool HdcDaemon::RemoveInstanceTask(const uint8_t op, HTaskInfo hTask)
268{
269    bool ret = true;
270    switch (hTask->taskType) {
271        case TYPE_UNITY:
272            ret = DoTaskRemove<HdcDaemonUnity>(hTask, op);
273            break;
274        case TYPE_SHELL:
275            ret = DoTaskRemove<HdcShell>(hTask, op);
276            break;
277        case TASK_FILE:
278            ret = DoTaskRemove<HdcTransferBase>(hTask, op);
279            break;
280        case TASK_FORWARD:
281            ret = DoTaskRemove<HdcDaemonForward>(hTask, op);
282            break;
283        case TASK_APP:
284            ret = DoTaskRemove<HdcDaemonApp>(hTask, op);
285            break;
286        case TASK_UPDATER:
287            ret = DoTaskRemove<DaemonUpdater>(hTask, op);
288            break;
289        default:
290            ret = false;
291            break;
292    }
293    return ret;
294}
295
296bool HdcDaemon::ServerCommand(const uint32_t sessionId, const uint32_t channelId, const uint16_t command,
297                              uint8_t *bufPtr, const int size)
298{
299    return Send(sessionId, channelId, command, (uint8_t *)bufPtr, size) > 0;
300}
301
302void HdcDaemon::JdwpNewFileDescriptor(const uint8_t *buf, const int bytesIO)
303{
304    uint32_t pid = *(uint32_t *)(buf + 1);
305    uint32_t fd = *(uint32_t *)(buf + 5);  // 5 : fd offset
306    ((HdcJdwp *)clsJdwp)->SendJdwpNewFD(pid, fd);
307};
308
309void HdcDaemon::NotifyInstanceSessionFree(HSession hSession, bool freeOrClear)
310{
311    if (!freeOrClear) {
312        return;  // ignore step 1
313    }
314    if (clsUSBServ != nullptr) {
315        auto clsUsbModule = reinterpret_cast<HdcDaemonUSB *>(clsUSBServ);
316        clsUsbModule->OnSessionFreeFinally(hSession);
317    }
318}
319}  // namespace Hdc
320