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