1 /*
2 * Copyright (c) 2022 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 "route_head_handler_impl.h"
16
17 #define LOG_TAG "RouteHeadHandler"
18
19 #include "auth_delegate.h"
20 #include "device_manager_adapter.h"
21 #include "kvstore_meta_manager.h"
22 #include "log_print.h"
23 #include "metadata/meta_data_manager.h"
24 #include "metadata/store_meta_data.h"
25 #include "securec.h"
26 #include "upgrade_manager.h"
27 #include "bootstrap.h"
28 #include "utils/anonymous.h"
29 #include "utils/endian_converter.h"
30
31 namespace OHOS::DistributedData {
32 using namespace OHOS::DistributedKv;
33 using DmAdapter = DistributedData::DeviceManagerAdapter;
34 constexpr const int ALIGN_WIDTH = 8;
Create(const ExtendInfo & info)35 std::shared_ptr<RouteHeadHandler> RouteHeadHandlerImpl::Create(const ExtendInfo &info)
36 {
37 auto handler = std::make_shared<RouteHeadHandlerImpl>(info);
38 if (handler == nullptr) {
39 ZLOGE("new instance failed");
40 return nullptr;
41 }
42 handler->Init();
43 return handler;
44 }
45
RouteHeadHandlerImpl(const ExtendInfo & info)46 RouteHeadHandlerImpl::RouteHeadHandlerImpl(const ExtendInfo &info)
47 : userId_(info.userId), appId_(info.appId), storeId_(info.storeId), deviceId_(info.dstTarget), headSize_(0)
48 {
49 ZLOGI("init route handler, app:%{public}s, user:%{public}s, peer:%{public}s", appId_.c_str(), userId_.c_str(),
50 Anonymous::Change(deviceId_).c_str());
51 }
52
Init()53 void RouteHeadHandlerImpl::Init()
54 {
55 ZLOGD("begin");
56 if (deviceId_.empty()) {
57 return;
58 }
59 SessionPoint localPoint { DmAdapter::GetInstance().GetLocalDevice().uuid,
60 static_cast<uint32_t>(atoi(userId_.c_str())), appId_, storeId_ };
61 session_ = SessionManager::GetInstance().GetSession(localPoint, deviceId_);
62 ZLOGD("valid session:appId:%{public}s, srcDevId:%{public}s, srcUser:%{public}u, trgDevId:%{public}s,",
63 session_.appId.c_str(), Anonymous::Change(session_.sourceDeviceId).c_str(),
64 session_.sourceUserId, Anonymous::Change(session_.targetDeviceId).c_str());
65 }
66
GetHeadDataSize(uint32_t & headSize)67 DistributedDB::DBStatus RouteHeadHandlerImpl::GetHeadDataSize(uint32_t &headSize)
68 {
69 ZLOGD("begin");
70 headSize = 0;
71 if (appId_ == Bootstrap::GetInstance().GetProcessLabel()) {
72 ZLOGI("meta data permitted");
73 return DistributedDB::OK;
74 }
75 bool flag = false;
76 auto peerCap = UpgradeManager::GetInstance().GetCapability(session_.targetDeviceId, flag);
77 if (!flag) {
78 ZLOGI("get peer cap failed");
79 return DistributedDB::DB_ERROR;
80 }
81 if (peerCap.version == CapMetaData::INVALID_VERSION) {
82 // older versions ignore pack extend head
83 ZLOGI("ignore older version device");
84 return DistributedDB::OK;
85 }
86 if (!session_.IsValid()) {
87 ZLOGI("no valid session to peer device");
88 return DistributedDB::DB_ERROR;
89 }
90 size_t expectSize = sizeof(RouteHead) + sizeof(SessionDevicePair) + sizeof(SessionUserPair)
91 + session_.targetUserIds.size() * sizeof(int) + sizeof(SessionAppId) + session_.appId.size();
92
93 // align message uint width
94 headSize = GET_ALIGNED_SIZE(expectSize, ALIGN_WIDTH);
95 ZLOGI("packed size:%{public}u", headSize);
96 headSize_ = headSize;
97 return DistributedDB::OK;
98 }
99
FillHeadData(uint8_t * data,uint32_t headSize,uint32_t totalLen)100 DistributedDB::DBStatus RouteHeadHandlerImpl::FillHeadData(uint8_t *data, uint32_t headSize, uint32_t totalLen)
101 {
102 ZLOGD("begin");
103 if (headSize != headSize_) {
104 ZLOGI("size not match");
105 return DistributedDB::DB_ERROR;
106 }
107 if (headSize_ == 0) {
108 ZLOGI("ignore older version device");
109 return DistributedDB::OK;
110 }
111 auto packRet = PackData(data, headSize);
112 ZLOGD("pack result:%{public}d", packRet);
113 return packRet ? DistributedDB::OK : DistributedDB::DB_ERROR;
114 }
115
PackData(uint8_t * data,uint32_t totalLen)116 bool RouteHeadHandlerImpl::PackData(uint8_t *data, uint32_t totalLen)
117 {
118 if (headSize_ > totalLen) {
119 ZLOGE("the buffer size is not enough, headSize:%{public}d, tatalLen:%{public}d",
120 headSize_, totalLen);
121 return false;
122 }
123
124 auto isOk = PackDataHead(data, headSize_);
125 if (isOk) {
126 return PackDataBody(data + sizeof(RouteHead), headSize_ - sizeof(RouteHead));
127 }
128 return false;
129 }
130
PackDataHead(uint8_t * data,uint32_t totalLen)131 bool RouteHeadHandlerImpl::PackDataHead(uint8_t *data, uint32_t totalLen)
132 {
133 uint8_t *ptr = data;
134 if (headSize_ < sizeof(RouteHead)) {
135 return false;
136 }
137 RouteHead *head = reinterpret_cast<RouteHead *>(ptr);
138 head->magic = HostToNet(RouteHead::MAGIC_NUMBER);
139 head->version = HostToNet(RouteHead::VERSION);
140 head->checkSum = HostToNet(uint64_t(0));
141 head->dataLen = HostToNet(uint32_t(totalLen - sizeof(RouteHead)));
142 return true;
143 }
144
PackDataBody(uint8_t * data,uint32_t totalLen)145 bool RouteHeadHandlerImpl::PackDataBody(uint8_t *data, uint32_t totalLen)
146 {
147 uint8_t *ptr = data;
148 SessionDevicePair *devicePair = reinterpret_cast<SessionDevicePair *>(ptr);
149 auto ret = strcpy_s(devicePair->sourceId, SessionDevicePair::MAX_DEVICE_ID, session_.sourceDeviceId.c_str());
150 if (ret != 0) {
151 ZLOGE("strcpy for source device id failed, ret is %{public}d", ret);
152 return false;
153 }
154 ret = strcpy_s(devicePair->targetId, SessionDevicePair::MAX_DEVICE_ID, session_.targetDeviceId.c_str());
155 if (ret != 0) {
156 ZLOGE("strcpy for target device id failed, ret is %{public}d", ret);
157 return false;
158 }
159 ptr += sizeof(SessionDevicePair);
160
161 SessionUserPair *userPair = reinterpret_cast<SessionUserPair *>(ptr);
162 userPair->sourceUserId = HostToNet(session_.sourceUserId);
163 userPair->targetUserCount = session_.targetUserIds.size();
164 for (size_t i = 0; i < session_.targetUserIds.size(); ++i) {
165 *(userPair->targetUserIds + i) = HostToNet(session_.targetUserIds[i]);
166 }
167 ptr += (sizeof(SessionUserPair) + session_.targetUserIds.size() * sizeof(int));
168
169 SessionAppId *appPair = reinterpret_cast<SessionAppId *>(ptr);
170 ptr += sizeof(SessionAppId);
171
172 uint8_t *end = data + totalLen;
173 uint32_t appIdSize = session_.appId.size();
174 ret = memcpy_s(appPair->appId, end - ptr, session_.appId.data(), appIdSize);
175 if (ret != 0) {
176 ZLOGE("strcpy for app id failed, error:%{public}d", errno);
177 return false;
178 }
179 appPair->len = HostToNet(appIdSize);
180 return true;
181 }
182
ParseHeadData(const uint8_t * data,uint32_t len,uint32_t & headSize,std::vector<std::string> & users)183 bool RouteHeadHandlerImpl::ParseHeadData(
184 const uint8_t *data, uint32_t len, uint32_t &headSize, std::vector<std::string> &users)
185 {
186 auto ret = UnPackData(data, len, headSize);
187 if (!ret) {
188 headSize = 0;
189 return false;
190 }
191 ZLOGI("unpacked size:%{public}u", headSize);
192 // flip the local and peer ends
193 SessionPoint local { .deviceId = session_.targetDeviceId, .appId = session_.appId };
194 SessionPoint peer { .deviceId = session_.sourceDeviceId, .userId = session_.sourceUserId, .appId = session_.appId };
195 ZLOGD("valid session:appId:%{public}s, srcDevId:%{public}s, srcUser:%{public}u, trgDevId:%{public}s,",
196 session_.appId.c_str(), Anonymous::Change(session_.sourceDeviceId).c_str(),
197 session_.sourceUserId, Anonymous::Change(session_.targetDeviceId).c_str());
198 for (const auto &item : session_.targetUserIds) {
199 local.userId = item;
200 if (SessionManager::GetInstance().CheckSession(local, peer)) {
201 users.emplace_back(std::to_string(item));
202 }
203 }
204 return true;
205 }
206
UnPackData(const uint8_t * data,uint32_t totalLen,uint32_t & unpackedSize)207 bool RouteHeadHandlerImpl::UnPackData(const uint8_t *data, uint32_t totalLen, uint32_t &unpackedSize)
208 {
209 if (data == nullptr || totalLen < sizeof(RouteHead)) {
210 ZLOGE("invalid input data, totalLen:%{public}d", totalLen);
211 return false;
212 }
213 unpackedSize = 0;
214 RouteHead head = { 0 };
215 bool result = UnPackDataHead(data, totalLen, head);
216 if (result && head.version == RouteHead::VERSION) {
217 auto isOk = UnPackDataBody(data + sizeof(RouteHead), totalLen - sizeof(RouteHead));
218 if (isOk) {
219 unpackedSize = sizeof(RouteHead) + head.dataLen;
220 }
221 return isOk;
222 }
223 return false;
224 }
225
UnPackDataHead(const uint8_t * data,uint32_t totalLen,RouteHead & routeHead)226 bool RouteHeadHandlerImpl::UnPackDataHead(const uint8_t *data, uint32_t totalLen, RouteHead &routeHead)
227 {
228 if (totalLen < sizeof(RouteHead)) {
229 ZLOGE("invalid route head len:%{public}d", totalLen);
230 return false;
231 }
232 const RouteHead *head = reinterpret_cast<const RouteHead *>(data);
233 routeHead.magic = NetToHost(head->magic);
234 routeHead.version = NetToHost(head->version);
235 routeHead.checkSum = NetToHost(head->checkSum);
236 routeHead.dataLen = NetToHost(head->dataLen);
237 if (routeHead.magic != RouteHead::MAGIC_NUMBER) {
238 ZLOGW("not route head data");
239 return false;
240 }
241 if (totalLen - sizeof(RouteHead) < routeHead.dataLen) {
242 ZLOGE("invalid route data len:%{public}d, totalLen:%{public}d.", routeHead.dataLen, totalLen);
243 return false;
244 }
245 return true;
246 }
247
UnPackDataBody(const uint8_t * data,uint32_t totalLen)248 bool RouteHeadHandlerImpl::UnPackDataBody(const uint8_t *data, uint32_t totalLen)
249 {
250 const uint8_t *ptr = data;
251 uint32_t leftSize = totalLen;
252
253 if (leftSize < sizeof(SessionDevicePair)) {
254 ZLOGE("failed to parse device pair, leftSize : %{public}d", leftSize);
255 return false;
256 }
257 const SessionDevicePair *devicePair = reinterpret_cast<const SessionDevicePair *>(ptr);
258 session_.sourceDeviceId =
259 std::string(devicePair->sourceId, strnlen(devicePair->sourceId, SessionDevicePair::MAX_DEVICE_ID));
260 session_.targetDeviceId =
261 std::string(devicePair->targetId, strnlen(devicePair->targetId, SessionDevicePair::MAX_DEVICE_ID));
262 ptr += sizeof(SessionDevicePair);
263 leftSize -= sizeof(SessionDevicePair);
264
265 if (leftSize < sizeof(SessionUserPair)) {
266 ZLOGE("failed to parse user pair, leftSize : %{public}d", leftSize);
267 return false;
268 }
269 const SessionUserPair *userPair = reinterpret_cast<const SessionUserPair *>(ptr);
270 session_.sourceUserId = NetToHost(userPair->sourceUserId);
271
272 auto userPairSize = sizeof(SessionUserPair) + userPair->targetUserCount * sizeof(uint32_t);
273 if (leftSize < userPairSize) {
274 ZLOGE("failed to parse user pair, target user, leftSize : %{public}d", leftSize);
275 return false;
276 }
277 for (int i = 0; i < userPair->targetUserCount; ++i) {
278 session_.targetUserIds.push_back(NetToHost(*(userPair->targetUserIds + i)));
279 }
280 ptr += userPairSize;
281 leftSize -= userPairSize;
282
283 if (leftSize < sizeof(SessionAppId)) {
284 ZLOGE("failed to parse app id, leftSize : %{public}d", leftSize);
285 return false;
286 }
287 const SessionAppId *appId = reinterpret_cast<const SessionAppId *>(ptr);
288 auto appIdLen = NetToHost(appId->len);
289 if (leftSize - sizeof(SessionAppId) < appIdLen) {
290 ZLOGE("failed to parse app id, appIdLen:%{public}d, leftSize:%{public}d.", appIdLen, leftSize);
291 return false;
292 }
293 session_.appId.append(appId->appId, appIdLen);
294 return true;
295 }
296 } // namespace OHOS::DistributedData