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