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
16 #include "user_idm_service.h"
17
18 #include "string_ex.h"
19 #include "accesstoken_kit.h"
20
21 #include "context_factory.h"
22 #include "context_helper.h"
23 #include "context_pool.h"
24 #include "hdi_wrapper.h"
25 #include "iam_check.h"
26 #include "iam_logger.h"
27 #include "iam_para2str.h"
28 #include "iam_defines.h"
29 #include "ipc_common.h"
30 #include "ipc_skeleton.h"
31 #include "iam_common_defines.h"
32 #include "resource_node_pool.h"
33 #include "resource_node_utils.h"
34 #include "user_idm_callback_proxy.h"
35 #include "user_idm_database.h"
36 #include "user_idm_session_controller.h"
37
38 #define LOG_LABEL UserIam::Common::LABEL_USER_AUTH_SA
39 namespace OHOS {
40 namespace UserIam {
41 namespace UserAuth {
42 REGISTER_SYSTEM_ABILITY_BY_ID(UserIdmService, SUBSYS_USERIAM_SYS_ABILITY_USERIDM, true);
43 constexpr int32_t USERIAM_IPC_THREAD_NUM = 4;
44
UserIdmService(int32_t systemAbilityId,bool runOnCreate)45 UserIdmService::UserIdmService(int32_t systemAbilityId, bool runOnCreate) : SystemAbility(systemAbilityId, runOnCreate)
46 {
47 }
48
OnStart()49 void UserIdmService::OnStart()
50 {
51 IAM_LOGI("start service");
52 IPCSkeleton::SetMaxWorkThreadNum(USERIAM_IPC_THREAD_NUM);
53 if (!Publish(this)) {
54 IAM_LOGE("failed to publish service");
55 }
56 }
57
OnStop()58 void UserIdmService::OnStop()
59 {
60 IAM_LOGI("stop service");
61 }
62
OpenSession(int32_t userId,std::vector<uint8_t> & challenge)63 int32_t UserIdmService::OpenSession(int32_t userId, std::vector<uint8_t> &challenge)
64 {
65 IAM_LOGI("start");
66 if (!IpcCommon::CheckPermission(*this, MANAGE_USER_IDM_PERMISSION)) {
67 IAM_LOGE("failed to check permission");
68 return CHECK_PERMISSION_FAILED;
69 }
70
71 auto contextList = ContextPool::Instance().Select(CONTEXT_ENROLL);
72 for (const auto &context : contextList) {
73 if (auto ctx = context.lock(); ctx != nullptr) {
74 IAM_LOGE("force stop the old context ****%{public}hx", static_cast<uint16_t>(ctx->GetContextId()));
75 ctx->Stop();
76 ContextPool::Instance().Delete(ctx->GetContextId());
77 }
78 }
79
80 if (!UserIdmSessionController::Instance().OpenSession(userId, challenge)) {
81 IAM_LOGE("failed to open session");
82 return GENERAL_ERROR;
83 }
84
85 return SUCCESS;
86 }
87
CloseSession(int32_t userId)88 void UserIdmService::CloseSession(int32_t userId)
89 {
90 IAM_LOGI("start");
91 if (!IpcCommon::CheckPermission(*this, MANAGE_USER_IDM_PERMISSION)) {
92 IAM_LOGE("failed to check permission");
93 return;
94 }
95
96 if (!UserIdmSessionController::Instance().CloseSession(userId)) {
97 IAM_LOGE("failed to get close session");
98 }
99 }
100
GetCredentialInfoInner(int32_t userId,AuthType authType,std::vector<CredentialInfo> & credInfoList)101 int32_t UserIdmService::GetCredentialInfoInner(int32_t userId, AuthType authType,
102 std::vector<CredentialInfo> &credInfoList)
103 {
104 IAM_LOGI("start");
105 if (!IpcCommon::CheckPermission(*this, USE_USER_IDM_PERMISSION)) {
106 IAM_LOGE("failed to check permission");
107 return CHECK_PERMISSION_FAILED;
108 }
109 auto credInfos = UserIdmDatabase::Instance().GetCredentialInfo(userId, authType);
110 if (credInfos.empty()) {
111 IAM_LOGE("no cred enrolled");
112 return NOT_ENROLLED;
113 }
114 for (const auto &credInfo : credInfos) {
115 if (credInfo == nullptr) {
116 IAM_LOGE("credInfo is nullptr");
117 return GENERAL_ERROR;
118 }
119 CredentialInfo info = {};
120 info.credentialId = credInfo->GetCredentialId();
121 info.templateId = credInfo->GetTemplateId();
122 info.authType = credInfo->GetAuthType();
123 if (info.authType == PIN) {
124 auto userInfo = UserIdmDatabase::Instance().GetSecUserInfo(userId);
125 if (userInfo == nullptr) {
126 IAM_LOGE("failed to get userInfo");
127 return GENERAL_ERROR;
128 }
129 info.pinType = userInfo->GetPinSubType();
130 }
131 credInfoList.push_back(info);
132 }
133 return SUCCESS;
134 }
135
GetCredentialInfo(int32_t userId,AuthType authType,const sptr<IdmGetCredInfoCallbackInterface> & callback)136 int32_t UserIdmService::GetCredentialInfo(int32_t userId, AuthType authType,
137 const sptr<IdmGetCredInfoCallbackInterface> &callback)
138 {
139 if (callback == nullptr) {
140 IAM_LOGE("callback is nullptr");
141 return INVALID_PARAMETERS;
142 }
143
144 std::vector<CredentialInfo> credInfoList;
145 int32_t ret = GetCredentialInfoInner(userId, authType, credInfoList);
146 if (ret != SUCCESS) {
147 IAM_LOGE("GetCredentialInfoInner fail, ret: %{public}d", ret);
148 credInfoList.clear();
149 }
150 callback->OnCredentialInfos(credInfoList);
151
152 return ret;
153 }
154
GetSecInfoInner(int32_t userId,SecUserInfo & secUserInfo)155 int32_t UserIdmService::GetSecInfoInner(int32_t userId, SecUserInfo &secUserInfo)
156 {
157 IAM_LOGI("start");
158 if (!IpcCommon::CheckPermission(*this, USE_USER_IDM_PERMISSION)) {
159 IAM_LOGE("failed to check permission");
160 return CHECK_PERMISSION_FAILED;
161 }
162 auto userInfos = UserIdmDatabase::Instance().GetSecUserInfo(userId);
163 if (userInfos == nullptr) {
164 IAM_LOGE("current userid %{public}d is not existed", userId);
165 return INVALID_PARAMETERS;
166 }
167 std::vector<std::shared_ptr<EnrolledInfoInterface>> enrolledInfos = userInfos->GetEnrolledInfo();
168 for (const auto &enrolledInfo : enrolledInfos) {
169 if (enrolledInfo == nullptr) {
170 IAM_LOGE("enrolledInfo is nullptr");
171 return GENERAL_ERROR;
172 }
173 EnrolledInfo info = {enrolledInfo->GetAuthType(), enrolledInfo->GetEnrolledId()};
174 secUserInfo.enrolledInfo.push_back(info);
175 }
176 secUserInfo.secureUid = userInfos->GetSecUserId();
177 return SUCCESS;
178 }
179
GetSecInfo(int32_t userId,const sptr<IdmGetSecureUserInfoCallbackInterface> & callback)180 int32_t UserIdmService::GetSecInfo(int32_t userId, const sptr<IdmGetSecureUserInfoCallbackInterface> &callback)
181 {
182 if (callback == nullptr) {
183 IAM_LOGE("callback is nullptr");
184 return INVALID_PARAMETERS;
185 }
186
187 SecUserInfo secUserInfo = {};
188 int32_t ret = GetSecInfoInner(userId, secUserInfo);
189 if (ret != SUCCESS) {
190 IAM_LOGE("GetSecInfoInner fail, ret: %{public}d", ret);
191 secUserInfo.secureUid = 0;
192 secUserInfo.enrolledInfo.clear();
193 }
194 callback->OnSecureUserInfo(secUserInfo);
195
196 return ret;
197 }
198
AddCredential(int32_t userId,const CredentialPara & credPara,const sptr<IdmCallbackInterface> & callback,bool isUpdate)199 void UserIdmService::AddCredential(int32_t userId, const CredentialPara &credPara,
200 const sptr<IdmCallbackInterface> &callback, bool isUpdate)
201 {
202 if (callback == nullptr) {
203 IAM_LOGE("callback is nullptr");
204 return;
205 }
206
207 Attributes extraInfo;
208 auto contextCallback = ContextCallback::NewInstance(callback,
209 isUpdate ? TRACE_UPDATE_CREDENTIAL : TRACE_ADD_CREDENTIAL);
210 if (contextCallback == nullptr) {
211 IAM_LOGE("failed to construct context callback");
212 callback->OnResult(GENERAL_ERROR, extraInfo);
213 return;
214 }
215 uint64_t callingUid = static_cast<uint64_t>(this->GetCallingUid());
216 contextCallback->SetTraceAuthType(credPara.authType);
217 contextCallback->SetTraceCallingUid(callingUid);
218 contextCallback->SetTraceUserId(userId);
219
220 if (!IpcCommon::CheckPermission(*this, MANAGE_USER_IDM_PERMISSION)) {
221 IAM_LOGE("failed to check permission");
222 contextCallback->OnResult(CHECK_PERMISSION_FAILED, extraInfo);
223 return;
224 }
225
226 std::lock_guard<std::mutex> lock(mutex_);
227 CancelCurrentEnrollIfExist();
228 auto tokenId = IpcCommon::GetAccessTokenId(*this);
229 ContextFactory::EnrollContextPara para = {};
230 para.authType = credPara.authType;
231 para.userId = userId;
232 para.pinType = credPara.pinType;
233 para.tokenId = tokenId;
234 para.token = credPara.token;
235 para.isUpdate = isUpdate;
236 auto context = ContextFactory::CreateEnrollContext(para, contextCallback);
237 if (!ContextPool::Instance().Insert(context)) {
238 IAM_LOGE("failed to insert context");
239 contextCallback->OnResult(GENERAL_ERROR, extraInfo);
240 return;
241 }
242
243 auto cleaner = ContextHelper::Cleaner(context);
244 contextCallback->SetCleaner(cleaner);
245
246 if (!context->Start()) {
247 IAM_LOGE("failed to start enroll");
248 contextCallback->OnResult(context->GetLatestError(), extraInfo);
249 }
250 }
251
UpdateCredential(int32_t userId,const CredentialPara & credPara,const sptr<IdmCallbackInterface> & callback)252 void UserIdmService::UpdateCredential(int32_t userId, const CredentialPara &credPara,
253 const sptr<IdmCallbackInterface> &callback)
254 {
255 if (callback == nullptr) {
256 IAM_LOGE("callback is nullptr");
257 return;
258 }
259
260 auto credInfos = UserIdmDatabase::Instance().GetCredentialInfo(userId, credPara.authType);
261 if (credInfos.empty()) {
262 IAM_LOGE("current userid %{public}d has no credential for type %{public}u", userId, credPara.authType);
263 Attributes extraInfo;
264 callback->OnResult(NOT_ENROLLED, extraInfo);
265 return;
266 }
267
268 AddCredential(userId, credPara, callback, true);
269 }
270
Cancel(int32_t userId)271 int32_t UserIdmService::Cancel(int32_t userId)
272 {
273 if (!IpcCommon::CheckPermission(*this, MANAGE_USER_IDM_PERMISSION)) {
274 IAM_LOGE("failed to check permission");
275 return CHECK_PERMISSION_FAILED;
276 }
277 if (!UserIdmSessionController::Instance().IsSessionOpened(userId)) {
278 IAM_LOGE("both user id and challenge are invalid");
279 return GENERAL_ERROR;
280 }
281
282 std::lock_guard<std::mutex> lock(mutex_);
283 return CancelCurrentEnroll();
284 }
285
CancelCurrentEnrollIfExist()286 void UserIdmService::CancelCurrentEnrollIfExist()
287 {
288 if (ContextPool::Instance().Select(CONTEXT_ENROLL).size() == 0) {
289 return;
290 }
291
292 IAM_LOGI("cancel current enroll due to new add credential request or delete");
293 CancelCurrentEnroll();
294 }
295
CancelCurrentEnroll()296 int32_t UserIdmService::CancelCurrentEnroll()
297 {
298 IAM_LOGD("start");
299 auto contextList = ContextPool::Instance().Select(CONTEXT_ENROLL);
300 int32_t ret = GENERAL_ERROR;
301 for (const auto &context : contextList) {
302 if (auto ctx = context.lock(); ctx != nullptr) {
303 IAM_LOGE("stop the old context %{public}s", GET_MASKED_STRING(ctx->GetContextId()).c_str());
304 ctx->Stop();
305 ContextPool::Instance().Delete(ctx->GetContextId());
306 ret = SUCCESS;
307 }
308 }
309 IAM_LOGI("result %{public}d", ret);
310 return ret;
311 }
312
EnforceDelUser(int32_t userId,const sptr<IdmCallbackInterface> & callback)313 int32_t UserIdmService::EnforceDelUser(int32_t userId, const sptr<IdmCallbackInterface> &callback)
314 {
315 IAM_LOGI("to delete userid: %{public}d", userId);
316 IF_FALSE_LOGE_AND_RETURN_VAL(callback != nullptr, INVALID_PARAMETERS);
317
318 Attributes extraInfo;
319 auto contextCallback = ContextCallback::NewInstance(callback, TRACE_ENFORCE_DELETE_USER);
320 if (contextCallback == nullptr) {
321 IAM_LOGE("failed to construct context callback");
322 callback->OnResult(GENERAL_ERROR, extraInfo);
323 return GENERAL_ERROR;
324 }
325 contextCallback->SetTraceUserId(userId);
326
327 if (!IpcCommon::CheckPermission(*this, ENFORCE_USER_IDM)) {
328 IAM_LOGE("failed to check permission");
329 contextCallback->OnResult(CHECK_PERMISSION_FAILED, extraInfo);
330 return CHECK_PERMISSION_FAILED;
331 }
332
333 std::lock_guard<std::mutex> lock(mutex_);
334 CancelCurrentEnrollIfExist();
335
336 auto userInfo = UserIdmDatabase::Instance().GetSecUserInfo(userId);
337 if (userInfo == nullptr) {
338 IAM_LOGE("current userid %{public}d is not existed", userId);
339 contextCallback->OnResult(INVALID_PARAMETERS, extraInfo);
340 return INVALID_PARAMETERS;
341 }
342
343 std::vector<std::shared_ptr<CredentialInfoInterface>> credInfos;
344 int32_t ret = UserIdmDatabase::Instance().DeleteUserEnforce(userId, credInfos);
345 if (ret != SUCCESS) {
346 IAM_LOGE("failed to enforce delete user");
347 static_cast<void>(extraInfo.SetUint64Value(Attributes::ATTR_CREDENTIAL_ID, 0));
348 contextCallback->OnResult(ret, extraInfo);
349 return ret;
350 }
351
352 ret = ResourceNodeUtils::NotifyExecutorToDeleteTemplates(credInfos);
353 if (ret != SUCCESS) {
354 IAM_LOGE("failed to delete executor info, error code : %{public}d", ret);
355 }
356
357 IAM_LOGI("delete user success");
358 contextCallback->OnResult(SUCCESS, extraInfo);
359 return SUCCESS;
360 }
361
DelUser(int32_t userId,const std::vector<uint8_t> authToken,const sptr<IdmCallbackInterface> & callback)362 void UserIdmService::DelUser(int32_t userId, const std::vector<uint8_t> authToken,
363 const sptr<IdmCallbackInterface> &callback)
364 {
365 IF_FALSE_LOGE_AND_RETURN(callback != nullptr);
366
367 Attributes extraInfo;
368 auto contextCallback = ContextCallback::NewInstance(callback, TRACE_DELETE_USER);
369 if (contextCallback == nullptr) {
370 IAM_LOGE("failed to construct context callback");
371 callback->OnResult(GENERAL_ERROR, extraInfo);
372 return;
373 }
374 contextCallback->SetTraceUserId(userId);
375
376 if (!IpcCommon::CheckPermission(*this, MANAGE_USER_IDM_PERMISSION)) {
377 IAM_LOGE("failed to check permission");
378 contextCallback->OnResult(CHECK_PERMISSION_FAILED, extraInfo);
379 return;
380 }
381
382 std::lock_guard<std::mutex> lock(mutex_);
383 CancelCurrentEnrollIfExist();
384
385 std::vector<std::shared_ptr<CredentialInfoInterface>> credInfos;
386 int32_t ret = UserIdmDatabase::Instance().DeleteUser(userId, authToken, credInfos);
387 if (ret != SUCCESS) {
388 IAM_LOGE("failed to delete user");
389 contextCallback->OnResult(ret, extraInfo);
390 return;
391 }
392
393 ret = ResourceNodeUtils::NotifyExecutorToDeleteTemplates(credInfos);
394 if (ret != SUCCESS) {
395 IAM_LOGE("failed to delete executor info, error code : %{public}d", ret);
396 }
397 IAM_LOGI("delete user end");
398
399 contextCallback->OnResult(ret, extraInfo);
400 }
401
DelCredential(int32_t userId,uint64_t credentialId,const std::vector<uint8_t> & authToken,const sptr<IdmCallbackInterface> & callback)402 void UserIdmService::DelCredential(int32_t userId, uint64_t credentialId,
403 const std::vector<uint8_t> &authToken, const sptr<IdmCallbackInterface> &callback)
404 {
405 IF_FALSE_LOGE_AND_RETURN(callback != nullptr);
406
407 Attributes extraInfo;
408 auto contextCallback = ContextCallback::NewInstance(callback, TRACE_DELETE_CREDENTIAL);
409 if (contextCallback == nullptr) {
410 IAM_LOGE("failed to construct context callback");
411 callback->OnResult(GENERAL_ERROR, extraInfo);
412 return;
413 }
414 contextCallback->SetTraceUserId(userId);
415
416 if (!IpcCommon::CheckPermission(*this, MANAGE_USER_IDM_PERMISSION)) {
417 IAM_LOGE("failed to check permission");
418 contextCallback->OnResult(CHECK_PERMISSION_FAILED, extraInfo);
419 return;
420 }
421
422 std::lock_guard<std::mutex> lock(mutex_);
423 CancelCurrentEnrollIfExist();
424
425 std::shared_ptr<CredentialInfoInterface> oldInfo;
426 auto ret = UserIdmDatabase::Instance().DeleteCredentialInfo(userId, credentialId, authToken, oldInfo);
427 if (ret != SUCCESS) {
428 IAM_LOGE("failed to delete CredentialInfo");
429 contextCallback->OnResult(ret, extraInfo);
430 return;
431 }
432 if (oldInfo != nullptr) {
433 contextCallback->SetTraceAuthType(oldInfo->GetAuthType());
434 }
435
436 IAM_LOGI("delete credentialInfo success");
437 std::vector<std::shared_ptr<CredentialInfoInterface>> list = {oldInfo};
438 ret = ResourceNodeUtils::NotifyExecutorToDeleteTemplates(list);
439 if (ret != SUCCESS) {
440 IAM_LOGE("failed to delete executor info, error code : %{public}d", ret);
441 }
442
443 contextCallback->OnResult(ret, extraInfo);
444 }
445
Dump(int fd,const std::vector<std::u16string> & args)446 int UserIdmService::Dump(int fd, const std::vector<std::u16string> &args)
447 {
448 IAM_LOGI("start");
449 if (fd < 0) {
450 IAM_LOGE("invalid parameters");
451 dprintf(fd, "Invalid parameters.\n");
452 return INVALID_PARAMETERS;
453 }
454 std::string arg0 = (args.empty() ? "" : Str16ToStr8(args[0]));
455 if (arg0.empty() || arg0.compare("-h") == 0) {
456 dprintf(fd, "Usage:\n");
457 dprintf(fd, " -h: command help.\n");
458 dprintf(fd, " -l: active user info dump.\n");
459 return SUCCESS;
460 }
461 if (arg0.compare("-l") != 0) {
462 IAM_LOGE("invalid option");
463 dprintf(fd, "Invalid option\n");
464 return GENERAL_ERROR;
465 }
466
467 std::optional<int32_t> activeUserId;
468 if (IpcCommon::GetActiveUserId(activeUserId) != SUCCESS) {
469 dprintf(fd, "Internal error.\n");
470 IAM_LOGE("failed to get active id");
471 return GENERAL_ERROR;
472 }
473 dprintf(fd, "Active user is %d\n", activeUserId.value());
474 auto userInfo = UserIdmDatabase::Instance().GetSecUserInfo(activeUserId.value());
475 if (userInfo == nullptr) {
476 IAM_LOGE("userInfo is null");
477 return SUCCESS;
478 }
479 auto enrolledInfo = userInfo->GetEnrolledInfo();
480 for (auto &info : enrolledInfo) {
481 if (info != nullptr) {
482 dprintf(fd, "AuthType %s is enrolled.\n", Common::AuthTypeToStr(info->GetAuthType()));
483 }
484 }
485 return SUCCESS;
486 }
487
488 } // namespace UserAuth
489 } // namespace UserIam
490 } // namespace OHOS