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 
22 namespace Hdc {
HdcDaemon(bool serverOrDaemonIn)23 HdcDaemon::HdcDaemon(bool serverOrDaemonIn)
24     : HdcSessionBase(serverOrDaemonIn)
25 {
26     clsTCPServ = nullptr;
27     clsUSBServ = nullptr;
28     clsJdwp = nullptr;
29     enableSecure = false;
30 }
31 
~HdcDaemon()32 HdcDaemon::~HdcDaemon()
33 {
34     WRITE_LOG(LOG_DEBUG, "~HdcDaemon");
35 }
36 
ClearInstanceResource()37 void 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 
TryStopInstance()56 void 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 
InitMod(bool bEnableTCP,bool bEnableUSB)73 void 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
RedirectToTask(HTaskInfo hTaskInfo,HSession hSession,const uint32_t channelId,const uint16_t command,uint8_t * payload,const int payloadSize)97 bool 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 
HandDaemonAuth(HSession hSession,const uint32_t channelId,SessionHandShake & handshake)150 bool 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 
DaemonSessionHandshake(HSession hSession,const uint32_t channelId,uint8_t * payload,int payloadSize)195 bool 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 
FetchCommand(HSession hSession,const uint32_t channelId,const uint16_t command,uint8_t * payload,int payloadSize)236 bool 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 
RemoveInstanceTask(const uint8_t op,HTaskInfo hTask)267 bool 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 
ServerCommand(const uint32_t sessionId,const uint32_t channelId,const uint16_t command,uint8_t * bufPtr,const int size)296 bool 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 
JdwpNewFileDescriptor(const uint8_t * buf,const int bytesIO)302 void 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 
NotifyInstanceSessionFree(HSession hSession,bool freeOrClear)309 void 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