• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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