Cemu/src/Cafe/IOSU/legacy/iosu_act.cpp

744 lines
26 KiB
C++

#include "iosu_act.h"
#include "iosu_ioctl.h"
#include "Cafe/OS/libs/nn_common.h"
#include "gui/CemuApp.h"
#include <algorithm>
#include <mutex>
#include "openssl/evp.h" /* EVP_Digest */
#include "openssl/sha.h" /* SHA256_DIGEST_LENGTH */
#include "Cafe/Account/Account.h"
#include "config/ActiveSettings.h"
#include "util/helpers/helpers.h"
#include "Cemu/napi/napi.h"
#include "Cemu/ncrypto/ncrypto.h"
#include "Cafe/IOSU/kernel/iosu_kernel.h"
#include "Cafe/IOSU/nn/iosu_nn_service.h"
using namespace iosu::kernel;
struct
{
bool isInitialized;
}iosuAct = { };
// account manager
typedef struct
{
bool isValid;
// options
bool isNetworkAccount;
bool hasParseError; // set if any occurs while parsing account.dat
// IDs
uint8 uuid[16];
uint32 persistentId;
uint64 transferableIdBase;
uint32 simpleAddressId;
uint32 principalId;
// NNID
char accountId[64];
uint8 accountPasswordCache[32];
// country & language
uint32 countryIndex;
char country[8];
// Mii
FFLData_t miiData;
uint16be miiNickname[ACT_NICKNAME_LENGTH];
}actAccountData_t;
#define IOSU_ACT_ACCOUNT_MAX_COUNT (0xC)
actAccountData_t _actAccountData[IOSU_ACT_ACCOUNT_MAX_COUNT] = {};
bool _actAccountDataInitialized = false;
void FillAccountData(const Account& account, const bool online_enabled, int index)
{
cemu_assert_debug(index < IOSU_ACT_ACCOUNT_MAX_COUNT);
auto& data = _actAccountData[index];
data.isValid = true;
// options
data.isNetworkAccount = account.IsValidOnlineAccount();
data.hasParseError = false;
// IDs
std::copy(account.GetUuid().cbegin(), account.GetUuid().cend(), data.uuid);
data.persistentId = account.GetPersistentId();
data.transferableIdBase = account.GetTransferableIdBase();
data.simpleAddressId = account.GetSimpleAddressId();
data.principalId = account.GetPrincipalId();
// NNID
std::copy(account.GetAccountId().begin(), account.GetAccountId().end(), data.accountId);
std::copy(account.GetAccountPasswordCache().begin(), account.GetAccountPasswordCache().end(), data.accountPasswordCache);
// country & language
data.countryIndex = account.GetCountry();
strcpy(data.country, NCrypto::GetCountryAsString(data.countryIndex));
// Mii
std::copy(account.GetMiiData().begin(), account.GetMiiData().end(), (uint8*)&data.miiData);
std::copy(account.GetMiiName().begin(), account.GetMiiName().end(), data.miiNickname);
// if online mode is disabled, make all accounts offline
if(!online_enabled)
{
data.isNetworkAccount = false;
data.principalId = 0;
data.simpleAddressId = 0;
memset(data.accountId, 0x00, sizeof(data.accountId));
}
}
void iosuAct_loadAccounts()
{
if (_actAccountDataInitialized)
return;
const bool online_enabled = ActiveSettings::IsOnlineEnabled();
const auto persistent_id = ActiveSettings::GetPersistentId();
// first account is always our selected one
int counter = 0;
const auto& first_acc = Account::GetAccount(persistent_id);
FillAccountData(first_acc, online_enabled, counter);
++counter;
cemuLog_force(L"IOSU_ACT: using account {} in first slot", first_acc.GetMiiName());
_actAccountDataInitialized = true;
}
bool iosuAct_isAccountDataLoaded()
{
return _actAccountDataInitialized;
}
uint32 iosuAct_acquirePrincipalIdByAccountId(const char* nnid, uint32* pid)
{
NAPI::AuthInfo authInfo;
NAPI::NAPI_MakeAuthInfoFromCurrentAccount(authInfo);
NAPI::ACTConvertNnidToPrincipalIdResult result = NAPI::ACT_ACTConvertNnidToPrincipalId(authInfo, nnid);
if (result.isValid() && result.isFound)
{
*pid = result.principalId;
}
else
{
*pid = 0;
return BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_ACT, 0); // what error should we return? The friend list app expects nn_act.AcquirePrincipalIdByAccountId to never return an error
}
return 0;
}
sint32 iosuAct_getAccountIndexBySlot(uint8 slot)
{
if (slot == iosu::act::ACT_SLOT_CURRENT)
return 0;
if (slot == 0xFF)
return 0; // ?
cemu_assert_debug(slot != 0);
cemu_assert_debug(slot <= IOSU_ACT_ACCOUNT_MAX_COUNT);
return slot - 1;
}
uint32 iosuAct_getAccountIdOfCurrentAccount()
{
cemu_assert_debug(_actAccountData[0].isValid);
return _actAccountData[0].persistentId;
}
// IOSU act API interface
namespace iosu
{
namespace act
{
uint8 getCurrentAccountSlot()
{
return 1;
}
bool getPrincipalId(uint8 slot, uint32* principalId)
{
sint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);
if (_actAccountData[accountIndex].isValid == false)
{
*principalId = 0;
return false;
}
*principalId = _actAccountData[accountIndex].principalId;
return true;
}
bool getAccountId(uint8 slot, char* accountId)
{
sint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);
if (_actAccountData[accountIndex].isValid == false)
{
*accountId = '\0';
return false;
}
strcpy(accountId, _actAccountData[accountIndex].accountId);
return true;
}
bool getMii(uint8 slot, FFLData_t* fflData)
{
sint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);
if (_actAccountData[accountIndex].isValid == false)
{
return false;
}
memcpy(fflData, &_actAccountData[accountIndex].miiData, sizeof(FFLData_t));
return true;
}
// return screenname in little-endian wide characters
bool getScreenname(uint8 slot, uint16 screenname[ACT_NICKNAME_LENGTH])
{
sint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);
if (_actAccountData[accountIndex].isValid == false)
{
screenname[0] = '\0';
return false;
}
for (sint32 i = 0; i < ACT_NICKNAME_LENGTH; i++)
{
screenname[i] = (uint16)_actAccountData[accountIndex].miiNickname[i];
}
return true;
}
bool getCountryIndex(uint8 slot, uint32* countryIndex)
{
sint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);
if (_actAccountData[accountIndex].isValid == false)
{
*countryIndex = 0;
return false;
}
*countryIndex = _actAccountData[accountIndex].countryIndex;
return true;
}
class ActService : public iosu::nn::IPCService
{
public:
ActService() : iosu::nn::IPCService("/dev/act") {}
nnResult ServiceCall(uint32 serviceId, void* request, void* response) override
{
cemuLog_log(LogType::Force, "Unsupported service call to /dec/act");
cemu_assert_unimplemented();
return BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_ACT, 0);
}
};
ActService gActService;
void Initialize()
{
gActService.Start();
}
void Stop()
{
gActService.Stop();
}
}
}
// IOSU act IO
typedef struct
{
/* +0x00 */ uint32be ukn00;
/* +0x04 */ uint32be ukn04;
/* +0x08 */ uint32be ukn08;
/* +0x0C */ uint32be subcommandCode;
/* +0x10 */ uint8 ukn10;
/* +0x11 */ uint8 ukn11;
/* +0x12 */ uint8 ukn12;
/* +0x13 */ uint8 accountSlot;
/* +0x14 */ uint32be unique; // is this command specific?
}cmdActRequest00_t;
typedef struct
{
uint32be returnCode;
uint8 transferableIdBase[8];
}cmdActGetTransferableIDResult_t;
#define ACT_SUBCMD_GET_TRANSFERABLE_ID 4
#define ACT_SUBCMD_INITIALIZE 0x14
#define _cancelIfAccountDoesNotExist() \
if (_actAccountData[accountIndex].isValid == false) \
{ \
/* account does not exist*/ \
ioctlReturnValue = 0; \
actCemuRequest->setACTReturnCode(BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_ACT, NN_ACT_RESULT_ACCOUNT_DOES_NOT_EXIST)); /* 0xA071F480 */ \
actCemuRequest->resultU64.u64 = 0; \
iosuIoctl_completeRequest(ioQueueEntry, ioctlReturnValue); \
continue; \
}
nnResult ServerActErrorCodeToNNResult(NAPI::ACT_ERROR_CODE ec)
{
switch (ec)
{
case (NAPI::ACT_ERROR_CODE)1:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2401);
case (NAPI::ACT_ERROR_CODE)2:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2402);
case (NAPI::ACT_ERROR_CODE)3:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2403);
case (NAPI::ACT_ERROR_CODE)4:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2458);
case (NAPI::ACT_ERROR_CODE)5:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2642);
case (NAPI::ACT_ERROR_CODE)6:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2641);
case (NAPI::ACT_ERROR_CODE)7:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2522);
case (NAPI::ACT_ERROR_CODE)8:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2534);
case (NAPI::ACT_ERROR_CODE)9:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2404);
case (NAPI::ACT_ERROR_CODE)10:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2451);
case (NAPI::ACT_ERROR_CODE)11:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2511);
case (NAPI::ACT_ERROR_CODE)12:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2812);
case (NAPI::ACT_ERROR_CODE)100:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2571);
case (NAPI::ACT_ERROR_CODE)101:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2572);
case (NAPI::ACT_ERROR_CODE)103:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2575);
case (NAPI::ACT_ERROR_CODE)104:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2452);
case (NAPI::ACT_ERROR_CODE)105:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2592);
case (NAPI::ACT_ERROR_CODE)106:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2611);
case (NAPI::ACT_ERROR_CODE)107:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2502);
case (NAPI::ACT_ERROR_CODE)108:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2802);
case (NAPI::ACT_ERROR_CODE)109:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2503);
case (NAPI::ACT_ERROR_CODE)110:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2501);
case (NAPI::ACT_ERROR_CODE)111:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2632);
case (NAPI::ACT_ERROR_CODE)112:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2631);
case (NAPI::ACT_ERROR_CODE)113:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2452);
case (NAPI::ACT_ERROR_CODE)114:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2593);
case (NAPI::ACT_ERROR_CODE)115:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2591);
case (NAPI::ACT_ERROR_CODE)116:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2614);
case (NAPI::ACT_ERROR_CODE)117:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2651);
case (NAPI::ACT_ERROR_CODE)118:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2484);
case (NAPI::ACT_ERROR_CODE)119:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2803);
case (NAPI::ACT_ERROR_CODE)120:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2813);
case (NAPI::ACT_ERROR_CODE)121:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2804);
case (NAPI::ACT_ERROR_CODE)122:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2814);
case (NAPI::ACT_ERROR_CODE)123:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2882);
case (NAPI::ACT_ERROR_CODE)124:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2512);
case (NAPI::ACT_ERROR_CODE)125:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2485);
case (NAPI::ACT_ERROR_CODE)126:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2805);
case (NAPI::ACT_ERROR_CODE)127:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2815);
case (NAPI::ACT_ERROR_CODE)128:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2661);
case (NAPI::ACT_ERROR_CODE)129:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2615);
case (NAPI::ACT_ERROR_CODE)130:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2531);
case (NAPI::ACT_ERROR_CODE)131:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2616);
case (NAPI::ACT_ERROR_CODE)132:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2822);
case (NAPI::ACT_ERROR_CODE)133:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2832);
case (NAPI::ACT_ERROR_CODE)134:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2823);
case (NAPI::ACT_ERROR_CODE)135:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2833);
case (NAPI::ACT_ERROR_CODE)136:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2824);
case (NAPI::ACT_ERROR_CODE)137:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2834);
case (NAPI::ACT_ERROR_CODE)138:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2825);
case (NAPI::ACT_ERROR_CODE)139:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2835);
case (NAPI::ACT_ERROR_CODE)142:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2635);
case (NAPI::ACT_ERROR_CODE)143:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2634);
case (NAPI::ACT_ERROR_CODE)1004:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2503);
case (NAPI::ACT_ERROR_CODE)1006:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2471);
case (NAPI::ACT_ERROR_CODE)1016:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2532);
case (NAPI::ACT_ERROR_CODE)1017:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2483);
case (NAPI::ACT_ERROR_CODE)1018:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2533);
case (NAPI::ACT_ERROR_CODE)1019:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2481);
case (NAPI::ACT_ERROR_CODE)1020:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2473);
case NAPI::ACT_ERROR_CODE::ACT_GAME_SERVER_NOT_FOUND:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2482);
case (NAPI::ACT_ERROR_CODE)1022:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2472);
case (NAPI::ACT_ERROR_CODE)1023:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2612);
case (NAPI::ACT_ERROR_CODE)1024:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2535);
case (NAPI::ACT_ERROR_CODE)1025:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2536);
case (NAPI::ACT_ERROR_CODE)1031:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2537);
case (NAPI::ACT_ERROR_CODE)1032:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2636);
case (NAPI::ACT_ERROR_CODE)1033:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2662);
case (NAPI::ACT_ERROR_CODE)1035:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2671);
case (NAPI::ACT_ERROR_CODE)1036:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2679);
case (NAPI::ACT_ERROR_CODE)1037:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2672);
case (NAPI::ACT_ERROR_CODE)1038:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2674);
case (NAPI::ACT_ERROR_CODE)1039:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2680);
case (NAPI::ACT_ERROR_CODE)1040:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2675);
case (NAPI::ACT_ERROR_CODE)1041:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2673);
case (NAPI::ACT_ERROR_CODE)1042:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2676);
case (NAPI::ACT_ERROR_CODE)1043:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2681);
case (NAPI::ACT_ERROR_CODE)1044:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2678);
case (NAPI::ACT_ERROR_CODE)1045:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2677);
case (NAPI::ACT_ERROR_CODE)1046:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2596);
case (NAPI::ACT_ERROR_CODE)1100:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2541);
case (NAPI::ACT_ERROR_CODE)1101:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2542);
case (NAPI::ACT_ERROR_CODE)1103:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2594);
case (NAPI::ACT_ERROR_CODE)1104:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2576);
case (NAPI::ACT_ERROR_CODE)1105:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2613);
case (NAPI::ACT_ERROR_CODE)1106:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2633);
case (NAPI::ACT_ERROR_CODE)1107:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2577);
case (NAPI::ACT_ERROR_CODE)1111:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2538);
case (NAPI::ACT_ERROR_CODE)1115:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2597);
case (NAPI::ACT_ERROR_CODE)1125:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2585);
case (NAPI::ACT_ERROR_CODE)1126:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2586);
case (NAPI::ACT_ERROR_CODE)1134:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2587);
case (NAPI::ACT_ERROR_CODE)1200:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2884);
case (NAPI::ACT_ERROR_CODE)2001:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2931);
case (NAPI::ACT_ERROR_CODE)2002:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2881);
case (NAPI::ACT_ERROR_CODE)2999:
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2883);
default:
break;
}
cemuLog_log(LogType::Force, "Received unknown ACT error code {}", (uint32)ec);
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, NN_ERROR_CODE::ACT_UNKNOWN_SERVER_ERROR);
}
int iosuAct_thread()
{
SetThreadName("iosuAct_thread");
while (true)
{
uint32 ioctlReturnValue = 0;
ioQueueEntry_t* ioQueueEntry = iosuIoctl_getNextWithWait(IOS_DEVICE_ACT);
if (ioQueueEntry->request == 0)
{
if (ioQueueEntry->countIn != 1 || ioQueueEntry->countOut != 1)
{
assert_dbg();
}
ioBufferVector_t* vectorsDebug = ioQueueEntry->bufferVectors.GetPtr();
void* outputBuffer = ioQueueEntry->bufferVectors[0].buffer.GetPtr();
cmdActRequest00_t* requestCmd = (cmdActRequest00_t*)ioQueueEntry->bufferVectors[0].unknownBuffer.GetPtr();
if (requestCmd->subcommandCode == ACT_SUBCMD_INITIALIZE)
{
// do nothing for now (there is no result?)
}
else if (requestCmd->subcommandCode == ACT_SUBCMD_GET_TRANSFERABLE_ID)
{
cmdActGetTransferableIDResult_t* cmdResult = (cmdActGetTransferableIDResult_t*)outputBuffer;
cmdResult->returnCode = 0;
*(uint64*)cmdResult->transferableIdBase = _swapEndianU64(0x1122334455667788);
}
else
assert_dbg();
}
else if (ioQueueEntry->request == IOSU_ACT_REQUEST_CEMU)
{
iosuActCemuRequest_t* actCemuRequest = (iosuActCemuRequest_t*)ioQueueEntry->bufferVectors[0].buffer.GetPtr();
sint32 accountIndex;
ioctlReturnValue = 0;
if (actCemuRequest->requestCode == IOSU_ARC_ACCOUNT_ID)
{
accountIndex = iosuAct_getAccountIndexBySlot(actCemuRequest->accountSlot);
_cancelIfAccountDoesNotExist();
strcpy(actCemuRequest->resultString.strBuffer, _actAccountData[accountIndex].accountId);
actCemuRequest->setACTReturnCode(0);
}
else if (actCemuRequest->requestCode == IOSU_ARC_UUID)
{
accountIndex = iosuAct_getAccountIndexBySlot(actCemuRequest->accountSlot);
if (actCemuRequest->accountSlot == 0xFF)
{
// common uuid (placeholder algorithm)
for (uint32 i = 0; i < 16; i++)
actCemuRequest->resultBinary.binBuffer[i] = i * 0x74 + i + ~i + i * 133;
}
else
{
_cancelIfAccountDoesNotExist();
memcpy(actCemuRequest->resultBinary.binBuffer, _actAccountData[accountIndex].uuid, 16);
}
cemu_assert_debug(actCemuRequest->uuidName != -1); // todo
if (actCemuRequest->uuidName != -1 && actCemuRequest->uuidName != -2)
{
// generate name based UUID
// format:
// first 10 bytes of UUID + 6 bytes of a hash
// hash algorithm:
// sha256 of
// 4 bytes uuidName (big-endian)
// 4 bytes 0x3A275E09 (big-endian)
// 6 bytes from the end of UUID
// bytes 10-15 are used from the hash and replace the last 6 bytes of the UUID
EVP_MD_CTX *ctx_sha256 = EVP_MD_CTX_new();
EVP_DigestInit(ctx_sha256, EVP_sha256());
uint32 name = (uint32)actCemuRequest->uuidName;
uint8 tempArray[] = {
(name >> 24) & 0xFF,
(name >> 16) & 0xFF,
(name >> 8) & 0xFF,
(name >> 0) & 0xFF,
0x3A,
0x27,
0x5E,
0x09,
};
EVP_DigestUpdate(ctx_sha256, tempArray, sizeof(tempArray));
EVP_DigestUpdate(ctx_sha256, actCemuRequest->resultBinary.binBuffer+10, 6);
uint8 h[SHA256_DIGEST_LENGTH];
EVP_DigestFinal_ex(ctx_sha256, h, NULL);
EVP_MD_CTX_free(ctx_sha256);
memcpy(actCemuRequest->resultBinary.binBuffer + 0xA, h + 0xA, 6);
}
else if (actCemuRequest->uuidName == -2)
{
// return account uuid
}
else
{
forceLogDebug_printf("Gen UUID unknown mode %d", actCemuRequest->uuidName);
}
actCemuRequest->setACTReturnCode(0);
}
else if (actCemuRequest->requestCode == IOSU_ARC_SIMPLEADDRESS)
{
accountIndex = iosuAct_getAccountIndexBySlot(actCemuRequest->accountSlot);
_cancelIfAccountDoesNotExist();
actCemuRequest->resultU32.u32 = _actAccountData[accountIndex].simpleAddressId;
actCemuRequest->setACTReturnCode(0);
}
else if (actCemuRequest->requestCode == IOSU_ARC_PRINCIPALID)
{
accountIndex = iosuAct_getAccountIndexBySlot(actCemuRequest->accountSlot);
_cancelIfAccountDoesNotExist();
actCemuRequest->resultU32.u32 = _actAccountData[accountIndex].principalId;
actCemuRequest->setACTReturnCode(0);
}
else if (actCemuRequest->requestCode == IOSU_ARC_TRANSFERABLEID)
{
accountIndex = iosuAct_getAccountIndexBySlot(actCemuRequest->accountSlot);
_cancelIfAccountDoesNotExist();
actCemuRequest->resultU64.u64 = _actAccountData[accountIndex].transferableIdBase;
// todo - transferable also contains a unique id
actCemuRequest->setACTReturnCode(0);
}
else if (actCemuRequest->requestCode == IOSU_ARC_PERSISTENTID)
{
accountIndex = iosuAct_getAccountIndexBySlot(actCemuRequest->accountSlot);
_cancelIfAccountDoesNotExist();
actCemuRequest->resultU32.u32 = _actAccountData[accountIndex].persistentId;
actCemuRequest->setACTReturnCode(0);
}
else if (actCemuRequest->requestCode == IOSU_ARC_COUNTRY)
{
accountIndex = iosuAct_getAccountIndexBySlot(actCemuRequest->accountSlot);
_cancelIfAccountDoesNotExist();
strcpy(actCemuRequest->resultString.strBuffer, _actAccountData[accountIndex].country);
actCemuRequest->setACTReturnCode(0);
}
else if (actCemuRequest->requestCode == IOSU_ARC_ISNETWORKACCOUNT)
{
accountIndex = iosuAct_getAccountIndexBySlot(actCemuRequest->accountSlot);
_cancelIfAccountDoesNotExist();
actCemuRequest->resultU32.u32 = _actAccountData[accountIndex].isNetworkAccount;
actCemuRequest->setACTReturnCode(0);
}
else if (actCemuRequest->requestCode == IOSU_ARC_ACQUIRENEXTOKEN)
{
NAPI::AuthInfo authInfo;
NAPI::NAPI_MakeAuthInfoFromCurrentAccount(authInfo);
NAPI::ACTGetNexTokenResult nexTokenResult = NAPI::ACT_GetNexToken_WithCache(authInfo, actCemuRequest->titleId, actCemuRequest->titleVersion, actCemuRequest->serverId);
uint32 returnCode = 0;
if (nexTokenResult.isValid())
{
*(NAPI::ACTNexToken*)actCemuRequest->resultBinary.binBuffer = nexTokenResult.nexToken;
returnCode = NN_RESULT_SUCCESS;
}
else if (nexTokenResult.apiError == NAPI_RESULT::SERVICE_ERROR)
{
returnCode = ServerActErrorCodeToNNResult(nexTokenResult.serviceError);
cemu_assert_debug((returnCode&0x80000000) != 0);
}
else
{
returnCode = nnResultStatus(NN_RESULT_MODULE_NN_ACT, NN_ERROR_CODE::ACT_UNKNOWN_SERVER_ERROR);
}
actCemuRequest->setACTReturnCode(returnCode);
}
else if (actCemuRequest->requestCode == IOSU_ARC_ACQUIREINDEPENDENTTOKEN)
{
NAPI::AuthInfo authInfo;
NAPI::NAPI_MakeAuthInfoFromCurrentAccount(authInfo);
NAPI::ACTGetIndependentTokenResult tokenResult = NAPI::ACT_GetIndependentToken_WithCache(authInfo, actCemuRequest->titleId, actCemuRequest->titleVersion, actCemuRequest->clientId);
uint32 returnCode = 0;
if (tokenResult.isValid())
{
for (size_t i = 0; i < std::min(tokenResult.token.size(), (size_t)200); i++)
{
actCemuRequest->resultBinary.binBuffer[i] = tokenResult.token[i];
actCemuRequest->resultBinary.binBuffer[i + 1] = '\0';
}
returnCode = 0;
}
else
{
returnCode = 0x80000000; // todo - proper error codes
}
actCemuRequest->setACTReturnCode(returnCode);
}
else if (actCemuRequest->requestCode == IOSU_ARC_ACQUIREPIDBYNNID)
{
uint32 returnCode = iosuAct_acquirePrincipalIdByAccountId(actCemuRequest->clientId, &actCemuRequest->resultU32.u32);
actCemuRequest->setACTReturnCode(returnCode);
}
else if (actCemuRequest->requestCode == IOSU_ARC_MIIDATA)
{
accountIndex = iosuAct_getAccountIndexBySlot(actCemuRequest->accountSlot);
_cancelIfAccountDoesNotExist();
memcpy(actCemuRequest->resultBinary.binBuffer, &_actAccountData[accountIndex].miiData, sizeof(FFLData_t));
actCemuRequest->setACTReturnCode(0);
}
else if (actCemuRequest->requestCode == IOSU_ARC_INIT)
{
iosuAct_loadAccounts();
actCemuRequest->setACTReturnCode(0);
}
else
assert_dbg();
}
else
{
assert_dbg();
}
iosuIoctl_completeRequest(ioQueueEntry, ioctlReturnValue);
}
return 0;
}
void iosuAct_init_depr()
{
if (iosuAct.isInitialized)
return;
std::thread t(iosuAct_thread);
t.detach();
iosuAct.isInitialized = true;
}
bool iosuAct_isInitialized()
{
return iosuAct.isInitialized;
}
uint16 FFLCalculateCRC16(uint8* input, sint32 length)
{
uint16 crc = 0;
for (sint32 c = 0; c < length; c++)
{
for (sint32 f = 0; f < 8; f++)
{
if ((crc & 0x8000) != 0)
{
uint16 t = crc << 1;
crc = t ^ 0x1021;
}
else
{
crc <<= 1;
}
}
crc ^= (uint16)input[c];
}
return crc;
}