1 // Copyright 2018 yuzu emulator team
2 // Licensed under GPLv2 or any later version
3 // Refer to the license.txt file included.
4
5 #include <algorithm>
6 #include <array>
7 #include "common/common_paths.h"
8 #include "common/common_types.h"
9 #include "common/file_util.h"
10 #include "common/logging/log.h"
11 #include "common/string_util.h"
12 #include "common/swap.h"
13 #include "core/constants.h"
14 #include "core/core.h"
15 #include "core/core_timing.h"
16 #include "core/file_sys/control_metadata.h"
17 #include "core/file_sys/patch_manager.h"
18 #include "core/hle/ipc_helpers.h"
19 #include "core/hle/kernel/kernel.h"
20 #include "core/hle/kernel/process.h"
21 #include "core/hle/service/acc/acc.h"
22 #include "core/hle/service/acc/acc_aa.h"
23 #include "core/hle/service/acc/acc_su.h"
24 #include "core/hle/service/acc/acc_u0.h"
25 #include "core/hle/service/acc/acc_u1.h"
26 #include "core/hle/service/acc/errors.h"
27 #include "core/hle/service/acc/profile_manager.h"
28 #include "core/hle/service/glue/arp.h"
29 #include "core/hle/service/glue/manager.h"
30 #include "core/hle/service/sm/sm.h"
31 #include "core/loader/loader.h"
32
33 namespace Service::Account {
34
35 constexpr ResultCode ERR_INVALID_BUFFER_SIZE{ErrorModule::Account, 30};
36 constexpr ResultCode ERR_FAILED_SAVE_DATA{ErrorModule::Account, 100};
37
GetImagePath(Common::UUID uuid)38 static std::string GetImagePath(Common::UUID uuid) {
39 return Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) +
40 "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg";
41 }
42
SanitizeJPEGSize(std::size_t size)43 static constexpr u32 SanitizeJPEGSize(std::size_t size) {
44 constexpr std::size_t max_jpeg_image_size = 0x20000;
45 return static_cast<u32>(std::min(size, max_jpeg_image_size));
46 }
47
48 class IManagerForSystemService final : public ServiceFramework<IManagerForSystemService> {
49 public:
IManagerForSystemService(Core::System & system_,Common::UUID)50 explicit IManagerForSystemService(Core::System& system_, Common::UUID)
51 : ServiceFramework{system_, "IManagerForSystemService"} {
52 // clang-format off
53 static const FunctionInfo functions[] = {
54 {0, nullptr, "CheckAvailability"},
55 {1, nullptr, "GetAccountId"},
56 {2, nullptr, "EnsureIdTokenCacheAsync"},
57 {3, nullptr, "LoadIdTokenCache"},
58 {100, nullptr, "SetSystemProgramIdentification"},
59 {101, nullptr, "RefreshNotificationTokenAsync"}, // 7.0.0+
60 {110, nullptr, "GetServiceEntryRequirementCache"}, // 4.0.0+
61 {111, nullptr, "InvalidateServiceEntryRequirementCache"}, // 4.0.0+
62 {112, nullptr, "InvalidateTokenCache"}, // 4.0.0 - 6.2.0
63 {113, nullptr, "GetServiceEntryRequirementCacheForOnlinePlay"}, // 6.1.0+
64 {120, nullptr, "GetNintendoAccountId"},
65 {121, nullptr, "CalculateNintendoAccountAuthenticationFingerprint"}, // 9.0.0+
66 {130, nullptr, "GetNintendoAccountUserResourceCache"},
67 {131, nullptr, "RefreshNintendoAccountUserResourceCacheAsync"},
68 {132, nullptr, "RefreshNintendoAccountUserResourceCacheAsyncIfSecondsElapsed"},
69 {133, nullptr, "GetNintendoAccountVerificationUrlCache"}, // 9.0.0+
70 {134, nullptr, "RefreshNintendoAccountVerificationUrlCache"}, // 9.0.0+
71 {135, nullptr, "RefreshNintendoAccountVerificationUrlCacheAsyncIfSecondsElapsed"}, // 9.0.0+
72 {140, nullptr, "GetNetworkServiceLicenseCache"}, // 5.0.0+
73 {141, nullptr, "RefreshNetworkServiceLicenseCacheAsync"}, // 5.0.0+
74 {142, nullptr, "RefreshNetworkServiceLicenseCacheAsyncIfSecondsElapsed"}, // 5.0.0+
75 {150, nullptr, "CreateAuthorizationRequest"},
76 };
77 // clang-format on
78
79 RegisterHandlers(functions);
80 }
81 };
82
83 // 3.0.0+
84 class IFloatingRegistrationRequest final : public ServiceFramework<IFloatingRegistrationRequest> {
85 public:
IFloatingRegistrationRequest(Core::System & system_,Common::UUID)86 explicit IFloatingRegistrationRequest(Core::System& system_, Common::UUID)
87 : ServiceFramework{system_, "IFloatingRegistrationRequest"} {
88 // clang-format off
89 static const FunctionInfo functions[] = {
90 {0, nullptr, "GetSessionId"},
91 {12, nullptr, "GetAccountId"},
92 {13, nullptr, "GetLinkedNintendoAccountId"},
93 {14, nullptr, "GetNickname"},
94 {15, nullptr, "GetProfileImage"},
95 {21, nullptr, "LoadIdTokenCache"},
96 {100, nullptr, "RegisterUser"}, // [1.0.0-3.0.2] RegisterAsync
97 {101, nullptr, "RegisterUserWithUid"}, // [1.0.0-3.0.2] RegisterWithUidAsync
98 {102, nullptr, "RegisterNetworkServiceAccountAsync"}, // 4.0.0+
99 {103, nullptr, "RegisterNetworkServiceAccountWithUidAsync"}, // 4.0.0+
100 {110, nullptr, "SetSystemProgramIdentification"},
101 {111, nullptr, "EnsureIdTokenCacheAsync"},
102 };
103 // clang-format on
104
105 RegisterHandlers(functions);
106 }
107 };
108
109 class IAdministrator final : public ServiceFramework<IAdministrator> {
110 public:
IAdministrator(Core::System & system_,Common::UUID)111 explicit IAdministrator(Core::System& system_, Common::UUID)
112 : ServiceFramework{system_, "IAdministrator"} {
113 // clang-format off
114 static const FunctionInfo functions[] = {
115 {0, nullptr, "CheckAvailability"},
116 {1, nullptr, "GetAccountId"},
117 {2, nullptr, "EnsureIdTokenCacheAsync"},
118 {3, nullptr, "LoadIdTokenCache"},
119 {100, nullptr, "SetSystemProgramIdentification"},
120 {101, nullptr, "RefreshNotificationTokenAsync"}, // 7.0.0+
121 {110, nullptr, "GetServiceEntryRequirementCache"}, // 4.0.0+
122 {111, nullptr, "InvalidateServiceEntryRequirementCache"}, // 4.0.0+
123 {112, nullptr, "InvalidateTokenCache"}, // 4.0.0 - 6.2.0
124 {113, nullptr, "GetServiceEntryRequirementCacheForOnlinePlay"}, // 6.1.0+
125 {120, nullptr, "GetNintendoAccountId"},
126 {121, nullptr, "CalculateNintendoAccountAuthenticationFingerprint"}, // 9.0.0+
127 {130, nullptr, "GetNintendoAccountUserResourceCache"},
128 {131, nullptr, "RefreshNintendoAccountUserResourceCacheAsync"},
129 {132, nullptr, "RefreshNintendoAccountUserResourceCacheAsyncIfSecondsElapsed"},
130 {133, nullptr, "GetNintendoAccountVerificationUrlCache"}, // 9.0.0+
131 {134, nullptr, "RefreshNintendoAccountVerificationUrlCacheAsync"}, // 9.0.0+
132 {135, nullptr, "RefreshNintendoAccountVerificationUrlCacheAsyncIfSecondsElapsed"}, // 9.0.0+
133 {140, nullptr, "GetNetworkServiceLicenseCache"}, // 5.0.0+
134 {141, nullptr, "RefreshNetworkServiceLicenseCacheAsync"}, // 5.0.0+
135 {142, nullptr, "RefreshNetworkServiceLicenseCacheAsyncIfSecondsElapsed"}, // 5.0.0+
136 {150, nullptr, "CreateAuthorizationRequest"},
137 {200, nullptr, "IsRegistered"},
138 {201, nullptr, "RegisterAsync"},
139 {202, nullptr, "UnregisterAsync"},
140 {203, nullptr, "DeleteRegistrationInfoLocally"},
141 {220, nullptr, "SynchronizeProfileAsync"},
142 {221, nullptr, "UploadProfileAsync"},
143 {222, nullptr, "SynchronizaProfileAsyncIfSecondsElapsed"},
144 {250, nullptr, "IsLinkedWithNintendoAccount"},
145 {251, nullptr, "CreateProcedureToLinkWithNintendoAccount"},
146 {252, nullptr, "ResumeProcedureToLinkWithNintendoAccount"},
147 {255, nullptr, "CreateProcedureToUpdateLinkageStateOfNintendoAccount"},
148 {256, nullptr, "ResumeProcedureToUpdateLinkageStateOfNintendoAccount"},
149 {260, nullptr, "CreateProcedureToLinkNnidWithNintendoAccount"}, // 3.0.0+
150 {261, nullptr, "ResumeProcedureToLinkNnidWithNintendoAccount"}, // 3.0.0+
151 {280, nullptr, "ProxyProcedureToAcquireApplicationAuthorizationForNintendoAccount"},
152 {290, nullptr, "GetRequestForNintendoAccountUserResourceView"}, // 8.0.0+
153 {300, nullptr, "TryRecoverNintendoAccountUserStateAsync"}, // 6.0.0+
154 {400, nullptr, "IsServiceEntryRequirementCacheRefreshRequiredForOnlinePlay"}, // 6.1.0+
155 {401, nullptr, "RefreshServiceEntryRequirementCacheForOnlinePlayAsync"}, // 6.1.0+
156 {900, nullptr, "GetAuthenticationInfoForWin"}, // 9.0.0+
157 {901, nullptr, "ImportAsyncForWin"}, // 9.0.0+
158 {997, nullptr, "DebugUnlinkNintendoAccountAsync"},
159 {998, nullptr, "DebugSetAvailabilityErrorDetail"},
160 };
161 // clang-format on
162
163 RegisterHandlers(functions);
164 }
165 };
166
167 class IAuthorizationRequest final : public ServiceFramework<IAuthorizationRequest> {
168 public:
IAuthorizationRequest(Core::System & system_,Common::UUID)169 explicit IAuthorizationRequest(Core::System& system_, Common::UUID)
170 : ServiceFramework{system_, "IAuthorizationRequest"} {
171 // clang-format off
172 static const FunctionInfo functions[] = {
173 {0, nullptr, "GetSessionId"},
174 {10, nullptr, "InvokeWithoutInteractionAsync"},
175 {19, nullptr, "IsAuthorized"},
176 {20, nullptr, "GetAuthorizationCode"},
177 {21, nullptr, "GetIdToken"},
178 {22, nullptr, "GetState"},
179 };
180 // clang-format on
181
182 RegisterHandlers(functions);
183 }
184 };
185
186 class IOAuthProcedure final : public ServiceFramework<IOAuthProcedure> {
187 public:
IOAuthProcedure(Core::System & system_,Common::UUID)188 explicit IOAuthProcedure(Core::System& system_, Common::UUID)
189 : ServiceFramework{system_, "IOAuthProcedure"} {
190 // clang-format off
191 static const FunctionInfo functions[] = {
192 {0, nullptr, "PrepareAsync"},
193 {1, nullptr, "GetRequest"},
194 {2, nullptr, "ApplyResponse"},
195 {3, nullptr, "ApplyResponseAsync"},
196 {10, nullptr, "Suspend"},
197 };
198 // clang-format on
199
200 RegisterHandlers(functions);
201 }
202 };
203
204 // 3.0.0+
205 class IOAuthProcedureForExternalNsa final : public ServiceFramework<IOAuthProcedureForExternalNsa> {
206 public:
IOAuthProcedureForExternalNsa(Core::System & system_,Common::UUID)207 explicit IOAuthProcedureForExternalNsa(Core::System& system_, Common::UUID)
208 : ServiceFramework{system_, "IOAuthProcedureForExternalNsa"} {
209 // clang-format off
210 static const FunctionInfo functions[] = {
211 {0, nullptr, "PrepareAsync"},
212 {1, nullptr, "GetRequest"},
213 {2, nullptr, "ApplyResponse"},
214 {3, nullptr, "ApplyResponseAsync"},
215 {10, nullptr, "Suspend"},
216 {100, nullptr, "GetAccountId"},
217 {101, nullptr, "GetLinkedNintendoAccountId"},
218 {102, nullptr, "GetNickname"},
219 {103, nullptr, "GetProfileImage"},
220 };
221 // clang-format on
222
223 RegisterHandlers(functions);
224 }
225 };
226
227 class IOAuthProcedureForNintendoAccountLinkage final
228 : public ServiceFramework<IOAuthProcedureForNintendoAccountLinkage> {
229 public:
IOAuthProcedureForNintendoAccountLinkage(Core::System & system_,Common::UUID)230 explicit IOAuthProcedureForNintendoAccountLinkage(Core::System& system_, Common::UUID)
231 : ServiceFramework{system_, "IOAuthProcedureForNintendoAccountLinkage"} {
232 // clang-format off
233 static const FunctionInfo functions[] = {
234 {0, nullptr, "PrepareAsync"},
235 {1, nullptr, "GetRequest"},
236 {2, nullptr, "ApplyResponse"},
237 {3, nullptr, "ApplyResponseAsync"},
238 {10, nullptr, "Suspend"},
239 {100, nullptr, "GetRequestWithTheme"},
240 {101, nullptr, "IsNetworkServiceAccountReplaced"},
241 {199, nullptr, "GetUrlForIntroductionOfExtraMembership"}, // 2.0.0 - 5.1.0
242 };
243 // clang-format on
244
245 RegisterHandlers(functions);
246 }
247 };
248
249 class INotifier final : public ServiceFramework<INotifier> {
250 public:
INotifier(Core::System & system_,Common::UUID)251 explicit INotifier(Core::System& system_, Common::UUID)
252 : ServiceFramework{system_, "INotifier"} {
253 // clang-format off
254 static const FunctionInfo functions[] = {
255 {0, nullptr, "GetSystemEvent"},
256 };
257 // clang-format on
258
259 RegisterHandlers(functions);
260 }
261 };
262
263 class IProfileCommon : public ServiceFramework<IProfileCommon> {
264 public:
IProfileCommon(Core::System & system_,const char * name,bool editor_commands,Common::UUID user_id_,ProfileManager & profile_manager_)265 explicit IProfileCommon(Core::System& system_, const char* name, bool editor_commands,
266 Common::UUID user_id_, ProfileManager& profile_manager_)
267 : ServiceFramework{system_, name}, profile_manager{profile_manager_}, user_id{user_id_} {
268 static const FunctionInfo functions[] = {
269 {0, &IProfileCommon::Get, "Get"},
270 {1, &IProfileCommon::GetBase, "GetBase"},
271 {10, &IProfileCommon::GetImageSize, "GetImageSize"},
272 {11, &IProfileCommon::LoadImage, "LoadImage"},
273 };
274
275 RegisterHandlers(functions);
276
277 if (editor_commands) {
278 static const FunctionInfo editor_functions[] = {
279 {100, &IProfileCommon::Store, "Store"},
280 {101, &IProfileCommon::StoreWithImage, "StoreWithImage"},
281 };
282
283 RegisterHandlers(editor_functions);
284 }
285 }
286
287 protected:
Get(Kernel::HLERequestContext & ctx)288 void Get(Kernel::HLERequestContext& ctx) {
289 LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format());
290 ProfileBase profile_base{};
291 ProfileData data{};
292 if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) {
293 ctx.WriteBuffer(data);
294 IPC::ResponseBuilder rb{ctx, 16};
295 rb.Push(RESULT_SUCCESS);
296 rb.PushRaw(profile_base);
297 } else {
298 LOG_ERROR(Service_ACC, "Failed to get profile base and data for user={}",
299 user_id.Format());
300 IPC::ResponseBuilder rb{ctx, 2};
301 rb.Push(RESULT_UNKNOWN); // TODO(ogniK): Get actual error code
302 }
303 }
304
GetBase(Kernel::HLERequestContext & ctx)305 void GetBase(Kernel::HLERequestContext& ctx) {
306 LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format());
307 ProfileBase profile_base{};
308 if (profile_manager.GetProfileBase(user_id, profile_base)) {
309 IPC::ResponseBuilder rb{ctx, 16};
310 rb.Push(RESULT_SUCCESS);
311 rb.PushRaw(profile_base);
312 } else {
313 LOG_ERROR(Service_ACC, "Failed to get profile base for user={}", user_id.Format());
314 IPC::ResponseBuilder rb{ctx, 2};
315 rb.Push(RESULT_UNKNOWN); // TODO(ogniK): Get actual error code
316 }
317 }
318
LoadImage(Kernel::HLERequestContext & ctx)319 void LoadImage(Kernel::HLERequestContext& ctx) {
320 LOG_DEBUG(Service_ACC, "called");
321
322 IPC::ResponseBuilder rb{ctx, 3};
323 rb.Push(RESULT_SUCCESS);
324
325 const Common::FS::IOFile image(GetImagePath(user_id), "rb");
326 if (!image.IsOpen()) {
327 LOG_WARNING(Service_ACC,
328 "Failed to load user provided image! Falling back to built-in backup...");
329 ctx.WriteBuffer(Core::Constants::ACCOUNT_BACKUP_JPEG);
330 rb.Push(SanitizeJPEGSize(Core::Constants::ACCOUNT_BACKUP_JPEG.size()));
331 return;
332 }
333
334 const u32 size = SanitizeJPEGSize(image.GetSize());
335 std::vector<u8> buffer(size);
336 image.ReadBytes(buffer.data(), buffer.size());
337
338 ctx.WriteBuffer(buffer);
339 rb.Push<u32>(size);
340 }
341
GetImageSize(Kernel::HLERequestContext & ctx)342 void GetImageSize(Kernel::HLERequestContext& ctx) {
343 LOG_DEBUG(Service_ACC, "called");
344 IPC::ResponseBuilder rb{ctx, 3};
345 rb.Push(RESULT_SUCCESS);
346
347 const Common::FS::IOFile image(GetImagePath(user_id), "rb");
348
349 if (!image.IsOpen()) {
350 LOG_WARNING(Service_ACC,
351 "Failed to load user provided image! Falling back to built-in backup...");
352 rb.Push(SanitizeJPEGSize(Core::Constants::ACCOUNT_BACKUP_JPEG.size()));
353 } else {
354 rb.Push(SanitizeJPEGSize(image.GetSize()));
355 }
356 }
357
Store(Kernel::HLERequestContext & ctx)358 void Store(Kernel::HLERequestContext& ctx) {
359 IPC::RequestParser rp{ctx};
360 const auto base = rp.PopRaw<ProfileBase>();
361
362 const auto user_data = ctx.ReadBuffer();
363
364 LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid={}",
365 Common::StringFromFixedZeroTerminatedBuffer(
366 reinterpret_cast<const char*>(base.username.data()), base.username.size()),
367 base.timestamp, base.user_uuid.Format());
368
369 if (user_data.size() < sizeof(ProfileData)) {
370 LOG_ERROR(Service_ACC, "ProfileData buffer too small!");
371 IPC::ResponseBuilder rb{ctx, 2};
372 rb.Push(ERR_INVALID_BUFFER_SIZE);
373 return;
374 }
375
376 ProfileData data;
377 std::memcpy(&data, user_data.data(), sizeof(ProfileData));
378
379 if (!profile_manager.SetProfileBaseAndData(user_id, base, data)) {
380 LOG_ERROR(Service_ACC, "Failed to update profile data and base!");
381 IPC::ResponseBuilder rb{ctx, 2};
382 rb.Push(ERR_FAILED_SAVE_DATA);
383 return;
384 }
385
386 IPC::ResponseBuilder rb{ctx, 2};
387 rb.Push(RESULT_SUCCESS);
388 }
389
StoreWithImage(Kernel::HLERequestContext & ctx)390 void StoreWithImage(Kernel::HLERequestContext& ctx) {
391 IPC::RequestParser rp{ctx};
392 const auto base = rp.PopRaw<ProfileBase>();
393
394 const auto user_data = ctx.ReadBuffer();
395 const auto image_data = ctx.ReadBuffer(1);
396
397 LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid={}",
398 Common::StringFromFixedZeroTerminatedBuffer(
399 reinterpret_cast<const char*>(base.username.data()), base.username.size()),
400 base.timestamp, base.user_uuid.Format());
401
402 if (user_data.size() < sizeof(ProfileData)) {
403 LOG_ERROR(Service_ACC, "ProfileData buffer too small!");
404 IPC::ResponseBuilder rb{ctx, 2};
405 rb.Push(ERR_INVALID_BUFFER_SIZE);
406 return;
407 }
408
409 ProfileData data;
410 std::memcpy(&data, user_data.data(), sizeof(ProfileData));
411
412 Common::FS::IOFile image(GetImagePath(user_id), "wb");
413
414 if (!image.IsOpen() || !image.Resize(image_data.size()) ||
415 image.WriteBytes(image_data.data(), image_data.size()) != image_data.size() ||
416 !profile_manager.SetProfileBaseAndData(user_id, base, data)) {
417 LOG_ERROR(Service_ACC, "Failed to update profile data, base, and image!");
418 IPC::ResponseBuilder rb{ctx, 2};
419 rb.Push(ERR_FAILED_SAVE_DATA);
420 return;
421 }
422
423 IPC::ResponseBuilder rb{ctx, 2};
424 rb.Push(RESULT_SUCCESS);
425 }
426
427 ProfileManager& profile_manager;
428 Common::UUID user_id{Common::INVALID_UUID}; ///< The user id this profile refers to.
429 };
430
431 class IProfile final : public IProfileCommon {
432 public:
IProfile(Core::System & system_,Common::UUID user_id_,ProfileManager & profile_manager_)433 explicit IProfile(Core::System& system_, Common::UUID user_id_,
434 ProfileManager& profile_manager_)
435 : IProfileCommon{system_, "IProfile", false, user_id_, profile_manager_} {}
436 };
437
438 class IProfileEditor final : public IProfileCommon {
439 public:
IProfileEditor(Core::System & system_,Common::UUID user_id_,ProfileManager & profile_manager_)440 explicit IProfileEditor(Core::System& system_, Common::UUID user_id_,
441 ProfileManager& profile_manager_)
442 : IProfileCommon{system_, "IProfileEditor", true, user_id_, profile_manager_} {}
443 };
444
445 class IAsyncContext final : public ServiceFramework<IAsyncContext> {
446 public:
IAsyncContext(Core::System & system_)447 explicit IAsyncContext(Core::System& system_) : ServiceFramework{system_, "IAsyncContext"} {
448 // clang-format off
449 static const FunctionInfo functions[] = {
450 {0, nullptr, "GetSystemEvent"},
451 {1, nullptr, "Cancel"},
452 {2, nullptr, "HasDone"},
453 {3, nullptr, "GetResult"},
454 };
455 // clang-format on
456
457 RegisterHandlers(functions);
458 }
459 };
460
461 class ISessionObject final : public ServiceFramework<ISessionObject> {
462 public:
ISessionObject(Core::System & system_,Common::UUID)463 explicit ISessionObject(Core::System& system_, Common::UUID)
464 : ServiceFramework{system_, "ISessionObject"} {
465 // clang-format off
466 static const FunctionInfo functions[] = {
467 {999, nullptr, "Dummy"},
468 };
469 // clang-format on
470
471 RegisterHandlers(functions);
472 }
473 };
474
475 class IGuestLoginRequest final : public ServiceFramework<IGuestLoginRequest> {
476 public:
IGuestLoginRequest(Core::System & system_,Common::UUID)477 explicit IGuestLoginRequest(Core::System& system_, Common::UUID)
478 : ServiceFramework{system_, "IGuestLoginRequest"} {
479 // clang-format off
480 static const FunctionInfo functions[] = {
481 {0, nullptr, "GetSessionId"},
482 {11, nullptr, "Unknown"}, // 1.0.0 - 2.3.0 (the name is blank on Switchbrew)
483 {12, nullptr, "GetAccountId"},
484 {13, nullptr, "GetLinkedNintendoAccountId"},
485 {14, nullptr, "GetNickname"},
486 {15, nullptr, "GetProfileImage"},
487 {21, nullptr, "LoadIdTokenCache"}, // 3.0.0+
488 };
489 // clang-format on
490
491 RegisterHandlers(functions);
492 }
493 };
494
495 class IManagerForApplication final : public ServiceFramework<IManagerForApplication> {
496 public:
IManagerForApplication(Core::System & system_,Common::UUID user_id_)497 explicit IManagerForApplication(Core::System& system_, Common::UUID user_id_)
498 : ServiceFramework{system_, "IManagerForApplication"}, user_id{user_id_} {
499 // clang-format off
500 static const FunctionInfo functions[] = {
501 {0, &IManagerForApplication::CheckAvailability, "CheckAvailability"},
502 {1, &IManagerForApplication::GetAccountId, "GetAccountId"},
503 {2, nullptr, "EnsureIdTokenCacheAsync"},
504 {3, nullptr, "LoadIdTokenCache"},
505 {130, nullptr, "GetNintendoAccountUserResourceCacheForApplication"},
506 {150, nullptr, "CreateAuthorizationRequest"},
507 {160, &IManagerForApplication::StoreOpenContext, "StoreOpenContext"},
508 {170, nullptr, "LoadNetworkServiceLicenseKindAsync"},
509 };
510 // clang-format on
511
512 RegisterHandlers(functions);
513 }
514
515 private:
CheckAvailability(Kernel::HLERequestContext & ctx)516 void CheckAvailability(Kernel::HLERequestContext& ctx) {
517 LOG_WARNING(Service_ACC, "(STUBBED) called");
518 IPC::ResponseBuilder rb{ctx, 3};
519 rb.Push(RESULT_SUCCESS);
520 rb.Push(false); // TODO: Check when this is supposed to return true and when not
521 }
522
GetAccountId(Kernel::HLERequestContext & ctx)523 void GetAccountId(Kernel::HLERequestContext& ctx) {
524 LOG_DEBUG(Service_ACC, "called");
525
526 IPC::ResponseBuilder rb{ctx, 4};
527 rb.Push(RESULT_SUCCESS);
528 rb.PushRaw<u64>(user_id.GetNintendoID());
529 }
530
StoreOpenContext(Kernel::HLERequestContext & ctx)531 void StoreOpenContext(Kernel::HLERequestContext& ctx) {
532 LOG_WARNING(Service_ACC, "(STUBBED) called");
533 IPC::ResponseBuilder rb{ctx, 2};
534 rb.Push(RESULT_SUCCESS);
535 }
536
537 Common::UUID user_id;
538 };
539
540 // 6.0.0+
541 class IAsyncNetworkServiceLicenseKindContext final
542 : public ServiceFramework<IAsyncNetworkServiceLicenseKindContext> {
543 public:
IAsyncNetworkServiceLicenseKindContext(Core::System & system_,Common::UUID)544 explicit IAsyncNetworkServiceLicenseKindContext(Core::System& system_, Common::UUID)
545 : ServiceFramework{system_, "IAsyncNetworkServiceLicenseKindContext"} {
546 // clang-format off
547 static const FunctionInfo functions[] = {
548 {0, nullptr, "GetSystemEvent"},
549 {1, nullptr, "Cancel"},
550 {2, nullptr, "HasDone"},
551 {3, nullptr, "GetResult"},
552 {4, nullptr, "GetNetworkServiceLicenseKind"},
553 };
554 // clang-format on
555
556 RegisterHandlers(functions);
557 }
558 };
559
560 // 8.0.0+
561 class IOAuthProcedureForUserRegistration final
562 : public ServiceFramework<IOAuthProcedureForUserRegistration> {
563 public:
IOAuthProcedureForUserRegistration(Core::System & system_,Common::UUID)564 explicit IOAuthProcedureForUserRegistration(Core::System& system_, Common::UUID)
565 : ServiceFramework{system_, "IOAuthProcedureForUserRegistration"} {
566 // clang-format off
567 static const FunctionInfo functions[] = {
568 {0, nullptr, "PrepareAsync"},
569 {1, nullptr, "GetRequest"},
570 {2, nullptr, "ApplyResponse"},
571 {3, nullptr, "ApplyResponseAsync"},
572 {10, nullptr, "Suspend"},
573 {100, nullptr, "GetAccountId"},
574 {101, nullptr, "GetLinkedNintendoAccountId"},
575 {102, nullptr, "GetNickname"},
576 {103, nullptr, "GetProfileImage"},
577 {110, nullptr, "RegisterUserAsync"},
578 {111, nullptr, "GetUid"},
579 };
580 // clang-format on
581
582 RegisterHandlers(functions);
583 }
584 };
585
586 class DAUTH_O final : public ServiceFramework<DAUTH_O> {
587 public:
DAUTH_O(Core::System & system_,Common::UUID)588 explicit DAUTH_O(Core::System& system_, Common::UUID) : ServiceFramework{system_, "dauth:o"} {
589 // clang-format off
590 static const FunctionInfo functions[] = {
591 {0, nullptr, "EnsureAuthenticationTokenCacheAsync"}, // [5.0.0-5.1.0] GeneratePostData
592 {1, nullptr, "LoadAuthenticationTokenCache"}, // 6.0.0+
593 {2, nullptr, "InvalidateAuthenticationTokenCache"}, // 6.0.0+
594 {10, nullptr, "EnsureEdgeTokenCacheAsync"}, // 6.0.0+
595 {11, nullptr, "LoadEdgeTokenCache"}, // 6.0.0+
596 {12, nullptr, "InvalidateEdgeTokenCache"}, // 6.0.0+
597 };
598 // clang-format on
599
600 RegisterHandlers(functions);
601 }
602 };
603
604 // 6.0.0+
605 class IAsyncResult final : public ServiceFramework<IAsyncResult> {
606 public:
IAsyncResult(Core::System & system_,Common::UUID)607 explicit IAsyncResult(Core::System& system_, Common::UUID)
608 : ServiceFramework{system_, "IAsyncResult"} {
609 // clang-format off
610 static const FunctionInfo functions[] = {
611 {0, nullptr, "GetResult"},
612 {1, nullptr, "Cancel"},
613 {2, nullptr, "IsAvailable"},
614 {3, nullptr, "GetSystemEvent"},
615 };
616 // clang-format on
617
618 RegisterHandlers(functions);
619 }
620 };
621
GetUserCount(Kernel::HLERequestContext & ctx)622 void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) {
623 LOG_DEBUG(Service_ACC, "called");
624 IPC::ResponseBuilder rb{ctx, 3};
625 rb.Push(RESULT_SUCCESS);
626 rb.Push<u32>(static_cast<u32>(profile_manager->GetUserCount()));
627 }
628
GetUserExistence(Kernel::HLERequestContext & ctx)629 void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) {
630 IPC::RequestParser rp{ctx};
631 Common::UUID user_id = rp.PopRaw<Common::UUID>();
632 LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format());
633
634 IPC::ResponseBuilder rb{ctx, 3};
635 rb.Push(RESULT_SUCCESS);
636 rb.Push(profile_manager->UserExists(user_id));
637 }
638
ListAllUsers(Kernel::HLERequestContext & ctx)639 void Module::Interface::ListAllUsers(Kernel::HLERequestContext& ctx) {
640 LOG_DEBUG(Service_ACC, "called");
641 ctx.WriteBuffer(profile_manager->GetAllUsers());
642 IPC::ResponseBuilder rb{ctx, 2};
643 rb.Push(RESULT_SUCCESS);
644 }
645
ListOpenUsers(Kernel::HLERequestContext & ctx)646 void Module::Interface::ListOpenUsers(Kernel::HLERequestContext& ctx) {
647 LOG_DEBUG(Service_ACC, "called");
648 ctx.WriteBuffer(profile_manager->GetOpenUsers());
649 IPC::ResponseBuilder rb{ctx, 2};
650 rb.Push(RESULT_SUCCESS);
651 }
652
GetLastOpenedUser(Kernel::HLERequestContext & ctx)653 void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) {
654 LOG_DEBUG(Service_ACC, "called");
655 IPC::ResponseBuilder rb{ctx, 6};
656 rb.Push(RESULT_SUCCESS);
657 rb.PushRaw<Common::UUID>(profile_manager->GetLastOpenedUser());
658 }
659
GetProfile(Kernel::HLERequestContext & ctx)660 void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) {
661 IPC::RequestParser rp{ctx};
662 Common::UUID user_id = rp.PopRaw<Common::UUID>();
663 LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format());
664
665 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
666 rb.Push(RESULT_SUCCESS);
667 rb.PushIpcInterface<IProfile>(system, user_id, *profile_manager);
668 }
669
IsUserRegistrationRequestPermitted(Kernel::HLERequestContext & ctx)670 void Module::Interface::IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx) {
671 LOG_WARNING(Service_ACC, "(STUBBED) called");
672 IPC::ResponseBuilder rb{ctx, 3};
673 rb.Push(RESULT_SUCCESS);
674 rb.Push(profile_manager->CanSystemRegisterUser());
675 }
676
InitializeApplicationInfo(Kernel::HLERequestContext & ctx)677 void Module::Interface::InitializeApplicationInfo(Kernel::HLERequestContext& ctx) {
678 IPC::RequestParser rp{ctx};
679
680 LOG_DEBUG(Service_ACC, "called");
681 IPC::ResponseBuilder rb{ctx, 2};
682 rb.Push(InitializeApplicationInfoBase());
683 }
684
InitializeApplicationInfoRestricted(Kernel::HLERequestContext & ctx)685 void Module::Interface::InitializeApplicationInfoRestricted(Kernel::HLERequestContext& ctx) {
686 IPC::RequestParser rp{ctx};
687
688 LOG_WARNING(Service_ACC, "(Partial implementation) called");
689
690 // TODO(ogniK): We require checking if the user actually owns the title and what not. As of
691 // currently, we assume the user owns the title. InitializeApplicationInfoBase SHOULD be called
692 // first then we do extra checks if the game is a digital copy.
693
694 IPC::ResponseBuilder rb{ctx, 2};
695 rb.Push(InitializeApplicationInfoBase());
696 }
697
InitializeApplicationInfoBase()698 ResultCode Module::Interface::InitializeApplicationInfoBase() {
699 if (application_info) {
700 LOG_ERROR(Service_ACC, "Application already initialized");
701 return ERR_ACCOUNTINFO_ALREADY_INITIALIZED;
702 }
703
704 // TODO(ogniK): This should be changed to reflect the target process for when we have multiple
705 // processes emulated. As we don't actually have pid support we should assume we're just using
706 // our own process
707 const auto& current_process = system.Kernel().CurrentProcess();
708 const auto launch_property =
709 system.GetARPManager().GetLaunchProperty(current_process->GetTitleID());
710
711 if (launch_property.Failed()) {
712 LOG_ERROR(Service_ACC, "Failed to get launch property");
713 return ERR_ACCOUNTINFO_BAD_APPLICATION;
714 }
715
716 switch (launch_property->base_game_storage_id) {
717 case FileSys::StorageId::GameCard:
718 application_info.application_type = ApplicationType::GameCard;
719 break;
720 case FileSys::StorageId::Host:
721 case FileSys::StorageId::NandUser:
722 case FileSys::StorageId::SdCard:
723 case FileSys::StorageId::None: // Yuzu specific, differs from hardware
724 application_info.application_type = ApplicationType::Digital;
725 break;
726 default:
727 LOG_ERROR(Service_ACC, "Invalid game storage ID! storage_id={}",
728 launch_property->base_game_storage_id);
729 return ERR_ACCOUNTINFO_BAD_APPLICATION;
730 }
731
732 LOG_WARNING(Service_ACC, "ApplicationInfo init required");
733 // TODO(ogniK): Actual initalization here
734
735 return RESULT_SUCCESS;
736 }
737
GetBaasAccountManagerForApplication(Kernel::HLERequestContext & ctx)738 void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx) {
739 LOG_DEBUG(Service_ACC, "called");
740 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
741 rb.Push(RESULT_SUCCESS);
742 rb.PushIpcInterface<IManagerForApplication>(system, profile_manager->GetLastOpenedUser());
743 }
744
IsUserAccountSwitchLocked(Kernel::HLERequestContext & ctx)745 void Module::Interface::IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx) {
746 LOG_DEBUG(Service_ACC, "called");
747 FileSys::NACP nacp;
748 const auto res = system.GetAppLoader().ReadControlData(nacp);
749
750 bool is_locked = false;
751
752 if (res != Loader::ResultStatus::Success) {
753 const FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID(),
754 system.GetFileSystemController(),
755 system.GetContentProvider()};
756 const auto nacp_unique = pm.GetControlMetadata().first;
757
758 if (nacp_unique != nullptr) {
759 is_locked = nacp_unique->GetUserAccountSwitchLock();
760 } else {
761 LOG_ERROR(Service_ACC, "nacp_unique is null!");
762 }
763 } else {
764 is_locked = nacp.GetUserAccountSwitchLock();
765 }
766
767 IPC::ResponseBuilder rb{ctx, 3};
768 rb.Push(RESULT_SUCCESS);
769 rb.Push(is_locked);
770 }
771
GetProfileEditor(Kernel::HLERequestContext & ctx)772 void Module::Interface::GetProfileEditor(Kernel::HLERequestContext& ctx) {
773 IPC::RequestParser rp{ctx};
774 Common::UUID user_id = rp.PopRaw<Common::UUID>();
775
776 LOG_DEBUG(Service_ACC, "called, user_id={}", user_id.Format());
777
778 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
779 rb.Push(RESULT_SUCCESS);
780 rb.PushIpcInterface<IProfileEditor>(system, user_id, *profile_manager);
781 }
782
ListQualifiedUsers(Kernel::HLERequestContext & ctx)783 void Module::Interface::ListQualifiedUsers(Kernel::HLERequestContext& ctx) {
784 LOG_DEBUG(Service_ACC, "called");
785
786 // All users should be qualified. We don't actually have parental control or anything to do with
787 // nintendo online currently. We're just going to assume the user running the game has access to
788 // the game regardless of parental control settings.
789 ctx.WriteBuffer(profile_manager->GetAllUsers());
790 IPC::ResponseBuilder rb{ctx, 2};
791 rb.Push(RESULT_SUCCESS);
792 }
793
LoadOpenContext(Kernel::HLERequestContext & ctx)794 void Module::Interface::LoadOpenContext(Kernel::HLERequestContext& ctx) {
795 LOG_WARNING(Service_ACC, "(STUBBED) called");
796
797 // This is similar to GetBaasAccountManagerForApplication
798 // This command is used concurrently with ListOpenContextStoredUsers
799 // TODO: Find the differences between this and GetBaasAccountManagerForApplication
800 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
801 rb.Push(RESULT_SUCCESS);
802 rb.PushIpcInterface<IManagerForApplication>(system, profile_manager->GetLastOpenedUser());
803 }
804
ListOpenContextStoredUsers(Kernel::HLERequestContext & ctx)805 void Module::Interface::ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx) {
806 LOG_WARNING(Service_ACC, "(STUBBED) called");
807
808 // TODO(ogniK): Handle open contexts
809 ctx.WriteBuffer(profile_manager->GetOpenUsers());
810 IPC::ResponseBuilder rb{ctx, 2};
811 rb.Push(RESULT_SUCCESS);
812 }
813
TrySelectUserWithoutInteraction(Kernel::HLERequestContext & ctx)814 void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) {
815 LOG_DEBUG(Service_ACC, "called");
816 // A u8 is passed into this function which we can safely ignore. It's to determine if we have
817 // access to use the network or not by the looks of it
818 IPC::ResponseBuilder rb{ctx, 6};
819 if (profile_manager->GetUserCount() != 1) {
820 rb.Push(RESULT_SUCCESS);
821 rb.PushRaw<u128>(Common::INVALID_UUID);
822 return;
823 }
824
825 const auto user_list = profile_manager->GetAllUsers();
826 if (std::all_of(user_list.begin(), user_list.end(),
827 [](const auto& user) { return user.uuid == Common::INVALID_UUID; })) {
828 rb.Push(RESULT_UNKNOWN); // TODO(ogniK): Find the correct error code
829 rb.PushRaw<u128>(Common::INVALID_UUID);
830 return;
831 }
832
833 // Select the first user we have
834 rb.Push(RESULT_SUCCESS);
835 rb.PushRaw<u128>(profile_manager->GetUser(0)->uuid);
836 }
837
Interface(std::shared_ptr<Module> module_,std::shared_ptr<ProfileManager> profile_manager_,Core::System & system_,const char * name)838 Module::Interface::Interface(std::shared_ptr<Module> module_,
839 std::shared_ptr<ProfileManager> profile_manager_,
840 Core::System& system_, const char* name)
841 : ServiceFramework{system_, name}, module{std::move(module_)}, profile_manager{std::move(
842 profile_manager_)} {}
843
844 Module::Interface::~Interface() = default;
845
InstallInterfaces(Core::System & system)846 void InstallInterfaces(Core::System& system) {
847 auto module = std::make_shared<Module>();
848 auto profile_manager = std::make_shared<ProfileManager>();
849
850 std::make_shared<ACC_AA>(module, profile_manager, system)
851 ->InstallAsService(system.ServiceManager());
852 std::make_shared<ACC_SU>(module, profile_manager, system)
853 ->InstallAsService(system.ServiceManager());
854 std::make_shared<ACC_U0>(module, profile_manager, system)
855 ->InstallAsService(system.ServiceManager());
856 std::make_shared<ACC_U1>(module, profile_manager, system)
857 ->InstallAsService(system.ServiceManager());
858 }
859
860 } // namespace Service::Account
861