diff options
| author | Léo Lam <leo@innovatetechnologi.es> | 2017-05-05 00:12:37 +0200 |
|---|---|---|
| committer | Léo Lam <leo@innovatetechnologi.es> | 2017-05-05 00:32:58 +0200 |
| commit | 5fb2ad2b3a93ad095693e4694caa301bd2f243d0 (patch) | |
| tree | 7c8091792a3005c292dbc92cdea94ba691a276ae /Source/Core | |
| parent | a7680a3d1a773883c2fe3689e6dff79176692389 (diff) | |
IOS/ES: Fix the implementation of ES_DeleteTicket
* It should take a ticket view, not a title ID.
* It's missing a lot of checks.
* It's not deleting tickets properly.
* It's not deleting only the ticket it needs to delete.
* It should not return -1017 when the ticket doesn't exist.
* It's not returning the proper error code when a read/write fails.
* It's not cleaning up the ticket directory if there is nothing left.
This commit fixes its implementation.
Diffstat (limited to 'Source/Core')
| -rw-r--r-- | Source/Core/Core/IOS/ES/Formats.cpp | 15 | ||||
| -rw-r--r-- | Source/Core/Core/IOS/ES/Formats.h | 3 | ||||
| -rw-r--r-- | Source/Core/Core/IOS/ES/TitleManagement.cpp | 41 |
3 files changed, 54 insertions, 5 deletions
diff --git a/Source/Core/Core/IOS/ES/Formats.cpp b/Source/Core/Core/IOS/ES/Formats.cpp index 17184bb942..831488d2df 100644 --- a/Source/Core/Core/IOS/ES/Formats.cpp +++ b/Source/Core/Core/IOS/ES/Formats.cpp @@ -300,6 +300,21 @@ std::vector<u8> TicketReader::GetTitleKey() const return key; } +void TicketReader::DeleteTicket(u64 ticket_id_to_delete) +{ + std::vector<u8> new_ticket; + const size_t num_tickets = GetNumberOfTickets(); + for (size_t i = 0; i < num_tickets; ++i) + { + const auto ticket_start = m_bytes.cbegin() + sizeof(Ticket) * i; + const u64 ticket_id = Common::swap64(&*ticket_start + offsetof(Ticket, ticket_id)); + if (ticket_id != ticket_id_to_delete) + new_ticket.insert(new_ticket.end(), ticket_start, ticket_start + sizeof(Ticket)); + } + + m_bytes = std::move(new_ticket); +} + s32 TicketReader::Unpersonalise() { const auto ticket_begin = m_bytes.begin(); diff --git a/Source/Core/Core/IOS/ES/Formats.h b/Source/Core/Core/IOS/ES/Formats.h index 5380afd953..6337aeaf32 100644 --- a/Source/Core/Core/IOS/ES/Formats.h +++ b/Source/Core/Core/IOS/ES/Formats.h @@ -193,6 +193,9 @@ public: u64 GetTitleId() const; std::vector<u8> GetTitleKey() const; + // Deletes a ticket with the given ticket ID from the internal buffer. + void DeleteTicket(u64 ticket_id); + // Decrypts the title key field for a "personalised" ticket -- one that is device-specific // and has a title key that must be decrypted first. s32 Unpersonalise(); diff --git a/Source/Core/Core/IOS/ES/TitleManagement.cpp b/Source/Core/Core/IOS/ES/TitleManagement.cpp index 93dfbee95c..cb0b6420f1 100644 --- a/Source/Core/Core/IOS/ES/TitleManagement.cpp +++ b/Source/Core/Core/IOS/ES/TitleManagement.cpp @@ -6,6 +6,7 @@ #include <algorithm> #include <cinttypes> +#include <cstddef> #include <utility> #include <vector> @@ -335,16 +336,46 @@ IPCCommandResult ES::DeleteTitle(const IOCtlVRequest& request) IPCCommandResult ES::DeleteTicket(const IOCtlVRequest& request) { - if (!request.HasNumberOfValidVectors(1, 0)) + if (!request.HasNumberOfValidVectors(1, 0) || + request.in_vectors[0].size != sizeof(IOS::ES::TicketView)) + { return GetDefaultReply(ES_EINVAL); + } - u64 TitleID = Memory::Read_U64(request.in_vectors[0].address); - INFO_LOG(IOS_ES, "IOCTL_ES_DELETETICKET: title: %08x/%08x", (u32)(TitleID >> 32), (u32)TitleID); + const u64 title_id = + Memory::Read_U64(request.in_vectors[0].address + offsetof(IOS::ES::TicketView, title_id)); - // Presumably return -1017 when delete fails - if (!File::Delete(Common::GetTicketFileName(TitleID, Common::FROM_SESSION_ROOT))) + if (!CanDeleteTitle(title_id)) return GetDefaultReply(ES_EINVAL); + auto ticket = DiscIO::FindSignedTicket(title_id); + if (!ticket.IsValid()) + return GetDefaultReply(FS_ENOENT); + + const u64 ticket_id = + Memory::Read_U64(request.in_vectors[0].address + offsetof(IOS::ES::TicketView, ticket_id)); + ticket.DeleteTicket(ticket_id); + + const std::vector<u8>& new_ticket = ticket.GetRawTicket(); + const std::string ticket_path = Common::GetTicketFileName(title_id, Common::FROM_SESSION_ROOT); + { + File::IOFile ticket_file(ticket_path, "wb"); + if (!ticket_file || !ticket_file.WriteBytes(new_ticket.data(), new_ticket.size())) + return GetDefaultReply(ES_EIO); + } + + // Delete the ticket file if it is now empty. + if (new_ticket.empty()) + File::Delete(ticket_path); + + // Delete the ticket directory if it is now empty. + const std::string ticket_parent_dir = + Common::RootUserPath(Common::FROM_CONFIGURED_ROOT) + + StringFromFormat("/ticket/%08x", static_cast<u32>(title_id >> 32)); + const auto ticket_parent_dir_entries = File::ScanDirectoryTree(ticket_parent_dir, false); + if (ticket_parent_dir_entries.children.empty()) + File::DeleteDir(ticket_parent_dir); + return GetDefaultReply(IPC_SUCCESS); } |
