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