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