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