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 22namespace Hdc { 23HdcDaemon::HdcDaemon(bool serverOrDaemonIn) 24 : HdcSessionBase(serverOrDaemonIn) 25{ 26 clsTCPServ = nullptr; 27 clsUSBServ = nullptr; 28 clsJdwp = nullptr; 29 enableSecure = false; 30} 31 32HdcDaemon::~HdcDaemon() 33{ 34 WRITE_LOG(LOG_DEBUG, "~HdcDaemon"); 35} 36 37void 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 56void 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 73void 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 97bool 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 150bool 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 195bool 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 236bool 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 267bool 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 296bool 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 302void 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 309void 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