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