summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am19
-rw-r--r--src/ace3.c277
-rw-r--r--src/ace3.h17
-rw-r--r--src/asr.c200
-rw-r--r--src/asr.h15
-rw-r--r--src/common.c537
-rw-r--r--src/common.h73
-rw-r--r--src/dfu.c242
-rw-r--r--src/dfu.h11
-rw-r--r--src/download.c47
-rw-r--r--src/download.h2
-rw-r--r--src/fdr.c132
-rw-r--r--src/fixedint.h72
-rw-r--r--src/fls.c30
-rw-r--r--src/fls.h8
-rw-r--r--src/ftab.c18
-rw-r--r--src/ftab.h8
-rw-r--r--src/idevicerestore.c1540
-rw-r--r--src/idevicerestore.h25
-rw-r--r--src/img3.c80
-rw-r--r--src/img3.h16
-rw-r--r--src/img4.c372
-rw-r--r--src/img4.h2
-rw-r--r--src/ipsw.c786
-rw-r--r--src/ipsw.h47
-rw-r--r--src/jsmn.c280
-rw-r--r--src/jsmn.h91
-rw-r--r--src/json_plist.c229
-rw-r--r--src/limera1n.c22
-rw-r--r--src/locking.c12
-rw-r--r--src/log.c227
-rw-r--r--src/log.h (renamed from src/json_plist.h)35
-rw-r--r--src/mbn.c489
-rw-r--r--src/mbn.h85
-rw-r--r--src/normal.c195
-rw-r--r--src/normal.h6
-rw-r--r--src/recovery.c166
-rw-r--r--src/recovery.h5
-rw-r--r--src/restore.c3276
-rw-r--r--src/restore.h20
-rw-r--r--src/sha1.c294
-rw-r--r--src/sha1.h44
-rw-r--r--src/sha512.c314
-rw-r--r--src/sha512.h32
-rw-r--r--src/tss.c2113
-rw-r--r--src/tss.h73
46 files changed, 6338 insertions, 6246 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 4a99dec..2b7084e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -3,22 +3,24 @@ AM_CFLAGS = \
$(LFS_CFLAGS) \
$(libirecovery_CFLAGS) \
$(libimobiledevice_CFLAGS) \
+ $(libusbmuxd_CFLAGS) \
$(libplist_CFLAGS) \
$(limd_glue_CFLAGS) \
+ $(libtatsu_CFLAGS) \
$(libzip_CFLAGS) \
$(zlib_CFLAGS) \
- $(openssl_CFLAGS) \
$(libcurl_CFLAGS)
AM_LDFLAGS = \
$(AC_LDFLAGS) \
$(libirecovery_LIBS) \
$(libimobiledevice_LIBS) \
+ $(libusbmuxd_LIBS) \
$(libplist_LIBS) \
$(limd_glue_LIBS) \
+ $(libtatsu_LIBS) \
$(libzip_LIBS) \
$(zlib_LIBS) \
- $(openssl_LIBS) \
$(libcurl_LIBS)
AM_LDADD = $(AC_LDADD)
@@ -27,9 +29,9 @@ bin_PROGRAMS = idevicerestore
idevicerestore_SOURCES = \
idevicerestore.c idevicerestore.h \
+ log.c log.h \
endianness.h \
common.c common.h \
- tss.c tss.h \
fls.c fls.h \
mbn.c mbn.h \
img3.c img3.h \
@@ -42,14 +44,11 @@ idevicerestore_SOURCES = \
restore.c restore.h \
asr.c asr.h \
fdr.c fdr.h \
- limera1n_payload.h \
- limera1n.c limera1n.h \
+ ace3.c ace3.h \
download.c download.h \
- locking.c locking.h \
- jsmn.c jsmn.h \
- json_plist.c json_plist.h
-if USE_INTERNAL_SHA
-idevicerestore_SOURCES += sha1.c sha1.h sha512.c sha512.h fixedint.h
+ locking.c locking.h
+if HAVE_LIMERA1N
+idevicerestore_SOURCES += limera1n_payload.h limera1n.c limera1n.h
endif
idevicerestore_CFLAGS = $(AM_CFLAGS)
idevicerestore_LDFLAGS = $(AM_LDFLAGS)
diff --git a/src/ace3.c b/src/ace3.c
new file mode 100644
index 0000000..d51613d
--- /dev/null
+++ b/src/ace3.c
@@ -0,0 +1,277 @@
+/*
+ * ace3.c
+ * Functions to handle Ace3/uarp firmware format
+ *
+ * Copyright (c) 2024 Nikias Bassen, All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <libimobiledevice-glue/nskeyedarchive.h>
+
+#include "common.h"
+#include "ace3.h"
+#include "endianness.h"
+
+static uint32_t crc_buffer(const unsigned char* buffer, unsigned int bufsize, unsigned int salt)
+{
+ uint32_t result;
+ unsigned int i;
+ unsigned int j;
+
+ if ( !buffer )
+ return 0xFFFFFFFF;
+ result = salt;
+ for (i = 0; i < bufsize; ++i) {
+ for (j = 0; j != 8; ++j) {
+ unsigned int tmp0 = 2 * result;
+ unsigned int tmp1 = *(unsigned char*)(buffer + i);
+ unsigned int tmp2 = ((unsigned int)result >> 31) ^ ((tmp1 >> j) & 1);
+ result = (tmp2 + 2 * result) ^ 0x4C11DB6;
+ if (!tmp2)
+ result = tmp0;
+ }
+ }
+ return result;
+}
+
+static int uarp_version_convert(uint32_t* version_data, uint32_t* version_out)
+{
+ if (version_out) *version_out = 0;
+ if (!version_data) {
+ return -1;
+ }
+ uint32_t part1 = (version_data[0] < 0xE00) ? version_data[0] : version_data[0] - 0xE00;
+ if (part1 > 0x63) {
+ return 0;
+ }
+ uint32_t part2 = (version_data[0] < 0xE00) ? 0 : 0xE00;
+ uint32_t part3 = version_data[1];
+ if (part3 > 0x3E7) {
+ return 0;
+ }
+ uint32_t part4 = version_data[2];
+ if (part4 > 0x63) {
+ return 0;
+ }
+ if (version_out) {
+ *version_out = (((((0x147B * (unsigned int)((uint16_t)part3 >> 2)) >> 9) & 0x3FF00) | (0x10 * (((uint8_t)((uint16_t)part3 / 0xA) % 0xA) & 0xF)) | ((uint16_t)part3 % 0xA)) << 8)
+ | ((((uint8_t)part1 % 0xA) | (0x10 * ((uint8_t)part1 / 0xA)) | part2) << 20)
+ | ((uint8_t)part4 % 0xA)
+ | (((0xCD * (unsigned int)(uint8_t)part4) >> 7) & 0xF0);
+ }
+ return 0;
+}
+
+int ace3_create_binary(const void* uarp_fw, size_t uarp_size, uint64_t bdid, unsigned int prev, plist_t tss, void** bin_out, size_t* bin_size)
+{
+ struct ace3bin_header {
+ uint32_t magic; // 0xACE00003
+ uint32_t version; // ace3 version, e.g. 0x00203400
+ uint32_t unk8; // 0x00002800
+ uint32_t header_size; // 0x00000040
+ uint32_t data1_size;
+ uint32_t data2_size;
+ uint32_t im4m_offset;
+ uint32_t im4m_dl_size;
+ uint32_t content_size;
+ uint32_t crc;
+ uint64_t fill1; // 0xFFFFFFFFFFFFFFFF
+ uint64_t fill2; // 0xFFFFFFFFFFFFFFFF
+ uint64_t fill3; // 0xFFFFFFFFFFFFFFFF
+ };
+
+ struct uarp_header {
+ uint32_t unk_00; // BE 0x00000002
+ uint32_t header_size; // BE usually 0x0000002C
+ uint32_t plist_offset; // BE
+ uint32_t unk_0c; // 0
+ uint32_t unk_10; // 0
+ uint32_t unk_14; // 0
+ uint32_t unk_18; // 0
+ uint32_t c_offset; // BE
+ uint32_t unk_20; // 0
+ uint32_t toc_offset; // BE usually 0x0000002c
+ uint32_t toc_size; // BE
+ };
+ struct uarp_toc_entry {
+ uint32_t this_size; // BE usually 0x28
+ uint32_t fourcc; // 'PT01' or similar
+ uint32_t version[4]; // BE values
+ uint32_t unk_18; // BE other offset, not sure
+ uint32_t unk_1c; // BE usually 0
+ uint32_t offset; // BE
+ uint32_t size; //
+ };
+
+ plist_t p_im4m = plist_dict_get_item(tss, "USBPortController1,Ticket");
+ uint64_t im4m_size = 0;
+ const char* im4m = plist_get_data_ptr(p_im4m, &im4m_size);
+
+ struct uarp_header* uarp_hdr = (struct uarp_header*)uarp_fw;
+ uint32_t uarp_hdr_size = be32toh(uarp_hdr->header_size);
+ uint32_t plist_offset = be32toh(uarp_hdr->plist_offset);
+ uint32_t plist_size = uarp_size - plist_offset;
+ nskeyedarchive_t ka = nskeyedarchive_new_from_data(uarp_fw + plist_offset, plist_size);
+ if (!ka) {
+ return -1;
+ }
+ plist_t uarp_dict = nskeyedarchive_to_plist(ka);
+ nskeyedarchive_free(ka);
+
+ // find the corresponding entries for given BoardID+PREV
+
+ char* payload_4cc = NULL;
+ char* data_payload_4ccs = NULL;
+
+ plist_t sb_payloads = plist_dict_get_item(uarp_dict, "SuperBinary Payloads");
+ if (PLIST_IS_ARRAY(sb_payloads)) {
+ plist_array_iter iter = NULL;
+ plist_array_new_iter(sb_payloads, &iter);
+ plist_t payload = NULL;
+ do {
+ plist_array_next_item(sb_payloads, iter, &payload);
+ if (!payload) {
+ break;
+ }
+ plist_t meta = plist_dict_get_item(payload, "Payload MetaData");
+ if (!PLIST_IS_DICT(meta)) {
+ continue;
+ }
+ plist_t prefix = plist_dict_get_item(meta, "Personalization Manifest Prefix");
+ if (!PLIST_IS_STRING(prefix)) {
+ continue;
+ }
+ if (strcmp(plist_get_string_ptr(prefix, NULL), "USBPortController") != 0) {
+ continue;
+ }
+ plist_t p_boardid = plist_dict_get_item(meta, "Personalization Board ID (64 bits)");
+ if (!PLIST_IS_INT(p_boardid)) {
+ continue;
+ }
+ uint64_t boardid = 0;
+ plist_get_uint_val(p_boardid, &boardid);
+ if (boardid == bdid) {
+ logger(LL_DEBUG, "%s: Found Board ID 0x%" PRIx64 "\n", __func__, bdid);
+ plist_t p4cc = plist_dict_get_item(payload, "Payload 4CC");
+ plist_get_string_val(p4cc, &payload_4cc);
+ plist_t matching = plist_dict_get_item(meta, "Personalization Matching Data");
+ if (PLIST_IS_ARRAY(matching)) {
+ plist_array_iter iter2 = NULL;
+ plist_array_new_iter(matching, &iter2);
+ plist_t match = NULL;
+ do {
+ plist_array_next_item(matching, iter2, &match);
+ if (!PLIST_IS_DICT(match)) {
+ break;
+ }
+ uint64_t minrev = 0;
+ plist_t p_min = plist_dict_get_item(match, "Personalization Matching Data Product Revision Minimum");
+ plist_get_uint_val(p_min, &minrev);
+ uint64_t maxrev = 0;
+ plist_t p_max = plist_dict_get_item(match, "Personalization Matching Data Product Revision Maximum");
+ plist_get_uint_val(p_max, &maxrev);
+ if (prev >= minrev && prev <= maxrev) {
+ plist_t tags = plist_dict_get_item(match, "Personalization Matching Data Payload Tags");
+ plist_get_string_val(tags, &data_payload_4ccs);
+ logger(LL_DEBUG, "%s: Found matching tags %s\n", __func__, data_payload_4ccs);
+ break;
+ }
+ } while (match);
+ plist_mem_free(iter2);
+ }
+ break;
+ }
+ } while (payload);
+ plist_mem_free(iter);
+ }
+ if (!payload_4cc) {
+ logger(LL_ERROR, "Failed to get payload 4cc\n");
+ return -1;
+ }
+ if (!data_payload_4ccs) {
+ logger(LL_ERROR, "Failed to get data payload 4ccs\n");
+ return -1;
+ }
+
+ // now find the blobs in UARP data
+ uint32_t dl_offset = 0;
+ uint32_t dl_size = 0;
+ uint32_t data1_offset = 0;
+ uint32_t data1_size = 0;
+ uint32_t data1_version = 0;
+ uint32_t data2_offset = 0;
+ uint32_t data2_size = 0;
+ uint32_t toc_size = be32toh(uarp_hdr->toc_size);
+ const unsigned char* p = uarp_fw + uarp_hdr_size;
+ while (p < (const unsigned char*)uarp_fw + toc_size) {
+ struct uarp_toc_entry* entry = (struct uarp_toc_entry*)p;
+ uint32_t te_size = be32toh(entry->this_size);
+ if (strncmp((char*)&(entry->fourcc), payload_4cc, 4) == 0) {
+ dl_offset = be32toh(entry->offset);
+ dl_size = be32toh(entry->size);
+ } else if (strncmp((char*)&(entry->fourcc), data_payload_4ccs, 4) == 0) {
+ uint32_t version_data[4];
+ version_data[0] = be32toh(entry->version[0]);
+ version_data[1] = be32toh(entry->version[1]);
+ version_data[2] = be32toh(entry->version[2]);
+ version_data[3] = be32toh(entry->version[3]);
+ data1_offset = be32toh(entry->offset);
+ data1_size = be32toh(entry->size);
+ uarp_version_convert(version_data, &data1_version);
+ } else if (strncmp((char*)&(entry->fourcc), data_payload_4ccs+5, 4) == 0) {
+ data2_offset = be32toh(entry->offset);
+ data2_size = be32toh(entry->size);
+ }
+ p += te_size;
+ }
+
+ uint32_t content_size = data1_size + data2_size + im4m_size + dl_size;
+
+ *bin_out = malloc(0x40 + content_size);
+ struct ace3bin_header* hdr = (struct ace3bin_header*)(*bin_out);
+ hdr->magic = htole32(0xACE00003);
+ hdr->version = htole32(data1_version);
+ hdr->unk8 = htole32(0x00002800);
+ hdr->header_size = htole32(0x40);
+ hdr->data1_size = htole32(data1_size);
+ hdr->data2_size = htole32(data2_size);;
+ hdr->im4m_offset = htole32(0x40 + data1_size + data2_size);
+ hdr->im4m_dl_size = htole32(im4m_size + dl_size);
+ hdr->content_size = htole32(content_size);
+ hdr->crc = 0;
+ hdr->fill1 = 0xFFFFFFFFFFFFFFFFLL;
+ hdr->fill2 = 0xFFFFFFFFFFFFFFFFLL;
+ hdr->fill3 = 0xFFFFFFFFFFFFFFFFLL;
+
+ // write data1 payload
+ memcpy(*bin_out + 0x40, uarp_fw + data1_offset, data1_size);
+ // write data2 payload
+ memcpy(*bin_out + 0x40 + data1_size, uarp_fw + data2_offset, data2_size);
+ // write IM4M
+ memcpy(*bin_out + 0x40 + data1_size + data2_size, im4m, im4m_size);
+ // write dl payload
+ memcpy(*bin_out + 0x40 + data1_size + data2_size + im4m_size, uarp_fw + dl_offset, dl_size);
+
+ // calculate CRC and update header
+ hdr->crc = htole32(crc_buffer(*bin_out + 0x40, content_size, 0xFFFFFFFF));
+
+ *bin_size = 0x40 + content_size;
+
+ return 0;
+}
diff --git a/src/ace3.h b/src/ace3.h
new file mode 100644
index 0000000..6c93e1e
--- /dev/null
+++ b/src/ace3.h
@@ -0,0 +1,17 @@
+#ifndef IDEVICERESTORE_ACE3_H
+#define IDEVICERESTORE_ACE3_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <plist/plist.h>
+
+int ace3_create_binary(const void* uarp_fw, size_t uarp_size, uint64_t bdid, unsigned int prev, plist_t tss, void** bin_out, size_t* bin_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/asr.c b/src/asr.c
index a1aba76..e140980 100644
--- a/src/asr.c
+++ b/src/asr.c
@@ -30,23 +30,16 @@
#include <unistd.h>
#include <errno.h>
#include <libimobiledevice/libimobiledevice.h>
-#ifdef HAVE_OPENSSL
-#include <openssl/sha.h>
-#else
-#include "sha1.h"
-#define SHA_CTX SHA1_CTX
-#define SHA1_Init SHA1Init
-#define SHA1_Update SHA1Update
-#define SHA1_Final SHA1Final
-#endif
+
+#include <libimobiledevice-glue/sha.h>
#include "asr.h"
#include "idevicerestore.h"
#include "common.h"
+#include "ipsw.h"
#define ASR_VERSION 1
#define ASR_STREAM_ID 1
-#define ASR_PORT 12345
#define ASR_BUFFER_SIZE 65536
#define ASR_FEC_SLICE_STRIDE 40
#define ASR_PACKETS_PER_FEC 25
@@ -54,7 +47,7 @@
#define ASR_PAYLOAD_CHUNK_SIZE 131072
#define ASR_CHECKSUM_CHUNK_SIZE 131072
-int asr_open_with_timeout(idevice_t device, asr_client_t* asr)
+int asr_open_with_timeout(idevice_t device, asr_client_t* asr, uint16_t port)
{
int i = 0;
int attempts = 10;
@@ -67,20 +60,24 @@ int asr_open_with_timeout(idevice_t device, asr_client_t* asr)
return -1;
}
- debug("Connecting to ASR\n");
+ if (port == 0) {
+ port = ASR_DEFAULT_PORT;
+ }
+ logger(LL_VERBOSE, "Connecting to ASR on port %u\n", port);
+
for (i = 1; i <= attempts; i++) {
- device_error = idevice_connect(device, ASR_PORT, &connection);
+ device_error = idevice_connect(device, port, &connection);
if (device_error == IDEVICE_E_SUCCESS) {
break;
}
if (i >= attempts) {
- error("ERROR: Unable to connect to ASR client\n");
+ logger(LL_ERROR, "Unable to connect to ASR client\n");
return -1;
}
sleep(2);
- debug("Retrying connection...\n");
+ logger(LL_VERBOSE, "Retrying connection...\n");
}
asr_client_t asr_loc = (asr_client_t)malloc(sizeof(struct asr_client));
@@ -91,7 +88,7 @@ int asr_open_with_timeout(idevice_t device, asr_client_t* asr)
plist_t data = NULL;
asr_loc->checksum_chunks = 0;
if (asr_receive(asr_loc, &data) < 0) {
- error("ERROR: Unable to receive data from ASR\n");
+ logger(LL_ERROR, "Unable to receive data from ASR\n");
asr_free(asr_loc);
plist_free(data);
return -1;
@@ -102,8 +99,8 @@ int asr_open_with_timeout(idevice_t device, asr_client_t* asr)
char* strval = NULL;
plist_get_string_val(node, &strval);
if (strval && (strcmp(strval, "Initiate") != 0)) {
- error("ERROR: unexpected ASR plist received:\n");
- debug_plist(data);
+ logger(LL_ERROR, "Unexpected ASR plist received\n");
+ logger_dump_plist(LL_VERBOSE, data, 1);
plist_free(data);
asr_free(asr_loc);
return -1;
@@ -141,13 +138,13 @@ int asr_receive(asr_client_t asr, plist_t* data)
buffer = (char*)malloc(ASR_BUFFER_SIZE);
if (buffer == NULL) {
- error("ERROR: Unable to allocate memory for ASR receive buffer\n");
+ logger(LL_ERROR, "Unable to allocate memory for ASR receive buffer\n");
return -1;
}
device_error = idevice_connection_receive(asr->connection, buffer, ASR_BUFFER_SIZE, &size);
if (device_error != IDEVICE_E_SUCCESS) {
- error("ERROR: Unable to receive data from ASR\n");
+ logger(LL_ERROR, "Unable to receive data from ASR\n");
free(buffer);
return -1;
}
@@ -155,9 +152,8 @@ int asr_receive(asr_client_t asr, plist_t* data)
*data = request;
- debug("Received %d bytes:\n", size);
- if (idevicerestore_debug)
- debug_plist(request);
+ logger(LL_DEBUG, "Received %d bytes:\n", size);
+ logger_dump_plist(LL_DEBUG, request, 1);
free(buffer);
return 0;
}
@@ -169,7 +165,7 @@ int asr_send(asr_client_t asr, plist_t data)
plist_to_xml(data, &buffer, &size);
if (asr_send_buffer(asr, buffer, size) < 0) {
- error("ERROR: Unable to send plist to ASR\n");
+ logger(LL_ERROR, "Unable to send plist to ASR\n");
free(buffer);
return -1;
}
@@ -179,14 +175,14 @@ int asr_send(asr_client_t asr, plist_t data)
return 0;
}
-int asr_send_buffer(asr_client_t asr, const char* data, uint32_t size)
+int asr_send_buffer(asr_client_t asr, const void* data, size_t size)
{
uint32_t bytes = 0;
idevice_error_t device_error = IDEVICE_E_SUCCESS;
device_error = idevice_connection_send(asr->connection, data, size, &bytes);
if (device_error != IDEVICE_E_SUCCESS || bytes != size) {
- error("ERROR: Unable to send data to ASR. Sent %u of %u bytes.\n", bytes, size);
+ logger(LL_ERROR, "Unable to send data to ASR. Sent %u of %zu bytes.\n", bytes, size);
return -1;
}
@@ -205,37 +201,13 @@ void asr_free(asr_client_t asr)
}
}
-int asr_perform_validation(asr_client_t asr, const char* filesystem)
+int asr_send_validation_packet_info(asr_client_t asr, uint64_t ipsw_size)
{
- FILE* file = NULL;
- uint64_t length = 0;
- char* command = NULL;
- plist_t node = NULL;
- plist_t packet = NULL;
- plist_t packet_info = NULL;
- plist_t payload_info = NULL;
- int attempts = 0;
-
- file = fopen(filesystem, "rb");
- if (file == NULL) {
- return -1;
- }
-
-#ifdef WIN32
- length = _lseeki64(fileno(file), 0, SEEK_END);
- _lseeki64(fileno(file), 0, SEEK_SET);
- rewind(file);
-#else
- fseeko(file, 0, SEEK_END);
- length = ftello(file);
- fseeko(file, 0, SEEK_SET);
-#endif
-
- payload_info = plist_new_dict();
+ plist_t payload_info = plist_new_dict();
plist_dict_set_item(payload_info, "Port", plist_new_uint(1));
- plist_dict_set_item(payload_info, "Size", plist_new_uint(length));
+ plist_dict_set_item(payload_info, "Size", plist_new_uint(ipsw_size));
- packet_info = plist_new_dict();
+ plist_t packet_info = plist_new_dict();
if (asr->checksum_chunks) {
plist_dict_set_item(packet_info, "Checksum Chunk Size", plist_new_uint(ASR_CHECKSUM_CHUNK_SIZE));
}
@@ -247,21 +219,39 @@ int asr_perform_validation(asr_client_t asr, const char* filesystem)
plist_dict_set_item(packet_info, "Version", plist_new_uint(ASR_VERSION));
if (asr_send(asr, packet_info)) {
- error("ERROR: Unable to sent packet information to ASR\n");
plist_free(packet_info);
return -1;
}
plist_free(packet_info);
+ return 0;
+}
+
+int asr_perform_validation(asr_client_t asr, ipsw_file_handle_t file)
+{
+ uint64_t length = 0;
+ char* command = NULL;
+ plist_t node = NULL;
+ plist_t packet = NULL;
+ int attempts = 0;
+
+ length = ipsw_file_size(file);
+
+ // Expected by device after every initiate
+ if (asr_send_validation_packet_info(asr, length) < 0) {
+ logger(LL_ERROR, "Unable to send validation packet info to ASR\n");
+ return -1;
+ }
+
while (1) {
if (asr_receive(asr, &packet) < 0) {
- error("ERROR: Unable to receive validation packet\n");
+ logger(LL_ERROR, "Unable to receive validation packet\n");
return -1;
}
if (packet == NULL) {
if (attempts < 5) {
- info("Retrying to receive validation packet... %d\n", attempts);
+ logger(LL_INFO, "Retrying to receive validation packet... %d\n", attempts);
attempts++;
sleep(1);
continue;
@@ -272,11 +262,30 @@ int asr_perform_validation(asr_client_t asr, const char* filesystem)
node = plist_dict_get_item(packet, "Command");
if (!node || plist_get_node_type(node) != PLIST_STRING) {
- error("ERROR: Unable to find command node in validation request\n");
+ logger(LL_ERROR, "Unable to find command node in validation request\n");
return -1;
}
plist_get_string_val(node, &command);
+ // Added for iBridgeOS 9.0 - second initiate request to change to checksum chunks
+ if (!strcmp(command, "Initiate")) {
+ // This might switch on the second Initiate
+ node = plist_dict_get_item(packet, "Checksum Chunks");
+ if (node && (plist_get_node_type(node) == PLIST_BOOLEAN)) {
+ plist_get_bool_val(node, &(asr->checksum_chunks));
+ }
+ plist_free(packet);
+
+ // Expected by device after every Initiate
+ if (asr_send_validation_packet_info(asr, length) < 0) {
+ logger(LL_ERROR, "Unable to send validation packet info to ASR\n");
+ return -1;
+ }
+
+ // A OOBData request should follow
+ continue;
+ }
+
if (!strcmp(command, "OOBData")) {
int ret = asr_handle_oob_data_request(asr, packet, file);
plist_free(packet);
@@ -287,7 +296,7 @@ int asr_perform_validation(asr_client_t asr, const char* filesystem)
break;
} else {
- error("ERROR: Unknown command received from ASR\n");
+ logger(LL_ERROR, "Unknown command received from ASR\n");
plist_free(packet);
return -1;
}
@@ -296,7 +305,7 @@ int asr_perform_validation(asr_client_t asr, const char* filesystem)
return 0;
}
-int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, FILE* file)
+int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, ipsw_file_handle_t file)
{
char* oob_data = NULL;
uint64_t oob_offset = 0;
@@ -306,38 +315,38 @@ int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, FILE* file)
oob_length_node = plist_dict_get_item(packet, "OOB Length");
if (!oob_length_node || PLIST_UINT != plist_get_node_type(oob_length_node)) {
- error("ERROR: Unable to find OOB data length\n");
+ logger(LL_ERROR, "Unable to find OOB data length\n");
return -1;
}
plist_get_uint_val(oob_length_node, &oob_length);
oob_offset_node = plist_dict_get_item(packet, "OOB Offset");
if (!oob_offset_node || PLIST_UINT != plist_get_node_type(oob_offset_node)) {
- error("ERROR: Unable to find OOB data offset\n");
+ logger(LL_ERROR, "Unable to find OOB data offset\n");
return -1;
}
plist_get_uint_val(oob_offset_node, &oob_offset);
oob_data = (char*) malloc(oob_length);
if (oob_data == NULL) {
- error("ERROR: Out of memory\n");
+ logger(LL_ERROR, "Out of memory\n");
return -1;
}
-#ifdef WIN32
- rewind(file);
- _lseeki64(fileno(file), oob_offset, SEEK_SET);
-#else
- fseeko(file, oob_offset, SEEK_SET);
-#endif
- if (fread(oob_data, 1, oob_length, file) != oob_length) {
- error("ERROR: Unable to read OOB data from filesystem offset: %s\n", strerror(errno));
+ if (ipsw_file_seek(file, oob_offset, SEEK_SET) < 0) {
+ logger(LL_ERROR, "Unable to seek to OOB offset 0x%" PRIx64 "\n", oob_offset);
+ free(oob_data);
+ return -1;
+ }
+ int64_t ir = ipsw_file_read(file, oob_data, oob_length);
+ if (ir != oob_length) {
+ logger(LL_ERROR, "Unable to read OOB data from filesystem offset 0x%" PRIx64 ", oob_length %" PRIu64 ", read returned %" PRIi64"\n", oob_offset, oob_length, ir);
free(oob_data);
return -1;
}
if (asr_send_buffer(asr, oob_data, oob_length) < 0) {
- error("ERROR: Unable to send OOB data to ASR\n");
+ logger(LL_ERROR, "Unable to send OOB data to ASR\n");
free(oob_data);
return -1;
}
@@ -345,58 +354,40 @@ int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, FILE* file)
return 0;
}
-int asr_send_payload(asr_client_t asr, const char* filesystem)
+int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file)
{
char *data = NULL;
- FILE* file = NULL;
uint64_t i, length, bytes = 0;
double progress = 0;
- file = fopen(filesystem, "rb");
- if (file == NULL) {
- error("ERROR: Unable to open filesystem image %s: %s\n", filesystem, strerror(errno));
- return -1;
- }
-
-#ifdef WIN32
- length = _lseeki64(fileno(file), 0, SEEK_END);
- _lseeki64(fileno(file), 0, SEEK_SET);
- rewind(file);
-#else
- fseeko(file, 0, SEEK_END);
- length = ftello(file);
- fseeko(file, 0, SEEK_SET);
-#endif
+ length = ipsw_file_size(file);
+ ipsw_file_seek(file, 0, SEEK_SET);
data = (char*)malloc(ASR_PAYLOAD_CHUNK_SIZE + 20);
- SHA_CTX sha1;
-
- if (asr->checksum_chunks) {
- SHA1_Init(&sha1);
- }
-
- int size = 0;
i = length;
int retry = 3;
while(i > 0 && retry >= 0) {
- size = ASR_PAYLOAD_CHUNK_SIZE;
+ uint32_t size = ASR_PAYLOAD_CHUNK_SIZE;
+ uint32_t sendsize = 0;
+
if (i < ASR_PAYLOAD_CHUNK_SIZE) {
size = i;
}
- if (fread(data, 1, size, file) != (size_t)size) {
- error("Error reading filesystem\n");
+ if (ipsw_file_read(file, data, size) != (int64_t)size) {
+ logger(LL_ERROR, "Error reading filesystem\n");
retry--;
continue;
}
+ sendsize = size;
if (asr->checksum_chunks) {
- SHA1((unsigned char*)data, size, (unsigned char*)(data+size));
+ sha1((unsigned char*)data, size, (unsigned char*)(data+size));
+ sendsize += 20;
}
-
- if (asr_send_buffer(asr, data, size+20) < 0) {
- error("ERROR: Unable to send filesystem payload\n");
+ if (asr_send_buffer(asr, data, sendsize) < 0) {
+ logger(LL_ERROR, "Unable to send filesystem payload chunk, retrying...\n");
retry--;
continue;
}
@@ -412,6 +403,5 @@ int asr_send_payload(asr_client_t asr, const char* filesystem)
}
free(data);
- fclose(file);
- return 0;
+ return (i == 0) ? 0 : -1;
}
diff --git a/src/asr.h b/src/asr.h
index b3336a5..52e8d75 100644
--- a/src/asr.h
+++ b/src/asr.h
@@ -30,6 +30,8 @@ extern "C" {
#include <libimobiledevice/libimobiledevice.h>
+#define ASR_DEFAULT_PORT 12345
+
typedef void (*asr_progress_cb_t)(double, void*);
struct asr_client {
@@ -41,15 +43,18 @@ struct asr_client {
};
typedef struct asr_client *asr_client_t;
-int asr_open_with_timeout(idevice_t device, asr_client_t* asr);
+struct ipsw_file_handle;
+typedef struct ipsw_file_handle* ipsw_file_handle_t;
+
+int asr_open_with_timeout(idevice_t device, asr_client_t* asr, uint16_t port);
void asr_set_progress_callback(asr_client_t asr, asr_progress_cb_t, void* userdata);
int asr_send(asr_client_t asr, plist_t data);
int asr_receive(asr_client_t asr, plist_t* data);
-int asr_send_buffer(asr_client_t asr, const char* data, uint32_t size);
+int asr_send_buffer(asr_client_t asr, const void* data, size_t size);
void asr_free(asr_client_t asr);
-int asr_perform_validation(asr_client_t asr, const char* filesystem);
-int asr_send_payload(asr_client_t asr, const char* filesystem);
-int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, FILE* file);
+int asr_perform_validation(asr_client_t asr, ipsw_file_handle_t file);
+int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file);
+int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, ipsw_file_handle_t file);
#ifdef __cplusplus
diff --git a/src/common.c b/src/common.c
index 4dbabc0..70f0742 100644
--- a/src/common.c
+++ b/src/common.c
@@ -35,6 +35,8 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>
+#include <libimobiledevice-glue/thread.h>
+#include <libimobiledevice-glue/collection.h>
#ifdef WIN32
#include <windows.h>
@@ -56,6 +58,13 @@
#define MAX_PRINT_LEN 64*1024
+int global_quit_flag = 0;
+static const char* STARS = "******************************************************************************";
+static const char* SPACES = " ";
+static const char* POUNDS = "##############################################################################";
+
+static uint32_t progress_unique_tag = 1;
+
struct idevicerestore_mode_t idevicerestore_modes[] = {
{ 0, "Unknown" },
{ 1, "WTF" },
@@ -63,106 +72,22 @@ struct idevicerestore_mode_t idevicerestore_modes[] = {
{ 3, "Recovery" },
{ 4, "Restore" },
{ 5, "Normal" },
+ { 6, "Port DFU" },
};
int idevicerestore_debug = 0;
-#define idevicerestore_err_buff_size 256
-static char idevicerestore_err_buff[idevicerestore_err_buff_size] = {0, };
-
-static FILE* info_stream = NULL;
-static FILE* error_stream = NULL;
-static FILE* debug_stream = NULL;
-
-static int info_disabled = 0;
-static int error_disabled = 0;
-static int debug_disabled = 0;
-
-void info(const char* format, ...)
-{
- if (info_disabled) return;
- va_list vargs;
- va_start(vargs, format);
- vfprintf((info_stream) ? info_stream : stdout, format, vargs);
- va_end(vargs);
-}
-
-void error(const char* format, ...)
-{
- va_list vargs, vargs2;
- va_start(vargs, format);
- va_copy(vargs2, vargs);
- vsnprintf(idevicerestore_err_buff, idevicerestore_err_buff_size, format, vargs);
- va_end(vargs);
- if (!error_disabled) {
- vfprintf((error_stream) ? error_stream : stderr, format, vargs2);
- }
- va_end(vargs2);
-}
-
-void debug(const char* format, ...)
-{
- if (debug_disabled) return;
- if (!idevicerestore_debug) {
- return;
- }
- va_list vargs;
- va_start(vargs, format);
- vfprintf((debug_stream) ? debug_stream : stderr, format, vargs);
- va_end(vargs);
-}
-
-void idevicerestore_set_info_stream(FILE* strm)
-{
- if (strm) {
- info_disabled = 0;
- info_stream = strm;
- } else {
- info_disabled = 1;
- }
-}
-
-void idevicerestore_set_error_stream(FILE* strm)
-{
- if (strm) {
- error_disabled = 0;
- error_stream = strm;
- } else {
- error_disabled = 1;
- }
-}
-
-void idevicerestore_set_debug_stream(FILE* strm)
-{
- if (strm) {
- debug_disabled = 0;
- debug_stream = strm;
- } else {
- debug_disabled = 1;
- }
-}
-
-const char* idevicerestore_get_error(void)
-{
- if (idevicerestore_err_buff[0] == 0) {
- return NULL;
- } else {
- char* p = NULL;
- while ((strlen(idevicerestore_err_buff) > 0) && (p = strrchr(idevicerestore_err_buff, '\n'))) {
- p[0] = '\0';
- }
- return (const char*)idevicerestore_err_buff;
- }
-}
+static void (*banner_func)(const char*) = NULL;
+static void (*banner_hide_func)(void) = NULL;
int write_file(const char* filename, const void* data, size_t size) {
size_t bytes = 0;
FILE* file = NULL;
- debug("Writing data to %s\n", filename);
+ logger(LL_DEBUG, "Writing data to %s\n", filename);
file = fopen(filename, "wb");
if (file == NULL) {
- error("write_file: Unable to open file %s\n", filename);
+ logger(LL_ERROR, "write_file: Unable to open file %s\n", filename);
return -1;
}
@@ -170,7 +95,7 @@ int write_file(const char* filename, const void* data, size_t size) {
fclose(file);
if (bytes != size) {
- error("ERROR: Unable to write entire file: %s: %d of %d\n", filename, (int)bytes, (int)size);
+ logger(LL_ERROR, "Unable to write entire file: %s: %d of %d\n", filename, (int)bytes, (int)size);
return -1;
}
@@ -184,26 +109,26 @@ int read_file(const char* filename, void** data, size_t* size) {
char* buffer = NULL;
struct stat fst;
- debug("Reading data from %s\n", filename);
+ logger(LL_DEBUG, "Reading data from %s\n", filename);
*size = 0;
*data = NULL;
file = fopen(filename, "rb");
if (file == NULL) {
- error("read_file: cannot open %s: %s\n", filename, strerror(errno));
+ logger(LL_ERROR, "read_file: cannot open %s: %s\n", filename, strerror(errno));
return -1;
}
if (fstat(fileno(file), &fst) < 0) {
- error("read_file: fstat: %s\n", strerror(errno));
+ logger(LL_ERROR, "read_file: fstat: %s\n", strerror(errno));
return -1;
}
length = fst.st_size;
buffer = (char*) malloc(length);
if (buffer == NULL) {
- error("ERROR: Out of memory\n");
+ logger(LL_ERROR, "Out of memory\n");
fclose(file);
return -1;
}
@@ -211,7 +136,7 @@ int read_file(const char* filename, void** data, size_t* size) {
fclose(file);
if (bytes != length) {
- error("ERROR: Unable to read entire file\n");
+ logger(LL_ERROR, "Unable to read entire file\n");
free(buffer);
return -1;
}
@@ -221,32 +146,308 @@ int read_file(const char* filename, void** data, size_t* size) {
return 0;
}
-void debug_plist(plist_t plist) {
- uint32_t size = 0;
- char* data = NULL;
- plist_to_xml(plist, &data, &size);
- if (size <= MAX_PRINT_LEN)
- info("%s:printing %i bytes plist:\n%s", __FILE__, size, data);
- else
- info("%s:supressed printing %i bytes plist...\n", __FILE__, size);
- free(data);
+int process_text_lines(const char* text, int maxwidth, struct tuple** lines_out, int* maxlen_out)
+{
+ if (!text) return 0;
+ int len = strlen(text);
+ int numlines = 0;
+ int maxlen = 0;
+ int linestart = 0;
+ int linelen = 0;
+ int lastspace = 0;
+ int maxlines = 8;
+ int count = 0;
+ struct tuple* lines = (struct tuple*)malloc(sizeof(struct tuple) * maxlines);
+ int i = 0;
+ while (i <= len) {
+ int split_line = 0;
+ if ((text[i] & 0xE0) == 0xC0) i += 1;
+ else if ((text[i] & 0xF0) == 0xE0) i += 2;
+ else if ((text[i] & 0xF8) == 0xF0) i += 3;
+ if (i > len) i = len;
+ linelen = i - linestart;
+ if (text[i] == '\0') {
+ split_line = 1;
+ }
+ if (linelen > maxwidth) {
+ if (lastspace > linestart+maxwidth/2+6) {
+ count -= i-lastspace;
+ i = lastspace;
+ linelen = i - linestart;
+ split_line = 1;
+ } else {
+ split_line = 1;
+ }
+ }
+ if ((linelen > 0 && split_line) || text[i] == '\n') {
+ split_line = 0;
+ if (numlines == maxlines) {
+ maxlines += 8;
+ struct tuple* newlines = (struct tuple*)realloc(lines, sizeof(struct tuple) * maxlines);
+ if (!newlines) {
+ printf("FATAL: Out of memory\n");
+ return -1;
+ }
+ lines = newlines;
+ }
+ lines[numlines].idx = linestart;
+ lines[numlines].len = linelen;
+ lines[numlines].plen = count;
+ if (count > maxlen) maxlen = count;
+ numlines++;
+ linestart = i+1;
+ count = 0;
+ }
+ else if (text[i] == ' ') {
+ lastspace = i;
+ count++;
+ } else {
+ count++;
+ }
+ i++;
+ }
+ *lines_out = lines;
+ *maxlen_out = maxlen;
+ return numlines;
}
-void print_progress_bar(double progress) {
-#ifndef WIN32
- if (info_disabled) return;
+void set_banner_funcs(void (*showfunc)(const char*), void (*hidefunc)(void))
+{
+ banner_func = showfunc;
+ banner_hide_func = hidefunc;
+}
+
+void show_banner(const char* text)
+{
+ if (banner_func) {
+ banner_func(text);
+ } else {
+ int i;
+ int maxlen = 0;
+ struct tuple* lines = NULL;
+ int numlines = process_text_lines(text, 74, &lines, &maxlen);
+ printf("%.*s\n", maxlen + 4, STARS);
+ for (i = 0; i < numlines; i++) {
+ printf("* %.*s%.*s *\n", lines[i].len, text + lines[i].idx, maxlen-lines[i].plen, SPACES);
+ }
+ printf("%.*s\n", maxlen + 4, STARS);
+ free(lines);
+ }
+}
+
+void hide_banner()
+{
+ if (banner_hide_func) {
+ banner_hide_func();
+ }
+}
+
+static int (*prompt_func)(const char* title, const char* text) = NULL;
+
+void set_prompt_func(int (*func)(const char* title, const char* text))
+{
+ prompt_func = func;
+}
+
+int prompt_user(const char* title, const char* text)
+{
+ if (!text) return -1;
+ if (prompt_func) {
+ return prompt_func(title, text);
+ }
+ int i;
+ int result = 0;
+ int maxlen = 0;
+ struct tuple* lines = NULL;
+ int numlines = process_text_lines(text, 74, &lines, &maxlen);
+ int outerlen = maxlen+4;
+ int titlelen = (title) ? strlen(title) : 0;
+ if (titlelen > 0) {
+ int lefttitlelen = (titlelen+4)/2;
+ int leftpounds = outerlen/2 - lefttitlelen;
+ int rightpounds = outerlen-(titlelen+4) - leftpounds;
+ printf("%.*s[ %.*s ]%.*s\n", leftpounds, POUNDS, titlelen, title, rightpounds, POUNDS);
+ } else {
+ printf("%.*s\n", outerlen, POUNDS);
+ }
+ for (i = 0; i < numlines; i++) {
+ printf("%c %.*s%.*s %c\n", *POUNDS, lines[i].len, text + lines[i].idx, maxlen-lines[i].plen, SPACES, *POUNDS);
+ }
+ free(lines);
+ const char* yesmsg = "Type YES and press ENTER to continue, or hit CTRL+C to cancel.";
+ int ylen = strlen(yesmsg);
+ printf("%c %.*s%.*s %c\n", *POUNDS, ylen, yesmsg, maxlen-ylen, SPACES, *POUNDS);
+ printf("%.*s\n", outerlen, POUNDS);
+
+ char input[64];
+ while (1) {
+ printf("> ");
+ fflush(stdout);
+ fflush(stdin);
+ input[0] = '\0';
+ get_user_input(input, 63, 0);
+ if (global_quit_flag) {
+ result = -1;
+ break;
+ }
+ if (*input != '\0' && !strcmp(input, "YES")) {
+ result = 1;
+ break;
+ } else {
+ printf("Invalid input. Please type YES or hit CTRL+C to abort.\n");
+ continue;
+ }
+ }
+ return result;
+}
+
+static void (*update_progress_func)(struct progress_info_entry** list, int count) = NULL;
+static double progress_granularity = 0.001;
+
+void set_update_progress_func(void (*func)(struct progress_info_entry** list, int count))
+{
+ update_progress_func = func;
+}
+
+void set_progress_granularity(double granularity)
+{
+ progress_granularity = granularity;
+}
+
+mutex_t prog_mutex;
+struct collection progress_info;
+thread_once_t progress_info_once = THREAD_ONCE_INIT;
+static void _init_progress_info(void)
+{
+ mutex_init(&prog_mutex);
+ collection_init(&progress_info);
+}
+
+uint32_t progress_get_next_tag(void)
+{
+ mutex_lock(&prog_mutex);
+ uint32_t newtag = ++progress_unique_tag;
+ mutex_unlock(&prog_mutex);
+ return newtag;
+}
+
+void progress_reset_tag(void)
+{
+ progress_unique_tag = 1;
+}
+
+void register_progress(uint32_t tag, const char* label)
+{
+ thread_once(&progress_info_once, _init_progress_info);
+ if (!label) {
+ return;
+ }
+ mutex_lock(&prog_mutex);
+ struct progress_info_entry* found = NULL;
+ FOREACH(struct progress_info_entry* e, &progress_info) {
+ if (e->tag == tag) {
+ found = e;
+ break;
+ }
+ } ENDFOREACH
+ if (found) {
+ if (strcmp(found->label, label) != 0) {
+ free(found->label);
+ found->label = strdup(label);
+ if (update_progress_func) {
+ update_progress_func((struct progress_info_entry**)(&progress_info)->list, progress_info.capacity);
+ } else {
+ print_progress_bar(found->label, found->progress);
+ }
+ }
+ mutex_unlock(&prog_mutex);
+ return;
+ }
+ struct progress_info_entry* newinfo = (struct progress_info_entry*)calloc(1, sizeof(struct progress_info_entry));
+ if (!newinfo) {
+ logger(LL_ERROR, "Out of memory?!\n");
+ exit(1);
+ }
+ newinfo->tag = tag;
+ newinfo->label = strdup(label);
+ newinfo->progress = 0;
+ collection_add(&progress_info, newinfo);
+ if (update_progress_func) {
+ update_progress_func((struct progress_info_entry**)(&progress_info)->list, progress_info.capacity);
+ } else {
+ print_progress_bar(newinfo->label, newinfo->progress);
+ }
+ mutex_unlock(&prog_mutex);
+}
+
+void finalize_progress(uint32_t tag)
+{
+ mutex_lock(&prog_mutex);
+ struct progress_info_entry* found = NULL;
+ FOREACH(struct progress_info_entry* e, &progress_info) {
+ if (e->tag == tag) {
+ found = e;
+ break;
+ }
+ } ENDFOREACH
+ if (!found) {
+ mutex_unlock(&prog_mutex);
+ return;
+ }
+ collection_remove(&progress_info, found);
+ free(found->label);
+ free(found);
+ if (update_progress_func) {
+ update_progress_func((struct progress_info_entry**)(&progress_info)->list, progress_info.capacity);
+ }
+ mutex_unlock(&prog_mutex);
+}
+
+void print_progress_bar(const char* prefix, double progress)
+{
int i = 0;
- if(progress < 0) return;
- if(progress > 100) progress = 100;
- info("\r[");
- for(i = 0; i < 50; i++) {
- if(i < progress / 2) info("=");
- else info(" ");
- }
- info("] %5.1f%%", progress);
- if(progress >= 100) info("\n");
- fflush((info_stream) ? info_stream : stdout);
-#endif
+ if (progress < 0) return;
+ if (progress > 1) progress = 1;
+ if (prefix) {
+ printf("\r%s [", prefix);
+ } else {
+ printf("\r[");
+ }
+ for (i = 0; i < 50; i++) {
+ if (i < (int)(progress*50.0)) printf("=");
+ else printf(" ");
+ }
+ printf("] %5.1f%% ", progress*100.0);
+ if (progress >= 1) printf("\n");
+ fflush(stdout);
+}
+
+void set_progress(uint32_t tag, double progress)
+{
+ mutex_lock(&prog_mutex);
+ struct progress_info_entry* found = NULL;
+ FOREACH(struct progress_info_entry* e, &progress_info) {
+ if (e->tag == tag) {
+ found = e;
+ break;
+ }
+ } ENDFOREACH
+ if (!found) {
+ mutex_unlock(&prog_mutex);
+ return;
+ }
+ if (progress < 0) progress = 0;
+ if (progress > 1.0) progress = 1.0;
+ found->progress = progress;
+ if ((progress == 0) || (found->progress - found->lastprog >= progress_granularity)) {
+ if (update_progress_func) {
+ update_progress_func((struct progress_info_entry**)(&progress_info)->list, progress_info.capacity);
+ } else {
+ print_progress_bar(found->label, found->progress);
+ }
+ found->lastprog = found->progress;
+ }
+ mutex_unlock(&prog_mutex);
}
#define GET_RAND(min, max) ((rand() % (max - min)) + min)
@@ -467,8 +668,8 @@ void idevicerestore_progress(struct idevicerestore_client_t* client, int step, d
client->progress_cb(step, progress, client->progress_cb_data);
} else {
// we don't want to be too verbose in regular idevicerestore.
- if ((step == RESTORE_STEP_UPLOAD_FS) || (step == RESTORE_STEP_VERIFY_FS) || (step == RESTORE_STEP_FLASH_FW)) {
- print_progress_bar(100.0 * progress);
+ if ((step == RESTORE_STEP_UPLOAD_FS) || (step == RESTORE_STEP_VERIFY_FS) || (step == RESTORE_STEP_FLASH_FW) || (step == RESTORE_STEP_UPLOAD_IMG)) {
+ print_progress_bar(NULL, progress);
}
}
}
@@ -557,91 +758,19 @@ void get_user_input(char *buf, int maxlen, int secure)
buf[len] = 0;
}
-uint64_t _plist_dict_get_uint(plist_t dict, const char *key)
-{
- uint64_t uintval = 0;
- char *strval = NULL;
- uint64_t strsz = 0;
- plist_t node = plist_dict_get_item(dict, key);
- if (!node) {
- return (uint64_t)-1LL;
- }
- switch (plist_get_node_type(node)) {
- case PLIST_UINT:
- plist_get_uint_val(node, &uintval);
- break;
- case PLIST_STRING:
- plist_get_string_val(node, &strval);
- if (strval) {
- uintval = strtoull(strval, NULL, 0);
- free(strval);
- }
- break;
- case PLIST_DATA:
- plist_get_data_val(node, &strval, &strsz);
- if (strval) {
- if (strsz == 8) {
- uintval = le64toh(*(uint64_t*)strval);
- } else if (strsz == 4) {
- uintval = le32toh(*(uint32_t*)strval);
- } else if (strsz == 2) {
- uintval = le16toh(*(uint16_t*)strval);
- } else if (strsz == 1) {
- uintval = strval[0];
- } else {
- error("%s: ERROR: invalid size %" PRIu64 " for data to integer conversion\n", __func__, strsz);
- }
- free(strval);
- }
- break;
- default:
- break;
- }
- return uintval;
-}
-
-uint8_t _plist_dict_get_bool(plist_t dict, const char *key)
+const char* path_get_basename(const char* path)
{
- uint8_t bval = 0;
- uint64_t uintval = 0;
- char *strval = NULL;
- uint64_t strsz = 0;
- plist_t node = plist_dict_get_item(dict, key);
- if (!node) {
- return 0;
- }
- switch (plist_get_node_type(node)) {
- case PLIST_BOOLEAN:
- plist_get_bool_val(node, &bval);
- break;
- case PLIST_UINT:
- plist_get_uint_val(node, &uintval);
- bval = (uint8_t)uintval;
- break;
- case PLIST_STRING:
- plist_get_string_val(node, &strval);
- if (strval) {
- if (strcmp(strval, "true")) {
- bval = 1;
- } else if (strcmp(strval, "false")) {
- bval = 0;
- }
- free(strval);
- }
- break;
- case PLIST_DATA:
- plist_get_data_val(node, &strval, &strsz);
- if (strval) {
- if (strsz == 1) {
- bval = strval[0];
- } else {
- error("%s: ERROR: invalid size %" PRIu64 " for data to boolean conversion\n", __func__, strsz);
- }
- free(strval);
+#ifdef WIN32
+ const char *p = path + strlen(path);
+ while (p > path) {
+ if ((*p == '/') || (*p == '\\')) {
+ return p+1;
}
- break;
- default:
- break;
+ p--;
}
- return bval;
+ return p;
+#else
+ const char *p = strrchr(path, '/');
+ return p ? p + 1 : path;
+#endif
}
diff --git a/src/common.h b/src/common.h
index 6c839ce..3bb648a 100644
--- a/src/common.h
+++ b/src/common.h
@@ -40,6 +40,7 @@ extern "C" {
#include <libimobiledevice-glue/thread.h>
#include "idevicerestore.h"
+#include "log.h"
#define _MODE_UNKNOWN 0
#define _MODE_WTF 1
@@ -47,6 +48,7 @@ extern "C" {
#define _MODE_RECOVERY 3
#define _MODE_RESTORE 4
#define _MODE_NORMAL 5
+#define _MODE_PORTDFU 6
#define MODE_UNKNOWN &idevicerestore_modes[_MODE_UNKNOWN]
#define MODE_WTF &idevicerestore_modes[_MODE_WTF]
@@ -54,6 +56,7 @@ extern "C" {
#define MODE_RECOVERY &idevicerestore_modes[_MODE_RECOVERY]
#define MODE_RESTORE &idevicerestore_modes[_MODE_RESTORE]
#define MODE_NORMAL &idevicerestore_modes[_MODE_NORMAL]
+#define MODE_PORTDFU &idevicerestore_modes[_MODE_PORTDFU]
#define FLAG_QUIT 1
@@ -70,24 +73,18 @@ struct dfu_client_t;
struct normal_client_t;
struct restore_client_t;
struct recovery_client_t;
+struct ipsw_archive;
+
+typedef struct ipsw_archive* ipsw_archive_t;
struct idevicerestore_mode_t {
int index;
const char* string;
};
-struct idevicerestore_entry_t {
- char* name;
- char* path;
- char* filename;
- char* blob_data;
- uint32_t blob_size;
- struct idevicerestore_entry* next;
- struct idevicerestore_entry* prev;
-};
-
struct idevicerestore_client_t {
int flags;
+ int debug_level;
plist_t tss;
plist_t tss_localpolicy;
plist_t tss_recoveryos_root_ticket;
@@ -98,19 +95,21 @@ struct idevicerestore_client_t {
int nonce_size;
int image4supported;
plist_t build_manifest;
+ plist_t firmware_preflight_info;
plist_t preflight_info;
+ plist_t parameters;
char* udid;
char* srnm;
- char* ipsw;
- const char* filesystem;
+ ipsw_archive_t ipsw;
struct dfu_client_t* dfu;
struct restore_client_t* restore;
struct recovery_client_t* recovery;
irecv_device_t device;
- struct idevicerestore_entry_t** entries;
struct idevicerestore_mode_t* mode;
char* version;
char* build;
+ char* device_version;
+ char* device_build;
int build_major;
char* restore_boot_args;
char* cache_dir;
@@ -123,21 +122,50 @@ struct idevicerestore_client_t {
mutex_t device_event_mutex;
cond_t device_event_cond;
int ignore_device_add_events;
+ plist_t macos_variant;
+ plist_t recovery_variant;
+ char* restore_variant;
+ char* filesystem;
+ int delete_fs;
+ int async_err;
};
+extern int global_quit_flag;
+
extern struct idevicerestore_mode_t idevicerestore_modes[];
extern int idevicerestore_debug;
-__attribute__((format(printf, 1, 2)))
-void info(const char* format, ...);
-__attribute__((format(printf, 1, 2)))
-void error(const char* format, ...);
-__attribute__((format(printf, 1, 2)))
-void debug(const char* format, ...);
+void set_banner_funcs(void (*showfunc)(const char*), void (*hidefunc)(void));
+void show_banner(const char* text);
+void hide_banner();
+
+struct progress_info_entry {
+ uint32_t tag;
+ char* label;
+ double progress;
+ int lastprog;
+};
+void set_update_progress_func(void (*func)(struct progress_info_entry** list, int count));
+void set_progress_granularity(double granularity);
+uint32_t progress_get_next_tag(void);
+void progress_reset_tag(void);
+void register_progress(uint32_t tag, const char* label);
+void set_progress(uint32_t tag, double progress);
+void finalize_progress(uint32_t tag);
+void print_progress_bar(const char* prefix, double progress);
+
+struct tuple {
+ int idx;
+ int len;
+ int plen;
+};
+
+int process_text_lines(const char* text, int maxwidth, struct tuple** lines_out, int* maxlen_out);
+
+void set_prompt_func(int (*func)(const char* title, const char* text));
+int prompt_user(const char* title, const char* message);
-void debug_plist(plist_t plist);
-void print_progress_bar(double progress);
int read_file(const char* filename, void** data, size_t* size);
int write_file(const char* filename, const void* data, size_t size);
@@ -180,8 +208,7 @@ char* realpath(const char *filename, char *resolved_name);
void get_user_input(char *buf, int maxlen, int secure);
-uint8_t _plist_dict_get_bool(plist_t dict, const char *key);
-uint64_t _plist_dict_get_uint(plist_t dict, const char *key);
+const char* path_get_basename(const char* path);
#ifdef __cplusplus
}
diff --git a/src/dfu.c b/src/dfu.c
index a675c53..6ba23e7 100644
--- a/src/dfu.c
+++ b/src/dfu.c
@@ -27,46 +27,36 @@
#include <unistd.h>
#include <libirecovery.h>
+#include <libtatsu/tss.h>
+
#include "dfu.h"
-#include "tss.h"
#include "recovery.h"
#include "idevicerestore.h"
#include "common.h"
static int dfu_progress_callback(irecv_client_t client, const irecv_event_t* event) {
if (event->type == IRECV_PROGRESS) {
- print_progress_bar(event->progress);
+ set_progress('DFUP', (double)event->progress/100.0);
}
return 0;
}
int dfu_client_new(struct idevicerestore_client_t* client)
{
- int i = 0;
- int attempts = 10;
irecv_client_t dfu = NULL;
if (client->dfu == NULL) {
client->dfu = (struct dfu_client_t*)malloc(sizeof(struct dfu_client_t));
memset(client->dfu, 0, sizeof(struct dfu_client_t));
if (client->dfu == NULL) {
- error("ERROR: Out of memory\n");
+ logger(LL_ERROR, "Out of memory\n");
return -1;
}
}
- for (i = 1; i <= attempts; i++) {
- if (irecv_open_with_ecid(&dfu, client->ecid) == IRECV_E_SUCCESS) {
- break;
- }
-
- if (i >= attempts) {
- error("ERROR: Unable to connect to device in DFU mode\n");
- return -1;
- }
-
- sleep(1);
- debug("Retrying connection...\n");
+ if (irecv_open_with_ecid_and_attempts(&dfu, client->ecid, 10) != IRECV_E_SUCCESS) {
+ logger(LL_ERROR, "Unable to connect to device in DFU mode\n");
+ return -1;
}
irecv_event_subscribe(dfu, IRECV_PROGRESS, &dfu_progress_callback, NULL);
@@ -77,6 +67,7 @@ int dfu_client_new(struct idevicerestore_client_t* client)
void dfu_client_free(struct idevicerestore_client_t* client)
{
if(client != NULL) {
+ finalize_progress('DFUP');
if (client->dfu != NULL) {
if(client->dfu->client != NULL) {
irecv_close(client->dfu->client);
@@ -94,12 +85,17 @@ irecv_device_t dfu_get_irecv_device(struct idevicerestore_client_t* client)
irecv_error_t dfu_error = IRECV_E_SUCCESS;
irecv_device_t device = NULL;
- irecv_init();
- if (irecv_open_with_ecid(&dfu, client->ecid) != IRECV_E_SUCCESS) {
+ if (irecv_open_with_ecid_and_attempts(&dfu, client->ecid, 10) != IRECV_E_SUCCESS) {
return NULL;
}
dfu_error = irecv_devices_get_device_by_client(dfu, &device);
+ if (dfu_error == IRECV_E_SUCCESS) {
+ if (client->ecid == 0) {
+ const struct irecv_device_info *device_info = irecv_get_device_info(dfu);
+ client->ecid = device_info->ecid;
+ }
+ }
irecv_close(dfu);
if (dfu_error != IRECV_E_SUCCESS) {
return NULL;
@@ -108,21 +104,26 @@ irecv_device_t dfu_get_irecv_device(struct idevicerestore_client_t* client)
return device;
}
-int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size)
+int dfu_send_buffer_with_options(struct idevicerestore_client_t* client, const void* buffer, size_t size, unsigned int irecv_options)
{
irecv_error_t err = 0;
- info("Sending data (%d bytes)...\n", size);
+ logger(LL_INFO, "Sending data (%zu bytes)...\n", size);
- err = irecv_send_buffer(client->dfu->client, buffer, size, 1);
+ err = irecv_send_buffer(client->dfu->client, (unsigned char*)buffer, size, irecv_options);
if (err != IRECV_E_SUCCESS) {
- error("ERROR: Unable to send data: %s\n", irecv_strerror(err));
+ logger(LL_ERROR, "Unable to send data: %s\n", irecv_strerror(err));
return -1;
}
return 0;
}
+int dfu_send_buffer(struct idevicerestore_client_t* client, const void* buffer, size_t size)
+{
+ return dfu_send_buffer_with_options(client, buffer, size, IRECV_SEND_OPT_DFU_NOTIFY_FINISH);
+}
+
int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component)
{
char* path = NULL;
@@ -133,8 +134,8 @@ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_ide
tss = client->tss_localpolicy;
}
- unsigned char* component_data = NULL;
- unsigned int component_size = 0;
+ void* component_data = NULL;
+ size_t component_size = 0;
if (strcmp(component, "Ap,LocalPolicy") == 0) {
// If Ap,LocalPolicy => Inject an empty policy
@@ -144,19 +145,19 @@ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_ide
} else {
if (tss) {
if (tss_response_get_path_by_entry(tss, component, &path) < 0) {
- debug("NOTE: No path for component %s in TSS, will fetch from build_identity\n", component);
+ logger(LL_DEBUG, "No path for component %s in TSS, will fetch from build_identity\n", component);
}
}
if (!path) {
if (build_identity_get_component_path(build_identity, component, &path) < 0) {
- error("ERROR: Unable to get path for component '%s'\n", component);
+ logger(LL_ERROR, "Unable to get path for component '%s'\n", component);
free(path);
return -1;
}
}
if (extract_component(client->ipsw, path, &component_data, &component_size) < 0) {
- error("ERROR: Unable to extract component: %s\n", component);
+ logger(LL_ERROR, "Unable to extract component: %s\n", component);
free(path);
return -1;
}
@@ -164,11 +165,11 @@ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_ide
path = NULL;
}
- unsigned char* data = NULL;
- uint32_t size = 0;
+ void* data = NULL;
+ size_t size = 0;
- if (personalize_component(component, component_data, component_size, tss, &data, &size) < 0) {
- error("ERROR: Unable to get personalized component: %s\n", component);
+ if (personalize_component(client, component, component_data, component_size, tss, &data, &size) < 0) {
+ logger(LL_ERROR, "Unable to get personalized component: %s\n", component);
free(component_data);
return -1;
}
@@ -179,14 +180,14 @@ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_ide
unsigned char* ticket = NULL;
unsigned int tsize = 0;
if (tss_response_get_ap_ticket(client->tss, &ticket, &tsize) < 0) {
- error("ERROR: Unable to get ApTicket from TSS request\n");
+ logger(LL_ERROR, "Unable to get ApTicket from TSS request\n");
return -1;
}
uint32_t fillsize = 0;
if (tsize % 64 != 0) {
fillsize = ((tsize / 64) + 1) * 64;
}
- debug("ticket size = %d\nfillsize = %d\n", tsize, fillsize);
+ logger(LL_DEBUG, "ticket size = %d\nfillsize = %d\n", tsize, fillsize);
unsigned char* newdata = (unsigned char*)malloc(size + fillsize);
memcpy(newdata, ticket, tsize);
memset(newdata + tsize, '\xFF', fillsize - tsize);
@@ -196,11 +197,13 @@ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_ide
size += fillsize;
}
- info("Sending %s (%d bytes)...\n", component, size);
+ logger(LL_INFO, "Sending %s (%zu bytes)...\n", component, size);
- irecv_error_t err = irecv_send_buffer(client->dfu->client, data, size, 1);
+ register_progress('DFUP', "Uploading");
+ irecv_error_t err = irecv_send_buffer(client->dfu->client, data, size, IRECV_SEND_OPT_DFU_NOTIFY_FINISH);
+ finalize_progress('DFUP');
if (err != IRECV_E_SUCCESS) {
- error("ERROR: Unable to send %s component: %s\n", component, irecv_strerror(err));
+ logger(LL_ERROR, "Unable to send %s component: %s\n", component, irecv_strerror(err));
free(data);
return -1;
}
@@ -209,7 +212,7 @@ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_ide
return 0;
}
-int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid)
+int dfu_get_bdid(struct idevicerestore_client_t* client, unsigned int* bdid)
{
if(client->dfu == NULL) {
if (dfu_client_new(client) < 0) {
@@ -222,12 +225,12 @@ int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid)
return -1;
}
- *cpid = device_info->cpid;
+ *bdid = device_info->bdid;
return 0;
}
-int dfu_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid)
+int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid)
{
if(client->dfu == NULL) {
if (dfu_client_new(client) < 0) {
@@ -240,11 +243,32 @@ int dfu_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid)
return -1;
}
- *ecid = device_info->ecid;
+ *cpid = device_info->cpid;
return 0;
}
+int dfu_get_prev(struct idevicerestore_client_t* client, unsigned int* prev)
+{
+ if(client->dfu == NULL) {
+ if (dfu_client_new(client) < 0) {
+ return -1;
+ }
+ }
+
+ const struct irecv_device_info *device_info = irecv_get_device_info(client->dfu->client);
+ if (!device_info) {
+ return -1;
+ }
+ char* ptr = strstr(device_info->serial_string, "PREV:");
+ if (ptr) {
+ sscanf(ptr, "PREV:%x", prev);
+ return 0;
+ }
+ return -1;
+}
+
+
int dfu_is_image4_supported(struct idevicerestore_client_t* client)
{
if(client->dfu == NULL) {
@@ -261,7 +285,36 @@ int dfu_is_image4_supported(struct idevicerestore_client_t* client)
return (device_info->ibfl & IBOOT_FLAG_IMAGE4_AWARE);
}
-int dfu_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size)
+int dfu_get_portdfu_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size)
+{
+ if(client->dfu == NULL) {
+ if (dfu_client_new(client) < 0) {
+ return -1;
+ }
+ }
+
+ const struct irecv_device_info *device_info = irecv_get_device_info(client->dfu->client);
+ if (!device_info) {
+ return -1;
+ }
+
+ if (device_info->ap_nonce && device_info->ap_nonce_size > 0) {
+ *nonce = (unsigned char*)malloc(device_info->ap_nonce_size);
+ if (!*nonce) {
+ return -1;
+ }
+ *nonce_size = device_info->ap_nonce_size;
+ // The nonce is backwards, so we have to swap the bytes
+ unsigned int i = 0;
+ for (i = 0; i < *nonce_size; i++) {
+ (*nonce)[(*nonce_size)-1-i] = device_info->ap_nonce[i];
+ }
+ }
+
+ return 0;
+}
+
+int dfu_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size)
{
if(client->dfu == NULL) {
if (dfu_client_new(client) < 0) {
@@ -286,7 +339,7 @@ int dfu_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** non
return 0;
}
-int dfu_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size)
+int dfu_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size)
{
if(client->dfu == NULL) {
if (dfu_client_new(client) < 0) {
@@ -316,14 +369,14 @@ int dfu_send_component_and_command(struct idevicerestore_client_t* client, plist
irecv_error_t dfu_error = IRECV_E_SUCCESS;
if (dfu_send_component(client, build_identity, component) < 0) {
- error("ERROR: Unable to send %s to device.\n", component);
+ logger(LL_ERROR, "Unable to send %s to device.\n", component);
return -1;
}
- info("INFO: executing command: %s\n", command);
+ logger(LL_INFO, "INFO: executing command: %s\n", command);
dfu_error = irecv_send_command(client->dfu->client, command);
if (dfu_error != IRECV_E_SUCCESS) {
- error("ERROR: Unable to execute %s\n", command);
+ logger(LL_ERROR, "Unable to execute %s\n", command);
return -1;
}
@@ -334,10 +387,10 @@ int dfu_send_command(struct idevicerestore_client_t* client, const char* command
{
irecv_error_t dfu_error = IRECV_E_SUCCESS;
- info("INFO: executing command: %s\n", command);
+ logger(LL_INFO, "INFO: executing command: %s\n", command);
dfu_error = irecv_send_command(client->dfu->client, command);
if (dfu_error != IRECV_E_SUCCESS) {
- error("ERROR: Unable to execute %s\n", command);
+ logger(LL_ERROR, "Unable to execute %s\n", command);
return -1;
}
@@ -348,7 +401,7 @@ int dfu_send_iboot_stage1_components(struct idevicerestore_client_t* client, pli
{
plist_t manifest_node = plist_dict_get_item(build_identity, "Manifest");
if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) {
- error("ERROR: Unable to find manifest node\n");
+ logger(LL_ERROR, "Unable to find manifest node\n");
return -1;
}
@@ -372,11 +425,13 @@ int dfu_send_iboot_stage1_components(struct idevicerestore_client_t* client, pli
uint8_t b = 0;
plist_get_bool_val(iboot_node, &b);
if (b) {
- debug("DEBUG: %s is loaded by iBoot Stage 1.\n", key);
- if (dfu_send_component_and_command(client, build_identity, key, "firmware") < 0) {
- error("ERROR: Unable to send component '%s' to device.\n", key);
- err++;
- }
+ logger(LL_DEBUG, "%s is loaded by iBoot Stage 1 and iBoot.\n", key);
+ } else {
+ logger(LL_DEBUG, "%s is loaded by iBoot Stage 1 but not iBoot...\n", key);
+ }
+ if (dfu_send_component_and_command(client, build_identity, key, "firmware") < 0) {
+ logger(LL_ERROR, "Unable to send component '%s' to device.\n", key);
+ err++;
}
}
free(key);
@@ -391,14 +446,14 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide
int mode = 0;
if (dfu_client_new(client) < 0) {
- error("ERROR: Unable to connect to DFU device\n");
+ logger(LL_ERROR, "Unable to connect to DFU device\n");
return -1;
}
irecv_get_mode(client->dfu->client, &mode);
if (mode != IRECV_K_DFU_MODE) {
- info("NOTE: device is not in DFU mode, assuming recovery mode.\n");
+ logger(LL_NOTICE, "device is not in DFU mode, assuming recovery mode.\n");
client->mode = MODE_RECOVERY;
return 0;
}
@@ -406,7 +461,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide
mutex_lock(&client->device_event_mutex);
if (dfu_send_component(client, build_identity, "iBSS") < 0) {
- error("ERROR: Unable to send iBSS to device\n");
+ logger(LL_ERROR, "Unable to send iBSS to device\n");
irecv_close(client->dfu->client);
client->dfu->client = NULL;
return -1;
@@ -415,21 +470,21 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide
if (client->build_major > 8) {
/* reconnect */
- debug("Waiting for device to disconnect...\n");
+ logger(LL_DEBUG, "Waiting for device to disconnect...\n");
cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000);
if (client->mode != MODE_UNKNOWN || (client->flags & FLAG_QUIT)) {
mutex_unlock(&client->device_event_mutex);
if (!(client->flags & FLAG_QUIT)) {
- error("ERROR: Device did not disconnect. Possibly invalid iBSS. Reset device and try again.\n");
+ logger(LL_ERROR, "Device did not disconnect. Possibly invalid iBSS. Reset device and try again.\n");
}
return -1;
}
- debug("Waiting for device to reconnect...\n");
+ logger(LL_DEBUG, "Waiting for device to reconnect...\n");
cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000);
if ((client->mode != MODE_DFU && client->mode != MODE_RECOVERY) || (client->flags & FLAG_QUIT)) {
mutex_unlock(&client->device_event_mutex);
if (!(client->flags & FLAG_QUIT)) {
- error("ERROR: Device did not reconnect in DFU or recovery mode. Possibly invalid iBSS. Reset device and try again.\n");
+ logger(LL_ERROR, "Device did not reconnect in DFU or recovery mode. Possibly invalid iBSS. Reset device and try again.\n");
}
return -1;
}
@@ -438,10 +493,10 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide
/* get nonce */
unsigned char* nonce = NULL;
- int nonce_size = 0;
+ unsigned int nonce_size = 0;
int nonce_changed = 0;
if (dfu_get_ap_nonce(client, &nonce, &nonce_size) < 0) {
- error("ERROR: Unable to get ApNonce from device!\n");
+ logger(LL_ERROR, "Unable to get ApNonce from device!\n");
return -1;
}
@@ -456,47 +511,58 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide
free(nonce);
}
- info("Nonce: ");
- int i;
- for (i = 0; i < client->nonce_size; i++) {
- info("%02x ", client->nonce[i]);
- }
- info("\n");
+ logger(LL_INFO, "Nonce: ");
+ logger_dump_hex(LL_INFO, client->nonce, client->nonce_size);
if (nonce_changed && !(client->flags & FLAG_CUSTOM)) {
// Welcome iOS5. We have to re-request the TSS with our nonce.
plist_free(client->tss);
if (get_tss_response(client, build_identity, &client->tss) < 0) {
- error("ERROR: Unable to get SHSH blobs for this device\n");
+ logger(LL_ERROR, "Unable to get SHSH blobs for this device\n");
return -1;
}
if (!client->tss) {
- error("ERROR: can't continue without TSS\n");
+ logger(LL_ERROR, "can't continue without TSS\n");
return -1;
}
fixup_tss(client->tss);
}
if (irecv_usb_set_configuration(client->dfu->client, 1) < 0) {
- error("ERROR: set configuration failed\n");
+ logger(LL_ERROR, "set configuration failed\n");
}
mutex_lock(&client->device_event_mutex);
// Now, before sending iBEC, we must send necessary firmwares on new versions.
- if (client->build_major >= 20) {
+ if (client->macos_variant) {
// Without this empty policy file & its special signature, iBEC won't start.
if (dfu_send_component_and_command(client, build_identity, "Ap,LocalPolicy", "lpolrestore") < 0) {
mutex_unlock(&client->device_event_mutex);
- error("ERROR: Unable to send Ap,LocalPolicy to device\n");
+ logger(LL_ERROR, "Unable to send Ap,LocalPolicy to device\n");
irecv_close(client->dfu->client);
client->dfu->client = NULL;
return -1;
}
+ char *value = NULL;
+ unsigned long boot_stage = 0;
+ irecv_getenv(client->dfu->client, "boot-stage", &value);
+ if (value) {
+ boot_stage = strtoul(value, NULL, 0);
+ }
+ if (boot_stage > 0) {
+ logger(LL_INFO, "iBoot boot-stage=%s\n", value);
+ free(value);
+ value = NULL;
+ if (boot_stage != 1) {
+ logger(LL_ERROR, "iBoot should be at boot stage 1, continuing anyway...\n");
+ }
+ }
+
if (dfu_send_iboot_stage1_components(client, build_identity) < 0) {
mutex_unlock(&client->device_event_mutex);
- error("ERROR: Unable to send iBoot stage 1 components to device\n");
+ logger(LL_ERROR, "Unable to send iBoot stage 1 components to device\n");
irecv_close(client->dfu->client);
client->dfu->client = NULL;
return -1;
@@ -504,7 +570,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide
if (dfu_send_command(client, "setenv auto-boot false") < 0) {
mutex_unlock(&client->device_event_mutex);
- error("ERROR: Unable to send command to device\n");
+ logger(LL_ERROR, "Unable to send command to device\n");
irecv_close(client->dfu->client);
client->dfu->client = NULL;
return -1;
@@ -512,7 +578,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide
if (dfu_send_command(client, "saveenv") < 0) {
mutex_unlock(&client->device_event_mutex);
- error("ERROR: Unable to send command to device\n");
+ logger(LL_ERROR, "Unable to send command to device\n");
irecv_close(client->dfu->client);
client->dfu->client = NULL;
return -1;
@@ -520,7 +586,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide
if (dfu_send_command(client, "setenvnp boot-args rd=md0 nand-enable-reformat=1 -progress -restore") < 0) {
mutex_unlock(&client->device_event_mutex);
- error("ERROR: Unable to send command to device\n");
+ logger(LL_ERROR, "Unable to send command to device\n");
irecv_close(client->dfu->client);
client->dfu->client = NULL;
return -1;
@@ -528,7 +594,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide
if (dfu_send_component(client, build_identity, "RestoreLogo") < 0) {
mutex_unlock(&client->device_event_mutex);
- error("ERROR: Unable to send RestoreDCP to device\n");
+ logger(LL_ERROR, "Unable to send RestoreDCP to device\n");
irecv_close(client->dfu->client);
client->dfu->client = NULL;
return -1;
@@ -536,7 +602,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide
if (dfu_send_command(client, "setpicture 4") < 0) {
mutex_unlock(&client->device_event_mutex);
- error("ERROR: Unable to send command to device\n");
+ logger(LL_ERROR, "Unable to send command to device\n");
irecv_close(client->dfu->client);
client->dfu->client = NULL;
return -1;
@@ -544,7 +610,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide
if (dfu_send_command(client, "bgcolor 0 0 0") < 0) {
mutex_unlock(&client->device_event_mutex);
- error("ERROR: Unable to send command to device\n");
+ logger(LL_ERROR, "Unable to send command to device\n");
irecv_close(client->dfu->client);
client->dfu->client = NULL;
return -1;
@@ -554,7 +620,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide
/* send iBEC */
if (dfu_send_component(client, build_identity, "iBEC") < 0) {
mutex_unlock(&client->device_event_mutex);
- error("ERROR: Unable to send iBEC to device\n");
+ logger(LL_ERROR, "Unable to send iBEC to device\n");
irecv_close(client->dfu->client);
client->dfu->client = NULL;
return -1;
@@ -564,7 +630,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide
sleep(1);
if (irecv_send_command_breq(client->dfu->client, "go", 1) != IRECV_E_SUCCESS) {
mutex_unlock(&client->device_event_mutex);
- error("ERROR: Unable to execute iBEC\n");
+ logger(LL_ERROR, "Unable to execute iBEC\n");
return -1;
}
@@ -575,28 +641,28 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide
dfu_client_free(client);
}
- debug("Waiting for device to disconnect...\n");
+ logger(LL_DEBUG, "Waiting for device to disconnect...\n");
cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000);
if (client->mode != MODE_UNKNOWN || (client->flags & FLAG_QUIT)) {
mutex_unlock(&client->device_event_mutex);
if (!(client->flags & FLAG_QUIT)) {
- error("ERROR: Device did not disconnect. Possibly invalid %s. Reset device and try again.\n", (client->build_major > 8) ? "iBEC" : "iBSS");
+ logger(LL_ERROR, "Device did not disconnect. Possibly invalid %s. Reset device and try again.\n", (client->build_major > 8) ? "iBEC" : "iBSS");
}
return -1;
}
- debug("Waiting for device to reconnect in recovery mode...\n");
+ logger(LL_DEBUG, "Waiting for device to reconnect in recovery mode...\n");
cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000);
if (client->mode != MODE_RECOVERY || (client->flags & FLAG_QUIT)) {
mutex_unlock(&client->device_event_mutex);
if (!(client->flags & FLAG_QUIT)) {
- error("ERROR: Device did not reconnect in recovery mode. Possibly invalid %s. Reset device and try again.\n", (client->build_major > 8) ? "iBEC" : "iBSS");
+ logger(LL_ERROR, "Device did not reconnect in recovery mode. Possibly invalid %s. Reset device and try again.\n", (client->build_major > 8) ? "iBEC" : "iBSS");
}
return -1;
}
mutex_unlock(&client->device_event_mutex);
if (recovery_client_new(client) < 0) {
- error("ERROR: Unable to connect to recovery device\n");
+ logger(LL_ERROR, "Unable to connect to recovery device\n");
if (client->recovery->client) {
irecv_close(client->recovery->client);
client->recovery->client = NULL;
diff --git a/src/dfu.h b/src/dfu.h
index f501531..7b1d092 100644
--- a/src/dfu.h
+++ b/src/dfu.h
@@ -40,13 +40,16 @@ struct dfu_client_t {
int dfu_client_new(struct idevicerestore_client_t* client);
void dfu_client_free(struct idevicerestore_client_t* client);
irecv_device_t dfu_get_irecv_device(struct idevicerestore_client_t* client);
-int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size);
+int dfu_send_buffer(struct idevicerestore_client_t* client, const void* buffer, size_t size);
+int dfu_send_buffer_with_options(struct idevicerestore_client_t* client, const void* buffer, size_t size, unsigned int irecv_options);
int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component);
+int dfu_get_bdid(struct idevicerestore_client_t* client, unsigned int* bdid);
int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid);
-int dfu_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid);
+int dfu_get_prev(struct idevicerestore_client_t* client, unsigned int* prev);
int dfu_is_image4_supported(struct idevicerestore_client_t* client);
-int dfu_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size);
-int dfu_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size);
+int dfu_get_portdfu_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size);
+int dfu_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size);
+int dfu_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size);
int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_identity);
diff --git a/src/download.c b/src/download.c
index a258da2..0b6b076 100644
--- a/src/download.c
+++ b/src/download.c
@@ -43,12 +43,12 @@ static size_t download_write_buffer_callback(char* data, size_t size, size_t nme
return total;
}
-int download_to_buffer(const char* url, char** buf, uint32_t* length)
+int download_to_buffer(const char* url, void** buf, size_t* length)
{
int res = 0;
CURL* handle = curl_easy_init();
if (handle == NULL) {
- error("ERROR: could not initialize CURL\n");
+ logger(LL_ERROR, "could not initialize CURL\n");
return -1;
}
@@ -57,7 +57,7 @@ int download_to_buffer(const char* url, char** buf, uint32_t* length)
response.content = malloc(1);
response.content[0] = '\0';
- if (idevicerestore_debug)
+ if (log_level >= LL_DEBUG)
curl_easy_setopt(handle, CURLOPT_VERBOSE, 1);
/* disable SSL verification to allow download from untrusted https locations */
@@ -86,17 +86,18 @@ int download_to_buffer(const char* url, char** buf, uint32_t* length)
return res;
}
-static int lastprogress = 0;
-
+#if LIBCURL_VERSION_NUM >= 0x072000
+static int download_progress(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
+#else
static int download_progress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
+#endif
{
- double p = (dlnow / dltotal) * 100;
+ double p = ((double)dlnow / (double)dltotal);
- if (p < 100.0) {
- if ((int)p > lastprogress) {
- info("downloading: %d%%\n", (int)p);
- lastprogress = (int)p;
- }
+ set_progress('DNLD', p);
+
+ if (global_quit_flag > 0) {
+ return 1;
}
return 0;
@@ -107,19 +108,17 @@ int download_to_file(const char* url, const char* filename, int enable_progress)
int res = 0;
CURL* handle = curl_easy_init();
if (handle == NULL) {
- error("ERROR: could not initialize CURL\n");
+ logger(LL_ERROR, "Could not initialize CURL\n");
return -1;
}
FILE* f = fopen(filename, "wb");
if (!f) {
- error("ERROR: cannot open '%s' for writing\n", filename);
+ logger(LL_ERROR, "Cannot open '%s' for writing\n", filename);
return -1;
}
- lastprogress = 0;
-
- if (idevicerestore_debug)
+ if (log_level >= LL_DEBUG)
curl_easy_setopt(handle, CURLOPT_VERBOSE, 1);
/* disable SSL verification to allow download from untrusted https locations */
@@ -128,8 +127,14 @@ int download_to_file(const char* url, const char* filename, int enable_progress)
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, NULL);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, f);
- if (enable_progress > 0)
+ if (enable_progress > 0) {
+ register_progress('DNLD', "Downloading");
+#if LIBCURL_VERSION_NUM >= 0x072000
+ curl_easy_setopt(handle, CURLOPT_XFERINFOFUNCTION, (curl_progress_callback)&download_progress);
+#else
curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, (curl_progress_callback)&download_progress);
+#endif
+ }
curl_easy_setopt(handle, CURLOPT_NOPROGRESS, enable_progress > 0 ? 0: 1);
curl_easy_setopt(handle, CURLOPT_USERAGENT, USER_AGENT_STRING);
@@ -137,6 +142,11 @@ int download_to_file(const char* url, const char* filename, int enable_progress)
curl_easy_setopt(handle, CURLOPT_URL, url);
curl_easy_perform(handle);
+
+ if (enable_progress) {
+ finalize_progress('DNLD');
+ }
+
curl_easy_cleanup(handle);
#ifdef WIN32
@@ -151,6 +161,9 @@ int download_to_file(const char* url, const char* filename, int enable_progress)
res = -1;
remove(filename);
}
+ if (global_quit_flag > 0) {
+ res = -2;
+ }
return res;
}
diff --git a/src/download.h b/src/download.h
index 1edde5b..bbb5aa0 100644
--- a/src/download.h
+++ b/src/download.h
@@ -28,7 +28,7 @@ extern "C" {
#include <stdint.h>
-int download_to_buffer(const char* url, char** buf, uint32_t* length);
+int download_to_buffer(const char* url, void** buf, size_t* length);
int download_to_file(const char* url, const char* filename, int enable_progress);
#ifdef __cplusplus
diff --git a/src/fdr.c b/src/fdr.c
index e3703fe..9dbe59c 100644
--- a/src/fdr.c
+++ b/src/fdr.c
@@ -66,7 +66,7 @@ int fdr_connect(idevice_t device, fdr_type_t type, fdr_client_t* fdr)
*fdr = NULL;
- debug("Connecting to FDR client at port %u\n", port);
+ logger(LL_DEBUG, "Connecting to FDR client at port %u\n", port);
for (i = 1; i <= attempts; i++) {
device_error = idevice_connect(device, port, &connection);
@@ -75,17 +75,17 @@ int fdr_connect(idevice_t device, fdr_type_t type, fdr_client_t* fdr)
}
if (i >= attempts) {
- error("ERROR: Unable to connect to FDR client (%d)\n", device_error);
+ logger(LL_ERROR, "Unable to connect to FDR client (%d)\n", device_error);
return -1;
}
sleep(2);
- debug("Retrying connection...\n");
+ logger(LL_DEBUG, "Retrying connection...\n");
}
fdr_client_t fdr_loc = calloc(1, sizeof(struct fdr_client));
if (!fdr_loc) {
- error("ERROR: Unable to allocate memory\n");
+ logger(LL_ERROR, "Unable to allocate memory\n");
return -1;
}
fdr_loc->connection = connection;
@@ -138,7 +138,7 @@ int fdr_poll_and_handle_message(fdr_client_t fdr)
uint16_t cmd;
if (!fdr) {
- error("ERROR: Invalid FDR client\n");
+ logger(LL_ERROR, "Invalid FDR client\n");
return -1;
}
@@ -149,49 +149,49 @@ int fdr_poll_and_handle_message(fdr_client_t fdr)
if (device_error == IDEVICE_E_SUCCESS && bytes != sizeof(cmd))
#endif
{
- debug("FDR %p timeout waiting for command\n", fdr);
+ logger(LL_DEBUG, "FDR %p timeout waiting for command\n", fdr);
return 0;
}
else if (device_error != IDEVICE_E_SUCCESS) {
if (fdr->connection) {
- error("ERROR: Unable to receive message from FDR %p (%d). %u/%u bytes\n", fdr, device_error, bytes, (uint32_t)sizeof(cmd));
+ logger(LL_ERROR, "Unable to receive message from FDR %p (%d). %u/%u bytes\n", fdr, device_error, bytes, (uint32_t)sizeof(cmd));
}
return -1;
}
if (cmd == FDR_SYNC_MSG) {
- debug("FDR %p got sync message\n", fdr);
+ logger(LL_DEBUG, "FDR %p got sync message\n", fdr);
return fdr_handle_sync_cmd(fdr);
}
if (cmd == FDR_PROXY_MSG) {
- debug("FDR %p got proxy message\n", fdr);
+ logger(LL_DEBUG, "FDR %p got proxy message\n", fdr);
return fdr_handle_proxy_cmd(fdr);
}
if (cmd == FDR_PLIST_MSG) {
- debug("FDR %p got plist message\n", fdr);
+ logger(LL_DEBUG, "FDR %p got plist message\n", fdr);
return fdr_handle_plist_cmd(fdr);
}
- error("WARNING: FDR %p received unknown packet %#x of size %u\n", fdr, cmd, bytes);
+ logger(LL_WARNING, "FDR %p received unknown packet %#x of size %u\n", fdr, cmd, bytes);
return 0;
}
void *fdr_listener_thread(void *cdata)
{
fdr_client_t fdr = cdata;
- int res;
+ int res = 0;
while (fdr && fdr->connection) {
- debug("FDR %p waiting for message...\n", fdr);
+ logger(LL_DEBUG, "FDR %p waiting for message...\n", fdr);
res = fdr_poll_and_handle_message(fdr);
if (fdr->type == FDR_CTRL && res >= 0)
continue; // main thread should always retry
if (res != 0)
break;
}
- debug("FDR %p terminating...\n", fdr);
+ logger(LL_DEBUG, "FDR %p terminating...\n", fdr);
fdr_free(fdr);
return (void *)(intptr_t)res;
}
@@ -204,26 +204,26 @@ static int fdr_receive_plist(fdr_client_t fdr, plist_t* data)
device_error = idevice_connection_receive(fdr->connection, (char*)&len, sizeof(len), &bytes);
if (device_error != IDEVICE_E_SUCCESS) {
- error("ERROR: Unable to receive packet length from FDR (%d)\n", device_error);
+ logger(LL_ERROR, "Unable to receive packet length from FDR (%d)\n", device_error);
return -1;
}
buf = calloc(1, len);
if (!buf) {
- error("ERROR: Unable to allocate memory for FDR receive buffer\n");
+ logger(LL_ERROR, "Unable to allocate memory for FDR receive buffer\n");
return -1;
}
device_error = idevice_connection_receive(fdr->connection, buf, len, &bytes);
if (device_error != IDEVICE_E_SUCCESS) {
- error("ERROR: Unable to receive data from FDR\n");
+ logger(LL_ERROR, "Unable to receive data from FDR\n");
free(buf);
return -1;
}
plist_from_bin(buf, bytes, data);
free(buf);
- debug("FDR Received %d bytes\n", bytes);
+ logger(LL_DEBUG, "FDR Received %d bytes\n", bytes);
return 0;
}
@@ -241,12 +241,11 @@ static int fdr_send_plist(fdr_client_t fdr, plist_t data)
if (!buf)
return -1;
- debug("FDR sending %d bytes:\n", len);
- if (idevicerestore_debug)
- debug_plist(data);
+ logger(LL_DEBUG, "FDR sending %d bytes:\n", len);
+ logger_dump_plist(LL_DEBUG, data, 1);
device_error = idevice_connection_send(fdr->connection, (char *)&len, sizeof(len), &bytes);
if (device_error != IDEVICE_E_SUCCESS || bytes != sizeof(len)) {
- error("ERROR: FDR unable to send data length. (%d) Sent %u of %u bytes.\n",
+ logger(LL_ERROR, "FDR unable to send data length. (%d) Sent %u of %u bytes.\n",
device_error, bytes, (uint32_t)sizeof(len));
free(buf);
return -1;
@@ -254,12 +253,12 @@ static int fdr_send_plist(fdr_client_t fdr, plist_t data)
device_error = idevice_connection_send(fdr->connection, buf, len, &bytes);
free(buf);
if (device_error != IDEVICE_E_SUCCESS || bytes != len) {
- error("ERROR: FDR unable to send data (%d). Sent %u of %u bytes.\n",
+ logger(LL_ERROR, "FDR unable to send data (%d). Sent %u of %u bytes.\n",
device_error, bytes, len);
return -1;
}
- debug("FDR Sent %d bytes\n", bytes);
+ logger(LL_DEBUG, "FDR Sent %d bytes\n", bytes);
return 0;
}
@@ -270,18 +269,18 @@ static int fdr_ctrl_handshake(fdr_client_t fdr)
plist_t dict, node;
int res;
- debug("About to do ctrl handshake\n");
+ logger(LL_DEBUG, "About to do ctrl handshake\n");
ctrlprotoversion = 2;
device_error = idevice_connection_send(fdr->connection, CTRLCMD, len, &bytes);
if (device_error != IDEVICE_E_SUCCESS || bytes != len) {
- debug("Hmm... looks like the device doesn't like the newer protocol, using the old one\n");
+ logger(LL_DEBUG, "Hmm... looks like the device doesn't like the newer protocol, using the old one\n");
ctrlprotoversion = 1;
len = sizeof(HELLOCTRLCMD);
device_error = idevice_connection_send(fdr->connection, HELLOCTRLCMD, len, &bytes);
if (device_error != IDEVICE_E_SUCCESS || bytes != len) {
- error("ERROR: FDR unable to send BeginCtrl. Sent %u of %u bytes.\n", bytes, len);
+ logger(LL_ERROR, "FDR unable to send BeginCtrl. Sent %u of %u bytes.\n", bytes, len);
return -1;
}
}
@@ -293,21 +292,20 @@ static int fdr_ctrl_handshake(fdr_client_t fdr)
res = fdr_send_plist(fdr, dict);
plist_free(dict);
if (res) {
- error("ERROR: FDR could not send Begin command.\n");
+ logger(LL_ERROR, "FDR could not send Begin command.\n");
return -1;
}
if (fdr_receive_plist(fdr, &dict)) {
- error("ERROR: FDR did not get Begin command reply.\n");
+ logger(LL_ERROR, "FDR did not get Begin command reply.\n");
return -1;
}
- if (idevicerestore_debug)
- debug_plist(dict);
+ logger_dump_plist(LL_DEBUG, dict, 1);
node = plist_dict_get_item(dict, "ConnPort");
if (node && plist_get_node_type(node) == PLIST_UINT) {
plist_get_uint_val(node, &conn_port);
} else {
- error("ERROR: Could not get FDR ConnPort value\n");
+ logger(LL_ERROR, "Could not get FDR ConnPort value\n");
return -1;
}
@@ -321,26 +319,26 @@ static int fdr_ctrl_handshake(fdr_client_t fdr)
bytes = 0;
device_error = idevice_connection_receive(fdr->connection, buf, 10, &bytes);
if (device_error != IDEVICE_E_SUCCESS) {
- error("ERROR: Could not receive reply to HelloCtrl command\n");
+ logger(LL_ERROR, "Could not receive reply to HelloCtrl command\n");
return -1;
}
if (memcmp(buf, "HelloCtrl", 10) != 0) {
buf[9] = '\0';
- error("ERROR: Did not receive HelloCtrl as reply, but %s\n", buf);
+ logger(LL_ERROR, "Did not receive HelloCtrl as reply, but %s\n", buf);
return -1;
}
bytes = 0;
device_error = idevice_connection_receive(fdr->connection, (char*)&cport, 2, &bytes);
if (device_error != IDEVICE_E_SUCCESS) {
- error("ERROR: Failed to receive conn port\n");
+ logger(LL_ERROR, "Failed to receive conn port\n");
return -1;
}
conn_port = le16toh(cport);
}
- debug("Ctrl handshake done (ConnPort = %" PRIu64 ")\n", (uint64_t)conn_port);
+ logger(LL_DEBUG, "Ctrl handshake done (ConnPort = %" PRIu64 ")\n", (uint64_t)conn_port);
return 0;
}
@@ -353,13 +351,13 @@ static int fdr_sync_handshake(fdr_client_t fdr)
device_error = idevice_connection_send(fdr->connection, HELLOCMD, len, &bytes);
if (device_error != IDEVICE_E_SUCCESS || bytes != len) {
- error("ERROR: FDR unable to send Hello. Sent %u of %u bytes.\n", bytes, len);
+ logger(LL_ERROR, "FDR unable to send Hello. Sent %u of %u bytes.\n", bytes, len);
return -1;
}
if (ctrlprotoversion == 2) {
if (fdr_receive_plist(fdr, &reply)) {
- error("ERROR: FDR did not get HelloConn reply.\n");
+ logger(LL_ERROR, "FDR did not get HelloConn reply.\n");
return -1;
}
char* identifier = NULL;
@@ -382,13 +380,13 @@ static int fdr_sync_handshake(fdr_client_t fdr)
if (identifier) {
free(identifier);
}
- error("ERROR: Did not receive HelloConn reply...\n");
+ logger(LL_ERROR, "Did not receive HelloConn reply...\n");
return -1;
}
free(cmd);
if (identifier) {
- debug("Got device identifier %s\n", identifier);
+ logger(LL_DEBUG, "Got device identifier %s\n", identifier);
free(identifier);
}
@@ -398,12 +396,12 @@ static int fdr_sync_handshake(fdr_client_t fdr)
bytes = 0;
device_error = idevice_connection_receive(fdr->connection, buf, 10, &bytes);
if (device_error != IDEVICE_E_SUCCESS) {
- error("ERROR: Could not receive reply to HelloConn command\n");
+ logger(LL_ERROR, "Could not receive reply to HelloConn command\n");
return -1;
}
if (memcmp(buf, "HelloConn", 10) != 0) {
buf[9] = '\0';
- error("ERROR: Did not receive HelloConn as reply, but %s\n", buf);
+ logger(LL_ERROR, "Did not receive HelloConn as reply, but %s\n", buf);
return -1;
}
}
@@ -422,18 +420,18 @@ static int fdr_handle_sync_cmd(fdr_client_t fdr_ctrl)
device_error = idevice_connection_receive(fdr_ctrl->connection, buf, sizeof(buf), &bytes);
if (device_error != IDEVICE_E_SUCCESS || bytes != 2) {
- error("ERROR: Unexpected data from FDR\n");
+ logger(LL_ERROR, "Unexpected data from FDR\n");
return -1;
}
/* Open a new connection and wait for messages on it */
if (fdr_connect(fdr_ctrl->device, FDR_CONN, &fdr)) {
- error("ERROR: Failed to connect to FDR port\n");
+ logger(LL_ERROR, "Failed to connect to FDR port\n");
return -1;
}
- debug("FDR connected in reply to sync message, starting command thread\n");
+ logger(LL_DEBUG, "FDR connected in reply to sync message, starting command thread\n");
res = thread_new(&fdr_thread, fdr_listener_thread, fdr);
if(res) {
- error("ERROR: Failed to start FDR command thread\n");
+ logger(LL_ERROR, "Failed to start FDR command thread\n");
fdr_free(fdr);
}
return res;
@@ -445,12 +443,12 @@ static int fdr_handle_plist_cmd(fdr_client_t fdr)
plist_t dict;
if (fdr_receive_plist(fdr, &dict)) {
- error("ERROR: FDR %p could not receive plist command.\n", fdr);
+ logger(LL_ERROR, "FDR %p could not receive plist command.\n", fdr);
return -1;
}
plist_t node = plist_dict_get_item(dict, "Command");
if (!node || (plist_get_node_type(node) != PLIST_STRING)) {
- error("ERROR: FDR %p Could not find Command in plist command\n", fdr);
+ logger(LL_ERROR, "FDR %p Could not find Command in plist command\n", fdr);
plist_free(dict);
return -1;
}
@@ -459,7 +457,7 @@ static int fdr_handle_plist_cmd(fdr_client_t fdr)
plist_free(dict);
if (!command) {
- info("FDR %p received empty plist command\n", fdr);
+ logger(LL_INFO, "FDR %p received empty plist command\n", fdr);
return -1;
}
@@ -469,12 +467,12 @@ static int fdr_handle_plist_cmd(fdr_client_t fdr)
res = fdr_send_plist(fdr, dict);
plist_free(dict);
if (res) {
- error("ERROR: FDR %p could not send Ping command reply.\n", fdr);
+ logger(LL_ERROR, "FDR %p could not send Ping command reply.\n", fdr);
free(command);
return -1;
}
} else {
- error("WARNING: FDR %p received unknown plist command: %s\n", fdr, command);
+ logger(LL_WARNING, "FDR %p received unknown plist command: %s\n", fdr, command);
free(command);
return -1;
}
@@ -495,17 +493,17 @@ static int fdr_handle_proxy_cmd(fdr_client_t fdr)
buf = malloc(bufsize);
if (!buf) {
- error("ERROR: %s: malloc failed\n", __func__);
+ logger(LL_ERROR, "%s: malloc failed\n", __func__);
return -1;
}
device_error = idevice_connection_receive(fdr->connection, buf, bufsize, &bytes);
if (device_error != IDEVICE_E_SUCCESS) {
free(buf);
- error("ERROR: FDR %p failed to read data for proxy command\n", fdr);
+ logger(LL_ERROR, "FDR %p failed to read data for proxy command\n", fdr);
return -1;
}
- debug("Got proxy command with %u bytes\n", bytes);
+ logger(LL_DEBUG, "Got proxy command with %u bytes\n", bytes);
/* Just return success here unconditionally because we don't know
* anything else and we will eventually abort on failure anyway */
@@ -513,13 +511,13 @@ static int fdr_handle_proxy_cmd(fdr_client_t fdr)
device_error = idevice_connection_send(fdr->connection, (char *)&ack, sizeof(ack), &sent);
if (device_error != IDEVICE_E_SUCCESS || sent != sizeof(ack)) {
free(buf);
- error("ERROR: FDR %p unable to send ack. Sent %u of %u bytes.\n",
+ logger(LL_ERROR, "FDR %p unable to send ack. Sent %u of %u bytes.\n",
fdr, sent, (uint32_t)sizeof(ack));
return -1;
}
if (bytes < 3) {
- debug("FDR %p proxy command data too short, retrying\n", fdr);
+ logger(LL_DEBUG, "FDR %p proxy command data too short, retrying\n", fdr);
return fdr_poll_and_handle_message(fdr);
}
@@ -527,7 +525,7 @@ static int fdr_handle_proxy_cmd(fdr_client_t fdr)
device_error = idevice_connection_send(fdr->connection, buf, bytes, &sent);
if (device_error != IDEVICE_E_SUCCESS || sent != bytes) {
free(buf);
- error("ERROR: FDR %p unable to send data. Sent %u of %u bytes.\n",
+ logger(LL_ERROR, "FDR %p unable to send data. Sent %u of %u bytes.\n",
fdr, sent, bytes);
return -1;
}
@@ -539,7 +537,7 @@ static int fdr_handle_proxy_cmd(fdr_client_t fdr)
port = be16toh(*p);
buf[bytes - 2] = '\0';
host = strdup(&buf[3]);
- debug("FDR %p Proxy connect request to %s:%u\n", fdr, host, port);
+ logger(LL_DEBUG, "FDR %p Proxy connect request to %s:%u\n", fdr, host, port);
}
if (!host || !buf[2]) {
@@ -553,7 +551,7 @@ static int fdr_handle_proxy_cmd(fdr_client_t fdr)
free(host);
if (sockfd < 0) {
free(buf);
- error("ERROR: Failed to connect socket: %s\n", strerror(errno));
+ logger(LL_ERROR, "Failed to connect socket: %s\n", strerror(errno));
return -1;
}
@@ -567,16 +565,16 @@ static int fdr_handle_proxy_cmd(fdr_client_t fdr)
if (device_error == IDEVICE_E_SUCCESS && !bytes)
#endif
{
- //debug("WARNING: Timeout waiting for proxy payload. %p\n", fdr);
+ //logger(LL_DEBUG, "Timeout waiting for proxy payload. %p\n", fdr);
}
else if (device_error != IDEVICE_E_SUCCESS) {
- error("ERROR: FDR %p Unable to receive proxy payload (%d)\n", fdr, device_error);
+ logger(LL_ERROR, "FDR %p Unable to receive proxy payload (%d)\n", fdr, device_error);
res = -1;
break;
}
if (bytes) {
- debug("FDR %p got payload of %u bytes, now try to proxy it\n", fdr, bytes);
- debug("Sending %u bytes of data\n", bytes);
+ logger(LL_DEBUG, "FDR %p got payload of %u bytes, now trying to proxy it\n", fdr, bytes);
+ logger(LL_DEBUG, "Sending %u bytes of data\n", bytes);
sent = 0;
while (sent < bytes) {
int s = socket_send(sockfd, buf + sent, bytes - sent);
@@ -586,7 +584,7 @@ static int fdr_handle_proxy_cmd(fdr_client_t fdr)
sent += s;
}
if (sent != bytes) {
- error("ERROR: Sending proxy payload failed: %s. Sent %u of %u bytes. \n", strerror(errno), sent, bytes);
+ logger(LL_ERROR, "Sending proxy payload failed: %s. Sent %u of %u bytes. \n", strerror(errno), sent, bytes);
socket_close(sockfd);
res = -1;
break;
@@ -599,14 +597,14 @@ static int fdr_handle_proxy_cmd(fdr_client_t fdr)
res = 1;
break;
} else if (bytes_ret < 0) {
- error("ERROR: FDR %p receiving proxy payload failed: %d (%s)\n",
+ logger(LL_ERROR, "FDR %p receiving proxy payload failed: %d (%s)\n",
fdr, bytes_ret, strerror(-bytes_ret));
break;
}
bytes = bytes_ret;
if (bytes) {
- debug("FDR %p Received %u bytes reply data,%s sending to device\n",
+ logger(LL_DEBUG, "FDR %p Received %u bytes reply data,%s sending to device\n",
fdr, bytes, (bytes ? "" : " not"));
sent = 0;
@@ -619,7 +617,7 @@ static int fdr_handle_proxy_cmd(fdr_client_t fdr)
sent += s;
}
if (device_error != IDEVICE_E_SUCCESS || bytes != sent) {
- error("ERROR: FDR %p unable to send data (%d). Sent %u of %u bytes.\n", fdr, device_error, sent, bytes);
+ logger(LL_ERROR, "FDR %p unable to send data (%d). Sent %u of %u bytes.\n", fdr, device_error, sent, bytes);
res = -1;
break;
}
diff --git a/src/fixedint.h b/src/fixedint.h
deleted file mode 100644
index 1a8745b..0000000
--- a/src/fixedint.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- Portable header to provide the 32 and 64 bits type.
-
- Not a compatible replacement for <stdint.h>, do not blindly use it as such.
-*/
-
-#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(__WATCOMC__) && (defined(_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_) || defined(__UINT_FAST64_TYPE__)) )) && !defined(FIXEDINT_H_INCLUDED)
- #include <stdint.h>
- #define FIXEDINT_H_INCLUDED
-
- #if defined(__WATCOMC__) && __WATCOMC__ >= 1250 && !defined(UINT64_C)
- #include <limits.h>
- #define UINT64_C(x) (x + (UINT64_MAX - UINT64_MAX))
- #endif
-#endif
-
-
-#ifndef FIXEDINT_H_INCLUDED
- #define FIXEDINT_H_INCLUDED
-
- #include <limits.h>
-
- /* (u)int32_t */
- #ifndef uint32_t
- #if (ULONG_MAX == 0xffffffffUL)
- typedef unsigned long uint32_t;
- #elif (UINT_MAX == 0xffffffffUL)
- typedef unsigned int uint32_t;
- #elif (USHRT_MAX == 0xffffffffUL)
- typedef unsigned short uint32_t;
- #endif
- #endif
-
-
- #ifndef int32_t
- #if (LONG_MAX == 0x7fffffffL)
- typedef signed long int32_t;
- #elif (INT_MAX == 0x7fffffffL)
- typedef signed int int32_t;
- #elif (SHRT_MAX == 0x7fffffffL)
- typedef signed short int32_t;
- #endif
- #endif
-
-
- /* (u)int64_t */
- #if (defined(__STDC__) && defined(__STDC_VERSION__) && __STDC__ && __STDC_VERSION__ >= 199901L)
- typedef long long int64_t;
- typedef unsigned long long uint64_t;
-
- #define UINT64_C(v) v ##ULL
- #define INT64_C(v) v ##LL
- #elif defined(__GNUC__)
- __extension__ typedef long long int64_t;
- __extension__ typedef unsigned long long uint64_t;
-
- #define UINT64_C(v) v ##ULL
- #define INT64_C(v) v ##LL
- #elif defined(__MWERKS__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__APPLE_CC__) || defined(_LONG_LONG) || defined(_CRAYC)
- typedef long long int64_t;
- typedef unsigned long long uint64_t;
-
- #define UINT64_C(v) v ##ULL
- #define INT64_C(v) v ##LL
- #elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined(__BORLANDC__) && __BORLANDC__ > 0x460) || defined(__alpha) || defined(__DECC)
- typedef __int64 int64_t;
- typedef unsigned __int64 uint64_t;
-
- #define UINT64_C(v) v ##UI64
- #define INT64_C(v) v ##I64
- #endif
-#endif
diff --git a/src/fls.c b/src/fls.c
index f422447..8b747a9 100644
--- a/src/fls.c
+++ b/src/fls.c
@@ -96,12 +96,12 @@ static void fls_parse_elements(fls_file* fls)
offset += cur->size;
} while (offset < fls->size);
if (offset != fls->size) {
- error("ERROR: %s: error parsing elements\n", __func__);
+ logger(LL_ERROR, "%s: error parsing elements\n", __func__);
return;
}
}
-fls_file* fls_parse(unsigned char* data, unsigned int size)
+fls_file* fls_parse(const void* data, size_t size)
{
fls_file* fls = (fls_file*)malloc(sizeof(fls_file));
if (!fls) {
@@ -132,37 +132,37 @@ void fls_free(fls_file* fls)
}
}
-int fls_update_sig_blob(fls_file* fls, const unsigned char* sigdata, unsigned int siglen)
+int fls_update_sig_blob(fls_file* fls, const void* sigdata, size_t siglen)
{
/* FIXME: the code in this function is not big endian safe */
if (!fls || !fls->num_elements) {
- error("ERROR: %s: no data\n", __func__);
+ logger(LL_ERROR, "%s: no data\n", __func__);
return -1;
}
if (!fls->c_element) {
- error("ERROR: %s: no fls_0c_element in fls data\n", __func__);
+ logger(LL_ERROR, "%s: no fls_0c_element in fls data\n", __func__);
return -1;
}
uint32_t datasize = *(uint32_t*)(fls->c_element->data + 0x10);
if (datasize != fls->c_element->data_size) {
- error("ERROR: %s: data size mismatch (0x%x != 0x%x)\n", __func__, datasize, fls->c_element->data_size);
+ logger(LL_ERROR, "%s: data size mismatch (0x%x != 0x%x)\n", __func__, datasize, fls->c_element->data_size);
return -1;
}
uint32_t sigoffset = *(uint32_t*)(fls->c_element->data + 0x14);
if (sigoffset > datasize) {
- error("ERROR: %s: signature offset greater than data size (0x%x > 0x%x)\n", __func__, sigoffset, datasize);
+ logger(LL_ERROR, "%s: signature offset greater than data size (0x%x > 0x%x)\n", __func__, sigoffset, datasize);
return -1;
}
- uint32_t oldsiglen = datasize - sigoffset;
- uint32_t newsize = fls->size - oldsiglen + siglen;
+ size_t oldsiglen = datasize - sigoffset;
+ size_t newsize = fls->size - oldsiglen + siglen;
unsigned int i;
uint32_t offset = 0;
void* newdata = malloc(newsize);
if (!newdata) {
- error("ERROR: %s: out of memory\n", __func__);
+ logger(LL_ERROR, "%s: out of memory\n", __func__);
return -1;
}
uint32_t hdrsize = 0;
@@ -239,15 +239,15 @@ int fls_update_sig_blob(fls_file* fls, const unsigned char* sigdata, unsigned in
return 0;
}
-int fls_insert_ticket(fls_file* fls, const unsigned char* data, unsigned int size)
+int fls_insert_ticket(fls_file* fls, const void* data, size_t size)
{
/* FIXME: the code in this function is not big endian safe */
if (!fls || !fls->num_elements) {
- error("ERROR: %s: no data\n", __func__);
+ logger(LL_ERROR, "%s: no data\n", __func__);
return -1;
}
if (!fls->c_element) {
- error("ERROR: %s: no fls_0c_element in fls data\n", __func__);
+ logger(LL_ERROR, "%s: no fls_0c_element in fls data\n", __func__);
return -1;
}
@@ -255,12 +255,12 @@ int fls_insert_ticket(fls_file* fls, const unsigned char* data, unsigned int siz
if (size%4 != 0) {
padding = 4-(size%4);
}
- uint32_t newsize = fls->size + size + padding;
+ size_t newsize = fls->size + size + padding;
unsigned int i;
uint32_t offset = 0;
void* newdata = malloc(newsize);
if (!newdata) {
- error("ERROR: %s: out of memory\n", __func__);
+ logger(LL_ERROR, "%s: out of memory\n", __func__);
return -1;
}
uint32_t hdrsize = 0;
diff --git a/src/fls.h b/src/fls.h
index 57b3869..2db9029 100644
--- a/src/fls.h
+++ b/src/fls.h
@@ -74,12 +74,12 @@ typedef struct {
fls_element** elements;
const fls_0c_element* c_element;
void* data;
- uint32_t size;
+ size_t size;
} fls_file;
-fls_file* fls_parse(unsigned char* data, unsigned int size);
+fls_file* fls_parse(const void* data, size_t size);
void fls_free(fls_file* fls);
-int fls_update_sig_blob(fls_file* fls, const unsigned char* data, unsigned int size);
-int fls_insert_ticket(fls_file* fls, const unsigned char* data, unsigned int size);
+int fls_update_sig_blob(fls_file* fls, const void* data, size_t size);
+int fls_insert_ticket(fls_file* fls, const void* data, size_t size);
#endif
diff --git a/src/ftab.c b/src/ftab.c
index 8515d1f..d0fc26b 100644
--- a/src/ftab.c
+++ b/src/ftab.c
@@ -28,20 +28,20 @@
#include "common.h"
#include "endianness.h"
-int ftab_parse(unsigned char *data, unsigned int data_size, ftab_t *ftab, uint32_t *tag)
+int ftab_parse(const void *data, size_t data_size, ftab_t *ftab, uint32_t *tag)
{
if (!data || !data_size || !ftab) {
return -1;
}
if (data_size < sizeof(struct ftab_header)) {
- error("ERROR: %s: Buffer too small for ftab data\n", __func__);
+ logger(LL_ERROR, "%s: Buffer too small for ftab data\n", __func__);
return -1;
}
struct ftab_header *hdr_ptr = (struct ftab_header*)data;
if (be32toh(hdr_ptr->magic) != 'ftab') {
- error("ERROR: %s: Unexpected magic value 0x%08x\n", __func__, le32toh(hdr_ptr->magic));
+ logger(LL_ERROR, "%s: Unexpected magic value 0x%08x\n", __func__, le32toh(hdr_ptr->magic));
return -1;
}
@@ -81,7 +81,7 @@ int ftab_parse(unsigned char *data, unsigned int data_size, ftab_t *ftab, uint32
return 0;
}
-int ftab_get_entry_ptr(ftab_t ftab, uint32_t tag, unsigned char **data, unsigned int *data_size)
+int ftab_get_entry_ptr(ftab_t ftab, uint32_t tag, void **data, size_t *data_size)
{
if (!ftab || !tag || !data || !data_size) {
return -1;
@@ -99,7 +99,7 @@ int ftab_get_entry_ptr(ftab_t ftab, uint32_t tag, unsigned char **data, unsigned
return res;
}
-int ftab_add_entry(ftab_t ftab, uint32_t tag, unsigned char *data, unsigned int data_size)
+int ftab_add_entry(ftab_t ftab, uint32_t tag, const void *data, size_t data_size)
{
if (!ftab || !tag || !data || !data_size) {
return -1;
@@ -108,13 +108,13 @@ int ftab_add_entry(ftab_t ftab, uint32_t tag, unsigned char *data, unsigned int
uint32_t new_index = ftab->header.num_entries;
struct ftab_entry *new_entries = realloc(ftab->entries, sizeof(struct ftab_entry) * (ftab->header.num_entries + 1));
if (!new_entries) {
- error("ERROR: %s: realloc failed!\n", __func__);
+ logger(LL_ERROR, "%s: realloc failed!\n", __func__);
return -1;
}
ftab->entries = new_entries;
unsigned char **new_storage = realloc(ftab->storage, sizeof(unsigned char*) * (ftab->header.num_entries + 1));
if (!new_storage) {
- error("ERROR: %s: realloc failed!\n", __func__);
+ logger(LL_ERROR, "%s: realloc failed!\n", __func__);
return -1;
}
ftab->storage = new_storage;
@@ -140,7 +140,7 @@ int ftab_add_entry(ftab_t ftab, uint32_t tag, unsigned char *data, unsigned int
return 0;
}
-int ftab_write(ftab_t ftab, unsigned char **data, unsigned int *data_size)
+int ftab_write(ftab_t ftab, void **data, size_t *data_size)
{
uint32_t i;
unsigned int total_size = sizeof(struct ftab_header);
@@ -151,7 +151,7 @@ int ftab_write(ftab_t ftab, unsigned char **data, unsigned int *data_size)
unsigned char *data_out = (unsigned char*)malloc(total_size);
if (!data_out) {
- error("ERROR: %s: Out of memory?!\n", __func__);
+ logger(LL_ERROR, "%s: Out of memory?!\n", __func__);
return -1;
}
diff --git a/src/ftab.h b/src/ftab.h
index a6ec6a4..d5d4d92 100644
--- a/src/ftab.h
+++ b/src/ftab.h
@@ -58,10 +58,10 @@ struct ftab_fmt {
typedef struct ftab_fmt *ftab_t;
-int ftab_parse(unsigned char *data, unsigned int data_size, ftab_t *ftab, uint32_t *tag);
-int ftab_get_entry_ptr(ftab_t ftab, uint32_t tag, unsigned char **data, unsigned int *data_size);
-int ftab_add_entry(ftab_t ftab, uint32_t tag, unsigned char *data, unsigned int data_size);
-int ftab_write(ftab_t ftab, unsigned char **data, unsigned int *data_size);
+int ftab_parse(const void *data, size_t data_size, ftab_t *ftab, uint32_t *tag);
+int ftab_get_entry_ptr(ftab_t ftab, uint32_t tag, void **data, size_t *data_size);
+int ftab_add_entry(ftab_t ftab, uint32_t tag, const void *data, size_t data_size);
+int ftab_write(ftab_t ftab, void **data, size_t *data_size);
int ftab_free(ftab_t ftab);
#ifdef __cplusplus
diff --git a/src/idevicerestore.c b/src/idevicerestore.c
index 017b45c..04070a1 100644
--- a/src/idevicerestore.c
+++ b/src/idevicerestore.c
@@ -38,15 +38,13 @@
#include <curl/curl.h>
-#ifdef HAVE_OPENSSL
-#include <openssl/sha.h>
-#else
-#include "sha512.h"
-#define SHA384 sha384
-#endif
+#include <libimobiledevice-glue/sha.h>
+#include <libimobiledevice-glue/utils.h>
+#include <libimobiledevice-glue/termcolors.h>
+#include <libtatsu/tss.h>
+#include "ace3.h"
#include "dfu.h"
-#include "tss.h"
#include "img3.h"
#include "img4.h"
#include "ipsw.h"
@@ -57,7 +55,9 @@
#include "recovery.h"
#include "idevicerestore.h"
+#ifdef HAVE_LIMERA1N
#include "limera1n.h"
+#endif
#include "locking.h"
@@ -72,11 +72,13 @@ static struct option longopts[] = {
{ "erase", no_argument, NULL, 'e' },
{ "custom", no_argument, NULL, 'c' },
{ "latest", no_argument, NULL, 'l' },
- { "cydia", no_argument, NULL, 's' },
+ { "server", required_argument, NULL, 's' },
{ "exclude", no_argument, NULL, 'x' },
{ "shsh", no_argument, NULL, 't' },
{ "keep-pers", no_argument, NULL, 'k' },
+#ifdef HAVE_LIMERA1N
{ "pwn", no_argument, NULL, 'p' },
+#endif
{ "no-action", no_argument, NULL, 'n' },
{ "cache-path", required_argument, NULL, 'C' },
{ "no-input", no_argument, NULL, 'y' },
@@ -87,11 +89,18 @@ static struct option longopts[] = {
{ "version", no_argument, NULL, 'v' },
{ "ipsw-info", no_argument, NULL, 'I' },
{ "ignore-errors", no_argument, NULL, 1 },
+ { "variant", required_argument, NULL, 2 },
+ { "logfile", required_argument, NULL, 3 },
{ NULL, 0, NULL, 0 }
};
static void usage(int argc, char* argv[], int err)
{
+#ifdef HAVE_LIMERA1N
+#define PWN_FLAG_LINE " -p, --pwn Put device in pwned DFU mode and exit (limera1n devices)\n"
+#else
+#define PWN_FLAG_LINE ""
+#endif
char* name = strrchr(argv[0], '/');
fprintf((err) ? stderr : stdout,
"Usage: %s [OPTIONS] PATH\n" \
@@ -126,20 +135,24 @@ static void usage(int argc, char* argv[], int err)
" -h, --help Prints this usage information\n" \
" -C, --cache-path DIR Use specified directory for caching extracted or other\n" \
" reused files.\n" \
- " -d, --debug Enable communication debugging\n" \
+ " --logfile=PATH Write logging output to file at PATH. If PATH equals\n" \
+ " 'NULL' or 'NONE', no log file will be written.\n" \
+ " -d, --debug Print additional debug output\n" \
" -v, --version Print version information\n" \
"\n" \
"Advanced/experimental options:\n"
" -c, --custom Restore with a custom firmware (requires bootrom exploit)\n" \
- " -s, --cydia Use Cydia's signature service instead of Apple's\n" \
- " -x, --exclude Exclude nor/baseband upgrade\n" \
+ " -s, --server URL Override default signing server request URL\n" \
+ " -x, --exclude Exclude nor/baseband upgrade (legacy devices)\n" \
" -t, --shsh Fetch TSS record and save to .shsh file, then exit\n" \
" -z, --no-restore Do not restore and end after booting to the ramdisk\n" \
" -k, --keep-pers Write personalized components to files for debugging\n" \
- " -p, --pwn Put device in pwned DFU mode and exit (limera1n devices)\n" \
+ PWN_FLAG_LINE \
" -P, --plain-progress Print progress as plain step and progress\n" \
" -R, --restore-mode Allow restoring from Restore mode\n" \
" -T, --ticket PATH Use file at PATH to send as AP ticket\n" \
+ " --variant VARIANT Use given VARIANT to match the build identity to use,\n" \
+ " e.g. 'Customer Erase Install (IPSW)'\n" \
" --ignore-errors Try to continue the restore process after certain\n" \
" errors (like a failed baseband update)\n" \
" WARNING: This might render the device unable to boot\n" \
@@ -158,8 +171,6 @@ const uint8_t lpol_file[22] = {
};
const uint32_t lpol_file_length = 22;
-static int idevicerestore_keep_pers = 0;
-
static int load_version_data(struct idevicerestore_client_t* client)
{
if (!client) {
@@ -190,9 +201,9 @@ static int load_version_data(struct idevicerestore_client_t* client)
if (download_to_file("http://itunes.apple.com/check/version", version_xml_tmp, 0) == 0) {
remove(version_xml);
if (rename(version_xml_tmp, version_xml) < 0) {
- error("ERROR: Could not update '%s'\n", version_xml);
+ logger(LL_ERROR, "Could not update '%s'\n", version_xml);
} else {
- info("NOTE: Updated version data.\n");
+ logger(LL_INFO, "Updated version data.\n");
}
}
} else {
@@ -204,7 +215,7 @@ static int load_version_data(struct idevicerestore_client_t* client)
read_file(version_xml, (void**)&verbuf, &verlen);
if (!verbuf) {
- error("ERROR: Could not load '%s'\n", version_xml);
+ logger(LL_ERROR, "Could not load '%s'\n", version_xml);
return -1;
}
@@ -214,12 +225,12 @@ static int load_version_data(struct idevicerestore_client_t* client)
if (!client->version_data) {
remove(version_xml);
- error("ERROR: Cannot parse plist data from '%s'.\n", version_xml);
+ logger(LL_ERROR, "Cannot parse plist data from '%s'.\n", version_xml);
return -1;
}
if (cached) {
- info("NOTE: using cached version data\n");
+ logger(LL_INFO, "Using cached version data\n");
}
return 0;
@@ -255,21 +266,24 @@ static void idevice_event_cb(const idevice_event_t *event, void *userdata)
if (normal_check_mode(client) == 0) {
mutex_lock(&client->device_event_mutex);
client->mode = MODE_NORMAL;
- debug("%s: device %016" PRIx64 " (udid: %s) connected in normal mode\n", __func__, client->ecid, client->udid);
+ logger(LL_DEBUG, "%s: device %016" PRIx64 " (udid: %s) connected in normal mode\n", __func__, client->ecid, client->udid);
cond_signal(&client->device_event_cond);
mutex_unlock(&client->device_event_mutex);
} else if (client->ecid && restore_check_mode(client) == 0) {
mutex_lock(&client->device_event_mutex);
client->mode = MODE_RESTORE;
- debug("%s: device %016" PRIx64 " (udid: %s) connected in restore mode\n", __func__, client->ecid, client->udid);
+ logger(LL_DEBUG, "%s: device %016" PRIx64 " (udid: %s) connected in restore mode\n", __func__, client->ecid, client->udid);
cond_signal(&client->device_event_cond);
mutex_unlock(&client->device_event_mutex);
}
+ if (!client->device) {
+ client->device = get_irecv_device(client);
+ }
} else if (event->event == IDEVICE_DEVICE_REMOVE) {
if (client->udid && !strcmp(event->udid, client->udid)) {
mutex_lock(&client->device_event_mutex);
client->mode = MODE_UNKNOWN;
- debug("%s: device %016" PRIx64 " (udid: %s) disconnected\n", __func__, client->ecid, client->udid);
+ logger(LL_DEBUG, "%s: device %016" PRIx64 " (udid: %s) disconnected\n", __func__, client->ecid, client->udid);
client->ignore_device_add_events = 0;
cond_signal(&client->device_event_cond);
mutex_unlock(&client->device_event_mutex);
@@ -293,6 +307,9 @@ static void irecv_event_cb(const irecv_device_event_t* event, void *userdata)
case IRECV_K_DFU_MODE:
client->mode = MODE_DFU;
break;
+ case IRECV_K_PORT_DFU_MODE:
+ client->mode = MODE_PORTDFU;
+ break;
case IRECV_K_RECOVERY_MODE_1:
case IRECV_K_RECOVERY_MODE_2:
case IRECV_K_RECOVERY_MODE_3:
@@ -302,7 +319,10 @@ static void irecv_event_cb(const irecv_device_event_t* event, void *userdata)
default:
client->mode = MODE_UNKNOWN;
}
- debug("%s: device %016" PRIx64 " (udid: %s) connected in %s mode\n", __func__, client->ecid, (client->udid) ? client->udid : "N/A", client->mode->string);
+ logger(LL_DEBUG, "%s: device %016" PRIx64 " (udid: %s) connected in %s mode\n", __func__, client->ecid, (client->udid) ? client->udid : "N/A", client->mode->string);
+ if (!client->device) {
+ client->device = get_irecv_device(client);
+ }
cond_signal(&client->device_event_cond);
mutex_unlock(&client->device_event_mutex);
}
@@ -310,13 +330,21 @@ static void irecv_event_cb(const irecv_device_event_t* event, void *userdata)
if (client->ecid && event->device_info->ecid == client->ecid) {
mutex_lock(&client->device_event_mutex);
client->mode = MODE_UNKNOWN;
- debug("%s: device %016" PRIx64 " (udid: %s) disconnected\n", __func__, client->ecid, (client->udid) ? client->udid : "N/A");
+ logger(LL_DEBUG, "%s: device %016" PRIx64 " (udid: %s) disconnected\n", __func__, client->ecid, (client->udid) ? client->udid : "N/A");
+ if (event->mode == IRECV_K_PORT_DFU_MODE) {
+ // We have to reset the ECID here if a port DFU device disconnects,
+ // because when the device reconnects in a different mode, it will
+ // have the actual device ECID and wouldn't get detected.
+ client->ecid = 0;
+ }
cond_signal(&client->device_event_cond);
mutex_unlock(&client->device_event_mutex);
}
}
}
+int build_identity_check_components_in_ipsw(plist_t build_identity, ipsw_archive_t ipsw);
+
int idevicerestore_start(struct idevicerestore_client_t* client)
{
int tss_enabled = 0;
@@ -327,27 +355,38 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
}
if ((client->flags & FLAG_LATEST) && (client->flags & FLAG_CUSTOM)) {
- error("ERROR: FLAG_LATEST cannot be used with FLAG_CUSTOM.\n");
+ logger(LL_ERROR, "FLAG_LATEST cannot be used with FLAG_CUSTOM.\n");
return -1;
}
if (!client->ipsw && !(client->flags & FLAG_PWN) && !(client->flags & FLAG_LATEST)) {
- error("ERROR: no ipsw file given\n");
+ logger(LL_ERROR, "no ipsw file given\n");
return -1;
}
- if (client->flags & FLAG_DEBUG) {
- idevice_set_debug_level(1);
- irecv_set_debug_level(1);
+ if (client->debug_level > 0) {
idevicerestore_debug = 1;
+ if (client->debug_level > 1) {
+ irecv_set_debug_level(1);
+ }
+ if (client->debug_level > 2) {
+ idevice_set_debug_level(1);
+ }
+ tss_set_debug_level(client->debug_level);
}
+ progress_reset_tag();
+
idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.0);
- irecv_device_event_subscribe(&client->irecv_e_ctx, irecv_event_cb, client);
+ if (!client->irecv_e_ctx) {
+ irecv_device_event_subscribe(&client->irecv_e_ctx, irecv_event_cb, client);
+ }
- idevice_event_subscribe(idevice_event_cb, client);
- client->idevice_e_ctx = idevice_event_cb;
+ if (!client->idevice_e_ctx) {
+ idevice_event_subscribe(idevice_event_cb, client);
+ client->idevice_e_ctx = idevice_event_cb;
+ }
// check which mode the device is currently in so we know where to start
mutex_lock(&client->device_event_mutex);
@@ -355,31 +394,31 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000);
if (client->mode == MODE_UNKNOWN || (client->flags & FLAG_QUIT)) {
mutex_unlock(&client->device_event_mutex);
- error("ERROR: Unable to discover device mode. Please make sure a device is attached.\n");
+ logger(LL_ERROR, "Unable to discover device mode. Please make sure a device is attached.\n");
return -1;
}
}
idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.1);
- info("Found device in %s mode\n", client->mode->string);
+ logger(LL_INFO, "Found device in %s mode\n", client->mode->string);
mutex_unlock(&client->device_event_mutex);
if (client->mode == MODE_WTF) {
unsigned int cpid = 0;
if (dfu_client_new(client) != 0) {
- error("ERROR: Could not open device in WTF mode\n");
+ logger(LL_ERROR, "Could not open device in WTF mode\n");
return -1;
}
if ((dfu_get_cpid(client, &cpid) < 0) || (cpid == 0)) {
- error("ERROR: Could not get CPID for WTF mode device\n");
+ logger(LL_ERROR, "Could not get CPID for WTF mode device\n");
dfu_client_free(client);
return -1;
}
char wtfname[256];
- sprintf(wtfname, "Firmware/dfu/WTF.s5l%04xxall.RELEASE.dfu", cpid);
- unsigned char* wtftmp = NULL;
- unsigned int wtfsize = 0;
+ snprintf(wtfname, sizeof(wtfname), "Firmware/dfu/WTF.s5l%04xxall.RELEASE.dfu", cpid);
+ void* wtftmp = NULL;
+ size_t wtfsize = 0;
// Prefer to get WTF file from the restore IPSW
ipsw_extract_to_memory(client->ipsw, wtfname, &wtftmp, &wtfsize);
@@ -394,7 +433,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
plist_get_string_val(wtfurl, &s_wtfurl);
}
if (!s_wtfurl) {
- info("Using hardcoded x12220000_5_Recovery.ipsw URL\n");
+ logger(LL_INFO, "Using hardcoded x12220000_5_Recovery.ipsw URL\n");
s_wtfurl = strdup("http://appldnld.apple.com.edgesuite.net/content.info.apple.com/iPhone/061-6618.20090617.Xse7Y/x12220000_5_Recovery.ipsw");
}
@@ -421,16 +460,18 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
download_to_file(s_wtfurl, wtfipsw, 0);
}
- ipsw_extract_to_memory(wtfipsw, wtfname, &wtftmp, &wtfsize);
+ ipsw_archive_t wtf_ipsw = ipsw_open(wtfipsw);
+ ipsw_extract_to_memory(wtf_ipsw, wtfname, &wtftmp, &wtfsize);
+ ipsw_close(wtf_ipsw);
if (!wtftmp) {
- error("ERROR: Could not extract WTF\n");
+ logger(LL_ERROR, "Could not extract WTF\n");
}
}
mutex_lock(&client->device_event_mutex);
if (wtftmp) {
if (dfu_send_buffer(client, wtftmp, wtfsize) != 0) {
- error("ERROR: Could not send WTF...\n");
+ logger(LL_ERROR, "Could not send WTF...\n");
}
}
dfu_client_free(client);
@@ -441,7 +482,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
if (client->mode != MODE_DFU || (client->flags & FLAG_QUIT)) {
mutex_unlock(&client->device_event_mutex);
/* TODO: verify if it actually goes from 0x1222 -> 0x1227 */
- error("ERROR: Failed to put device into DFU from WTF mode\n");
+ logger(LL_ERROR, "Failed to put device into DFU from WTF mode\n");
return -1;
}
mutex_unlock(&client->device_event_mutex);
@@ -450,40 +491,70 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
// discover the device type
client->device = get_irecv_device(client);
if (client->device == NULL) {
- error("ERROR: Unable to discover device type\n");
+ logger(LL_ERROR, "Unable to discover device type\n");
return -1;
}
+ if (client->ecid == 0) {
+ logger(LL_ERROR, "Unable to determine ECID\n");
+ return -1;
+ }
+ logger(LL_INFO, "ECID: %" PRIu64 "\n", client->ecid);
+
idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.2);
- info("Identified device as %s, %s\n", client->device->hardware_model, client->device->product_type);
+ logger(LL_INFO, "Identified device as %s, %s\n", client->device->hardware_model, client->device->product_type);
if ((client->flags & FLAG_PWN) && (client->mode != MODE_DFU)) {
- error("ERROR: you need to put your device into DFU mode to pwn it.\n");
+ logger(LL_ERROR, "you need to put your device into DFU mode to pwn it.\n");
return -1;
}
+ if (client->mode == MODE_NORMAL) {
+ plist_t pver = normal_get_lockdown_value(client, NULL, "ProductVersion");
+ if (pver) {
+ plist_get_string_val(pver, &client->device_version);
+ plist_free(pver);
+ }
+ pver = normal_get_lockdown_value(client, NULL, "BuildVersion");
+ if (pver) {
+ plist_get_string_val(pver, &client->device_build);
+ plist_free(pver);
+ }
+ }
+ logger(LL_INFO, "Device Product Version: %s\n", (client->device_version) ? client->device_version : "N/A");
+ logger(LL_INFO, "Device Product Build: %s\n", (client->device_build) ? client->device_build : "N/A");
+
if (client->flags & FLAG_PWN) {
+#ifdef HAVE_LIMERA1N
recovery_client_free(client);
if (client->mode != MODE_DFU) {
- error("ERROR: Device needs to be in DFU mode for this option.\n");
+ logger(LL_ERROR, "Device needs to be in DFU mode for this option.\n");
return -1;
}
- info("connecting to DFU\n");
+ logger(LL_INFO, "connecting to DFU\n");
if (dfu_client_new(client) < 0) {
return -1;
}
- info("exploiting with limera1n...\n");
- // TODO: check for non-limera1n device and fail
- if (limera1n_exploit(client->device, &client->dfu->client) != 0) {
- error("ERROR: limera1n exploit failed\n");
+
+ if (limera1n_is_supported(client->device)) {
+ logger(LL_INFO, "exploiting with limera1n...\n");
+ if (limera1n_exploit(client->device, &client->dfu->client) != 0) {
+ logger(LL_ERROR, "limera1n exploit failed\n");
+ dfu_client_free(client);
+ return -1;
+ }
+ dfu_client_free(client);
+ logger(LL_INFO, "Device should be in pwned DFU state now.\n");
+
+ return 0;
+ }
+ else {
dfu_client_free(client);
+ logger(LL_ERROR, "This device is not supported by the limera1n exploit");
return -1;
}
- dfu_client_free(client);
- info("Device should be in pwned DFU state now.\n");
-
- return 0;
+#endif
}
if (client->flags & FLAG_LATEST) {
@@ -493,30 +564,24 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
plist_t signed_fws = NULL;
int res = ipsw_get_signed_firmwares(client->device->product_type, &signed_fws);
if (res < 0) {
- error("ERROR: Could not fetch list of signed firmwares.\n");
+ logger(LL_ERROR, "Could not fetch list of signed firmwares.\n");
return res;
}
uint32_t count = plist_array_get_size(signed_fws);
if (count == 0) {
plist_free(signed_fws);
- error("ERROR: No firmwares are currently being signed for %s (REALLY?!)\n", client->device->product_type);
+ logger(LL_ERROR, "No firmwares are currently being signed for %s (REALLY?!)\n", client->device->product_type);
return -1;
}
plist_t selected_fw = NULL;
if (client->flags & FLAG_INTERACTIVE) {
uint32_t i = 0;
- info("The following firmwares are currently being signed for %s:\n", client->device->product_type);
+ logger(LL_INFO, "The following firmwares are currently being signed for %s:\n", client->device->product_type);
for (i = 0; i < count; i++) {
plist_t fw = plist_array_get_item(signed_fws, i);
plist_t p_version = plist_dict_get_item(fw, "version");
plist_t p_build = plist_dict_get_item(fw, "buildid");
- char *s_version = NULL;
- char *s_build = NULL;
- plist_get_string_val(p_version, &s_version);
- plist_get_string_val(p_build, &s_build);
- info(" [%d] %s (build %s)\n", i+1, s_version, s_build);
- free(s_version);
- free(s_build);
+ logger(LL_INFO, " [%d] %s (build %s)\n", i+1, plist_get_string_ptr(p_version, NULL), plist_get_string_ptr(p_build, NULL));
}
while (1) {
char input[64];
@@ -540,23 +605,17 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
break;
}
} else {
- info("NOTE: Running non-interactively, automatically selecting latest available version\n");
+ logger(LL_NOTICE, "Running non-interactively, automatically selecting latest available version\n");
selected_fw = plist_array_get_item(signed_fws, 0);
}
if (!selected_fw) {
- error("ERROR: failed to select latest firmware?!\n");
+ logger(LL_ERROR, "failed to select latest firmware?!\n");
plist_free(signed_fws);
return -1;
} else {
plist_t p_version = plist_dict_get_item(selected_fw, "version");
plist_t p_build = plist_dict_get_item(selected_fw, "buildid");
- char *s_version = NULL;
- char *s_build = NULL;
- plist_get_string_val(p_version, &s_version);
- plist_get_string_val(p_build, &s_build);
- info("Selected firmware %s (build %s)\n", s_version, s_build);
- free(s_version);
- free(s_build);
+ logger(LL_NOTICE, "Selected firmware %s (build %s)\n", plist_get_string_ptr(p_version, NULL), plist_get_string_ptr(p_build, NULL));
plist_t p_url = plist_dict_get_item(selected_fw, "url");
plist_t p_sha1 = plist_dict_get_item(selected_fw, "sha1sum");
char *s_sha1 = NULL;
@@ -572,25 +631,29 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
}
p_fwsha1 = &fwsha1[0];
} else {
- error("ERROR: unexpected size of sha1sum\n");
+ logger(LL_ERROR, "unexpected size of sha1sum\n");
}
}
plist_free(signed_fws);
if (!fwurl || !p_fwsha1) {
- error("ERROR: Missing firmware URL or SHA1\n");
+ logger(LL_ERROR, "Missing firmware URL or SHA1\n");
return -1;
}
char* ipsw = NULL;
res = ipsw_download_fw(fwurl, p_fwsha1, client->cache_dir, &ipsw);
if (res != 0) {
- if (ipsw) {
- free(ipsw);
- }
+ free(ipsw);
return res;
} else {
- client->ipsw = ipsw;
+ client->ipsw = ipsw_open(ipsw);
+ if (!client->ipsw) {
+ logger(LL_ERROR, "Failed to open ipsw '%s'\n", ipsw);
+ free(ipsw);
+ return -1;
+ }
+ free(ipsw);
}
}
idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.6);
@@ -599,16 +662,31 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
return 0;
}
+ // extract buildmanifest
+ if (client->flags & FLAG_CUSTOM) {
+ logger(LL_INFO, "Extracting Restore.plist from IPSW\n");
+ if (ipsw_extract_restore_plist(client->ipsw, &client->build_manifest) < 0) {
+ logger(LL_ERROR, "Unable to extract Restore.plist from %s. Firmware file might be corrupt.\n", client->ipsw->path);
+ return -1;
+ }
+ } else {
+ logger(LL_INFO, "Extracting BuildManifest from IPSW\n");
+ if (ipsw_extract_build_manifest(client->ipsw, &client->build_manifest, &tss_enabled) < 0) {
+ logger(LL_ERROR, "Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", client->ipsw->path);
+ return -1;
+ }
+ }
+
+ if (client->flags & FLAG_CUSTOM) {
+ // prevent attempt to sign custom firmware
+ tss_enabled = 0;
+ logger(LL_INFO, "Custom firmware requested; TSS has been disabled.\n");
+ }
+
if (client->mode == MODE_RESTORE) {
- if (client->flags & FLAG_ALLOW_RESTORE_MODE) {
- tss_enabled = 0;
- if (!client->root_ticket) {
- client->root_ticket = (void*)strdup("");
- client->root_ticket_len = 0;
- }
- } else {
+ if (!(client->flags & FLAG_ALLOW_RESTORE_MODE)) {
if (restore_reboot(client) < 0) {
- error("ERROR: Unable to exit restore mode\n");
+ logger(LL_ERROR, "Unable to exit restore mode\n");
return -2;
}
@@ -617,62 +695,189 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 60000);
if (client->mode == MODE_UNKNOWN || (client->flags & FLAG_QUIT)) {
mutex_unlock(&client->device_event_mutex);
- error("ERROR: Unable to discover device mode. Please make sure a device is attached.\n");
+ logger(LL_ERROR, "Unable to discover device mode. Please make sure a device is attached.\n");
return -1;
}
- info("Found device in %s mode\n", client->mode->string);
+ logger(LL_INFO, "Found device in %s mode\n", client->mode->string);
mutex_unlock(&client->device_event_mutex);
}
}
- // verify if ipsw file exists
- if (access(client->ipsw, F_OK) < 0) {
- error("ERROR: Firmware file %s does not exist.\n", client->ipsw);
- return -1;
- }
+ if (client->mode == MODE_PORTDFU) {
+ unsigned int pdfu_bdid = 0;
+ unsigned int pdfu_cpid = 0;
+ unsigned int prev = 0;
- // extract buildmanifest
- if (client->flags & FLAG_CUSTOM) {
- info("Extracting Restore.plist from IPSW\n");
- if (ipsw_extract_restore_plist(client->ipsw, &client->build_manifest) < 0) {
- error("ERROR: Unable to extract Restore.plist from %s. Firmware file might be corrupt.\n", client->ipsw);
+ if (dfu_get_bdid(client, &pdfu_bdid) < 0) {
+ logger(LL_ERROR, "Failed to get bdid for Port DFU device!\n");
return -1;
}
- } else {
- info("Extracting BuildManifest from IPSW\n");
- if (ipsw_extract_build_manifest(client->ipsw, &client->build_manifest, &tss_enabled) < 0) {
- error("ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", client->ipsw);
+ if (dfu_get_cpid(client, &pdfu_cpid) < 0) {
+ logger(LL_ERROR, "Failed to get cpid for Port DFU device!\n");
+ return -1;
+ }
+ if (dfu_get_prev(client, &prev) < 0) {
+ logger(LL_ERROR, "Failed to get PREV for Port DFU device!\n");
+ return -1;
+ }
+
+ unsigned char* pdfu_nonce = NULL;
+ unsigned int pdfu_nsize = 0;
+ if (dfu_get_portdfu_nonce(client, &pdfu_nonce, &pdfu_nsize) < 0) {
+ logger(LL_ERROR, "Failed to get nonce for Port DFU device!\n");
+ return -1;
+ }
+
+ plist_t build_identity = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, RESTORE_VARIANT_ERASE_INSTALL, 0);
+ if (!build_identity) {
+ logger(LL_ERROR, "ERORR: Failed to get build identity\n");
+ return -1;
+ }
+
+ unsigned int b_pdfu_cpid = (unsigned int)plist_dict_get_uint(build_identity, "USBPortController1,ChipID");
+ if (b_pdfu_cpid != pdfu_cpid) {
+ logger(LL_ERROR, "cpid 0x%02x doesn't match USBPortController1,ChipID in build identity (0x%02x)\n", pdfu_cpid, b_pdfu_cpid);
+ return -1;
+ }
+ unsigned int b_pdfu_bdid = (unsigned int)plist_dict_get_uint(build_identity, "USBPortController1,BoardID");
+ if (b_pdfu_bdid != pdfu_bdid) {
+ logger(LL_ERROR, "bdid 0x%x doesn't match USBPortController1,BoardID in build identity (0x%x)\n", pdfu_bdid, b_pdfu_bdid);
return -1;
}
+
+ plist_t parameters = plist_new_dict();
+ plist_dict_set_item(parameters, "@USBPortController1,Ticket", plist_new_bool(1));
+ plist_dict_set_item(parameters, "USBPortController1,ECID", plist_new_int(client->ecid));
+ plist_dict_copy_item(parameters, build_identity, "USBPortController1,BoardID", NULL);
+ plist_dict_copy_item(parameters, build_identity, "USBPortController1,ChipID", NULL);
+ plist_dict_copy_item(parameters, build_identity, "USBPortController1,SecurityDomain", NULL);
+ plist_dict_set_item(parameters, "USBPortController1,SecurityMode", plist_new_bool(1));
+ plist_dict_set_item(parameters, "USBPortController1,ProductionMode", plist_new_bool(1));
+ int is_mac = plist_access_path(build_identity, 2, "Info", "MacOSVariant") != NULL;
+ plist_t usbf = plist_access_path(build_identity, 2, "Manifest", "USBPortController1,USBFirmware");
+ if (!usbf) {
+ plist_free(parameters);
+ logger(LL_ERROR, "Unable to find USBPortController1,USBFirmware in build identity\n");
+ return -1;
+ }
+ plist_t p_fwpath = plist_access_path(usbf, 2, "Info", "Path");
+ if (!p_fwpath) {
+ plist_free(parameters);
+ logger(LL_ERROR, "Unable to find path of USBPortController1,USBFirmware component\n");
+ return -1;
+ }
+ const char* fwpath = plist_get_string_ptr(p_fwpath, NULL);
+ if (!fwpath) {
+ plist_free(parameters);
+ logger(LL_ERROR, "Unable to get path of USBPortController1,USBFirmware component\n");
+ return -1;
+ }
+ void* uarp_buf = NULL;
+ size_t uarp_size = 0;
+ if (ipsw_extract_to_memory(client->ipsw, fwpath, &uarp_buf, &uarp_size) < 0) {
+ plist_free(parameters);
+ logger(LL_ERROR, "Unable to extract '%s' from IPSW\n", fwpath);
+ return -1;
+ }
+ usbf = plist_copy(usbf);
+ plist_dict_remove_item(usbf, "Info");
+ plist_dict_set_item(parameters, "USBPortController1,USBFirmware", usbf);
+ plist_dict_set_item(parameters, "USBPortController1,Nonce", plist_new_data((const char*)pdfu_nonce, pdfu_nsize));
+
+ plist_t request = tss_request_new(NULL);
+ if (request == NULL) {
+ plist_free(parameters);
+ logger(LL_ERROR, "Unable to create TSS request\n");
+ return -1;
+ }
+ plist_dict_merge(&request, parameters);
+ plist_free(parameters);
+
+ // send request and grab response
+ plist_t response = tss_request_send(request, client->tss_url);
+ plist_free(request);
+ if (response == NULL) {
+ logger(LL_ERROR, "Unable to send TSS request\n");
+ return -1;
+ }
+ logger(LL_INFO, "Received USBPortController1,Ticket\n");
+
+ logger(LL_INFO, "Creating Ace3Binary\n");
+ void* ace3bin = NULL;
+ size_t ace3bin_size = 0;
+ if (ace3_create_binary(uarp_buf, uarp_size, pdfu_bdid, prev, response, &ace3bin, &ace3bin_size) < 0) {
+ logger(LL_ERROR, "Could not create Ace3Binary\n");
+ return -1;
+ }
+ plist_free(response);
+ free(uarp_buf);
+
+ if (client->flags & FLAG_KEEP_PERS) {
+ write_file("Ace3Binary", ace3bin, ace3bin_size);
+ }
+
+ if (dfu_send_buffer_with_options(client, ace3bin, ace3bin_size, IRECV_SEND_OPT_DFU_NOTIFY_FINISH | IRECV_SEND_OPT_DFU_SMALL_PKT) < 0) {
+ logger(LL_ERROR, "Could not send Ace3Buffer to device\n");
+ return -1;
+ }
+
+ logger(LL_DEBUG, "Waiting for device to disconnect...\n");
+ cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 5000);
+ if (client->mode != MODE_UNKNOWN || (client->flags & FLAG_QUIT)) {
+ mutex_unlock(&client->device_event_mutex);
+
+ if (!(client->flags & FLAG_QUIT)) {
+ logger(LL_ERROR, "Device did not disconnect. Port DFU failed.\n");
+ }
+ return -2;
+ }
+ dfu_client_free(client);
+ logger(LL_DEBUG, "Waiting for device to reconnect in DFU mode...\n");
+ cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 20000);
+ if (client->mode != MODE_DFU || (client->flags & FLAG_QUIT)) {
+ mutex_unlock(&client->device_event_mutex);
+ if (!(client->flags & FLAG_QUIT)) {
+ logger(LL_ERROR, "Device did not reconnect in DFU mode. Port DFU failed.\n");
+ if (is_mac) {
+ logger(LL_ERROR, "Make sure to use the correct USB port for this model, see https://support.apple.com/120694\n");
+ }
+ }
+ return -2;
+ }
+ mutex_unlock(&client->device_event_mutex);
+
+ if (client->flags & FLAG_NOACTION) {
+ logger(LL_INFO, "Port DFU restore successful.\n");
+ return 0;
+ } else {
+ logger(LL_INFO, "Port DFU restore successful. Continuing.\n");
+ }
}
+
idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.8);
/* check if device type is supported by the given build manifest */
if (build_manifest_check_compatibility(client->build_manifest, client->device->product_type) < 0) {
- error("ERROR: Could not make sure this firmware is suitable for the current device. Refusing to continue.\n");
+ logger(LL_ERROR, "Could not make sure this firmware is suitable for the current device. Refusing to continue.\n");
return -1;
}
/* print iOS information from the manifest */
build_manifest_get_version_information(client->build_manifest, client);
- info("Product Version: %s\n", client->version);
- info("Product Build: %s Major: %d\n", client->build, client->build_major);
+ logger(LL_INFO, "IPSW Product Version: %s\n", client->version);
+ logger(LL_INFO, "IPSW Product Build: %s Major: %d\n", client->build, client->build_major);
client->image4supported = is_image4_supported(client);
- info("Device supports Image4: %s\n", (client->image4supported) ? "true" : "false");
-
- if (client->flags & FLAG_CUSTOM) {
- /* prevent signing custom firmware */
- tss_enabled = 0;
- info("Custom firmware requested. Disabled TSS request.\n");
- }
+ logger(LL_INFO, "Device supports Image4: %s\n", (client->image4supported) ? "true" : "false");
// choose whether this is an upgrade or a restore (default to upgrade)
client->tss = NULL;
plist_t build_identity = NULL;
+ int build_identity_needs_free = 0;
if (client->flags & FLAG_CUSTOM) {
build_identity = plist_new_dict();
+ build_identity_needs_free = 1;
{
plist_t node;
plist_t comp;
@@ -689,16 +894,17 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
x++;
}
- sprintf(p_all_flash, "Firmware/all_flash/all_flash.%s.%s", lcmodel, "production");
+ snprintf(p_all_flash, sizeof(p_all_flash), "Firmware/all_flash/all_flash.%s.%s", lcmodel, "production");
strcpy(tmpstr, p_all_flash);
strcat(tmpstr, "/manifest");
// get all_flash file manifest
char *files[16];
- char *fmanifest = NULL;
- uint32_t msize = 0;
- if (ipsw_extract_to_memory(client->ipsw, tmpstr, (unsigned char**)&fmanifest, &msize) < 0) {
- error("ERROR: could not extract %s from IPSW\n", tmpstr);
+ void *fmanifest = NULL;
+ size_t msize = 0;
+ if (ipsw_extract_to_memory(client->ipsw, tmpstr, &fmanifest, &msize) < 0) {
+ logger(LL_ERROR, "could not extract %s from IPSW\n", tmpstr);
+ free(build_identity);
return -1;
}
@@ -730,7 +936,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
plist_dict_set_item(manifest, "RestoreDeviceTree", plist_copy(comp));
}
} else {
- error("WARNING: unhandled component %s\n", files[x]);
+ logger(LL_WARNING, "Unhandled component %s\n", files[x]);
plist_free(comp);
}
free(files[x]);
@@ -738,7 +944,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
}
// add iBSS
- sprintf(tmpstr, "Firmware/dfu/iBSS.%s.%s.dfu", lcmodel, "RELEASE");
+ snprintf(tmpstr, sizeof(tmpstr), "Firmware/dfu/iBSS.%s.%s.dfu", lcmodel, "RELEASE");
inf = plist_new_dict();
plist_dict_set_item(inf, "Path", plist_new_string(tmpstr));
comp = plist_new_dict();
@@ -746,7 +952,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
plist_dict_set_item(manifest, "iBSS", comp);
// add iBEC
- sprintf(tmpstr, "Firmware/dfu/iBEC.%s.%s.dfu", lcmodel, "RELEASE");
+ snprintf(tmpstr, sizeof(tmpstr), "Firmware/dfu/iBEC.%s.%s.dfu", lcmodel, "RELEASE");
inf = plist_new_dict();
plist_dict_set_item(inf, "Path", plist_new_string(tmpstr));
comp = plist_new_dict();
@@ -800,11 +1006,11 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
// add OS filesystem
node = plist_dict_get_item(client->build_manifest, "SystemRestoreImages");
if (!node) {
- error("ERROR: missing SystemRestoreImages in Restore.plist\n");
+ logger(LL_ERROR, "missing SystemRestoreImages in Restore.plist\n");
}
plist_t os = plist_dict_get_item(node, "User");
if (!os) {
- error("ERROR: missing filesystem in Restore.plist\n");
+ logger(LL_ERROR, "missing filesystem in Restore.plist\n");
} else {
inf = plist_new_dict();
plist_dict_set_item(inf, "Path", plist_copy(os));
@@ -816,73 +1022,64 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
// add info
inf = plist_new_dict();
plist_dict_set_item(inf, "RestoreBehavior", plist_new_string((client->flags & FLAG_ERASE) ? "Erase" : "Update"));
- plist_dict_set_item(inf, "Variant", plist_new_string((client->flags & FLAG_ERASE) ? "Customer Erase Install (IPSW)" : "Customer Upgrade Install (IPSW)"));
+ plist_dict_set_item(inf, "Variant", plist_new_string((client->flags & FLAG_ERASE) ? "Customer " RESTORE_VARIANT_ERASE_INSTALL : "Customer " RESTORE_VARIANT_UPGRADE_INSTALL));
plist_dict_set_item(build_identity, "Info", inf);
// finally add manifest
plist_dict_set_item(build_identity, "Manifest", manifest);
}
+ } else if (client->restore_variant) {
+ build_identity = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, client->restore_variant, 1);
} else if (client->flags & FLAG_ERASE) {
- build_identity = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, "Customer Erase Install (IPSW)");
- if (build_identity == NULL) {
- error("ERROR: Unable to find any build identities\n");
- return -1;
- }
+ build_identity = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, RESTORE_VARIANT_ERASE_INSTALL, 0);
} else {
- build_identity = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, "Customer Upgrade Install (IPSW)");
+ build_identity = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, RESTORE_VARIANT_UPGRADE_INSTALL, 0);
if (!build_identity) {
build_identity = build_manifest_get_build_identity_for_model(client->build_manifest, client->device->hardware_model);
}
}
+ if (build_identity == NULL) {
+ logger(LL_ERROR, "Unable to find a matching build identity\n");
+ return -1;
+ }
+
+ client->macos_variant = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, RESTORE_VARIANT_MACOS_RECOVERY_OS, 1);
/* print information about current build identity */
build_identity_print_information(build_identity);
+ if (client->macos_variant) {
+ logger(LL_INFO, "Performing macOS restore\n");
+ }
+
if (client->mode == MODE_NORMAL && !(client->flags & FLAG_ERASE) && !(client->flags & FLAG_SHSHONLY)) {
- plist_t pver = normal_get_lockdown_value(client, NULL, "ProductVersion");
- char *device_version = NULL;
- if (pver) {
- plist_get_string_val(pver, &device_version);
- plist_free(pver);
- }
- if (device_version && (compare_versions(device_version, client->version) > 0)) {
+ if (client->device_version && (compare_versions(client->device_version, client->version) > 0)) {
if (client->flags & FLAG_INTERACTIVE) {
- char input[64];
- char spaces[16];
- int num_spaces = 13 - strlen(client->version) - strlen(device_version);
- memset(spaces, ' ', num_spaces);
- spaces[num_spaces] = '\0';
- printf("################################ [ WARNING ] #################################\n"
- "# You are trying to DOWNGRADE a %s device with an IPSW for %s while%s #\n"
- "# trying to preserve the user data (Upgrade restore). This *might* work, but #\n"
- "# there is a VERY HIGH chance it might FAIL BADLY with COMPLETE DATA LOSS. #\n"
- "# Hit CTRL+C now if you want to abort the restore. #\n"
- "# If you want to take the risk (and have a backup of your important data!) #\n"
- "# type YES and press ENTER to continue. You have been warned. #\n"
- "##############################################################################\n",
- device_version, client->version, spaces);
- while (1) {
- printf("> ");
- fflush(stdout);
- fflush(stdin);
- input[0] = '\0';
- get_user_input(input, 63, 0);
- if (client->flags & FLAG_QUIT) {
- return -1;
- }
- if (*input != '\0' && !strcmp(input, "YES")) {
- break;
- } else {
- printf("Invalid input. Please type YES or hit CTRL+C to abort.\n");
- continue;
- }
+ char msgtext[512];
+ snprintf(msgtext, 512, "You are trying to DOWNGRADE a %s device with an IPSW for %s while\n"
+ "trying to preserve the user data (Upgrade restore). This *might* work, but\n"
+ "there is a VERY HIGH chance it might FAIL BADLY with COMPLETE DATA LOSS.\n"
+ "If you want to take the risk (and have a backup of your important data!) you may continue.\n"
+ "You have been warned.\n", client->device_version, client->version);
+ int pres = prompt_user("WARNING", msgtext);
+ if (pres < 0) {
+ client->flags |= FLAG_QUIT;
+ return -1;
}
}
}
- free(device_version);
}
if (client->flags & FLAG_ERASE && client->flags & FLAG_INTERACTIVE) {
+ int pres = prompt_user(
+ "WARNING",
+ "You are about to perform an *ERASE* restore. ALL DATA on the target device will be IRREVERSIBLY DESTROYED. If you want to update your device without erasing the user data, cancel now and restart without -e or --erase command line switch.\n"
+ );
+ if (pres < 0) {
+ client->flags |= FLAG_QUIT;
+ return -1;
+ }
+#if 0
char input[64];
printf("################################ [ WARNING ] #################################\n"
"# You are about to perform an *ERASE* restore. ALL DATA on the target device #\n"
@@ -907,119 +1104,82 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
continue;
}
}
+#endif
}
idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.0);
/* check if all components we need are actually there */
- info("Checking IPSW for required components...\n");
+ logger(LL_INFO, "Checking IPSW for required components...\n");
if (build_identity_check_components_in_ipsw(build_identity, client->ipsw) < 0) {
- error("ERROR: Could not find all required components in IPSW %s\n", client->ipsw);
+ logger(LL_ERROR, "Could not find all required components in IPSW %s\n", client->ipsw->path);
return -1;
}
- info("All required components found in IPSW\n");
+ logger(LL_INFO, "All required components found in IPSW\n");
- // Get filesystem name from build identity
- char* fsname = NULL;
- if (build_identity_get_component_path(build_identity, "OS", &fsname) < 0) {
- error("ERROR: Unable to get path for filesystem component\n");
+ /* Get OS (filesystem) name from build identity */
+ char* os_path = NULL;
+ if (build_identity_get_component_path(build_identity, "OS", &os_path) < 0) {
+ logger(LL_ERROR, "Unable to get path for filesystem component\n");
return -1;
}
- // check if we already have an extracted filesystem
- int delete_fs = 0;
- char* filesystem = NULL;
- struct stat st;
- memset(&st, '\0', sizeof(struct stat));
- char tmpf[1024];
- if (client->cache_dir) {
- if (stat(client->cache_dir, &st) < 0) {
- mkdir_with_parents(client->cache_dir, 0755);
+ /* check if IPSW has OS component 'stored' in ZIP archive, otherwise we need to extract it */
+ int needs_os_extraction = 0;
+ if (client->ipsw->zip) {
+ ipsw_file_handle_t zfile = ipsw_file_open(client->ipsw, os_path);
+ if (zfile) {
+ if (!zfile->seekable) {
+ needs_os_extraction = 1;
+ }
+ ipsw_file_close(zfile);
}
- strcpy(tmpf, client->cache_dir);
- strcat(tmpf, "/");
- char *ipswtmp = strdup(client->ipsw);
- strcat(tmpf, basename(ipswtmp));
- free(ipswtmp);
- } else {
- strcpy(tmpf, client->ipsw);
}
- if (!ipsw_is_directory(client->ipsw)) {
- // strip off file extension if given ipsw is not a directory
- char* s = tmpf + strlen(tmpf) - 1;
- char* p = s;
- while (*p != '\0' && *p != '.' && *p != '/' && *p != '\\') p--;
- if (s - p < 6) {
- if (*p == '.') {
+ if (needs_os_extraction && !(client->flags & FLAG_SHSHONLY)) {
+ char* tmpf = NULL;
+ struct stat st;
+ if (client->cache_dir) {
+ memset(&st, '\0', sizeof(struct stat));
+ if (stat(client->cache_dir, &st) < 0) {
+ mkdir_with_parents(client->cache_dir, 0755);
+ }
+ char* ipsw_basename = strdup(path_get_basename(client->ipsw->path));
+ char* p = strrchr(ipsw_basename, '.');
+ if (p && isalpha(*(p+1))) {
*p = '\0';
}
- }
- }
-
- if (stat(tmpf, &st) < 0) {
- __mkdir(tmpf, 0755);
- }
- strcat(tmpf, "/");
- strcat(tmpf, fsname);
-
- memset(&st, '\0', sizeof(struct stat));
- if (stat(tmpf, &st) == 0) {
- uint64_t fssize = 0;
- ipsw_get_file_size(client->ipsw, fsname, &fssize);
- if ((fssize > 0) && ((uint64_t)st.st_size == fssize)) {
- info("Using cached filesystem from '%s'\n", tmpf);
- filesystem = strdup(tmpf);
- }
- }
-
- if (!filesystem && !(client->flags & FLAG_SHSHONLY)) {
- char extfn[1024];
- strcpy(extfn, tmpf);
- strcat(extfn, ".extract");
- char lockfn[1024];
- strcpy(lockfn, tmpf);
- strcat(lockfn, ".lock");
- lock_info_t li;
-
- lock_file(lockfn, &li);
- FILE* extf = NULL;
- if (access(extfn, F_OK) != 0) {
- extf = fopen(extfn, "wb");
- }
- unlock_file(&li);
- if (!extf) {
- // use temp filename
- filesystem = get_temp_filename("ipsw_");
- if (!filesystem) {
- error("WARNING: Could not get temporary filename, using '%s' in current directory\n", fsname);
- filesystem = strdup(fsname);
- }
- delete_fs = 1;
+ tmpf = string_build_path(client->cache_dir, ipsw_basename, NULL);
+ mkdir_with_parents(tmpf, 0755);
+ free(tmpf);
+ tmpf = string_build_path(client->cache_dir, ipsw_basename, os_path, NULL);
+ free(ipsw_basename);
} else {
- // use <fsname>.extract as filename
- filesystem = strdup(extfn);
- fclose(extf);
- }
- remove(lockfn);
-
- // Extract filesystem from IPSW
- info("Extracting filesystem from IPSW: %s\n", fsname);
- if (ipsw_extract_to_file_with_progress(client->ipsw, fsname, filesystem, 1) < 0) {
- error("ERROR: Unable to extract filesystem from IPSW\n");
- if (client->tss)
- plist_free(client->tss);
- info("Removing %s\n", filesystem);
- unlink(filesystem);
- return -1;
+ tmpf = get_temp_filename(NULL);
+ client->delete_fs = 1;
}
- if (strstr(filesystem, ".extract")) {
- // rename <fsname>.extract to <fsname>
- remove(tmpf);
- rename(filesystem, tmpf);
- free(filesystem);
- filesystem = strdup(tmpf);
+ /* check if we already have it extracted */
+ uint64_t fssize = 0;
+ ipsw_get_file_size(client->ipsw, os_path, &fssize);
+ memset(&st, '\0', sizeof(struct stat));
+ if (stat(tmpf, &st) == 0) {
+ if ((fssize > 0) && ((uint64_t)st.st_size == fssize)) {
+ logger(LL_INFO, "Using cached filesystem from '%s'\n", tmpf);
+ client->filesystem = tmpf;
+ }
+ }
+
+ if (!client->filesystem) {
+ logger(LL_INFO, "Extracting filesystem from IPSW: %s\n", os_path);
+ if (ipsw_extract_to_file_with_progress(client->ipsw, os_path, tmpf, 1) < 0) {
+ logger(LL_ERROR, "Unable to extract filesystem from IPSW\n");
+ logger(LL_INFO, "Removing %s\n", tmpf);
+ unlink(tmpf);
+ free(tmpf);
+ return -1;
+ }
+ client->filesystem = tmpf;
}
}
@@ -1028,13 +1188,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
/* retrieve shsh blobs if required */
if (tss_enabled) {
int stashbag_commit_required = 0;
- debug("Getting device's ECID for TSS request\n");
- /* fetch the device's ECID for the TSS request */
- if (get_ecid(client, &client->ecid) < 0) {
- error("ERROR: Unable to find device ECID\n");
- return -1;
- }
- info("Found ECID %" PRIu64 "\n", client->ecid);
if (client->mode == MODE_NORMAL && !(client->flags & FLAG_ERASE) && !(client->flags & FLAG_SHSHONLY)) {
plist_t node = normal_get_lockdown_value(client, NULL, "HasSiDP");
@@ -1043,19 +1196,19 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
plist_get_bool_val(node, &needs_preboard);
}
if (needs_preboard) {
- info("Checking if device requires stashbag...\n");
+ logger(LL_INFO, "Checking if device requires stashbag...\n");
plist_t manifest;
if (get_preboard_manifest(client, build_identity, &manifest) < 0) {
- error("ERROR: Unable to create preboard manifest.\n");
+ logger(LL_ERROR, "Unable to create preboard manifest.\n");
return -1;
}
- debug("DEBUG: creating stashbag...\n");
+ logger(LL_DEBUG, "creating stashbag...\n");
int err = normal_handle_create_stashbag(client, manifest);
if (err < 0) {
if (err == -2) {
- error("ERROR: Could not create stashbag (timeout).\n");
+ logger(LL_ERROR, "Could not create stashbag (timeout).\n");
} else {
- error("ERROR: An error occurred while creating the stashbag.\n");
+ logger(LL_ERROR, "An error occurred while creating the stashbag.\n");
}
return -1;
} else if (err == 1) {
@@ -1067,10 +1220,10 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
if (client->build_major > 8) {
unsigned char* nonce = NULL;
- int nonce_size = 0;
+ unsigned int nonce_size = 0;
if (get_ap_nonce(client, &nonce, &nonce_size) < 0) {
/* the first nonce request with older firmware releases can fail and it's OK */
- info("NOTE: Unable to get nonce from device\n");
+ logger(LL_NOTICE, "Unable to get nonce from device\n");
}
if (!client->nonce || (nonce_size != client->nonce_size) || (memcmp(nonce, client->nonce, nonce_size) != 0)) {
@@ -1082,55 +1235,101 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
} else {
free(nonce);
}
+ if (client->mode == MODE_NORMAL) {
+ plist_t ap_params = normal_get_lockdown_value(client, NULL, "ApParameters");
+ if (ap_params) {
+ if (!client->parameters) {
+ client->parameters = plist_new_dict();
+ }
+ plist_dict_merge(&client->parameters, ap_params);
+ plist_t p_sep_nonce = plist_dict_get_item(ap_params, "SepNonce");
+ uint64_t sep_nonce_size = 0;
+ const char* sep_nonce = plist_get_data_ptr(p_sep_nonce, &sep_nonce_size);
+ if (sep_nonce) {
+ logger(LL_INFO, "Getting SepNonce in normal mode... ");
+ logger_dump_hex(LL_INFO, sep_nonce, sep_nonce_size);
+ }
+ plist_free(ap_params);
+ }
+ plist_t req_nonce_slot = plist_access_path(build_identity, 2, "Info", "RequiresNonceSlot");
+ if (req_nonce_slot) {
+ plist_dict_set_item(client->parameters, "RequiresNonceSlot", plist_copy(req_nonce_slot));
+ }
+ }
}
if (client->flags & FLAG_QUIT) {
return -1;
}
- if (get_tss_response(client, build_identity, &client->tss) < 0) {
- error("ERROR: Unable to get SHSH blobs for this device\n");
- return -1;
- }
- if (client->build_major >= 20) {
- if (get_local_policy_tss_response(client, build_identity, &client->tss_localpolicy) < 0) {
- error("ERROR: Unable to get SHSH blobs for this device (local policy)\n");
+ if (client->mode == MODE_RESTORE && client->root_ticket) {
+ plist_t ap_ticket = plist_new_data((char*)client->root_ticket, client->root_ticket_len);
+ if (!ap_ticket) {
+ logger(LL_ERROR, "Failed to create ApImg4Ticket node value.\n");
return -1;
}
- if (get_recoveryos_root_ticket_tss_response(client, build_identity, &client->tss_recoveryos_root_ticket) <
- 0) {
- error("ERROR: Unable to get SHSH blobs for this device (recovery OS Root Ticket)\n");
+ client->tss = plist_new_dict();
+ if (!client->tss) {
+ logger(LL_ERROR, "Failed to create ApImg4Ticket node.\n");
return -1;
}
+ plist_dict_set_item(client->tss, "ApImg4Ticket", ap_ticket);
+ } else {
+ if (get_tss_response(client, build_identity, &client->tss) < 0) {
+ logger(LL_ERROR, "Unable to get SHSH blobs for this device\n");
+ return -1;
+ }
+ if (client->macos_variant) {
+ if (get_local_policy_tss_response(client, build_identity, &client->tss_localpolicy) < 0) {
+ logger(LL_ERROR, "Unable to get SHSH blobs for this device (local policy)\n");
+ return -1;
+ }
+ if (get_recoveryos_root_ticket_tss_response(client, build_identity, &client->tss_recoveryos_root_ticket) < 0) {
+ logger(LL_ERROR, "Unable to get SHSH blobs for this device (recovery OS Root Ticket)\n");
+ return -1;
+ }
+ } else {
+ plist_t recovery_variant = plist_access_path(build_identity, 2, "Info", "RecoveryVariant");
+ if (recovery_variant) {
+ const char* recovery_variant_str = plist_get_string_ptr(recovery_variant, NULL);
+ client->recovery_variant = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, recovery_variant_str, 1);
+ if (!client->recovery_variant) {
+ logger(LL_ERROR, "Variant '%s' not found in BuildManifest\n", recovery_variant_str);
+ return -1;
+ }
+ if (get_tss_response(client, client->recovery_variant, &client->tss_recoveryos_root_ticket) < 0) {
+ logger(LL_ERROR, "Unable to get SHSH blobs for this device (%s)\n", recovery_variant_str);
+ return -1;
+ }
+ }
+ }
}
if (stashbag_commit_required) {
plist_t ticket = plist_dict_get_item(client->tss, "ApImg4Ticket");
if (!ticket || plist_get_node_type(ticket) != PLIST_DATA) {
- error("ERROR: Missing ApImg4Ticket in TSS response for stashbag commit\n");
+ logger(LL_ERROR, "Missing ApImg4Ticket in TSS response for stashbag commit\n");
return -1;
}
- info("Committing stashbag...\n");
+ logger(LL_INFO, "Committing stashbag...\n");
int err = normal_handle_commit_stashbag(client, ticket);
if (err < 0) {
- error("ERROR: Could not commit stashbag (%d). Aborting.\n", err);
+ logger(LL_ERROR, "Could not commit stashbag (%d). Aborting.\n", err);
return -1;
}
}
}
if (client->flags & FLAG_QUIT) {
- if (delete_fs && filesystem)
- unlink(filesystem);
return -1;
}
if (client->flags & FLAG_SHSHONLY) {
if (!tss_enabled) {
- info("This device does not require a TSS record\n");
+ logger(LL_INFO, "This device does not require a TSS record\n");
return 0;
}
if (!client->tss) {
- error("ERROR: could not fetch TSS record\n");
+ logger(LL_ERROR, "could not fetch TSS record\n");
return -1;
} else {
char *bin = NULL;
@@ -1145,19 +1344,19 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
strcpy(zfn, "shsh");
}
mkdir_with_parents(zfn, 0755);
- sprintf(zfn+strlen(zfn), "/%" PRIu64 "-%s-%s.shsh", client->ecid, client->device->product_type, client->version);
+ snprintf(&zfn[0]+strlen(zfn), sizeof(zfn)-strlen(zfn), "/%" PRIu64 "-%s-%s.shsh", client->ecid, client->device->product_type, client->version);
struct stat fst;
if (stat(zfn, &fst) != 0) {
gzFile zf = gzopen(zfn, "wb");
gzwrite(zf, bin, blen);
gzclose(zf);
- info("SHSH saved to '%s'\n", zfn);
+ logger(LL_INFO, "SHSH saved to '%s'\n", zfn);
} else {
- info("SHSH '%s' already present.\n", zfn);
+ logger(LL_INFO, "SHSH '%s' already present.\n", zfn);
}
free(bin);
} else {
- error("ERROR: could not get TSS record data\n");
+ logger(LL_ERROR, "could not get TSS record data\n");
}
plist_free(client->tss);
return 0;
@@ -1166,7 +1365,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
/* verify if we have tss records if required */
if ((tss_enabled) && (client->tss == NULL)) {
- error("ERROR: Unable to proceed without a TSS record.\n");
+ logger(LL_ERROR, "Unable to proceed without a TSS record.\n");
return -1;
}
@@ -1176,16 +1375,14 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
}
idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.25);
if (client->flags & FLAG_QUIT) {
- if (delete_fs && filesystem)
- unlink(filesystem);
return -1;
}
// if the device is in normal mode, place device into recovery mode
if (client->mode == MODE_NORMAL) {
- info("Entering recovery mode...\n");
+ logger(LL_INFO, "Entering recovery mode...\n");
if (normal_enter_recovery(client) < 0) {
- error("ERROR: Unable to place device into recovery mode from normal mode\n");
+ logger(LL_ERROR, "Unable to place device into recovery mode from normal mode\n");
if (client->tss)
plist_free(client->tss);
return -5;
@@ -1194,8 +1391,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.3);
if (client->flags & FLAG_QUIT) {
- if (delete_fs && filesystem)
- unlink(filesystem);
return -1;
}
@@ -1203,31 +1398,26 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
// if the device is in DFU mode, place it into recovery mode
dfu_client_free(client);
recovery_client_free(client);
+#ifdef HAVE_LIMERA1N
if ((client->flags & FLAG_CUSTOM) && limera1n_is_supported(client->device)) {
- info("connecting to DFU\n");
+ logger(LL_INFO, "connecting to DFU\n");
if (dfu_client_new(client) < 0) {
- if (delete_fs && filesystem)
- unlink(filesystem);
return -1;
}
- info("exploiting with limera1n\n");
- // TODO: check for non-limera1n device and fail
+ logger(LL_INFO, "exploiting with limera1n\n");
if (limera1n_exploit(client->device, &client->dfu->client) != 0) {
- error("ERROR: limera1n exploit failed\n");
+ logger(LL_ERROR, "limera1n exploit failed\n");
dfu_client_free(client);
- if (delete_fs && filesystem)
- unlink(filesystem);
return -1;
}
dfu_client_free(client);
- info("exploited\n");
+ logger(LL_INFO, "exploited\n");
}
+#endif
if (dfu_enter_recovery(client, build_identity) < 0) {
- error("ERROR: Unable to place device into recovery mode from DFU mode\n");
+ logger(LL_ERROR, "Unable to place device into recovery mode from DFU mode\n");
if (client->tss)
plist_free(client->tss);
- if (delete_fs && filesystem)
- unlink(filesystem);
return -2;
}
} else if (client->mode == MODE_RECOVERY) {
@@ -1236,9 +1426,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
if (!client->image4supported) {
/* send ApTicket */
if (recovery_send_ticket(client) < 0) {
- error("ERROR: Unable to send APTicket\n");
- if (delete_fs && filesystem)
- unlink(filesystem);
+ logger(LL_ERROR, "Unable to send APTicket\n");
return -2;
}
}
@@ -1249,55 +1437,46 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
/* now we load the iBEC */
if (recovery_send_ibec(client, build_identity) < 0) {
mutex_unlock(&client->device_event_mutex);
- error("ERROR: Unable to send iBEC\n");
- if (delete_fs && filesystem)
- unlink(filesystem);
+ logger(LL_ERROR, "Unable to send iBEC\n");
return -2;
}
recovery_client_free(client);
- debug("Waiting for device to disconnect...\n");
- cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000);
+ logger(LL_DEBUG, "Waiting for device to disconnect...\n");
+ cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 60000);
if (client->mode != MODE_UNKNOWN || (client->flags & FLAG_QUIT)) {
mutex_unlock(&client->device_event_mutex);
if (!(client->flags & FLAG_QUIT)) {
- error("ERROR: Device did not disconnect. Possibly invalid iBEC. Reset device and try again.\n");
+ logger(LL_ERROR, "Device did not disconnect. Possibly invalid iBEC. Reset device and try again.\n");
}
- if (delete_fs && filesystem)
- unlink(filesystem);
return -2;
}
- debug("Waiting for device to reconnect in recovery mode...\n");
- cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000);
+ recovery_client_free(client);
+ logger(LL_DEBUG, "Waiting for device to reconnect in recovery mode...\n");
+ cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 60000);
if (client->mode != MODE_RECOVERY || (client->flags & FLAG_QUIT)) {
mutex_unlock(&client->device_event_mutex);
if (!(client->flags & FLAG_QUIT)) {
- error("ERROR: Device did not reconnect in recovery mode. Possibly invalid iBEC. Reset device and try again.\n");
+ logger(LL_ERROR, "Device did not reconnect in recovery mode. Possibly invalid iBEC. Reset device and try again.\n");
}
- if (delete_fs && filesystem)
- unlink(filesystem);
return -2;
}
mutex_unlock(&client->device_event_mutex);
}
idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.5);
if (client->flags & FLAG_QUIT) {
- if (delete_fs && filesystem)
- unlink(filesystem);
return -1;
}
if (!client->image4supported && (client->build_major > 8)) {
// we need another tss request with nonce.
unsigned char* nonce = NULL;
- int nonce_size = 0;
+ unsigned int nonce_size = 0;
int nonce_changed = 0;
if (get_ap_nonce(client, &nonce, &nonce_size) < 0) {
- error("ERROR: Unable to get nonce from device!\n");
+ logger(LL_ERROR, "Unable to get nonce from device!\n");
recovery_send_reset(client);
- if (delete_fs && filesystem)
- unlink(filesystem);
return -2;
}
@@ -1316,15 +1495,11 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
// Welcome iOS5. We have to re-request the TSS with our nonce.
plist_free(client->tss);
if (get_tss_response(client, build_identity, &client->tss) < 0) {
- error("ERROR: Unable to get SHSH blobs for this device\n");
- if (delete_fs && filesystem)
- unlink(filesystem);
+ logger(LL_ERROR, "Unable to get SHSH blobs for this device\n");
return -1;
}
if (!client->tss) {
- error("ERROR: can't continue without TSS\n");
- if (delete_fs && filesystem)
- unlink(filesystem);
+ logger(LL_ERROR, "can't continue without TSS\n");
return -1;
}
fixup_tss(client->tss);
@@ -1332,25 +1507,15 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
}
idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.7);
if (client->flags & FLAG_QUIT) {
- if (delete_fs && filesystem)
- unlink(filesystem);
return -1;
}
// now finally do the magic to put the device into restore mode
if (client->mode == MODE_RECOVERY) {
- if (client->srnm == NULL) {
- error("ERROR: could not retrieve device serial number. Can't continue.\n");
- if (delete_fs && filesystem)
- unlink(filesystem);
- return -1;
- }
if (recovery_enter_restore(client, build_identity) < 0) {
- error("ERROR: Unable to place device into restore mode\n");
+ logger(LL_ERROR, "Unable to place device into restore mode\n");
if (client->tss)
plist_free(client->tss);
- if (delete_fs && filesystem)
- unlink(filesystem);
return -2;
}
recovery_client_free(client);
@@ -1359,14 +1524,16 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
if (client->mode != MODE_RESTORE) {
mutex_lock(&client->device_event_mutex);
- info("Waiting for device to enter restore mode...\n");
- cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 180000);
+ logger(LL_INFO, "Waiting for device to enter restore mode...\n");
+ cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 300000);
if (client->mode != MODE_RESTORE || (client->flags & FLAG_QUIT)) {
mutex_unlock(&client->device_event_mutex);
- error("ERROR: Device failed to enter restore mode.\n");
- error("Please make sure that usbmuxd is running.\n");
- if (delete_fs && filesystem)
- unlink(filesystem);
+ logger(LL_ERROR, "Device failed to enter restore mode.\n");
+ if (client->mode == MODE_UNKNOWN) {
+ logger(LL_ERROR, "Make sure that usbmuxd is running.\n");
+ } else if (client->mode == MODE_RECOVERY || client->mode == MODE_DFU) {
+ logger(LL_ERROR, "Device reconnected in %s mode, most likely image personalization failed.\n", client->mode->string);
+ }
return -1;
}
mutex_unlock(&client->device_event_mutex);
@@ -1375,44 +1542,39 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
// device is finally in restore mode, let's do this
if (client->mode == MODE_RESTORE) {
if ((client->flags & FLAG_NO_RESTORE) != 0) {
- info("Device is now in restore mode. Exiting as requested.");
+ logger(LL_INFO, "Device is now in restore mode. Exiting as requested.\n");
return 0;
}
client->ignore_device_add_events = 1;
- info("About to restore device... \n");
- result = restore_device(client, build_identity, filesystem);
+ logger(LL_INFO, "About to restore device... \n");
+ result = restore_device(client, build_identity);
if (result < 0) {
- error("ERROR: Unable to restore device\n");
- if (delete_fs && filesystem)
- unlink(filesystem);
+ logger(LL_ERROR, "Unable to restore device\n");
return result;
}
}
- info("Cleaning up...\n");
- if (delete_fs && filesystem)
- unlink(filesystem);
-
/* special handling of older AppleTVs as they enter Recovery mode on boot when plugged in to USB */
if ((strncmp(client->device->product_type, "AppleTV", 7) == 0) && (client->device->product_type[7] < '5')) {
if (recovery_client_new(client) == 0) {
if (recovery_set_autoboot(client, 1) == 0) {
recovery_send_reset(client);
} else {
- error("Setting auto-boot failed?!\n");
+ logger(LL_ERROR, "Setting auto-boot failed?!\n");
}
} else {
- error("Could not connect to device in recovery mode.\n");
+ logger(LL_ERROR, "Could not connect to device in recovery mode.\n");
}
}
- info("DONE\n");
-
if (result == 0) {
+ logger(LL_INFO, "DONE\n");
idevicerestore_progress(client, RESTORE_NUM_STEPS-1, 1.0);
+ } else {
+ logger(LL_INFO, "RESTORE FAILED\n");
}
- if (build_identity)
+ if (build_identity_needs_free)
plist_free(build_identity);
return result;
@@ -1422,7 +1584,7 @@ struct idevicerestore_client_t* idevicerestore_client_new(void)
{
struct idevicerestore_client_t* client = (struct idevicerestore_client_t*) malloc(sizeof(struct idevicerestore_client_t));
if (client == NULL) {
- error("ERROR: Out of memory\n");
+ logger(LL_ERROR, "Out of memory\n");
return NULL;
}
memset(client, '\0', sizeof(struct idevicerestore_client_t));
@@ -1463,14 +1625,18 @@ void idevicerestore_client_free(struct idevicerestore_client_t* client)
free(client->srnm);
}
if (client->ipsw) {
- free(client->ipsw);
- }
- if (client->version) {
- free(client->version);
+ ipsw_close(client->ipsw);
}
- if (client->build) {
- free(client->build);
+ if (client->filesystem) {
+ if (client->delete_fs) {
+ unlink(client->filesystem);
+ }
+ free(client->filesystem);
}
+ free(client->version);
+ free(client->build);
+ free(client->device_version);
+ free(client->device_build);
if (client->restore_boot_args) {
free(client->restore_boot_args);
}
@@ -1483,9 +1649,13 @@ void idevicerestore_client_free(struct idevicerestore_client_t* client)
if (client->build_manifest) {
plist_free(client->build_manifest);
}
+ if (client->firmware_preflight_info) {
+ plist_free(client->firmware_preflight_info);
+ }
if (client->preflight_info) {
plist_free(client->preflight_info);
}
+ free(client->restore_variant);
free(client);
}
@@ -1521,11 +1691,11 @@ void idevicerestore_set_ipsw(struct idevicerestore_client_t* client, const char*
if (!client)
return;
if (client->ipsw) {
- free(client->ipsw);
+ ipsw_close(client->ipsw);
client->ipsw = NULL;
}
if (path) {
- client->ipsw = strdup(path);
+ client->ipsw = ipsw_open(path);
}
}
@@ -1557,6 +1727,7 @@ static void handle_signal(int sig)
{
if (idevicerestore_client) {
idevicerestore_client->flags |= FLAG_QUIT;
+ global_quit_flag++;
ipsw_cancel();
}
}
@@ -1567,16 +1738,51 @@ void plain_progress_cb(int step, double step_progress, void* userdata)
fflush(stdout);
}
-int main(int argc, char* argv[]) {
+static void plain_progress_func(struct progress_info_entry** progress_info, int count)
+{
+ int i = 0;
+ for (i = 0; i < count; i++) {
+ if (!progress_info[i]) continue;
+ printf("%s: %5.1f\n", progress_info[i]->label, progress_info[i]->progress);
+ fflush(stdout);
+ }
+}
+
+static void tty_print(enum loglevel level, const char* fmt, va_list ap)
+{
+ switch (level) {
+ case 0:
+ cprintf(FG_RED STYLE_BRIGHT);
+ break;
+ case 1:
+ cprintf(FG_YELLOW STYLE_BRIGHT);
+ break;
+ case 2:
+ cprintf(STYLE_BRIGHT);
+ break;
+ default:
+ break;
+ }
+
+ cvfprintf(stdout, fmt, ap);
+
+ cprintf(COLOR_RESET);
+}
+
+int main(int argc, char* argv[])
+{
int opt = 0;
int optindex = 0;
char* ipsw = NULL;
int ipsw_info = 0;
int result = 0;
+ const char* logfile = NULL;
+
+ logger_set_print_func(tty_print);
struct idevicerestore_client_t* client = idevicerestore_client_new();
if (client == NULL) {
- error("ERROR: could not create idevicerestore client\n");
+ logger(LL_ERROR, "Could not create idevicerestore client\n");
return EXIT_FAILURE;
}
@@ -1603,7 +1809,13 @@ int main(int argc, char* argv[]) {
client->flags |= FLAG_INTERACTIVE;
}
- while ((opt = getopt_long(argc, argv, "dhcesxtpli:u:nC:kyPRT:zv", longopts, &optindex)) > 0) {
+#ifdef HAVE_LIMERA1N
+#define P_FLAG "p"
+#else
+#define P_FLAG ""
+#endif
+
+ while ((opt = getopt_long(argc, argv, "dhces:xtli:u:nC:kyPRT:zv" P_FLAG, longopts, &optindex)) > 0) {
switch (opt) {
case 'h':
usage(argc, argv, 0);
@@ -1611,6 +1823,10 @@ int main(int argc, char* argv[]) {
case 'd':
client->flags |= FLAG_DEBUG;
+ client->debug_level++;
+ if (client->debug_level > 0) {
+ log_level = LL_DEBUG;
+ }
break;
case 'e':
@@ -1621,8 +1837,36 @@ int main(int argc, char* argv[]) {
client->flags |= FLAG_CUSTOM;
break;
- case 's':
- client->tss_url = strdup("http://cydia.saurik.com/TSS/controller?action=2");
+ case 's': {
+ if (!*optarg) {
+ logger(LL_ERROR, "URL argument for --server must not be empty!\n");
+ usage(argc, argv, 1);
+ return EXIT_FAILURE;
+ }
+ char *baseurl = NULL;
+ if (!strncmp(optarg, "http://", 7) && (strlen(optarg) > 7) && (optarg[7] != '/')) {
+ baseurl = optarg+7;
+ } else if (!strncmp(optarg, "https://", 8) && (strlen(optarg) > 8) && (optarg[8] != '/')) {
+ baseurl = optarg+8;
+ }
+ if (baseurl) {
+ char *p = strchr(baseurl, '/');
+ if (!p || *(p+1) == '\0') {
+ // no path component, add default path
+ const char default_path[] = "/TSS/controller?action=2";
+ size_t usize = strlen(optarg)+sizeof(default_path);
+ char* newurl = malloc(usize);
+ snprintf(newurl, usize, "%s%s", optarg, (p) ? default_path+1 : default_path);
+ client->tss_url = newurl;
+ } else {
+ client->tss_url = strdup(optarg);
+ }
+ } else {
+ logger(LL_ERROR, "URL argument for --server is invalid, must start with http:// or https://\n");
+ usage(argc, argv, 1);
+ return EXIT_FAILURE;
+ }
+ }
break;
case 'x':
@@ -1641,7 +1885,7 @@ int main(int argc, char* argv[]) {
client->ecid = 0;
}
if (client->ecid == 0) {
- error("ERROR: Could not parse ECID from '%s'\n", optarg);
+ logger(LL_ERROR, "Could not parse ECID from '%s'\n", optarg);
return EXIT_FAILURE;
}
}
@@ -1649,7 +1893,7 @@ int main(int argc, char* argv[]) {
case 'u':
if (!*optarg) {
- error("ERROR: UDID must not be empty!\n");
+ logger(LL_ERROR, "UDID must not be empty!\n");
usage(argc, argv, 1);
return EXIT_FAILURE;
}
@@ -1661,12 +1905,14 @@ int main(int argc, char* argv[]) {
break;
case 'k':
- idevicerestore_keep_pers = 1;
+ client->flags |= FLAG_KEEP_PERS;
break;
+#ifdef HAVE_LIMERA1N
case 'p':
client->flags |= FLAG_PWN;
break;
+#endif
case 'n':
client->flags |= FLAG_NOACTION;
@@ -1682,6 +1928,8 @@ int main(int argc, char* argv[]) {
case 'P':
idevicerestore_set_progress_callback(client, plain_progress_cb, NULL);
+ set_update_progress_func(plain_progress_func);
+ set_progress_granularity(0.01); // 1% granularity
break;
case 'R':
@@ -1693,7 +1941,7 @@ int main(int argc, char* argv[]) {
break;
case 'v':
- info("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
+ printf("%s %s (libirecovery %s, libtatsu %s)\n", PACKAGE_NAME, PACKAGE_VERSION, irecv_version(), libtatsu_version());
return EXIT_SUCCESS;
case 'T': {
@@ -1704,7 +1952,7 @@ int main(int argc, char* argv[]) {
}
client->root_ticket = root_ticket;
client->root_ticket_len = (int)root_ticket_len;
- info("Using ApTicket found at %s length %u\n", optarg, client->root_ticket_len);
+ logger(LL_INFO, "Using ApTicket found at %s length %u\n", optarg, client->root_ticket_len);
break;
}
@@ -1716,6 +1964,20 @@ int main(int argc, char* argv[]) {
client->flags |= FLAG_IGNORE_ERRORS;
break;
+ case 2:
+ free(client->restore_variant);
+ client->restore_variant = strdup(optarg);
+ break;
+
+ case 3:
+ if (!*optarg) {
+ logger(LL_ERROR, "logfile must not be empty!\n");
+ usage(argc, argv, 1);
+ return EXIT_FAILURE;
+ }
+ logfile = optarg;
+ break;
+
default:
usage(argc, argv, 1);
return EXIT_FAILURE;
@@ -1724,7 +1986,7 @@ int main(int argc, char* argv[]) {
if (ipsw_info) {
if (argc-optind != 1) {
- error("ERROR: --ipsw-info requires an IPSW path.\n");
+ logger(LL_ERROR, "--ipsw-info requires an IPSW path.\n");
usage(argc, argv, 1);
return EXIT_FAILURE;
}
@@ -1742,17 +2004,41 @@ int main(int argc, char* argv[]) {
}
if ((client->flags & FLAG_LATEST) && (client->flags & FLAG_CUSTOM)) {
- error("ERROR: You can't use --custom and --latest options at the same time.\n");
+ logger(LL_ERROR, "You can't use --custom and --latest options at the same time.\n");
return EXIT_FAILURE;
}
+ if (!logfile) {
+ char logfn[256];
+ int64_t timestamp = time(NULL);
+ if (client->ecid) {
+ snprintf(logfn, sizeof(logfn), "restore_%016" PRIx64 "_%" PRIi64 ".log", client->ecid, timestamp);
+ } else if (client->udid) {
+ snprintf(logfn, sizeof(logfn), "restore_%s_%" PRIi64 ".log", client->udid, timestamp);
+ } else {
+ snprintf(logfn, sizeof(logfn), "restore_%" PRIi64 ".log", timestamp);
+ }
+ logger_set_logfile(logfn);
+ } else {
+ logger_set_logfile(logfile);
+ }
+
+ logger(LL_INFO, "%s %s (libirecovery %s, libtatsu %s)\n", PACKAGE_NAME, PACKAGE_VERSION, irecv_version(), libtatsu_version());
+
if (ipsw) {
- client->ipsw = strdup(ipsw);
+ // verify if ipsw file exists
+ client->ipsw = ipsw_open(ipsw);
+ if (!client->ipsw) {
+ logger(LL_ERROR, "Firmware file %s cannot be opened.\n", ipsw);
+ return -1;
+ }
}
curl_global_init(CURL_GLOBAL_ALL);
+ client->flags |= FLAG_IN_PROGRESS;
result = idevicerestore_start(client);
+ client->flags &= ~FLAG_IN_PROGRESS;
idevicerestore_client_free(client);
@@ -1778,6 +2064,7 @@ irecv_device_t get_irecv_device(struct idevicerestore_client_t *client)
return normal_get_irecv_device(client);
case _MODE_DFU:
+ case _MODE_PORTDFU:
case _MODE_RECOVERY:
return dfu_get_irecv_device(client);
@@ -1809,158 +2096,107 @@ int is_image4_supported(struct idevicerestore_client_t* client)
res = recovery_is_image4_supported(client);
break;
default:
- error("ERROR: Device is in an invalid state\n");
+ logger(LL_ERROR, "Device is in an invalid state\n");
return 0;
}
return res;
}
-int get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid)
-{
- int mode = _MODE_UNKNOWN;
-
- if (client->mode) {
- mode = client->mode->index;
- }
-
- switch (mode) {
- case _MODE_NORMAL:
- if (normal_get_ecid(client, ecid) < 0) {
- *ecid = 0;
- return -1;
- }
- break;
-
- case _MODE_DFU:
- if (dfu_get_ecid(client, ecid) < 0) {
- *ecid = 0;
- return -1;
- }
- break;
-
- case _MODE_RECOVERY:
- if (recovery_get_ecid(client, ecid) < 0) {
- *ecid = 0;
- return -1;
- }
- break;
-
- default:
- error("ERROR: Device is in an invalid state\n");
- *ecid = 0;
- return -1;
- }
-
- return 0;
-}
-
-int get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size)
+int get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size)
{
int mode = _MODE_UNKNOWN;
*nonce = NULL;
*nonce_size = 0;
- info("Getting ApNonce ");
-
if (client->mode) {
mode = client->mode->index;
}
switch (mode) {
case _MODE_NORMAL:
- info("in normal mode... ");
+ logger(LL_INFO, "Getting ApNonce in Normal mode... ");
if (normal_get_ap_nonce(client, nonce, nonce_size) < 0) {
- info("failed\n");
+ logger(LL_INFO, "failed\n");
return -1;
}
break;
case _MODE_DFU:
- info("in dfu mode... ");
+ logger(LL_INFO, "Getting ApNonce in DFU mode... ");
if (dfu_get_ap_nonce(client, nonce, nonce_size) < 0) {
- info("failed\n");
+ logger(LL_INFO, "failed\n");
return -1;
}
break;
case _MODE_RECOVERY:
- info("in recovery mode... ");
+ logger(LL_INFO, "Getting ApNonce in Recovery mode... ");
if (recovery_get_ap_nonce(client, nonce, nonce_size) < 0) {
- info("failed\n");
+ logger(LL_INFO, "failed\n");
return -1;
}
break;
default:
- info("failed\n");
- error("ERROR: Device is in an invalid state\n");
+ logger(LL_INFO, "Getting ApNonce failed\n");
+ logger(LL_ERROR, "Device is in an invalid state\n");
return -1;
}
- int i = 0;
- for (i = 0; i < *nonce_size; i++) {
- info("%02x ", (*nonce)[i]);
- }
- info("\n");
+ logger_dump_hex(LL_INFO, *nonce, *nonce_size);
return 0;
}
-int get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size)
+int get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size)
{
int mode = _MODE_UNKNOWN;
*nonce = NULL;
*nonce_size = 0;
- info("Getting SepNonce ");
-
if (client->mode) {
mode = client->mode->index;
}
switch (mode) {
case _MODE_NORMAL:
- info("in normal mode... ");
+ logger(LL_INFO, "Getting SepNonce in normal mode... ");
if (normal_get_sep_nonce(client, nonce, nonce_size) < 0) {
- info("failed\n");
+ logger(LL_INFO, "failed\n");
return -1;
}
break;
case _MODE_DFU:
- info("in dfu mode... ");
+ logger(LL_INFO, "Getting SepNonce in dfu mode... ");
if (dfu_get_sep_nonce(client, nonce, nonce_size) < 0) {
- info("failed\n");
+ logger(LL_INFO, "failed\n");
return -1;
}
break;
case _MODE_RECOVERY:
- info("in recovery mode... ");
+ logger(LL_INFO, "Getting SepNonce in recovery mode... ");
if (recovery_get_sep_nonce(client, nonce, nonce_size) < 0) {
- info("failed\n");
+ logger(LL_INFO, "failed\n");
return -1;
}
break;
default:
- info("failed\n");
- error("ERROR: Device is in an invalid state\n");
+ logger(LL_INFO, "Getting SepNonce failed\n");
+ logger(LL_ERROR, "Device is in an invalid state\n");
return -1;
}
- int i = 0;
- for (i = 0; i < *nonce_size; i++) {
- info("%02x ", (*nonce)[i]);
- }
- info("\n");
+ logger_dump_hex(LL_INFO, *nonce, *nonce_size);
return 0;
}
-plist_t build_manifest_get_build_identity_for_model_with_variant(plist_t build_manifest, const char *hardware_model, const char *variant)
+plist_t build_manifest_get_build_identity_for_model_with_variant(plist_t build_manifest, const char *hardware_model, const char *variant, int exact)
{
plist_t build_identities_array = plist_dict_get_item(build_manifest, "BuildIdentities");
if (!build_identities_array || plist_get_node_type(build_identities_array) != PLIST_ARRAY) {
- error("ERROR: Unable to find build identities node\n");
+ logger(LL_ERROR, "Unable to find build identities node\n");
return NULL;
}
@@ -1978,30 +2214,27 @@ plist_t build_manifest_get_build_identity_for_model_with_variant(plist_t build_m
if (!devclass || plist_get_node_type(devclass) != PLIST_STRING) {
continue;
}
- char *str = NULL;
- plist_get_string_val(devclass, &str);
+ const char *str = plist_get_string_ptr(devclass, NULL);
if (strcasecmp(str, hardware_model) != 0) {
- free(str);
continue;
}
- free(str);
- str = NULL;
if (variant) {
plist_t rvariant = plist_dict_get_item(info_dict, "Variant");
if (!rvariant || plist_get_node_type(rvariant) != PLIST_STRING) {
continue;
}
- plist_get_string_val(rvariant, &str);
- if (strcasecmp(str, variant) != 0) {
- free(str);
+ str = plist_get_string_ptr(rvariant, NULL);
+ if (strcmp(str, variant) != 0) {
+ /* if it's not a full match, let's try a partial match, but ignore "*Research*" */
+ if (!exact && strstr(str, variant) && !strstr(str, "Research")) {
+ return ident;
+ }
continue;
} else {
- free(str);
- return plist_copy(ident);
+ return ident;
}
- free(str);
} else {
- return plist_copy(ident);
+ return ident;
}
}
@@ -2010,7 +2243,7 @@ plist_t build_manifest_get_build_identity_for_model_with_variant(plist_t build_m
plist_t build_manifest_get_build_identity_for_model(plist_t build_manifest, const char *hardware_model)
{
- return build_manifest_get_build_identity_for_model_with_variant(build_manifest, hardware_model, NULL);
+ return build_manifest_get_build_identity_for_model_with_variant(build_manifest, hardware_model, NULL, 0);
}
int get_preboard_manifest(struct idevicerestore_client_t* client, plist_t build_identity, plist_t* manifest)
@@ -2028,25 +2261,25 @@ int get_preboard_manifest(struct idevicerestore_client_t* client, plist_t build_
plist_t overrides = plist_new_dict();
plist_dict_set_item(overrides, "@APTicket", plist_new_bool(1));
plist_dict_set_item(overrides, "ApProductionMode", plist_new_uint(0));
- plist_dict_set_item(overrides, "ApSecurityDomain", plist_new_uint(0));
+ plist_dict_set_item(overrides, "ApSecurityDomain", plist_new_uint(1));
plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(0));
plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(0));
plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(1));
- tss_parameters_add_from_manifest(parameters, build_identity);
+ tss_parameters_add_from_manifest(parameters, build_identity, true);
/* create basic request */
request = tss_request_new(NULL);
if (request == NULL) {
- error("ERROR: Unable to create TSS request\n");
+ logger(LL_ERROR, "Unable to create TSS request\n");
plist_free(parameters);
return -1;
}
/* add common tags from manifest */
if (tss_request_add_common_tags(request, parameters, overrides) < 0) {
- error("ERROR: Unable to add common tags\n");
+ logger(LL_ERROR, "Unable to add common tags\n");
plist_free(request);
plist_free(parameters);
return -1;
@@ -2056,7 +2289,7 @@ int get_preboard_manifest(struct idevicerestore_client_t* client, plist_t build_
/* add tags from manifest */
if (tss_request_add_ap_tags(request, parameters, NULL) < 0) {
- error("ERROR: Unable to add ap tags\n");
+ logger(LL_ERROR, "Unable to add ap tags\n");
plist_free(request);
plist_free(parameters);
return -1;
@@ -2081,15 +2314,15 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident
*tss = NULL;
if ((client->build_major <= 8) || (client->flags & FLAG_CUSTOM)) {
- error("checking for local shsh\n");
+ logger(LL_ERROR, "checking for local shsh\n");
/* first check for local copy */
char zfn[1024];
if (client->version) {
if (client->cache_dir) {
- sprintf(zfn, "%s/shsh/%" PRIu64 "-%s-%s.shsh", client->cache_dir, client->ecid, client->device->product_type, client->version);
+ snprintf(zfn, sizeof(zfn), "%s/shsh/%" PRIu64 "-%s-%s.shsh", client->cache_dir, client->ecid, client->device->product_type, client->version);
} else {
- sprintf(zfn, "shsh/%" PRIu64 "-%s-%s.shsh", client->ecid, client->device->product_type, client->version);
+ snprintf(zfn, sizeof(zfn), "shsh/%" PRIu64 "-%s-%s.shsh", client->ecid, client->device->product_type, client->version);
}
struct stat fst;
if (stat(zfn, &fst) == 0) {
@@ -2103,7 +2336,7 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident
do {
int bytes_read = gzread(zf, p, readsize);
if (bytes_read < 0) {
- fprintf(stderr, "Error reading gz compressed data\n");
+ logger(LL_ERROR, "Error reading gz compressed data\n");
exit(EXIT_FAILURE);
}
blen += bytes_read;
@@ -2128,33 +2361,37 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident
free(bin);
}
} else {
- error("no local file %s\n", zfn);
+ logger(LL_ERROR, "no local file %s\n", zfn);
}
} else {
- error("No version found?!\n");
+ logger(LL_ERROR, "No version found?!\n");
}
}
if (*tss) {
- info("Using cached SHSH\n");
+ logger(LL_INFO, "Using cached SHSH\n");
return 0;
} else {
- info("Trying to fetch new SHSH blob\n");
+ logger(LL_INFO, "Trying to fetch new SHSH blob\n");
}
/* populate parameters */
plist_t parameters = plist_new_dict();
+ plist_dict_merge(&parameters, client->parameters);
+
plist_dict_set_item(parameters, "ApECID", plist_new_uint(client->ecid));
if (client->nonce) {
plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size));
}
- unsigned char* sep_nonce = NULL;
- int sep_nonce_size = 0;
- get_sep_nonce(client, &sep_nonce, &sep_nonce_size);
- if (sep_nonce) {
- plist_dict_set_item(parameters, "ApSepNonce", plist_new_data((const char*)sep_nonce, sep_nonce_size));
- free(sep_nonce);
+ if (!plist_dict_get_item(parameters, "SepNonce")) {
+ unsigned char* sep_nonce = NULL;
+ unsigned int sep_nonce_size = 0;
+ get_sep_nonce(client, &sep_nonce, &sep_nonce_size);
+ if (sep_nonce) {
+ plist_dict_set_item(parameters, "ApSepNonce", plist_new_data((const char*)sep_nonce, sep_nonce_size));
+ free(sep_nonce);
+ }
}
plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1));
@@ -2165,19 +2402,19 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident
plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(0));
}
- tss_parameters_add_from_manifest(parameters, build_identity);
+ tss_parameters_add_from_manifest(parameters, build_identity, true);
/* create basic request */
request = tss_request_new(NULL);
if (request == NULL) {
- error("ERROR: Unable to create TSS request\n");
+ logger(LL_ERROR, "Unable to create TSS request\n");
plist_free(parameters);
return -1;
}
/* add common tags from manifest */
if (tss_request_add_common_tags(request, parameters, NULL) < 0) {
- error("ERROR: Unable to add common tags to TSS request\n");
+ logger(LL_ERROR, "Unable to add common tags to TSS request\n");
plist_free(request);
plist_free(parameters);
return -1;
@@ -2185,7 +2422,7 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident
/* add tags from manifest */
if (tss_request_add_ap_tags(request, parameters, NULL) < 0) {
- error("ERROR: Unable to add common tags to TSS request\n");
+ logger(LL_ERROR, "Unable to add common tags to TSS request\n");
plist_free(request);
plist_free(parameters);
return -1;
@@ -2194,7 +2431,7 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident
if (client->image4supported) {
/* add personalized parameters */
if (tss_request_add_ap_img4_tags(request, parameters) < 0) {
- error("ERROR: Unable to add img4 tags to TSS request\n");
+ logger(LL_ERROR, "Unable to add img4 tags to TSS request\n");
plist_free(request);
plist_free(parameters);
return -1;
@@ -2202,7 +2439,7 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident
} else {
/* add personalized parameters */
if (tss_request_add_ap_img3_tags(request, parameters) < 0) {
- error("ERROR: Unable to add img3 tags to TSS request\n");
+ logger(LL_ERROR, "Unable to add img3 tags to TSS request\n");
plist_free(request);
plist_free(parameters);
return -1;
@@ -2212,70 +2449,46 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident
if (client->mode == MODE_NORMAL) {
/* normal mode; request baseband ticket aswell */
plist_t pinfo = NULL;
- normal_get_preflight_info(client, &pinfo);
+ normal_get_firmware_preflight_info(client, &pinfo);
if (pinfo) {
- plist_t node;
- node = plist_dict_get_item(pinfo, "Nonce");
- if (node) {
- plist_dict_set_item(parameters, "BbNonce", plist_copy(node));
- }
- node = plist_dict_get_item(pinfo, "ChipID");
- if (node) {
- plist_dict_set_item(parameters, "BbChipID", plist_copy(node));
- }
- node = plist_dict_get_item(pinfo, "CertID");
- if (node) {
- plist_dict_set_item(parameters, "BbGoldCertId", plist_copy(node));
- }
- node = plist_dict_get_item(pinfo, "ChipSerialNo");
- if (node) {
- plist_dict_set_item(parameters, "BbSNUM", plist_copy(node));
- }
-
- /* add baseband parameters */
- tss_request_add_baseband_tags(request, parameters, NULL);
-
- node = plist_dict_get_item(pinfo, "EUICCChipID");
- uint64_t euiccchipid = 0;
- if (node && plist_get_node_type(node) == PLIST_UINT) {
- plist_get_uint_val(node, &euiccchipid);
- plist_dict_set_item(parameters, "eUICC,ChipID", plist_copy(node));
- }
- if (euiccchipid >= 5) {
- node = plist_dict_get_item(pinfo, "EUICCCSN");
- if (node) {
- plist_dict_set_item(parameters, "eUICC,EID", plist_copy(node));
+ plist_dict_copy_data(parameters, pinfo, "BbNonce", "Nonce");
+ plist_dict_copy_uint(parameters, pinfo, "BbChipID", "ChipID");
+ plist_dict_copy_uint(parameters, pinfo, "BbGoldCertId", "CertID");
+ plist_dict_copy_data(parameters, pinfo, "BbSNUM", "ChipSerialNo");
+
+ if (plist_dict_get_item(parameters, "BbSNUM")) {
+ /* add baseband parameters */
+ tss_request_add_baseband_tags(request, parameters, NULL);
+
+ plist_dict_copy_uint(parameters, pinfo, "eUICC,ChipID", "EUICCChipID");
+ if (plist_dict_get_uint(parameters, "eUICC,ChipID") >= 5) {
+ plist_dict_copy_data(parameters, pinfo, "eUICC,EID", "EUICCCSN");
+ plist_dict_copy_data(parameters, pinfo, "eUICC,RootKeyIdentifier", "EUICCCertIdentifier");
+ plist_dict_copy_data(parameters, pinfo, "EUICCGoldNonce", NULL);
+ plist_dict_copy_data(parameters, pinfo, "EUICCMainNonce", NULL);
+
+ /* add vinyl parameters */
+ tss_request_add_vinyl_tags(request, parameters, NULL);
}
- node = plist_dict_get_item(pinfo, "EUICCCertIdentifier");
- if (node) {
- plist_dict_set_item(parameters, "eUICC,RootKeyIdentifier", plist_copy(node));
- }
- node = plist_dict_get_item(pinfo, "EUICCGoldNonce");
- if (node) {
- plist_dict_set_item(parameters, "EUICCGoldNonce", plist_copy(node));
- }
- node = plist_dict_get_item(pinfo, "EUICCMainNonce");
- if (node) {
- plist_dict_set_item(parameters, "EUICCMainNonce", plist_copy(node));
- }
-
- /* add vinyl parameters */
- tss_request_add_vinyl_tags(request, parameters, NULL);
}
}
+ client->firmware_preflight_info = pinfo;
+ pinfo = NULL;
+
+ normal_get_preflight_info(client, &pinfo);
client->preflight_info = pinfo;
}
/* send request and grab response */
response = tss_request_send(request, client->tss_url);
if (response == NULL) {
- info("ERROR: Unable to send TSS request\n");
+ logger(LL_INFO, "ERROR: Unable to send TSS request\n");
plist_free(request);
plist_free(parameters);
return -1;
}
- info("Received SHSH blobs\n");
+ logger(LL_INFO, "Received SHSH blobs\n");
plist_free(request);
plist_free(parameters);
@@ -2303,7 +2516,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie
plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size));
}
unsigned char* sep_nonce = NULL;
- int sep_nonce_size = 0;
+ unsigned int sep_nonce_size = 0;
get_sep_nonce(client, &sep_nonce, &sep_nonce_size);
/* ApSepNonce */
@@ -2323,21 +2536,21 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie
plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(0));
}
- tss_parameters_add_from_manifest(parameters, build_identity);
+ tss_parameters_add_from_manifest(parameters, build_identity, true);
/* create basic request */
- /* Adds @BBTicket, @HostPlatformInfo, @VersionInfo, @UUID */
+ /* Adds @HostPlatformInfo, @VersionInfo, @UUID */
request = tss_request_new(NULL);
if (request == NULL) {
- error("ERROR: Unable to create TSS request\n");
+ logger(LL_ERROR, "Unable to create TSS request\n");
plist_free(parameters);
return -1;
}
/* add common tags from manifest */
- /* Adds Ap,OSLongVersion, AppNonce, @ApImg4Ticket */
+ /* Adds Ap,OSLongVersion, ApNonce, @ApImg4Ticket */
if (tss_request_add_ap_img4_tags(request, parameters) < 0) {
- error("ERROR: Unable to add AP IMG4 tags to TSS request\n");
+ logger(LL_ERROR, "Unable to add AP IMG4 tags to TSS request\n");
plist_free(request);
plist_free(parameters);
return -1;
@@ -2345,7 +2558,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie
/* add AP tags from manifest */
if (tss_request_add_common_tags(request, parameters, NULL) < 0) {
- error("ERROR: Unable to add common tags to TSS request\n");
+ logger(LL_ERROR, "Unable to add common tags to TSS request\n");
plist_free(request);
plist_free(parameters);
return -1;
@@ -2354,7 +2567,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie
/* add AP tags from manifest */
/* Fills digests & co */
if (tss_request_add_ap_recovery_tags(request, parameters, NULL) < 0) {
- error("ERROR: Unable to add common tags to TSS request\n");
+ logger(LL_ERROR, "Unable to add common tags to TSS request\n");
plist_free(request);
plist_free(parameters);
return -1;
@@ -2363,14 +2576,14 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie
/* send request and grab response */
response = tss_request_send(request, client->tss_url);
if (response == NULL) {
- info("ERROR: Unable to send TSS request\n");
+ logger(LL_INFO, "ERROR: Unable to send TSS request\n");
plist_free(request);
plist_free(parameters);
return -1;
}
// request_add_ap_tags
- info("Received SHSH blobs\n");
+ logger(LL_INFO, "Received SHSH blobs\n");
plist_free(request);
plist_free(parameters);
@@ -2403,21 +2616,18 @@ int get_recovery_os_local_policy_tss_response(
plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(0));
}
- tss_parameters_add_from_manifest(parameters, build_identity);
+ tss_parameters_add_from_manifest(parameters, build_identity, true);
// Add Ap,LocalPolicy
uint8_t digest[SHA384_DIGEST_LENGTH];
- SHA384(lpol_file, lpol_file_length, digest);
+ sha384(lpol_file, lpol_file_length, digest);
plist_t lpol = plist_new_dict();
plist_dict_set_item(lpol, "Digest", plist_new_data((char*)digest, SHA384_DIGEST_LENGTH));
plist_dict_set_item(lpol, "Trusted", plist_new_bool(1));
plist_dict_set_item(parameters, "Ap,LocalPolicy", lpol);
- plist_t im4m_hash = plist_dict_get_item(args, "Ap,NextStageIM4MHash");
- plist_dict_set_item(parameters, "Ap,NextStageIM4MHash", plist_copy(im4m_hash));
-
- plist_t nonce_hash = plist_dict_get_item(args, "Ap,RecoveryOSPolicyNonceHash");
- plist_dict_set_item(parameters, "Ap,RecoveryOSPolicyNonceHash", plist_copy(nonce_hash));
+ plist_dict_copy_data(parameters, args, "Ap,NextStageIM4MHash", NULL);
+ plist_dict_copy_data(parameters, args, "Ap,RecoveryOSPolicyNonceHash", NULL);
plist_t vol_uuid_node = plist_dict_get_item(args, "Ap,VolumeUUID");
char* vol_uuid_str = NULL;
@@ -2425,7 +2635,7 @@ int get_recovery_os_local_policy_tss_response(
unsigned int vuuid[16];
unsigned char vol_uuid[16];
if (sscanf(vol_uuid_str, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", &vuuid[0], &vuuid[1], &vuuid[2], &vuuid[3], &vuuid[4], &vuuid[5], &vuuid[6], &vuuid[7], &vuuid[8], &vuuid[9], &vuuid[10], &vuuid[11], &vuuid[12], &vuuid[13], &vuuid[14], &vuuid[15]) != 16) {
- error("ERROR: Failed to parse Ap,VolumeUUID (%s)\n", vol_uuid_str);
+ logger(LL_ERROR, "Failed to parse Ap,VolumeUUID (%s)\n", vol_uuid_str);
free(vol_uuid_str);
return -1;
}
@@ -2439,14 +2649,14 @@ int get_recovery_os_local_policy_tss_response(
/* create basic request */
request = tss_request_new(NULL);
if (request == NULL) {
- error("ERROR: Unable to create TSS request\n");
+ logger(LL_ERROR, "Unable to create TSS request\n");
plist_free(parameters);
return -1;
}
/* add common tags from manifest */
if (tss_request_add_local_policy_tags(request, parameters) < 0) {
- error("ERROR: Unable to add common tags to TSS request\n");
+ logger(LL_ERROR, "Unable to add common tags to TSS request\n");
plist_free(request);
plist_free(parameters);
return -1;
@@ -2455,13 +2665,13 @@ int get_recovery_os_local_policy_tss_response(
/* send request and grab response */
response = tss_request_send(request, client->tss_url);
if (response == NULL) {
- info("ERROR: Unable to send TSS request\n");
+ logger(LL_INFO, "ERROR: Unable to send TSS request\n");
plist_free(request);
plist_free(parameters);
return -1;
}
- info("Received SHSH blobs\n");
+ logger(LL_INFO, "Received SHSH blobs\n");
plist_free(request);
plist_free(parameters);
@@ -2485,7 +2695,7 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_
plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size));
}
unsigned char* sep_nonce = NULL;
- int sep_nonce_size = 0;
+ unsigned int sep_nonce_size = 0;
get_sep_nonce(client, &sep_nonce, &sep_nonce_size);
if (sep_nonce) {
@@ -2501,11 +2711,11 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_
plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(0));
}
- tss_parameters_add_from_manifest(parameters, build_identity);
+ tss_parameters_add_from_manifest(parameters, build_identity, true);
// Add Ap,LocalPolicy
uint8_t digest[SHA384_DIGEST_LENGTH];
- SHA384(lpol_file, lpol_file_length, digest);
+ sha384(lpol_file, lpol_file_length, digest);
plist_t lpol = plist_new_dict();
plist_dict_set_item(lpol, "Digest", plist_new_data((char*)digest, SHA384_DIGEST_LENGTH));
plist_dict_set_item(lpol, "Trusted", plist_new_bool(1));
@@ -2518,20 +2728,20 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_
tss_response_get_ap_img4_ticket(client->tss, &ticket, &ticket_length);
// Hash it and add it as Ap,NextStageIM4MHash
uint8_t hash[SHA384_DIGEST_LENGTH];
- SHA384(ticket, ticket_length, hash);
+ sha384(ticket, ticket_length, hash);
plist_dict_set_item(parameters, "Ap,NextStageIM4MHash", plist_new_data((char*)hash, SHA384_DIGEST_LENGTH));
/* create basic request */
request = tss_request_new(NULL);
if (request == NULL) {
- error("ERROR: Unable to create TSS request\n");
+ logger(LL_ERROR, "Unable to create TSS request\n");
plist_free(parameters);
return -1;
}
/* add common tags from manifest */
if (tss_request_add_local_policy_tags(request, parameters) < 0) {
- error("ERROR: Unable to add common tags to TSS request\n");
+ logger(LL_ERROR, "Unable to add common tags to TSS request\n");
plist_free(request);
plist_free(parameters);
return -1;
@@ -2540,13 +2750,13 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_
/* send request and grab response */
response = tss_request_send(request, client->tss_url);
if (response == NULL) {
- info("ERROR: Unable to send TSS request\n");
+ logger(LL_INFO, "ERROR: Unable to send TSS request\n");
plist_free(request);
plist_free(parameters);
return -1;
}
- info("Received SHSH blobs\n");
+ logger(LL_INFO, "Received SHSH blobs\n");
plist_free(request);
plist_free(parameters);
@@ -2591,15 +2801,13 @@ int build_manifest_get_identity_count(plist_t build_manifest)
// fetch build identities array from BuildManifest
plist_t build_identities_array = plist_dict_get_item(build_manifest, "BuildIdentities");
if (!build_identities_array || plist_get_node_type(build_identities_array) != PLIST_ARRAY) {
- error("ERROR: Unable to find build identities node\n");
+ logger(LL_ERROR, "Unable to find build identities node\n");
return -1;
}
-
- // check and make sure this identity exists in buildmanifest
return plist_array_get_size(build_identities_array);
}
-int extract_component(const char* ipsw, const char* path, unsigned char** component_data, unsigned int* component_size)
+int extract_component(ipsw_archive_t ipsw, const char* path, void** component_data, size_t* component_size)
{
char* component_name = NULL;
if (!ipsw || !path || !component_data || !component_size) {
@@ -2612,39 +2820,38 @@ int extract_component(const char* ipsw, const char* path, unsigned char** compon
else
component_name = (char*) path;
- info("Extracting %s (%s)...\n", component_name, path);
+ logger(LL_INFO, "Extracting %s (%s)...\n", component_name, path);
if (ipsw_extract_to_memory(ipsw, path, component_data, component_size) < 0) {
- error("ERROR: Unable to extract %s from %s\n", component_name, ipsw);
+ logger(LL_ERROR, "Unable to extract %s from %s\n", component_name, ipsw->path);
return -1;
}
return 0;
}
-int personalize_component(const char *component_name, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** personalized_component, unsigned int* personalized_component_size)
+int personalize_component(struct idevicerestore_client_t* client, const char *component_name, const void* component_data, size_t component_size, plist_t tss_response, void** personalized_component, size_t* personalized_component_size)
{
- unsigned char* component_blob = NULL;
- unsigned int component_blob_size = 0;
- unsigned char* stitched_component = NULL;
- unsigned int stitched_component_size = 0;
+ void* component_blob = NULL;
+ void* stitched_component = NULL;
+ size_t stitched_component_size = 0;
- if (tss_response && tss_response_get_ap_img4_ticket(tss_response, &component_blob, &component_blob_size) == 0) {
+ if (tss_response && plist_dict_get_item(tss_response, "ApImg4Ticket")) {
/* stitch ApImg4Ticket into IMG4 file */
- img4_stitch_component(component_name, component_data, component_size, component_blob, component_blob_size, &stitched_component, &stitched_component_size);
+ img4_stitch_component(component_name, component_data, component_size, client->parameters, tss_response, &stitched_component, &stitched_component_size);
} else {
/* try to get blob for current component from tss response */
- if (tss_response && tss_response_get_blob_by_entry(tss_response, component_name, &component_blob) < 0) {
- debug("NOTE: No SHSH blob found for component %s\n", component_name);
+ if (tss_response && tss_response_get_blob_by_entry(tss_response, component_name, (unsigned char**)&component_blob) < 0) {
+ logger(LL_DEBUG, "NOTE: No SHSH blob found for component %s\n", component_name);
}
if (component_blob != NULL) {
if (img3_stitch_component(component_name, component_data, component_size, component_blob, 64, &stitched_component, &stitched_component_size) < 0) {
- error("ERROR: Unable to replace %s IMG3 signature\n", component_name);
+ logger(LL_ERROR, "Unable to replace %s IMG3 signature\n", component_name);
free(component_blob);
return -1;
}
} else {
- info("Not personalizing component %s...\n", component_name);
+ logger(LL_INFO, "Not personalizing component %s...\n", component_name);
stitched_component = (unsigned char*)malloc(component_size);
if (stitched_component) {
stitched_component_size = component_size;
@@ -2654,7 +2861,7 @@ int personalize_component(const char *component_name, const unsigned char* compo
}
free(component_blob);
- if (idevicerestore_keep_pers) {
+ if (client->flags & FLAG_KEEP_PERS) {
write_file(component_name, stitched_component, stitched_component_size);
}
@@ -2668,9 +2875,9 @@ int build_manifest_check_compatibility(plist_t build_manifest, const char* produ
int res = -1;
plist_t node = plist_dict_get_item(build_manifest, "SupportedProductTypes");
if (!node || (plist_get_node_type(node) != PLIST_ARRAY)) {
- debug("%s: ERROR: SupportedProductTypes key missing\n", __func__);
- debug("%s: WARNING: If attempting to install iPhoneOS 2.x, be advised that Restore.plist does not contain the", __func__);
- debug("%s: WARNING: key 'SupportedProductTypes'. Recommendation is to manually add it to the Restore.plist.", __func__);
+ logger(LL_DEBUG, "%s: ERROR: SupportedProductTypes key missing\n", __func__);
+ logger(LL_DEBUG, "%s: WARNING: If attempting to install iPhoneOS 2.x, be advised that Restore.plist does not contain the\n", __func__);
+ logger(LL_DEBUG, "%s: WARNING: key 'SupportedProductTypes'. Recommendation is to manually add it to the Restore.plist.\n", __func__);
return -1;
}
uint32_t pc = plist_array_get_size(node);
@@ -2698,14 +2905,14 @@ void build_manifest_get_version_information(plist_t build_manifest, struct idevi
node = plist_dict_get_item(build_manifest, "ProductVersion");
if (!node || plist_get_node_type(node) != PLIST_STRING) {
- error("ERROR: Unable to find ProductVersion node\n");
+ logger(LL_ERROR, "Unable to find ProductVersion node\n");
return;
}
plist_get_string_val(node, &client->version);
node = plist_dict_get_item(build_manifest, "ProductBuildVersion");
if (!node || plist_get_node_type(node) != PLIST_STRING) {
- error("ERROR: Unable to find ProductBuildVersion node\n");
+ logger(LL_ERROR, "Unable to find ProductBuildVersion node\n");
return;
}
plist_get_string_val(node, &client->build);
@@ -2721,32 +2928,25 @@ void build_identity_print_information(plist_t build_identity)
info_node = plist_dict_get_item(build_identity, "Info");
if (!info_node || plist_get_node_type(info_node) != PLIST_DICT) {
- error("ERROR: Unable to find Info node\n");
+ logger(LL_ERROR, "Unable to find Info node\n");
return;
}
node = plist_dict_get_item(info_node, "Variant");
if (!node || plist_get_node_type(node) != PLIST_STRING) {
- error("ERROR: Unable to find Variant node\n");
+ logger(LL_ERROR, "Unable to find Variant node\n");
return;
}
plist_get_string_val(node, &value);
- info("Variant: %s\n", value);
- free(value);
+ logger(LL_INFO, "Variant: %s\n", value);
- node = plist_dict_get_item(info_node, "RestoreBehavior");
- if (!node || plist_get_node_type(node) != PLIST_STRING) {
- error("ERROR: Unable to find RestoreBehavior node\n");
- return;
- }
- plist_get_string_val(node, &value);
-
- if (!strcmp(value, "Erase"))
- info("This restore will erase your device data.\n");
-
- if (!strcmp(value, "Update"))
- info("This restore will update your device without erasing user data.\n");
+ if (strstr(value, RESTORE_VARIANT_UPGRADE_INSTALL))
+ logger(LL_INFO, "This restore will update the device without erasing user data.\n");
+ else if (strstr(value, RESTORE_VARIANT_ERASE_INSTALL))
+ logger(LL_INFO, "This restore will erase all device data.\n");
+ else
+ logger(LL_INFO, "Unknown Variant '%s'\n", value);
free(value);
@@ -2754,7 +2954,7 @@ void build_identity_print_information(plist_t build_identity)
node = NULL;
}
-int build_identity_check_components_in_ipsw(plist_t build_identity, const char *ipsw)
+int build_identity_check_components_in_ipsw(plist_t build_identity, ipsw_archive_t ipsw)
{
plist_t manifest_node = plist_dict_get_item(build_identity, "Manifest");
if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) {
@@ -2776,7 +2976,7 @@ int build_identity_check_components_in_ipsw(plist_t build_identity, const char *
plist_get_string_val(path, &comp_path);
if (comp_path) {
if (!ipsw_file_exists(ipsw, comp_path)) {
- error("ERROR: %s file %s not found in IPSW\n", key, comp_path);
+ logger(LL_ERROR, "%s file %s not found in IPSW\n", key, comp_path);
res = -1;
}
free(comp_path);
@@ -2809,7 +3009,7 @@ int build_identity_get_component_path(plist_t build_identity, const char* compon
plist_t manifest_node = plist_dict_get_item(build_identity, "Manifest");
if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) {
- error("ERROR: Unable to find manifest node\n");
+ logger(LL_ERROR, "Unable to find manifest node\n");
if (filename)
free(filename);
return -1;
@@ -2817,7 +3017,7 @@ int build_identity_get_component_path(plist_t build_identity, const char* compon
plist_t component_node = plist_dict_get_item(manifest_node, component);
if (!component_node || plist_get_node_type(component_node) != PLIST_DICT) {
- error("ERROR: Unable to find component node for %s\n", component);
+ logger(LL_ERROR, "Unable to find component node for %s\n", component);
if (filename)
free(filename);
return -1;
@@ -2825,7 +3025,7 @@ int build_identity_get_component_path(plist_t build_identity, const char* compon
plist_t component_info_node = plist_dict_get_item(component_node, "Info");
if (!component_info_node || plist_get_node_type(component_info_node) != PLIST_DICT) {
- error("ERROR: Unable to find component info node for %s\n", component);
+ logger(LL_ERROR, "Unable to find component info node for %s\n", component);
if (filename)
free(filename);
return -1;
@@ -2833,7 +3033,7 @@ int build_identity_get_component_path(plist_t build_identity, const char* compon
plist_t component_info_path_node = plist_dict_get_item(component_info_node, "Path");
if (!component_info_path_node || plist_get_node_type(component_info_path_node) != PLIST_STRING) {
- error("ERROR: Unable to find component info path node for %s\n", component);
+ logger(LL_ERROR, "Unable to find component info path node for %s\n", component);
if (filename)
free(filename);
return -1;
@@ -2846,42 +3046,38 @@ int build_identity_get_component_path(plist_t build_identity, const char* compon
const char* get_component_name(const char* filename)
{
- if (!strncmp(filename, "LLB", 3)) {
- return "LLB";
- } else if (!strncmp(filename, "iBoot", 5)) {
- return "iBoot";
- } else if (!strncmp(filename, "DeviceTree", 10)) {
- return "DeviceTree";
- } else if (!strncmp(filename, "applelogo", 9)) {
- return "AppleLogo";
- } else if (!strncmp(filename, "liquiddetect", 12)) {
- return "Liquid";
- } else if (!strncmp(filename, "lowpowermode", 12)) {
- return "LowPowerWallet0";
- } else if (!strncmp(filename, "recoverymode", 12)) {
- return "RecoveryMode";
- } else if (!strncmp(filename, "batterylow0", 11)) {
- return "BatteryLow0";
- } else if (!strncmp(filename, "batterylow1", 11)) {
- return "BatteryLow1";
- } else if (!strncmp(filename, "glyphcharging", 13)) {
- return "BatteryCharging";
- } else if (!strncmp(filename, "glyphplugin", 11)) {
- return "BatteryPlugin";
- } else if (!strncmp(filename, "batterycharging0", 16)) {
- return "BatteryCharging0";
- } else if (!strncmp(filename, "batterycharging1", 16)) {
- return "BatteryCharging1";
- } else if (!strncmp(filename, "batteryfull", 11)) {
- return "BatteryFull";
- } else if (!strncmp(filename, "needservice", 11)) {
- return "NeedService";
- } else if (!strncmp(filename, "SCAB", 4)) {
- return "SCAB";
- } else if (!strncmp(filename, "sep-firmware", 12)) {
- return "RestoreSEP";
- } else {
- error("WARNING: Unhandled component '%s'", filename);
- return NULL;
+ struct filename_component_map {
+ const char *fnprefix;
+ int matchlen;
+ const char *compname;
+ };
+ struct filename_component_map fn_comp_map[] = {
+ { "LLB", 3, "LLB" },
+ { "iBoot", 5, "iBoot" },
+ { "DeviceTree", 10, "DeviceTree" },
+ { "applelogo", 9, "AppleLogo" },
+ { "liquiddetect", 12, "Liquid" },
+ { "lowpowermode", 12, "LowPowerWallet0" },
+ { "recoverymode", 12, "RecoveryMode" },
+ { "batterylow0", 11, "BatteryLow0" },
+ { "batterylow1", 11, "BatteryLow1" },
+ { "glyphcharging", 13, "BatteryCharging" },
+ { "glyphplugin", 11, "BatteryPlugin" },
+ { "batterycharging0", 16, "BatteryCharging0" },
+ { "batterycharging1", 16, "BatteryCharging1" },
+ { "batteryfull", 11, "BatteryFull" },
+ { "needservice", 11, "NeedService" },
+ { "SCAB", 4, "SCAB" },
+ { "sep-firmware", 12, "RestoreSEP" },
+ { NULL, 0, NULL }
+ };
+ int i = 0;
+ while (fn_comp_map[i].fnprefix) {
+ if (!strncmp(filename, fn_comp_map[i].fnprefix, fn_comp_map[i].matchlen)) {
+ return fn_comp_map[i].compname;
+ }
+ i++;
}
+ logger(LL_WARNING, "Unhandled component '%s'", filename);
+ return NULL;
}
diff --git a/src/idevicerestore.h b/src/idevicerestore.h
index 880f9ee..ce8686f 100644
--- a/src/idevicerestore.h
+++ b/src/idevicerestore.h
@@ -46,8 +46,16 @@ extern "C" {
#define FLAG_ALLOW_RESTORE_MODE (1 << 10)
#define FLAG_NO_RESTORE (1 << 11)
#define FLAG_IGNORE_ERRORS (1 << 12)
+#define FLAG_KEEP_PERS (1 << 13)
+#define FLAG_IN_PROGRESS (1 << 30)
+
+#define RESTORE_VARIANT_ERASE_INSTALL "Erase Install (IPSW)"
+#define RESTORE_VARIANT_UPGRADE_INSTALL "Upgrade Install (IPSW)"
+#define RESTORE_VARIANT_MACOS_RECOVERY_OS "macOS Customer"
struct idevicerestore_client_t;
+struct ipsw_archive;
+typedef struct ipsw_archive* ipsw_archive_t;
enum {
RESTORE_STEP_DETECT = 0,
@@ -57,6 +65,7 @@ enum {
RESTORE_STEP_FLASH_FW,
RESTORE_STEP_FLASH_BB,
RESTORE_STEP_FUD,
+ RESTORE_STEP_UPLOAD_IMG,
RESTORE_NUM_STEPS
};
@@ -76,9 +85,6 @@ void idevicerestore_set_flags(struct idevicerestore_client_t* client, int flags)
void idevicerestore_set_ipsw(struct idevicerestore_client_t* client, const char* path);
void idevicerestore_set_cache_path(struct idevicerestore_client_t* client, const char* path);
void idevicerestore_set_progress_callback(struct idevicerestore_client_t* client, idevicerestore_progress_cb_t cbfunc, void* userdata);
-void idevicerestore_set_info_stream(FILE* strm);
-void idevicerestore_set_error_stream(FILE* strm);
-void idevicerestore_set_debug_stream(FILE* strm);
int idevicerestore_start(struct idevicerestore_client_t* client);
const char* idevicerestore_get_error(void);
@@ -86,8 +92,8 @@ const char* idevicerestore_get_error(void);
irecv_device_t get_irecv_device(struct idevicerestore_client_t* client);
int get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid);
int is_image4_supported(struct idevicerestore_client_t* client);
-int get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size);
-int get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size);
+int get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size);
+int get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size);
int get_tss_response(struct idevicerestore_client_t* client, plist_t build_identity, plist_t* tss);
int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_t build_identity, plist_t* tss);
int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* client, plist_t build_identity, plist_t* tss);
@@ -101,15 +107,14 @@ int build_manifest_get_identity_count(plist_t build_manifest);
int build_manifest_check_compatibility(plist_t build_manifest, const char* product);
void build_manifest_get_version_information(plist_t build_manifest, struct idevicerestore_client_t* client);
plist_t build_manifest_get_build_identity_for_model(plist_t build_manifest, const char *hardware_model);
-plist_t build_manifest_get_build_identity_for_model_with_variant(plist_t build_manifest, const char *hardware_model, const char *variant);
+plist_t build_manifest_get_build_identity_for_model_with_variant(plist_t build_manifest, const char *hardware_model, const char *variant, int exact);
int build_manifest_get_build_count(plist_t build_manifest);
void build_identity_print_information(plist_t build_identity);
-int build_identity_check_components_in_ipsw(plist_t build_identity, const char* ipsw);
int build_identity_has_component(plist_t build_identity, const char* component);
int build_identity_get_component_path(plist_t build_identity, const char* component, char** path);
-int ipsw_extract_filesystem(const char* ipsw, plist_t build_identity, char** filesystem);
-int extract_component(const char* ipsw, const char* path, unsigned char** component_data, unsigned int* component_size);
-int personalize_component(const char *component, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** personalized_component, unsigned int* personalized_component_size);
+int ipsw_extract_filesystem(ipsw_archive_t ipsw, plist_t build_identity, char** filesystem);
+int extract_component(ipsw_archive_t ipsw, const char* path, void** component_data, size_t* component_size);
+int personalize_component(struct idevicerestore_client_t* client, const char *component, const void* component_data, size_t component_size, plist_t tss_response, void** personalized_component, size_t* personalized_component_size);
int get_preboard_manifest(struct idevicerestore_client_t* client, plist_t build_identity, plist_t* manifest);
const char* get_component_name(const char* filename);
diff --git a/src/img3.c b/src/img3.c
index fb8d49e..db50703 100644
--- a/src/img3.c
+++ b/src/img3.c
@@ -38,13 +38,13 @@ static img3_file* img3_parse_file(const unsigned char* data, unsigned int size)
img3_element* element;
img3_header* header = (img3_header*) data;
if (header->signature != kImg3Container) {
- error("ERROR: Invalid IMG3 file\n");
+ logger(LL_ERROR, "Invalid IMG3 file\n");
return NULL;
}
img3_file* image = (img3_file*) malloc(sizeof(img3_file));
if (image == NULL) {
- error("ERROR: Unable to allocate memory for IMG3 file\n");
+ logger(LL_ERROR, "Unable to allocate memory for IMG3 file\n");
return NULL;
}
memset(image, '\0', sizeof(img3_file));
@@ -54,7 +54,7 @@ static img3_file* img3_parse_file(const unsigned char* data, unsigned int size)
image->header = (img3_header*) malloc(sizeof(img3_header));
if (image->header == NULL) {
- error("ERROR: Unable to allocate memory for IMG3 header\n");
+ logger(LL_ERROR, "Unable to allocate memory for IMG3 header\n");
img3_free(image);
return NULL;
}
@@ -68,129 +68,129 @@ static img3_file* img3_parse_file(const unsigned char* data, unsigned int size)
case kTypeElement:
element = img3_parse_element(&data[data_offset]);
if (element == NULL) {
- error("ERROR: Unable to parse TYPE element\n");
+ logger(LL_ERROR, "Unable to parse TYPE element\n");
img3_free(image);
return NULL;
}
image->elements[image->num_elements++] = element;
- debug("Parsed TYPE element\n");
+ logger(LL_DEBUG, "Parsed TYPE element\n");
break;
case kDataElement:
element = img3_parse_element(&data[data_offset]);
if (element == NULL) {
- error("ERROR: Unable to parse DATA element\n");
+ logger(LL_ERROR, "Unable to parse DATA element\n");
img3_free(image);
return NULL;
}
image->elements[image->num_elements++] = element;
- debug("Parsed DATA element\n");
+ logger(LL_DEBUG, "Parsed DATA element\n");
break;
case kVersElement:
element = img3_parse_element(&data[data_offset]);
if (element == NULL) {
- error("ERROR: Unable to parse VERS element\n");
+ logger(LL_ERROR, "Unable to parse VERS element\n");
img3_free(image);
return NULL;
}
image->elements[image->num_elements++] = element;
- debug("Parsed VERS element\n");
+ logger(LL_DEBUG, "Parsed VERS element\n");
break;
case kSepoElement:
element = img3_parse_element(&data[data_offset]);
if (element == NULL) {
- error("ERROR: Unable to parse SEPO element\n");
+ logger(LL_ERROR, "Unable to parse SEPO element\n");
img3_free(image);
return NULL;
}
image->elements[image->num_elements++] = element;
- debug("Parsed SEPO element\n");
+ logger(LL_DEBUG, "Parsed SEPO element\n");
break;
case kBordElement:
element = img3_parse_element(&data[data_offset]);
if (element == NULL) {
- error("ERROR: Unable to parse BORD element\n");
+ logger(LL_ERROR, "Unable to parse BORD element\n");
img3_free(image);
return NULL;
}
image->elements[image->num_elements++] = element;
- debug("Parsed BORD element\n");
+ logger(LL_DEBUG, "Parsed BORD element\n");
break;
case kChipElement:
element = img3_parse_element(&data[data_offset]);
if (element == NULL) {
- error("ERROR: Unable to parse CHIP element\n");
+ logger(LL_ERROR, "Unable to parse CHIP element\n");
img3_free(image);
return NULL;
}
image->elements[image->num_elements++] = element;
- debug("Parsed CHIP element\n");
+ logger(LL_DEBUG, "Parsed CHIP element\n");
break;
case kKbagElement:
element = img3_parse_element(&data[data_offset]);
if (element == NULL) {
- error("ERROR: Unable to parse first KBAG element\n");
+ logger(LL_ERROR, "Unable to parse first KBAG element\n");
img3_free(image);
return NULL;
}
image->elements[image->num_elements++] = element;
- debug("Parsed KBAG element\n");
+ logger(LL_DEBUG, "Parsed KBAG element\n");
break;
case kEcidElement:
element = img3_parse_element(&data[data_offset]);
if (element == NULL) {
- error("ERROR: Unable to parse ECID element\n");
+ logger(LL_ERROR, "Unable to parse ECID element\n");
img3_free(image);
return NULL;
}
image->idx_ecid_element = image->num_elements;
image->elements[image->num_elements++] = element;
- debug("Parsed ECID element\n");
+ logger(LL_DEBUG, "Parsed ECID element\n");
break;
case kShshElement:
element = img3_parse_element(&data[data_offset]);
if (element == NULL) {
- error("ERROR: Unable to parse SHSH element\n");
+ logger(LL_ERROR, "Unable to parse SHSH element\n");
img3_free(image);
return NULL;
}
image->idx_shsh_element = image->num_elements;
image->elements[image->num_elements++] = element;
- debug("Parsed SHSH element\n");
+ logger(LL_DEBUG, "Parsed SHSH element\n");
break;
case kCertElement:
element = img3_parse_element(&data[data_offset]);
if (element == NULL) {
- error("ERROR: Unable to parse CERT element\n");
+ logger(LL_ERROR, "Unable to parse CERT element\n");
img3_free(image);
return NULL;
}
image->idx_cert_element = image->num_elements;
image->elements[image->num_elements++] = element;
- debug("Parsed CERT element\n");
+ logger(LL_DEBUG, "Parsed CERT element\n");
break;
case kUnknElement:
element = img3_parse_element(&data[data_offset]);
if (element == NULL) {
- error("ERROR: Unable to parse UNKN element\n");
+ logger(LL_ERROR, "Unable to parse UNKN element\n");
img3_free(image);
return NULL;
}
image->elements[image->num_elements++] = element;
- debug("Parsed UNKN element\n");
+ logger(LL_DEBUG, "Parsed UNKN element\n");
break;
default:
- error("ERROR: Unknown IMG3 element type %08x\n", current->signature);
+ logger(LL_ERROR, "Unknown IMG3 element type %08x\n", current->signature);
img3_free(image);
return NULL;
}
@@ -204,14 +204,14 @@ static img3_element* img3_parse_element(const unsigned char* data) {
img3_element_header* element_header = (img3_element_header*) data;
img3_element* element = (img3_element*) malloc(sizeof(img3_element));
if (element == NULL) {
- error("ERROR: Unable to allocate memory for IMG3 element\n");
+ logger(LL_ERROR, "Unable to allocate memory for IMG3 element\n");
return NULL;
}
memset(element, '\0', sizeof(img3_element));
element->data = (unsigned char*) malloc(element_header->full_size);
if (element->data == NULL) {
- error("ERROR: Unable to allocate memory for IMG3 element data\n");
+ logger(LL_ERROR, "Unable to allocate memory for IMG3 element data\n");
free(element);
return NULL;
}
@@ -254,21 +254,21 @@ static int img3_replace_signature(img3_file* image, const unsigned char* signatu
int offset = 0;
img3_element* ecid = img3_parse_element(&signature[offset]);
if (ecid == NULL || ecid->type != kEcidElement) {
- error("ERROR: Unable to find ECID element in signature\n");
+ logger(LL_ERROR, "Unable to find ECID element in signature\n");
return -1;
}
offset += ecid->header->full_size;
img3_element* shsh = img3_parse_element(&signature[offset]);
if (shsh == NULL || shsh->type != kShshElement) {
- error("ERROR: Unable to find SHSH element in signature\n");
+ logger(LL_ERROR, "Unable to find SHSH element in signature\n");
return -1;
}
offset += shsh->header->full_size;
img3_element* cert = img3_parse_element(&signature[offset]);
if (cert == NULL || cert->type != kCertElement) {
- error("ERROR: Unable to find CERT element in signature\n");
+ logger(LL_ERROR, "Unable to find CERT element in signature\n");
return -1;
}
offset += cert->header->full_size;
@@ -364,11 +364,11 @@ static int img3_get_data(img3_file* image, unsigned char** pdata, unsigned int*
size += image->elements[i]->header->full_size;
}
- info("reconstructed size: %d\n", size);
+ logger(LL_INFO, "reconstructed size: %d\n", size);
unsigned char* data = (unsigned char*) malloc(size);
if (data == NULL) {
- error("ERROR: Unable to allocate memory for IMG3 data\n");
+ logger(LL_ERROR, "Unable to allocate memory for IMG3 data\n");
return -1;
}
@@ -390,7 +390,7 @@ static int img3_get_data(img3_file* image, unsigned char** pdata, unsigned int*
}
if (offset != size) {
- error("ERROR: Incorrectly sized image data\n");
+ logger(LL_ERROR, "Incorrectly sized image data\n");
free(data);
*pdata = 0;
*psize = 0;
@@ -402,7 +402,7 @@ static int img3_get_data(img3_file* image, unsigned char** pdata, unsigned int*
return 0;
}
-int img3_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, const unsigned char* blob, unsigned int blob_size, unsigned char** img3_data, unsigned int *img3_size)
+int img3_stitch_component(const char* component_name, const void* component_data, size_t component_size, const void* blob, size_t blob_size, void** img3_data, size_t *img3_size)
{
img3_file *img3 = NULL;
unsigned char* outbuf = NULL;
@@ -412,31 +412,31 @@ int img3_stitch_component(const char* component_name, const unsigned char* compo
return -1;
}
- info("Personalizing IMG3 component %s...\n", component_name);
+ logger(LL_INFO, "Personalizing IMG3 component %s...\n", component_name);
/* parse current component as img3 */
img3 = img3_parse_file(component_data, component_size);
if (img3 == NULL) {
- error("ERROR: Unable to parse %s IMG3 file\n", component_name);
+ logger(LL_ERROR, "Unable to parse %s IMG3 file\n", component_name);
return -1;
}
if (((img3_element_header*)blob)->full_size != blob_size) {
- error("ERROR: Invalid blob passed for %s IMG3: The size %d embedded in the blob does not match the passed size of %d\n", component_name, ((img3_element_header*)blob)->full_size, blob_size);
+ logger(LL_ERROR, "Invalid blob passed for %s IMG3: The size %d embedded in the blob does not match the passed size of %zu\n", component_name, ((img3_element_header*)blob)->full_size, blob_size);
img3_free(img3);
return -1;
}
/* personalize the component using the blob */
if (img3_replace_signature(img3, blob) < 0) {
- error("ERROR: Unable to replace %s IMG3 signature\n", component_name);
+ logger(LL_ERROR, "Unable to replace %s IMG3 signature\n", component_name);
img3_free(img3);
return -1;
}
/* get the img3 file as data */
if (img3_get_data(img3, &outbuf, &outsize) < 0) {
- error("ERROR: Unable to reconstruct %s IMG3\n", component_name);
+ logger(LL_ERROR, "Unable to reconstruct %s IMG3\n", component_name);
img3_free(img3);
return -1;
}
diff --git a/src/img3.h b/src/img3.h
index 20d9248..b8e30e9 100644
--- a/src/img3.h
+++ b/src/img3.h
@@ -79,23 +79,9 @@ typedef struct {
int idx_ecid_element;
int idx_shsh_element;
int idx_cert_element;
-/* img3_element* type_element;
- img3_element* data_element;
- img3_element* vers_element;
- img3_element* sepo_element;
- img3_element* bord_element;
- img3_element* sepo2_element;
- img3_element* chip_element;
- img3_element* bord2_element;
- img3_element* kbag1_element;
- img3_element* kbag2_element;
- img3_element* ecid_element;
- img3_element* shsh_element;
- img3_element* cert_element;
- img3_element* unkn_element;*/
} img3_file;
-int img3_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, const unsigned char* blob, unsigned int blob_size, unsigned char** img3_data, unsigned int *img3_size);
+int img3_stitch_component(const char* component_name, const void* component_data, size_t component_size, const void* blob, size_t blob_size, void** img3_data, size_t *img3_size);
#ifdef __cplusplus
}
diff --git a/src/img4.c b/src/img4.c
index 4988293..732ef69 100644
--- a/src/img4.c
+++ b/src/img4.c
@@ -22,8 +22,11 @@
#include <stdlib.h>
#include <string.h>
+#include <libtatsu/tss.h>
+
#include "common.h"
#include "img4.h"
+#include "endianness.h"
#define ASN1_PRIVATE 0xc0
#define ASN1_PRIMITIVE_TAG 0x1f
@@ -201,7 +204,7 @@ static void asn1_write_element(unsigned char **p, unsigned int *length, unsigned
}
} break;
default:
- fprintf(stderr, "ERROR: %s: type %02x is not implemented", __func__, type);
+ logger(LL_ERROR, "%s: type %02x is not implemented\n", __func__, type);
return;
}
}
@@ -275,28 +278,43 @@ static const char *_img4_get_component_tag(const char *compname)
{ "ACIBT", "acib" },
{ "ACIBTLPEM", "lpbt" },
{ "ACIWIFI", "aciw" },
- { "Alamo", "almo" },
{ "ANE", "anef" },
{ "ANS", "ansf" },
{ "AOP", "aopf" },
+ { "AVE", "avef" },
+ { "Alamo", "almo" },
+ { "Ap,ANE1", "ane1" },
+ { "Ap,ANE2", "ane2" },
+ { "Ap,ANE3", "ane3" },
{ "Ap,AudioAccessibilityBootChime", "auac" },
{ "Ap,AudioBootChime", "aubt" },
{ "Ap,AudioPowerAttachChime", "aupr" },
+ { "Ap,BootabilityBrainTrustCache", "trbb" },
{ "Ap,CIO", "ciof" },
+ { "Ap,DCP2", "dcp2" },
{ "Ap,HapticAssets", "hpas" },
{ "Ap,LocalBoot", "lobo" },
{ "Ap,LocalPolicy", "lpol" },
{ "Ap,NextStageIM4MHash", "nsih" },
{ "Ap,RecoveryOSPolicyNonceHash", "ronh" },
+ { "Ap,RestoreANE1", "ran1" },
+ { "Ap,RestoreANE2", "ran2" },
+ { "Ap,RestoreANE3", "ran3" },
{ "Ap,RestoreCIO", "rcio" },
+ { "Ap,RestoreDCP2", "rdc2", },
{ "Ap,RestoreTMU", "rtmu" },
{ "Ap,Scorpius", "scpf" },
+ { "Ap,RestoreSecureM3Firmware", "rsm3" },
+ { "Ap,RestoreSecurePageTableMonitor", "rspt" },
+ { "Ap,RestoreTrustedExecutionMonitor", "rtrx" },
+ { "Ap,RestorecL4", "rxcl" },
{ "Ap,SystemVolumeCanonicalMetadata", "msys" },
{ "Ap,TMU", "tmuf" },
{ "Ap,VolumeUUID", "vuid" },
+ { "Ap,rOSLogo1", "rlg1" },
+ { "Ap,rOSLogo2", "rlg2" },
{ "AppleLogo", "logo" },
{ "AudioCodecFirmware", "acfw" },
- { "AVE", "avef" },
{ "BatteryCharging", "glyC" },
{ "BatteryCharging0", "chg0" },
{ "BatteryCharging1", "chg1" },
@@ -305,28 +323,22 @@ static const char *_img4_get_component_tag(const char *compname)
{ "BatteryLow1", "bat1" },
{ "BatteryPlugin", "glyP" },
{ "CFELoader", "cfel" },
- { "Dali", "dali" },
+ { "CrownFirmware", "crwn" },
{ "DCP", "dcpf" },
+ { "Dali", "dali" },
{ "DeviceTree", "dtre" },
{ "Diags", "diag" },
{ "EngineeringTrustCache", "dtrs" },
{ "ExtDCP", "edcp" },
- { "ftap", "ftap" },
- { "ftsp", "ftsp" },
{ "GFX", "gfxf" },
{ "Hamm", "hamf" },
{ "Homer", "homr" },
- { "iBEC", "ibec" },
- { "iBoot", "ibot" },
- { "iBootData", "ibdt" },
- { "iBootTest", "itst" },
- { "iBSS", "ibss" },
- { "InputDevice", "ipdf" },
{ "ISP", "ispf" },
+ { "InputDevice", "ipdf" },
{ "KernelCache", "krnl" },
+ { "LLB", "illb" },
{ "LeapHaptics", "lphp" },
{ "Liquid", "liqd" },
- { "LLB", "illb" },
{ "LoadableTrustCache", "ltrs" },
{ "LowPowerWallet0", "lpw0" },
{ "LowPowerWallet1", "lpw1" },
@@ -337,12 +349,13 @@ static const char *_img4_get_component_tag(const char *compname)
{ "NeedService", "nsrv" },
{ "OS", "OS\0\0" },
{ "OSRamdisk", "osrd" },
- { "PersonalizedDMG", "pdmg" },
{ "PEHammer", "hmmr" },
{ "PERTOS", "pert" },
{ "PHLEET", "phlt" },
{ "PMP", "pmpf" },
+ { "PersonalizedDMG", "pdmg" },
{ "RBM", "rmbt" },
+ { "RTP", "rtpf" },
{ "Rap,SoftwareBinaryDsp1", "sbd1" },
{ "Rap,RTKitOS", "rkos" },
{ "Rap,RestoreRTKitOS", "rrko" },
@@ -353,12 +366,10 @@ static const char *_img4_get_component_tag(const char *compname)
{ "RestoreExtDCP", "recp" },
{ "RestoreKernelCache", "rkrn" },
{ "RestoreLogo", "rlgo" },
+ { "RestoreRTP", "rrtp" },
{ "RestoreRamDisk", "rdsk" },
{ "RestoreSEP", "rsep" },
{ "RestoreTrustCache", "rtsc" },
- { "rfta", "rfta" },
- { "rfts", "rfts" },
- { "RTP", "rtpf" },
{ "SCE", "scef" },
{ "SCE1Firmware", "sc1f" },
{ "SEP", "sepi" },
@@ -367,6 +378,16 @@ static const char *_img4_get_component_tag(const char *compname)
{ "SystemLocker", "lckr" },
{ "SystemVolume", "isys" },
{ "WCHFirmwareUpdater", "wchf" },
+ { "ftap", "ftap" },
+ { "ftsp", "ftsp" },
+ { "iBEC", "ibec" },
+ { "iBSS", "ibss" },
+ { "iBoot", "ibot" },
+ { "iBootData", "ibdt" },
+ { "iBootDataStage1", "ibd1" },
+ { "iBootTest", "itst" },
+ { "rfta", "rfta" },
+ { "rfts", "rfts" },
{ NULL, NULL }
};
int i = 0;
@@ -381,7 +402,7 @@ static const char *_img4_get_component_tag(const char *compname)
return NULL;
}
-int img4_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, const unsigned char* blob, unsigned int blob_size, unsigned char** img4_data, unsigned int *img4_size)
+int img4_stitch_component(const char* component_name, const void* component_data, size_t component_size, plist_t parameters, plist_t tss_response, void** img4_data, size_t *img4_size)
{
unsigned char* magic_header = NULL;
unsigned int magic_header_size = 0;
@@ -392,44 +413,272 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo
unsigned int content_size;
unsigned char* outbuf;
unsigned char* p;
+ unsigned char* blob = NULL;
+ unsigned int blob_size = 0;
+
+ if (!component_name || !component_data || component_size == 0 || !tss_response || !img4_data || !img4_size) {
+ return -1;
+ }
- if (!component_name || !component_data || component_size == 0 || !blob || blob_size == 0 || !img4_data || !img4_size) {
+ if (tss_response_get_ap_img4_ticket(tss_response, &blob, &blob_size) != 0) {
+ logger(LL_ERROR, "%s: Failed to get ApImg4Ticket from TSS response\n", __func__);
return -1;
}
- info("Personalizing IMG4 component %s...\n", component_name);
+ logger(LL_INFO, "Personalizing IMG4 component %s...\n", component_name);
/* first we need check if we have to change the tag for the given component */
const void *tag = asn1_find_element(1, ASN1_IA5_STRING, component_data);
if (tag) {
- debug("Tag found\n");
- if (strcmp(component_name, "RestoreKernelCache") == 0) {
- memcpy((void*)tag, "rkrn", 4);
- } else if (strcmp(component_name, "RestoreDeviceTree") == 0) {
- memcpy((void*)tag, "rdtr", 4);
- } else if (strcmp(component_name, "RestoreSEP") == 0) {
- memcpy((void*)tag, "rsep", 4);
- } else if (strcmp(component_name, "RestoreLogo") == 0) {
- memcpy((void*)tag, "rlgo", 4);
- } else if (strcmp(component_name, "RestoreTrustCache") == 0) {
- memcpy((void*)tag, "rtsc", 4);
- } else if (strcmp(component_name, "RestoreDCP") == 0) {
- memcpy((void*)tag, "rdcp", 4);
- } else if (strcmp(component_name, "Ap,RestoreTMU") == 0) {
- memcpy((void*)tag, "rtmu", 4);
- } else if (strcmp(component_name, "Ap,RestoreCIO") == 0) {
- memcpy((void*)tag, "rcio", 4);
- } else if (strcmp(component_name, "Ap,DCP2") == 0) {
- memcpy((void*)tag, "dcp2", 4);
+ logger(LL_DEBUG, "Tag found\n");
+ const char* matches[] = {
+ "RestoreKernelCache",
+ "RestoreDeviceTree",
+ "RestoreSEP",
+ "RestoreLogo",
+ "RestoreTrustCache",
+ "RestoreDCP",
+ "Ap,RestoreDCP2",
+ "Ap,RestoreTMU",
+ "Ap,RestoreCIO",
+ "Ap,DCP2",
+ "Ap,RestoreSecureM3Firmware",
+ "Ap,RestoreSecurePageTableMonitor",
+ "Ap,RestoreTrustedExecutionMonitor",
+ "Ap,RestorecL4",
+ NULL
+ };
+ int i = 0;
+ while (matches[i]) {
+ if (!strcmp(matches[i], component_name)) {
+ const char* comptag = _img4_get_component_tag(component_name);
+ if (comptag) {
+ memcpy((void*)tag, comptag, 4);
+ } else {
+ logger(LL_WARNING, "Cannot find tag for component '%s'\n", component_name);
+ }
+ break;
+ }
+ i++;
+ }
+ } else {
+ logger(LL_ERROR, "Personalization failed for component '%s': Tag not found\n", component_name);
+ return -1;
+ }
+
+ // check if we have a *-TBM entry for the given component
+ unsigned char *additional_data = NULL;
+ unsigned int additional_size = 0;
+ char *tbm_key = malloc(strlen(component_name) + 5);
+ snprintf(tbm_key, strlen(component_name)+5, "%s-TBM", component_name);
+ plist_t tbm_dict = plist_dict_get_item(tss_response, tbm_key);
+ free(tbm_key);
+ uint64_t ucon_size = 0;
+ const char* ucon_data = NULL;
+ uint64_t ucer_size = 0;
+ const char* ucer_data = NULL;
+ if (tbm_dict) {
+ plist_t dt = plist_dict_get_item(tbm_dict, "ucon");
+ if (!dt) {
+ logger(LL_ERROR, "%s: Missing ucon node in %s-TBM dictionary\n", __func__, component_name);
+ return -1;
+ }
+ ucon_data = plist_get_data_ptr(dt, &ucon_size);
+ if (!ucon_data) {
+ logger(LL_ERROR, "%s: Missing ucon data in %s-TBM dictionary\n", __func__, component_name);
+ return -1;
+ }
+ dt = plist_dict_get_item(tbm_dict, "ucer");
+ if (!dt) {
+ logger(LL_ERROR, "%s: Missing ucer data node in %s-TBM dictionary\n", __func__, component_name);
+ return -1;
+ }
+ ucer_data = plist_get_data_ptr(dt, &ucer_size);
+ if (!ucer_data) {
+ logger(LL_ERROR, "%s: Missing ucer data in %s-TBM dictionary\n", __func__, component_name);
+ return -1;
}
}
+ int nonce_slot_required = plist_dict_get_bool(parameters, "RequiresNonceSlot") && (!strcmp(component_name, "SEP") || !strcmp(component_name, "SepStage1") || !strcmp(component_name, "LLB"));
+
+ if (ucon_data || ucer_data || nonce_slot_required) {
+ size_t im4r_size = 16;
+ if (ucon_data) {
+ im4r_size += 8 + 8 + ucon_size + 16;
+ }
+ if (ucer_data) {
+ im4r_size += 8 + 8 + ucer_size + 16;
+ }
+ if (nonce_slot_required) {
+ im4r_size += 16;
+ }
+ unsigned char *im4rset = (unsigned char*)malloc(im4r_size);
+ unsigned char *p_im4rset = im4rset;
+ unsigned int im4rlen = 0;
+
+ // ----------- anid/snid -------
+ if (nonce_slot_required) {
+ const char* tag_name = NULL;
+ uint64_t tag_value = 0;
+ if (!strcmp(component_name, "SEP") || !strcmp(component_name, "SepStage1")) {
+ tag_name = "snid";
+ tag_value = 2;
+ if (plist_dict_get_item(parameters, "SepNonceSlotID")) {
+ tag_value = plist_dict_get_uint(parameters, "SepNonceSlotID");
+ }
+ } else {
+ tag_name = "anid";
+ tag_value = 0;
+ if (plist_dict_get_item(parameters, "ApNonceSlotID")) {
+ tag_value = plist_dict_get_uint(parameters, "ApNonceSlotID");
+ }
+ }
+ // write priv anid/snid element
+ asn1_write_priv_element(&p_im4rset, &im4rlen, __bswap_32(*(uint32_t*)tag_name));
+ // write anid/snid IA5STRING and anid/snid value
+ unsigned char inner_seq[16];
+ unsigned char *p_inner_seq = &inner_seq[0];
+ unsigned int inner_seq_hdr_len = 0;
+ asn1_write_element(&p_inner_seq, &inner_seq_hdr_len, ASN1_IA5_STRING, (void*)tag_name, -1);
+ asn1_write_element(&p_inner_seq, &inner_seq_hdr_len, ASN1_INTEGER, (void*)&tag_value, -1);
+
+ // write anid/snid sequence
+ unsigned char elem_seq[8];
+ unsigned char *p = &elem_seq[0];
+ unsigned int seq_hdr_len = 0;
+ asn1_write_element_header(ASN1_SEQUENCE | ASN1_CONSTRUCTED, inner_seq_hdr_len, &p, &seq_hdr_len);
+
+ // add size to priv anid/snid element
+ asn1_write_size(inner_seq_hdr_len + seq_hdr_len, &p_im4rset, &im4rlen);
+
+ // put it together
+ memcpy(p_im4rset, elem_seq, seq_hdr_len);
+ p_im4rset += seq_hdr_len;
+ im4rlen += seq_hdr_len;
+ memcpy(p_im4rset, inner_seq, inner_seq_hdr_len);
+ p_im4rset += inner_seq_hdr_len;
+ im4rlen += inner_seq_hdr_len;
+ }
+
+ // ----------- ucon ------------
+ if (ucon_data) {
+ // write priv ucon element
+ asn1_write_priv_element(&p_im4rset, &im4rlen, *(uint32_t*)"nocu");
+
+ // write ucon IA5STRING and ucon data header
+ unsigned char inner_seq[16];
+ unsigned char *p_inner_seq = &inner_seq[0];
+ unsigned int inner_seq_hdr_len = 0;
+ asn1_write_element(&p_inner_seq, &inner_seq_hdr_len, ASN1_IA5_STRING, (void*)"ucon", -1);
+ asn1_write_element_header(ASN1_OCTET_STRING, ucon_size, &p_inner_seq, &inner_seq_hdr_len);
+
+ // write ucon sequence
+ unsigned char elem_seq[8];
+ unsigned char *p = &elem_seq[0];
+ unsigned int seq_hdr_len = 0;
+ asn1_write_element_header(ASN1_SEQUENCE | ASN1_CONSTRUCTED, inner_seq_hdr_len + ucon_size, &p, &seq_hdr_len);
+
+ // add size to priv ucon element
+ asn1_write_size(inner_seq_hdr_len + ucon_size + seq_hdr_len, &p_im4rset, &im4rlen);
+
+ // put it together
+ memcpy(p_im4rset, elem_seq, seq_hdr_len);
+ p_im4rset += seq_hdr_len;
+ im4rlen += seq_hdr_len;
+ memcpy(p_im4rset, inner_seq, inner_seq_hdr_len);
+ p_im4rset += inner_seq_hdr_len;
+ im4rlen += inner_seq_hdr_len;
+ // write ucon data
+ memcpy(p_im4rset, ucon_data, ucon_size);
+ p_im4rset += ucon_size;
+ im4rlen += ucon_size;
+ }
+
+ // ----------- ucer ------------
+ if (ucer_data) {
+ // write priv ucer element
+ asn1_write_priv_element(&p_im4rset, &im4rlen, *(uint32_t*)"recu");
+
+ // write ucer IA5STRING and ucer data header
+ unsigned char inner_seq[16];
+ unsigned char *p_inner_seq = &inner_seq[0];
+ unsigned int inner_seq_hdr_len = 0;
+ asn1_write_element(&p_inner_seq, &inner_seq_hdr_len, ASN1_IA5_STRING, (void*)"ucer", -1);
+ asn1_write_element_header(ASN1_OCTET_STRING, ucer_size, &p_inner_seq, &inner_seq_hdr_len);
+
+ // write ucer sequence
+ unsigned char elem_seq[8];
+ unsigned char *p = &elem_seq[0];
+ unsigned int seq_hdr_len = 0;
+ asn1_write_element_header(ASN1_SEQUENCE | ASN1_CONSTRUCTED, inner_seq_hdr_len + ucer_size, &p, &seq_hdr_len);
+
+ // add size to priv ucer element
+ asn1_write_size(inner_seq_hdr_len + ucer_size + seq_hdr_len, &p_im4rset, &im4rlen);
+
+ // put it together
+ memcpy(p_im4rset, elem_seq, seq_hdr_len);
+ p_im4rset += seq_hdr_len;
+ im4rlen += seq_hdr_len;
+ memcpy(p_im4rset, inner_seq, inner_seq_hdr_len);
+ p_im4rset += inner_seq_hdr_len;
+ im4rlen += inner_seq_hdr_len;
+ // write ucer data
+ memcpy(p_im4rset, ucer_data, ucer_size);
+ p_im4rset += ucer_size;
+ im4rlen += ucer_size;
+ }
+
+ // now construct IM4R
+
+ /* write inner set */
+ unsigned char inner_set_[8];
+ unsigned char *inner_set = &inner_set_[0];
+ unsigned int inner_set_len = 0;
+ asn1_write_element_header(ASN1_SET | ASN1_CONSTRUCTED, im4rlen, &inner_set, &inner_set_len);
+
+ /* write header values */
+ unsigned char hdrdata_[16];
+ unsigned char *hdrdata = &hdrdata_[0];
+ unsigned int hdrdata_len = 0;
+ asn1_write_element(&hdrdata, &hdrdata_len, ASN1_IA5_STRING, (void*)"IM4R", -1);
+
+ /* write sequence now that we know the entire size */
+ unsigned char seq_[8];
+ unsigned char *seq = &seq_[0];
+ unsigned int seq_len = 0;
+ asn1_write_element_header(ASN1_SEQUENCE | ASN1_CONSTRUCTED, im4rlen + inner_set_len + hdrdata_len, &seq, &seq_len);
+
+ /* write outer cont[1] */
+ unsigned char cont_[8];
+ unsigned char *cont = &cont_[0];
+ unsigned int cont_len = 0;
+ asn1_write_element_header(ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 1, im4rlen + inner_set_len + hdrdata_len + seq_len, &cont, &cont_len);
+
+ // now put everything together
+ additional_data = malloc(im4rlen + inner_set_len + hdrdata_len + seq_len + cont_len);
+ p = additional_data;
+ memcpy(p, cont_, cont_len);
+ p += cont_len;
+ memcpy(p, seq_, seq_len);
+ p += seq_len;
+ memcpy(p, hdrdata_, hdrdata_len);
+ p += hdrdata_len;
+ memcpy(p, inner_set_, inner_set_len);
+ p += inner_set_len;
+ memcpy(p, im4rset, im4rlen);
+ p += im4rlen;
+ additional_size = (unsigned int)(p - additional_data);
+
+ free(im4rset);
+ }
+
// create element header for the "IMG4" magic
asn1_create_element_header(ASN1_IA5_STRING, IMG4_MAGIC_SIZE, &magic_header, &magic_header_size);
// create element header for the blob (ApImg4Ticket)
asn1_create_element_header(ASN1_CONTEXT_SPECIFIC|ASN1_CONSTRUCTED, blob_size, &blob_header, &blob_header_size);
// calculate the size for the final IMG4 file (asn1 sequence)
- content_size = magic_header_size + IMG4_MAGIC_SIZE + component_size + blob_header_size + blob_size;
+ content_size = magic_header_size + IMG4_MAGIC_SIZE + component_size + blob_header_size + blob_size + additional_size;
// create element header for the final IMG4 asn1 blob
asn1_create_element_header(ASN1_SEQUENCE|ASN1_CONSTRUCTED, content_size, &img4header, &img4header_size);
@@ -445,7 +694,8 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo
if (img4header) {
free(img4header);
}
- error("ERROR: out of memory when personalizing IMG4 component %s\n", component_name);
+ free(additional_data);
+ logger(LL_ERROR, "out of memory when personalizing IMG4 component %s\n", component_name);
return -1;
}
p = outbuf;
@@ -463,6 +713,10 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo
p += blob_header_size;
memcpy(p, blob, blob_size);
p += blob_size;
+ if (additional_size) {
+ memcpy(p, additional_data, additional_size);
+ p += additional_size;
+ }
*img4_data = outbuf;
*img4_size = (p - outbuf);
@@ -476,6 +730,7 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo
if (img4header) {
free(img4header);
}
+ free(additional_data);
return 0;
}
@@ -540,13 +795,11 @@ static void _manifest_write_component(unsigned char **p, unsigned int *length, c
node = plist_dict_get_item(comp, "Digest");
if (node) {
- char *digest = NULL;
uint64_t digest_len = 0;
- plist_get_data_val(node, &digest, &digest_len);
+ const char *digest = plist_get_data_ptr(node, &digest_len);
if (digest_len > 0) {
- _manifest_write_key_value(&tmp, &tmp_len, "DGST", ASN1_OCTET_STRING, digest, digest_len);
+ _manifest_write_key_value(&tmp, &tmp_len, "DGST", ASN1_OCTET_STRING, (void*)digest, digest_len);
}
- free(digest);
}
node = plist_dict_get_item(comp, "Trusted");
@@ -575,9 +828,8 @@ static void _manifest_write_component(unsigned char **p, unsigned int *length, c
node = plist_dict_get_item(comp, "TBMDigests");
if (node) {
- char *data = NULL;
uint64_t datalen = 0;
- plist_get_data_val(node, &data, &datalen);
+ const char *data = plist_get_data_ptr(node, &datalen);
const char *tbmtag = NULL;
if (!strcmp(tag, "sepi")) {
tbmtag = "tbms";
@@ -585,11 +837,10 @@ static void _manifest_write_component(unsigned char **p, unsigned int *length, c
tbmtag = "tbmr";
}
if (!tbmtag) {
- error("ERROR: Unexpected TMBDigests for comp '%s'\n", tag);
+ logger(LL_ERROR, "Unexpected TMBDigests for comp '%s'\n", tag);
} else {
- _manifest_write_key_value(&tmp, &tmp_len, tbmtag, ASN1_OCTET_STRING, data, datalen);
+ _manifest_write_key_value(&tmp, &tmp_len, tbmtag, ASN1_OCTET_STRING, (void*)data, datalen);
}
- free(data);
}
asn1_write_element_header(ASN1_SET | ASN1_CONSTRUCTED, tmp_len, &inner_start, &inner_length);
@@ -627,30 +878,28 @@ int img4_create_local_manifest(plist_t request, plist_t build_identity, plist_t*
unsigned int length = 0;
uint64_t uintval = 0;
unsigned int boolval = 0;
- char *strval = NULL;
- plist_t node = NULL;
unsigned char tmp_[1024];
unsigned char *tmp = &tmp_[0];
unsigned int tmp_len = 0;
/* write manifest properties */
- uintval = _plist_dict_get_uint(request, "ApBoardID");
+ uintval = plist_dict_get_uint(request, "ApBoardID");
_manifest_write_key_value(&tmp, &tmp_len, "BORD", ASN1_INTEGER, &uintval, -1);
uintval = 0;
_manifest_write_key_value(&tmp, &tmp_len, "CEPO", ASN1_INTEGER, &uintval, -1);
- uintval = _plist_dict_get_uint(request, "ApChipID");
+ uintval = plist_dict_get_uint(request, "ApChipID");
_manifest_write_key_value(&tmp, &tmp_len, "CHIP", ASN1_INTEGER, &uintval, -1);
- boolval = _plist_dict_get_bool(request, "ApProductionMode");
+ boolval = plist_dict_get_bool(request, "ApProductionMode");
_manifest_write_key_value(&tmp, &tmp_len, "CPRO", ASN1_BOOLEAN, &boolval, -1);
boolval = 0;
_manifest_write_key_value(&tmp, &tmp_len, "CSEC", ASN1_BOOLEAN, &boolval, -1);
- uintval = _plist_dict_get_uint(request, "ApSecurityDomain");
+ uintval = plist_dict_get_uint(request, "ApSecurityDomain");
_manifest_write_key_value(&tmp, &tmp_len, "SDOM", ASN1_INTEGER, &uintval, -1);
/* create manifest properties set */
@@ -681,13 +930,12 @@ int img4_create_local_manifest(plist_t request, plist_t build_identity, plist_t*
comp = _img4_get_component_tag(key);
}
if (!comp) {
- error("ERROR: %s: Unhandled component '%s' - can't create manifest\n", __func__, key);
- free(iter);
- free(buf);
- return -1;
+ logger(LL_DEBUG, "%s: Unhandled component '%s'\n", __func__, key);
+ _manifest_write_component(&p, &length, key, val);
+ } else {
+ logger(LL_DEBUG, "found component %s (%s)\n", comp, key);
+ _manifest_write_component(&p, &length, comp, val);
}
- debug("DEBUG: found component %s (%s)\n", comp, key);
- _manifest_write_component(&p, &length, comp, val);
}
free(key);
} while (val);
diff --git a/src/img4.h b/src/img4.h
index 37dea56..1c5ef36 100644
--- a/src/img4.h
+++ b/src/img4.h
@@ -26,7 +26,7 @@
extern "C" {
#endif
-int img4_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, const unsigned char* blob, unsigned int blob_size, unsigned char** img4_data, unsigned int *img4_size);
+int img4_stitch_component(const char* component_name, const void* component_data, size_t component_size, plist_t parameters, plist_t tss_response, void** img4_data, size_t *img4_size);
int img4_create_local_manifest(plist_t request, plist_t build_identity, plist_t* manifest);
#ifdef __cplusplus
diff --git a/src/ipsw.c b/src/ipsw.c
index da00a6e..cebfa49 100644
--- a/src/ipsw.c
+++ b/src/ipsw.c
@@ -34,37 +34,21 @@
#include <sys/types.h>
#include <dirent.h>
#include <zip.h>
-#ifdef HAVE_OPENSSL
-#include <openssl/sha.h>
-#else
-#include "sha1.h"
-#define SHA_CTX SHA1_CTX
-#define SHA1_Init SHA1Init
-#define SHA1_Update SHA1Update
-#define SHA1_Final SHA1Final
-#endif
+#include <libimobiledevice-glue/sha.h>
#include <libimobiledevice-glue/termcolors.h>
+#include <plist/plist.h>
#include "ipsw.h"
#include "locking.h"
#include "download.h"
#include "common.h"
#include "idevicerestore.h"
-#include "json_plist.h"
#define BUFSIZE 0x100000
-typedef struct {
- struct zip* zip;
- char *path;
-} ipsw_archive;
-
static int cancel_flag = 0;
-ipsw_archive* ipsw_open(const char* ipsw);
-void ipsw_close(ipsw_archive* archive);
-
static char* build_path(const char* path, const char* file)
{
size_t plen = strlen(path);
@@ -85,56 +69,59 @@ int ipsw_print_info(const char* path)
struct stat fst;
if (stat(path, &fst) != 0) {
- error("ERROR: '%s': %s\n", path, strerror(errno));
+ logger(LL_ERROR, "'%s': %s\n", path, strerror(errno));
return -1;
}
char thepath[PATH_MAX];
if (S_ISDIR(fst.st_mode)) {
- sprintf(thepath, "%s/BuildManifest.plist", path);
+ snprintf(thepath, sizeof(thepath), "%s/BuildManifest.plist", path);
if (stat(thepath, &fst) != 0) {
- error("ERROR: '%s': %s\n", thepath, strerror(errno));
+ logger(LL_ERROR, "'%s': %s\n", thepath, strerror(errno));
return -1;
}
} else {
- sprintf(thepath, "%s", path);
+ snprintf(thepath, sizeof(thepath), "%s", path);
}
FILE* f = fopen(thepath, "r");
if (!f) {
- error("ERROR: Can't open '%s': %s\n", thepath, strerror(errno));
+ logger(LL_ERROR, "Can't open '%s': %s\n", thepath, strerror(errno));
return -1;
}
uint32_t magic;
if (fread(&magic, 1, 4, f) != 4) {
fclose(f);
- fprintf(stderr, "Failed to read from '%s'\n", path);
+ logger(LL_ERROR, "Failed to read from '%s'\n", path);
return -1;
}
fclose(f);
- char* plist_buf = NULL;
+ void* plist_buf = NULL;
uint32_t plist_len = 0;
if (memcmp(&magic, "PK\x03\x04", 4) == 0) {
- unsigned int rlen = 0;
- if (ipsw_extract_to_memory(thepath, "BuildManifest.plist", (unsigned char**)&plist_buf, &rlen) < 0) {
- error("ERROR: Failed to extract BuildManifest.plist from IPSW!\n");
+ ipsw_archive_t ipsw = ipsw_open(thepath);
+ size_t rlen = 0;
+ if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", &plist_buf, &rlen) < 0) {
+ ipsw_close(ipsw);
+ logger(LL_ERROR, "Failed to extract BuildManifest.plist from IPSW!\n");
return -1;
}
+ ipsw_close(ipsw);
plist_len = (uint32_t)rlen;
} else {
size_t rlen = 0;
- if (read_file(thepath, (void**)&plist_buf, &rlen) < 0) {
- error("ERROR: Failed to read BuildManifest.plist!\n");
+ if (read_file(thepath, &plist_buf, &rlen) < 0) {
+ logger(LL_ERROR, "Failed to read BuildManifest.plist!\n");
return -1;
}
plist_len = (uint32_t)rlen;
}
plist_t manifest = NULL;
- plist_from_memory(plist_buf, plist_len, &manifest);
+ plist_from_memory(plist_buf, plist_len, &manifest, NULL);
free(plist_buf);
plist_t val;
@@ -152,10 +139,10 @@ int ipsw_print_info(const char* path)
plist_get_string_val(val, &build_ver);
}
- cprintf(COLOR_WHITE "Product Version: " COLOR_BRIGHT_YELLOW "%s" COLOR_RESET COLOR_WHITE " Build: " COLOR_BRIGHT_YELLOW "%s" COLOR_RESET "\n", prod_ver, build_ver);
+ cprintf(FG_WHITE "Product Version: " FG_BRIGHT_YELLOW "%s" COLOR_RESET FG_WHITE " Build: " FG_BRIGHT_YELLOW "%s" COLOR_RESET "\n", prod_ver, build_ver);
free(prod_ver);
free(build_ver);
- cprintf(COLOR_WHITE "Supported Product Types:" COLOR_RESET);
+ cprintf(FG_WHITE "Supported Product Types:" COLOR_RESET);
val = plist_dict_get_item(manifest, "SupportedProductTypes");
if (val) {
plist_array_iter iter = NULL;
@@ -167,7 +154,7 @@ int ipsw_print_info(const char* path)
if (item) {
char* item_str = NULL;
plist_get_string_val(item, &item_str);
- cprintf(" " COLOR_BRIGHT_CYAN "%s" COLOR_RESET, item_str);
+ cprintf(" " FG_BRIGHT_CYAN "%s" COLOR_RESET, item_str);
free(item_str);
}
} while (item);
@@ -176,7 +163,7 @@ int ipsw_print_info(const char* path)
}
cprintf("\n");
- cprintf(COLOR_WHITE "Build Identities:" COLOR_RESET "\n");
+ cprintf(FG_WHITE "Build Identities:" COLOR_RESET "\n");
plist_t build_ids_grouped = plist_new_dict();
@@ -201,7 +188,15 @@ int ipsw_print_info(const char* path)
if (!group) {
group = plist_new_dict();
node = plist_access_path(build_identity, 2, "Info", "RestoreBehavior");
- plist_dict_set_item(group, "RestoreBehavior", plist_copy(node));
+ if (node) {
+ plist_dict_set_item(group, "RestoreBehavior", plist_copy(node));
+ } else {
+ if (strstr(variant_str, "Upgrade")) {
+ plist_dict_set_item(group, "RestoreBehavior", plist_new_string("Update"));
+ } else if (strstr(variant_str, "Erase")) {
+ plist_dict_set_item(group, "RestoreBehavior", plist_new_string("Erase"));
+ }
+ }
entries = plist_new_array();
plist_dict_set_item(group, "Entries", entries);
plist_dict_set_item(build_ids_grouped, variant_str, group);
@@ -232,7 +227,7 @@ int ipsw_print_info(const char* path)
group_no++;
node = plist_dict_get_item(group, "RestoreBehavior");
plist_get_string_val(node, &rbehavior);
- cprintf(" " COLOR_WHITE "[%d] Variant: " COLOR_BRIGHT_CYAN "%s" COLOR_WHITE " Behavior: " COLOR_BRIGHT_CYAN "%s" COLOR_RESET "\n", group_no, key, rbehavior);
+ cprintf(" " FG_WHITE "[%d] Variant: " FG_BRIGHT_CYAN "%s" FG_WHITE " Behavior: " FG_BRIGHT_CYAN "%s" COLOR_RESET "\n", group_no, key, rbehavior);
free(key);
free(rbehavior);
@@ -285,9 +280,9 @@ int ipsw_print_info(const char* path)
irecv_device_t irecvdev = NULL;
if (irecv_devices_get_device_by_hardware_model(hwmodel, &irecvdev) == 0) {
- cprintf(" ChipID: " COLOR_GREEN "%04x" COLOR_RESET " BoardID: " COLOR_GREEN "%02x" COLOR_RESET " Model: " COLOR_YELLOW "%-8s" COLOR_RESET " " COLOR_MAGENTA "%s" COLOR_RESET "\n", (int)chip_id, (int)board_id, hwmodel, irecvdev->display_name);
+ cprintf(" ChipID: " FG_GREEN "%04x" COLOR_RESET " BoardID: " FG_GREEN "%02x" COLOR_RESET " Model: " FG_YELLOW "%-8s" COLOR_RESET " " FG_MAGENTA "%s" COLOR_RESET "\n", (int)chip_id, (int)board_id, hwmodel, irecvdev->display_name);
} else {
- cprintf(" ChipID: " COLOR_GREEN "%04x" COLOR_RESET " BoardID: " COLOR_GREEN "%02x" COLOR_RESET " Model: " COLOR_YELLOW "%s" COLOR_RESET "\n", (int)chip_id, (int)board_id, hwmodel);
+ cprintf(" ChipID: " FG_GREEN "%04x" COLOR_RESET " BoardID: " FG_GREEN "%02x" COLOR_RESET " Model: " FG_YELLOW "%s" COLOR_RESET "\n", (int)chip_id, (int)board_id, hwmodel);
}
free(hwmodel);
} while (build_id);
@@ -302,32 +297,41 @@ int ipsw_print_info(const char* path)
return 0;
}
-ipsw_archive* ipsw_open(const char* ipsw)
+ipsw_archive_t ipsw_open(const char* ipsw)
{
int err = 0;
- ipsw_archive* archive = (ipsw_archive*) malloc(sizeof(ipsw_archive));
+ ipsw_archive_t archive = (ipsw_archive_t)calloc(1, sizeof(struct ipsw_archive));
if (archive == NULL) {
- error("ERROR: Out of memory\n");
+ logger(LL_ERROR, "Out of memory\n");
return NULL;
}
struct stat fst;
if (stat(ipsw, &fst) != 0) {
- error("ERROR: ipsw_open %s: %s\n", ipsw, strerror(errno));
+ logger(LL_ERROR, "ipsw_open %s: %s\n", ipsw, strerror(errno));
return NULL;
}
- archive->path = strdup(ipsw);
if (S_ISDIR(fst.st_mode)) {
- archive->zip = NULL;
+ archive->zip = 0;
} else {
- archive->zip = zip_open(ipsw, 0, &err);
- if (archive->zip == NULL) {
- error("ERROR: zip_open: %s: %d\n", ipsw, err);
+ struct zip *zip = zip_open(ipsw, 0, &err);
+ if (zip == NULL) {
+ logger(LL_ERROR, "zip_open: %s: %d\n", ipsw, err);
free(archive);
return NULL;
}
+ archive->zip = 1;
+ }
+ archive->path = strdup(ipsw);
+ return (ipsw_archive_t)archive;
+}
+
+void ipsw_close(ipsw_archive_t ipsw)
+{
+ if (ipsw != NULL) {
+ free(ipsw->path);
+ free(ipsw);
}
- return archive;
}
int ipsw_is_directory(const char* ipsw)
@@ -340,37 +344,45 @@ int ipsw_is_directory(const char* ipsw)
return S_ISDIR(fst.st_mode);
}
-int ipsw_get_file_size(const char* ipsw, const char* infile, uint64_t* size)
+int ipsw_get_file_size(ipsw_archive_t ipsw, const char* infile, uint64_t* size)
{
- ipsw_archive* archive = ipsw_open(ipsw);
- if (archive == NULL) {
- error("ERROR: Invalid archive\n");
+ if (ipsw == NULL) {
+ logger(LL_ERROR, "Invalid archive\n");
return -1;
}
- if (archive->zip) {
- int zindex = zip_name_locate(archive->zip, infile, 0);
+ if (ipsw->zip) {
+ int err = 0;
+ struct zip *zip = zip_open(ipsw->path, 0, &err);
+ if (zip == NULL) {
+ logger(LL_ERROR, "zip_open: %s: %d\n", ipsw->path, err);
+ return -1;
+ }
+ int zindex = zip_name_locate(zip, infile, 0);
if (zindex < 0) {
- error("ERROR: zip_name_locate: %s\n", infile);
- ipsw_close(archive);
+ logger(LL_ERROR, "zip_name_locate: %s\n", infile);
+ zip_unchange_all(zip);
+ zip_close(zip);
return -1;
}
struct zip_stat zstat;
zip_stat_init(&zstat);
- if (zip_stat_index(archive->zip, zindex, 0, &zstat) != 0) {
- error("ERROR: zip_stat_index: %s\n", infile);
- ipsw_close(archive);
+ if (zip_stat_index(zip, zindex, 0, &zstat) != 0) {
+ logger(LL_ERROR, "zip_stat_index: %s\n", infile);
+ zip_unchange_all(zip);
+ zip_close(zip);
return -1;
}
+ zip_unchange_all(zip);
+ zip_close(zip);
*size = zstat.size;
} else {
- char *filepath = build_path(archive->path, infile);
+ char *filepath = build_path(ipsw->path, infile);
struct stat fst;
if (stat(filepath, &fst) != 0) {
free(filepath);
- ipsw_close(archive);
return -1;
}
free(filepath);
@@ -378,57 +390,75 @@ int ipsw_get_file_size(const char* ipsw, const char* infile, uint64_t* size)
*size = fst.st_size;
}
- ipsw_close(archive);
return 0;
}
-int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, const char* outfile, int print_progress)
+int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile, const char* outfile, int print_progress)
{
int ret = 0;
- ipsw_archive* archive = ipsw_open(ipsw);
- if (archive == NULL) {
- error("ERROR: Invalid archive\n");
+
+ if (!ipsw || !infile || !outfile) {
+ logger(LL_ERROR, "Invalid argument\n");
return -1;
}
cancel_flag = 0;
- if (archive->zip) {
- int zindex = zip_name_locate(archive->zip, infile, 0);
+ if (ipsw->zip) {
+ int err = 0;
+ struct zip *zip = zip_open(ipsw->path, 0, &err);
+ if (zip == NULL) {
+ logger(LL_ERROR, "zip_open: %s: %d\n", ipsw->path, err);
+ return -1;
+ }
+
+ int zindex = zip_name_locate(zip, infile, 0);
if (zindex < 0) {
- error("ERROR: zip_name_locate: %s\n", infile);
+ zip_unchange_all(zip);
+ zip_close(zip);
+ logger(LL_ERROR, "zip_name_locate: %s\n", infile);
return -1;
}
struct zip_stat zstat;
zip_stat_init(&zstat);
- if (zip_stat_index(archive->zip, zindex, 0, &zstat) != 0) {
- error("ERROR: zip_stat_index: %s\n", infile);
+ if (zip_stat_index(zip, zindex, 0, &zstat) != 0) {
+ zip_unchange_all(zip);
+ zip_close(zip);
+ logger(LL_ERROR, "zip_stat_index: %s\n", infile);
return -1;
}
char* buffer = (char*) malloc(BUFSIZE);
if (buffer == NULL) {
- error("ERROR: Unable to allocate memory\n");
+ zip_unchange_all(zip);
+ zip_close(zip);
+ logger(LL_ERROR, "Unable to allocate memory\n");
return -1;
}
- struct zip_file* zfile = zip_fopen_index(archive->zip, zindex, 0);
+ struct zip_file* zfile = zip_fopen_index(zip, zindex, 0);
if (zfile == NULL) {
- error("ERROR: zip_fopen_index: %s\n", infile);
+ zip_unchange_all(zip);
+ zip_close(zip);
+ logger(LL_ERROR, "zip_fopen_index: %s\n", infile);
return -1;
}
FILE* fd = fopen(outfile, "wb");
if (fd == NULL) {
- error("ERROR: Unable to open output file: %s\n", outfile);
zip_fclose(zfile);
+ zip_unchange_all(zip);
+ zip_close(zip);
+ logger(LL_ERROR, "Unable to open output file: %s\n", outfile);
return -1;
}
+ if (print_progress) {
+ register_progress('IPSW', "Extracting");
+ }
uint64_t i, bytes = 0;
int count, size = BUFSIZE;
- double progress;
for(i = zstat.size; i > 0; i -= count) {
if (cancel_flag) {
break;
@@ -437,31 +467,43 @@ int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, con
size = i;
count = zip_fread(zfile, buffer, size);
if (count < 0) {
- error("ERROR: zip_fread: %s\n", infile);
+ int zep = 0;
+ int sep = 0;
+ zip_file_error_get(zfile, &zep, &sep);
+ logger(LL_ERROR, "zip_fread: %s %d %d\n", infile, zep, sep);
ret = -1;
break;
}
if (fwrite(buffer, 1, count, fd) != count) {
- error("ERROR: frite: %s\n", outfile);
+ logger(LL_ERROR, "Writing to '%s' failed: %s\n", outfile, strerror(errno));
ret = -1;
break;
}
bytes += size;
if (print_progress) {
- progress = ((double)bytes / (double)zstat.size) * 100.0;
- print_progress_bar(progress);
+ double progress = ((double)bytes / (double)zstat.size);
+ set_progress('IPSW', progress);
}
}
free(buffer);
+ if (print_progress) {
+ finalize_progress('IPSW');
+ }
fclose(fd);
zip_fclose(zfile);
+ zip_unchange_all(zip);
+ zip_close(zip);
} else {
- char *filepath = build_path(archive->path, infile);
+ char *filepath = build_path(ipsw->path, infile);
char actual_filepath[PATH_MAX+1];
char actual_outfile[PATH_MAX+1];
+ if (!filepath) {
+ ret = -1;
+ goto leave;
+ }
if (!realpath(filepath, actual_filepath)) {
- error("ERROR: realpath failed on %s: %s\n", filepath, strerror(errno));
+ logger(LL_ERROR, "realpath failed on %s: %s\n", filepath, strerror(errno));
ret = -1;
goto leave;
} else {
@@ -475,21 +517,21 @@ int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, con
}
FILE *fi = fopen(actual_filepath, "rb");
if (!fi) {
- error("ERROR: fopen: %s: %s\n", actual_filepath, strerror(errno));
+ logger(LL_ERROR, "fopen: %s: %s\n", actual_filepath, strerror(errno));
ret = -1;
goto leave;
}
struct stat fst;
if (fstat(fileno(fi), &fst) != 0) {
fclose(fi);
- error("ERROR: fstat: %s: %s\n", actual_filepath, strerror(errno));
+ logger(LL_ERROR, "fstat: %s: %s\n", actual_filepath, strerror(errno));
ret = -1;
goto leave;
}
FILE *fo = fopen(actual_outfile, "wb");
if (!fo) {
fclose(fi);
- error("ERROR: fopen: %s: %s\n", actual_outfile, strerror(errno));
+ logger(LL_ERROR, "fopen: %s: %s\n", actual_outfile, strerror(errno));
ret = -1;
goto leave;
}
@@ -497,34 +539,39 @@ int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, con
if (buffer == NULL) {
fclose(fi);
fclose(fo);
- error("ERROR: Unable to allocate memory\n");
+ logger(LL_ERROR, "Unable to allocate memory\n");
ret = -1;
goto leave;;
}
+ if (print_progress) {
+ register_progress('IPSW', "Extracting");
+ }
uint64_t bytes = 0;
- double progress;
while (!feof(fi)) {
if (cancel_flag) {
break;
}
ssize_t r = fread(buffer, 1, BUFSIZE, fi);
if (r < 0) {
- error("ERROR: fread failed: %s\n", strerror(errno));
+ logger(LL_ERROR, "fread failed: %s\n", strerror(errno));
ret = -1;
break;
}
if (fwrite(buffer, 1, r, fo) != r) {
- error("ERROR: fwrite failed\n");
+ logger(LL_ERROR, "Writing to '%s' failed: %s\n", actual_outfile, strerror(errno));
ret = -1;
break;
}
bytes += r;
if (print_progress) {
- progress = ((double)bytes / (double)fst.st_size) * 100.0;
- print_progress_bar(progress);
+ double progress = ((double)bytes / (double)fst.st_size);
+ set_progress('IPSW', progress);
}
}
+ if (print_progress) {
+ finalize_progress('IPSW');
+ }
free(buffer);
fclose(fi);
@@ -534,146 +581,172 @@ int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, con
leave:
free(filepath);
}
- ipsw_close(archive);
if (cancel_flag) {
ret = -2;
}
return ret;
}
-int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfile)
+int ipsw_extract_to_file(ipsw_archive_t ipsw, const char* infile, const char* outfile)
{
return ipsw_extract_to_file_with_progress(ipsw, infile, outfile, 0);
}
-int ipsw_file_exists(const char* ipsw, const char* infile)
+int ipsw_file_exists(ipsw_archive_t ipsw, const char* infile)
{
- ipsw_archive* archive = ipsw_open(ipsw);
- if (archive == NULL) {
+ if (!ipsw) {
return 0;
}
- if (archive->zip) {
- int zindex = zip_name_locate(archive->zip, infile, 0);
+ if (ipsw->zip) {
+ int err = 0;
+ struct zip *zip = zip_open(ipsw->path, 0, &err);
+ if (zip == NULL) {
+ logger(LL_ERROR, "zip_open: %s: %d\n", ipsw->path, err);
+ return 0;
+ }
+ int zindex = zip_name_locate(zip, infile, 0);
+ zip_unchange_all(zip);
+ zip_close(zip);
if (zindex < 0) {
- ipsw_close(archive);
return 0;
}
} else {
- char *filepath = build_path(archive->path, infile);
+ char *filepath = build_path(ipsw->path, infile);
if (access(filepath, R_OK) != 0) {
free(filepath);
- ipsw_close(archive);
return 0;
}
free(filepath);
}
- ipsw_close(archive);
-
return 1;
}
-int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** pbuffer, unsigned int* psize)
+int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, void** pbuffer, size_t* psize)
{
size_t size = 0;
unsigned char* buffer = NULL;
- ipsw_archive* archive = ipsw_open(ipsw);
- if (archive == NULL) {
- error("ERROR: Invalid archive\n");
+ if (ipsw == NULL) {
+ logger(LL_ERROR, "Invalid archive\n");
return -1;
}
- if (archive->zip) {
- int zindex = zip_name_locate(archive->zip, infile, 0);
+ if (ipsw->zip) {
+ int err = 0;
+ struct zip *zip = zip_open(ipsw->path, 0, &err);
+ if (zip == NULL) {
+ logger(LL_ERROR, "zip_open: %s: %d\n", ipsw->path, err);
+ return -1;
+ }
+
+ int zindex = zip_name_locate(zip, infile, 0);
if (zindex < 0) {
- debug("NOTE: zip_name_locate: '%s' not found in archive.\n", infile);
- ipsw_close(archive);
+ zip_unchange_all(zip);
+ zip_close(zip);
+ logger(LL_DEBUG, "zip_name_locate: '%s' not found in archive.\n", infile);
return -1;
}
struct zip_stat zstat;
zip_stat_init(&zstat);
- if (zip_stat_index(archive->zip, zindex, 0, &zstat) != 0) {
- error("ERROR: zip_stat_index: %s\n", infile);
- ipsw_close(archive);
+ if (zip_stat_index(zip, zindex, 0, &zstat) != 0) {
+ zip_unchange_all(zip);
+ zip_close(zip);
+ logger(LL_ERROR, "zip_stat_index: %s\n", infile);
return -1;
}
- struct zip_file* zfile = zip_fopen_index(archive->zip, zindex, 0);
+ struct zip_file* zfile = zip_fopen_index(zip, zindex, 0);
if (zfile == NULL) {
- error("ERROR: zip_fopen_index: %s\n", infile);
- ipsw_close(archive);
+ zip_unchange_all(zip);
+ zip_close(zip);
+ logger(LL_ERROR, "zip_fopen_index: %s\n", infile);
return -1;
}
size = zstat.size;
+ if ((uint64_t)size != (uint64_t)zstat.size) {
+ logger(LL_ERROR, "Not enough memory to allocate a buffer of size %" PRIu64 "\n", (uint64_t)zstat.size);
+ zip_fclose(zfile);
+ zip_unchange_all(zip);
+ zip_close(zip);
+ return -1;
+ }
buffer = (unsigned char*) malloc(size+1);
if (buffer == NULL) {
- error("ERROR: Out of memory\n");
+ logger(LL_ERROR, "Out of memory\n");
zip_fclose(zfile);
- ipsw_close(archive);
+ zip_unchange_all(zip);
+ zip_close(zip);
return -1;
}
- if (zip_fread(zfile, buffer, size) != size) {
- error("ERROR: zip_fread: %s\n", infile);
- zip_fclose(zfile);
+ zip_int64_t zr = zip_fread(zfile, buffer, size);
+ zip_fclose(zfile);
+ zip_unchange_all(zip);
+ zip_close(zip);
+ if (zr < 0) {
+ int zep = 0;
+ int sep = 0;
+ zip_file_error_get(zfile, &zep, &sep);
+ logger(LL_ERROR, "zip_fread: %s %d %d\n", infile, zep, sep);
+ free(buffer);
+ return -1;
+ } else if (zr != size) {
+ logger(LL_ERROR, "zip_fread: %s got only %zu of %zu\n", infile, (size_t)zr, size);
free(buffer);
- ipsw_close(archive);
return -1;
}
buffer[size] = '\0';
-
- zip_fclose(zfile);
} else {
- char *filepath = build_path(archive->path, infile);
+ char *filepath = build_path(ipsw->path, infile);
struct stat fst;
#ifdef WIN32
if (stat(filepath, &fst) != 0) {
#else
if (lstat(filepath, &fst) != 0) {
#endif
- error("ERROR: %s: stat failed for %s: %s\n", __func__, filepath, strerror(errno));
+ logger(LL_ERROR, "%s: stat failed for %s: %s\n", __func__, filepath, strerror(errno));
free(filepath);
- ipsw_close(archive);
return -1;
}
size = fst.st_size;
+ if ((uint64_t)size != (uint64_t)fst.st_size) {
+ logger(LL_ERROR, "Not enough memory to allocate a buffer of size %" PRIu64 "\n", (uint64_t)fst.st_size);
+ free(filepath);
+ return -1;
+ }
buffer = (unsigned char*)malloc(size+1);
if (buffer == NULL) {
- error("ERROR: Out of memory\n");
+ logger(LL_ERROR, "Out of memory\n");
free(filepath);
- ipsw_close(archive);
return -1;
}
#ifndef WIN32
if (S_ISLNK(fst.st_mode)) {
if (readlink(filepath, (char*)buffer, size) < 0) {
- error("ERROR: %s: readlink failed for %s: %s\n", __func__, filepath, strerror(errno));
+ logger(LL_ERROR, "%s: readlink failed for %s: %s\n", __func__, filepath, strerror(errno));
free(filepath);
free(buffer);
- ipsw_close(archive);
return -1;
}
} else {
#endif
FILE *f = fopen(filepath, "rb");
if (!f) {
- error("ERROR: %s: fopen failed for %s: %s\n", __func__, filepath, strerror(errno));
+ logger(LL_ERROR, "%s: fopen failed for %s: %s\n", __func__, filepath, strerror(errno));
free(filepath);
free(buffer);
- ipsw_close(archive);
return -2;
}
if (fread(buffer, 1, size, f) != size) {
fclose(f);
- error("ERROR: %s: fread failed for %s: %s\n", __func__, filepath, strerror(errno));
+ logger(LL_ERROR, "%s: fread failed for %s: %s\n", __func__, filepath, strerror(errno));
free(filepath);
free(buffer);
- ipsw_close(archive);
return -1;
}
fclose(f);
@@ -684,24 +757,171 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char**
free(filepath);
}
- ipsw_close(archive);
*pbuffer = buffer;
*psize = size;
return 0;
}
-int ipsw_extract_build_manifest(const char* ipsw, plist_t* buildmanifest, int *tss_enabled)
+int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ipsw_send_cb send_callback, void* ctx)
+{
+ unsigned char* buffer = NULL;
+ size_t done = 0;
+ size_t total_size = 0;
+
+ if (ipsw == NULL) {
+ logger(LL_ERROR, "Invalid archive\n");
+ return -1;
+ }
+
+ if (ipsw->zip) {
+ int err = 0;
+ struct zip *zip = zip_open(ipsw->path, 0, &err);
+ if (zip == NULL) {
+ logger(LL_ERROR, "zip_open: %s: %d\n", ipsw->path, err);
+ return -1;
+ }
+
+ int zindex = zip_name_locate(zip, infile, 0);
+ if (zindex < 0) {
+ zip_unchange_all(zip);
+ zip_close(zip);
+ logger(LL_DEBUG, "zip_name_locate: '%s' not found in archive.\n", infile);
+ return -1;
+ }
+
+ struct zip_stat zstat;
+ zip_stat_init(&zstat);
+ if (zip_stat_index(zip, zindex, 0, &zstat) != 0) {
+ zip_unchange_all(zip);
+ zip_close(zip);
+ logger(LL_ERROR, "zip_stat_index: %s\n", infile);
+ return -1;
+ }
+
+ struct zip_file* zfile = zip_fopen_index(zip, zindex, 0);
+ if (zfile == NULL) {
+ zip_unchange_all(zip);
+ zip_close(zip);
+ logger(LL_ERROR, "zip_fopen_index: %s\n", infile);
+ return -1;
+ }
+
+ total_size = zstat.size;
+ buffer = (unsigned char*) malloc(blocksize);
+ if (buffer == NULL) {
+ zip_fclose(zfile);
+ zip_unchange_all(zip);
+ zip_close(zip);
+ logger(LL_ERROR, "Out of memory\n");
+ return -1;
+ }
+
+ while (done < total_size) {
+ size_t size = total_size-done;
+ if (size > blocksize) size = blocksize;
+ zip_int64_t zr = zip_fread(zfile, buffer, size);
+ if (zr < 0) {
+ logger(LL_ERROR, "%s: zip_fread: %s\n", __func__, infile);
+ break;
+ } else if (zr == 0) {
+ // EOF
+ break;
+ }
+ if (send_callback(ctx, buffer, zr, done, total_size) < 0) {
+ logger(LL_ERROR, "%s: send failed\n", __func__);
+ break;
+ }
+ done += zr;
+ }
+ free(buffer);
+ zip_fclose(zfile);
+ zip_unchange_all(zip);
+ zip_close(zip);
+ } else {
+ char *filepath = build_path(ipsw->path, infile);
+ struct stat fst;
+#ifdef WIN32
+ if (stat(filepath, &fst) != 0) {
+#else
+ if (lstat(filepath, &fst) != 0) {
+#endif
+ logger(LL_ERROR, "%s: stat failed for %s: %s\n", __func__, filepath, strerror(errno));
+ free(filepath);
+ return -1;
+ }
+ total_size = fst.st_size;
+ buffer = (unsigned char*)malloc(blocksize);
+ if (buffer == NULL) {
+ logger(LL_ERROR, "Out of memory\n");
+ free(filepath);
+ return -1;
+ }
+
+#ifndef WIN32
+ if (S_ISLNK(fst.st_mode)) {
+ ssize_t rl = readlink(filepath, (char*)buffer, (total_size > blocksize) ? blocksize : total_size);
+ if (rl < 0) {
+ logger(LL_ERROR, "%s: readlink failed for %s: %s\n", __func__, filepath, strerror(errno));
+ free(filepath);
+ free(buffer);
+ return -1;
+ }
+ send_callback(ctx, buffer, (size_t)rl, 0, 0);
+ } else {
+#endif
+ FILE *f = fopen(filepath, "rb");
+ if (!f) {
+ logger(LL_ERROR, "%s: fopen failed for %s: %s\n", __func__, filepath, strerror(errno));
+ free(filepath);
+ free(buffer);
+ return -2;
+ }
+
+ while (done < total_size) {
+ size_t size = total_size-done;
+ if (size > blocksize) size = blocksize;
+ size_t fr = fread(buffer, 1, size, f);
+ if (fr != size) {
+ logger(LL_ERROR, "%s: fread failed for %s: %s\n", __func__, filepath, strerror(errno));
+ break;
+ }
+ if (send_callback(ctx, buffer, fr, done, total_size) < 0) {
+ logger(LL_ERROR, "%s: send failed\n", __func__);
+ break;
+ }
+ done += fr;
+ }
+ fclose(f);
+#ifndef WIN32
+ }
+#endif
+ free(filepath);
+ free(buffer);
+ }
+
+ if (done < total_size) {
+ logger(LL_ERROR, "%s: Sending file data for %s failed (sent %" PRIu64 "/%" PRIu64 ")\n", __func__, infile, (uint64_t)done, (uint64_t)total_size);
+ return -1;
+ }
+
+ // send a NULL buffer to mark end of transfer
+ send_callback(ctx, NULL, 0, done, total_size);
+
+ return 0;
+}
+
+int ipsw_extract_build_manifest(ipsw_archive_t ipsw, plist_t* buildmanifest, int *tss_enabled)
{
- unsigned int size = 0;
- unsigned char* data = NULL;
+ size_t size = 0;
+ void* data = NULL;
*tss_enabled = 0;
/* older devices don't require personalized firmwares and use a BuildManifesto.plist */
if (ipsw_file_exists(ipsw, "BuildManifesto.plist")) {
if (ipsw_extract_to_memory(ipsw, "BuildManifesto.plist", &data, &size) == 0) {
- plist_from_xml((char*)data, size, buildmanifest);
+ plist_from_memory((char*)data, size, buildmanifest, NULL);
free(data);
return 0;
}
@@ -713,7 +933,7 @@ int ipsw_extract_build_manifest(const char* ipsw, plist_t* buildmanifest, int *t
/* whereas newer devices do not require personalized firmwares and use a BuildManifest.plist */
if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", &data, &size) == 0) {
*tss_enabled = 1;
- plist_from_xml((char*)data, size, buildmanifest);
+ plist_from_memory((char*)data, size, buildmanifest, NULL);
free(data);
return 0;
}
@@ -721,13 +941,13 @@ int ipsw_extract_build_manifest(const char* ipsw, plist_t* buildmanifest, int *t
return -1;
}
-int ipsw_extract_restore_plist(const char* ipsw, plist_t* restore_plist)
+int ipsw_extract_restore_plist(ipsw_archive_t ipsw, plist_t* restore_plist)
{
- unsigned int size = 0;
- unsigned char* data = NULL;
+ size_t size = 0;
+ void* data = NULL;
if (ipsw_extract_to_memory(ipsw, "Restore.plist", &data, &size) == 0) {
- plist_from_xml((char*)data, size, restore_plist);
+ plist_from_memory((char*)data, size, restore_plist, NULL);
free(data);
return 0;
}
@@ -735,15 +955,15 @@ int ipsw_extract_restore_plist(const char* ipsw, plist_t* restore_plist)
return -1;
}
-static int ipsw_list_contents_recurse(ipsw_archive *archive, const char *path, ipsw_list_cb cb, void *ctx)
+static int ipsw_list_contents_recurse(ipsw_archive_t ipsw, const char *path, ipsw_list_cb cb, void *ctx)
{
int ret = 0;
- char *base = build_path(archive->path, path);
+ char *base = build_path(ipsw->path, path);
DIR *dirp = opendir(base);
if (!dirp) {
- error("ERROR: failed to open directory %s\n", base);
+ logger(LL_ERROR, "failed to open directory %s\n", base);
free(base);
return -1;
}
@@ -770,16 +990,16 @@ static int ipsw_list_contents_recurse(ipsw_archive *archive, const char *path, i
ret = lstat(fpath, &st);
#endif
if (ret != 0) {
- error("ERROR: %s: stat failed for %s: %s\n", __func__, fpath, strerror(errno));
+ logger(LL_ERROR, "%s: stat failed for %s: %s\n", __func__, fpath, strerror(errno));
free(fpath);
free(subpath);
break;
}
- ret = cb(ctx, archive->path, subpath, &st);
+ ret = cb(ctx, ipsw, subpath, &st);
if (ret >= 0 && S_ISDIR(st.st_mode))
- ipsw_list_contents_recurse(archive, subpath, cb, ctx);
+ ipsw_list_contents_recurse(ipsw, subpath, cb, ctx);
free(fpath);
free(subpath);
@@ -790,21 +1010,26 @@ static int ipsw_list_contents_recurse(ipsw_archive *archive, const char *path, i
return ret;
}
-int ipsw_list_contents(const char* ipsw, ipsw_list_cb cb, void *ctx)
+int ipsw_list_contents(ipsw_archive_t ipsw, ipsw_list_cb cb, void *ctx)
{
int ret = 0;
- ipsw_archive* archive = ipsw_open(ipsw);
- if (archive == NULL) {
- error("ERROR: Invalid archive\n");
+ if (ipsw == NULL) {
+ logger(LL_ERROR, "Invalid IPSW archive\n");
return -1;
}
- if (archive->zip) {
- int64_t entries = zip_get_num_entries(archive->zip, 0);
+ if (ipsw->zip) {
+ int err = 0;
+ struct zip *zip = zip_open(ipsw->path, 0, &err);
+ if (zip == NULL) {
+ logger(LL_ERROR, "zip_open: %s: %d\n", ipsw->path, err);
+ return -1;
+ }
+
+ int64_t entries = zip_get_num_entries(zip, 0);
if (entries < 0) {
- error("ERROR: zip_get_num_entries failed\n");
- ipsw_close(archive);
+ logger(LL_ERROR, "zip_get_num_entries failed\n");
return -1;
}
@@ -812,21 +1037,21 @@ int ipsw_list_contents(const char* ipsw, ipsw_list_cb cb, void *ctx)
zip_stat_t stat;
zip_stat_init(&stat);
- if (zip_stat_index(archive->zip, index, 0, &stat) < 0) {
- error("ERROR: zip_stat_index failed for %s\n", stat.name);
+ if (zip_stat_index(zip, index, 0, &stat) < 0) {
+ logger(LL_ERROR, "zip_stat_index failed for %s\n", stat.name);
ret = -1;
continue;
}
uint8_t opsys;
uint32_t attributes;
- if (zip_file_get_external_attributes(archive->zip, index, 0, &opsys, &attributes) < 0) {
- error("ERROR: zip_file_get_external_attributes failed for %s\n", stat.name);
+ if (zip_file_get_external_attributes(zip, index, 0, &opsys, &attributes) < 0) {
+ logger(LL_ERROR, "zip_file_get_external_attributes failed for %s\n", stat.name);
ret = -1;
continue;
}
if (opsys != ZIP_OPSYS_UNIX) {
- error("ERROR: File %s does not have UNIX attributes\n", stat.name);
+ logger(LL_ERROR, "File %s does not have UNIX attributes\n", stat.name);
ret = -1;
continue;
}
@@ -850,30 +1075,17 @@ int ipsw_list_contents(const char* ipsw, ipsw_list_cb cb, void *ctx)
break;
}
} else {
- ret = ipsw_list_contents_recurse(archive, "", cb, ctx);
+ ret = ipsw_list_contents_recurse(ipsw, "", cb, ctx);
}
- ipsw_close(archive);
return ret;
}
-void ipsw_close(ipsw_archive* archive)
-{
- if (archive != NULL) {
- free(archive->path);
- if (archive->zip) {
- zip_unchange_all(archive->zip);
- zip_close(archive->zip);
- }
- free(archive);
- }
-}
-
int ipsw_get_signed_firmwares(const char* product, plist_t* firmwares)
{
char url[256];
char *jdata = NULL;
- uint32_t jsize = 0;
+ size_t jsize = 0;
plist_t dict = NULL;
plist_t node = NULL;
plist_t fws = NULL;
@@ -888,33 +1100,33 @@ int ipsw_get_signed_firmwares(const char* product, plist_t* firmwares)
*firmwares = NULL;
snprintf(url, sizeof(url), "https://api.ipsw.me/v4/device/%s", product);
- if (download_to_buffer(url, &jdata, &jsize) < 0) {
- error("ERROR: Download from %s failed.\n", url);
+ if (download_to_buffer(url, (void**)&jdata, &jsize) < 0) {
+ logger(LL_ERROR, "Download from %s failed.\n", url);
return -1;
}
- dict = json_to_plist(jdata);
+ plist_from_json(jdata, jsize, &dict);
free(jdata);
if (!dict || plist_get_node_type(dict) != PLIST_DICT) {
- error("ERROR: Failed to parse json data.\n");
+ logger(LL_ERROR, "Failed to parse json data.\n");
plist_free(dict);
return -1;
}
node = plist_dict_get_item(dict, "identifier");
if (!node || plist_get_node_type(node) != PLIST_STRING) {
- error("ERROR: Unexpected json data returned - missing 'identifier'\n");
+ logger(LL_ERROR, "Unexpected json data returned - missing 'identifier'\n");
plist_free(dict);
return -1;
}
product_type = plist_get_string_ptr(node, NULL);
if (!product_type || strcmp(product_type, product) != 0) {
- error("ERROR: Unexpected json data returned - failed to read identifier\n");
+ logger(LL_ERROR, "Unexpected json data returned - failed to read identifier\n");
plist_free(dict);
return -1;
}
fws = plist_dict_get_item(dict, "firmwares");
if (!fws || plist_get_node_type(fws) != PLIST_ARRAY) {
- error("ERROR: Unexpected json data returned - missing 'firmwares'\n");
+ logger(LL_ERROR, "Unexpected json data returned - missing 'firmwares'\n");
plist_free(dict);
return -1;
}
@@ -946,14 +1158,14 @@ int ipsw_get_latest_fw(plist_t version_data, const char* product, char** fwurl,
plist_t n1 = plist_dict_get_item(version_data, "MobileDeviceSoftwareVersionsByVersion");
if (!n1) {
- error("%s: ERROR: Can't find MobileDeviceSoftwareVersionsByVersion dict in version data\n", __func__);
+ logger(LL_ERROR, "%s: ERROR: Can't find MobileDeviceSoftwareVersionsByVersion dict in version data\n", __func__);
return -1;
}
plist_dict_iter iter = NULL;
plist_dict_new_iter(n1, &iter);
if (!iter) {
- error("%s: ERROR: Can't get dict iter\n", __func__);
+ logger(LL_ERROR, "%s: ERROR: Can't get dict iter\n", __func__);
return -1;
}
char* key = NULL;
@@ -974,21 +1186,21 @@ int ipsw_get_latest_fw(plist_t version_data, const char* product, char** fwurl,
free(iter);
if (major == 0) {
- error("%s: ERROR: Can't find major version?!\n", __func__);
+ logger(LL_ERROR, "%s: ERROR: Can't find major version?!\n", __func__);
return -1;
}
char majstr[32]; // should be enough for a uint64_t value
- sprintf(majstr, "%"PRIu64, (uint64_t)major);
+ snprintf(majstr, sizeof(majstr), "%"PRIu64, (uint64_t)major);
n1 = plist_access_path(version_data, 7, "MobileDeviceSoftwareVersionsByVersion", majstr, "MobileDeviceSoftwareVersions", product, "Unknown", "Universal", "Restore");
if (!n1) {
- error("%s: ERROR: Can't get Unknown/Universal/Restore node?!\n", __func__);
+ logger(LL_ERROR, "%s: ERROR: Can't get Unknown/Universal/Restore node?!\n", __func__);
return -1;
}
plist_t n2 = plist_dict_get_item(n1, "BuildVersion");
if (!n2 || (plist_get_node_type(n2) != PLIST_STRING)) {
- error("%s: ERROR: Can't get build version node?!\n", __func__);
+ logger(LL_ERROR, "%s: ERROR: Can't get build version node?!\n", __func__);
return -1;
}
@@ -997,7 +1209,7 @@ int ipsw_get_latest_fw(plist_t version_data, const char* product, char** fwurl,
n1 = plist_access_path(version_data, 5, "MobileDeviceSoftwareVersionsByVersion", majstr, "MobileDeviceSoftwareVersions", product, strval);
if (!n1) {
- error("%s: ERROR: Can't get MobileDeviceSoftwareVersions/%s node?!\n", __func__, strval);
+ logger(LL_ERROR, "%s: ERROR: Can't get MobileDeviceSoftwareVersions/%s node?!\n", __func__, strval);
free(strval);
return -1;
}
@@ -1013,7 +1225,7 @@ int ipsw_get_latest_fw(plist_t version_data, const char* product, char** fwurl,
free(strval);
strval = NULL;
if (!n1 || (plist_dict_get_size(n1) == 0)) {
- error("%s: ERROR: Can't get MobileDeviceSoftwareVersions/%s dict\n", __func__, product);
+ logger(LL_ERROR, "%s: ERROR: Can't get MobileDeviceSoftwareVersions/%s dict\n", __func__, product);
return -1;
}
}
@@ -1031,7 +1243,7 @@ int ipsw_get_latest_fw(plist_t version_data, const char* product, char** fwurl,
n2 = plist_access_path(n1, 2, "Restore", "FirmwareURL");
if (!n2 || (plist_get_node_type(n2) != PLIST_STRING)) {
- error("%s: ERROR: Can't get FirmwareURL node\n", __func__);
+ logger(LL_ERROR, "%s: ERROR: Can't get FirmwareURL node\n", __func__);
return -1;
}
@@ -1064,15 +1276,25 @@ static int sha1_verify_fp(FILE* f, unsigned char* expected_sha1)
{
unsigned char tsha1[20];
char buf[8192];
+ size_t total = 0;
+ struct stat fst;
+ int lastprog = 0;
if (!f) return 0;
- SHA_CTX sha1ctx;
- SHA1_Init(&sha1ctx);
+ sha1_context sha1ctx;
+ sha1_init(&sha1ctx);
rewind(f);
+ fstat(fileno(f), &fst);
while (!feof(f)) {
size_t sz = fread(buf, 1, 8192, f);
- SHA1_Update(&sha1ctx, (const void*)buf, sz);
+ sha1_update(&sha1ctx, buf, sz);
+ total += sz;
+ double p = (double)total / (double)fst.st_size;
+ if ((int)(p*100) > lastprog) {
+ set_progress('SHA1', p);
+ lastprog = (int)(p*100);
+ }
}
- SHA1_Final(tsha1, &sha1ctx);
+ sha1_final(&sha1ctx, tsha1);
return (memcmp(expected_sha1, tsha1, 20) == 0) ? 1 : 0;
}
@@ -1080,25 +1302,25 @@ int ipsw_download_fw(const char *fwurl, unsigned char* isha1, const char* todir,
{
char* fwfn = strrchr(fwurl, '/');
if (!fwfn) {
- error("ERROR: can't get local filename for firmware ipsw\n");
+ logger(LL_ERROR, "can't get local filename for firmware ipsw\n");
return -2;
}
fwfn++;
char fwlfn[PATH_MAX - 5];
if (todir) {
- sprintf(fwlfn, "%s/%s", todir, fwfn);
+ snprintf(fwlfn, sizeof(fwlfn), "%s/%s", todir, fwfn);
} else {
- sprintf(fwlfn, "%s", fwfn);
+ snprintf(fwlfn, sizeof(fwlfn), "%s", fwfn);
}
char fwlock[PATH_MAX];
- sprintf(fwlock, "%s.lock", fwlfn);
+ snprintf(fwlock, sizeof(fwlock), "%s.lock", fwlfn);
lock_info_t lockinfo;
if (lock_file(fwlock, &lockinfo) != 0) {
- error("WARNING: Could not lock file '%s'\n", fwlock);
+ logger(LL_WARNING, "Could not lock file '%s'\n", fwlock);
}
int need_dl = 0;
@@ -1106,13 +1328,15 @@ int ipsw_download_fw(const char *fwurl, unsigned char* isha1, const char* todir,
FILE* f = fopen(fwlfn, "rb");
if (f) {
if (memcmp(zsha1, isha1, 20) != 0) {
- info("Verifying '%s'...\n", fwlfn);
+ logger(LL_INFO, "Verifying '%s'...\n", fwlfn);
+ register_progress('SHA1', "Verifying");
if (sha1_verify_fp(f, isha1)) {
- info("Checksum matches.\n");
+ logger(LL_INFO, "Checksum matches.\n");
} else {
- info("Checksum does not match.\n");
+ logger(LL_INFO, "Checksum does not match.\n");
need_dl = 1;
}
+ finalize_progress('SHA1');
}
fclose(f);
} else {
@@ -1122,29 +1346,35 @@ int ipsw_download_fw(const char *fwurl, unsigned char* isha1, const char* todir,
int res = 0;
if (need_dl) {
if (strncmp(fwurl, "protected:", 10) == 0) {
- error("ERROR: Can't download '%s' because it needs a purchase.\n", fwfn);
+ logger(LL_ERROR, "Can't download '%s' because it needs a purchase.\n", fwfn);
res = -3;
} else {
remove(fwlfn);
- info("Downloading firmware (%s)\n", fwurl);
+ logger(LL_INFO, "Downloading firmware (%s)\n", fwurl);
download_to_file(fwurl, fwlfn, 1);
+ if (global_quit_flag > 0) {
+ logger(LL_NOTICE, "Download aborted by user\n");
+ return -1;
+ }
if (memcmp(isha1, zsha1, 20) != 0) {
- info("\nVerifying '%s'...\n", fwlfn);
+ logger(LL_INFO, "Verifying '%s'...\n", fwlfn);
FILE* f = fopen(fwlfn, "rb");
if (f) {
+ register_progress('SHA1', "Verifying");
if (sha1_verify_fp(f, isha1)) {
- info("Checksum matches.\n");
+ logger(LL_INFO, "Checksum matches.\n");
} else {
- error("ERROR: File download failed (checksum mismatch).\n");
+ logger(LL_ERROR, "File download failed (checksum mismatch).\n");
res = -4;
}
+ finalize_progress('SHA1');
fclose(f);
// make sure to remove invalid files
if (res < 0)
remove(fwlfn);
} else {
- error("ERROR: Can't open '%s' for checksum verification\n", fwlfn);
+ logger(LL_ERROR, "Can't open '%s' for checksum verification\n", fwlfn);
res = -5;
}
}
@@ -1155,7 +1385,7 @@ int ipsw_download_fw(const char *fwurl, unsigned char* isha1, const char* todir,
}
if (unlock_file(&lockinfo) != 0) {
- error("WARNING: Could not unlock file '%s'\n", fwlock);
+ logger(LL_WARNING, "Could not unlock file '%s'\n", fwlock);
}
return res;
@@ -1169,17 +1399,17 @@ int ipsw_download_latest_fw(plist_t version_data, const char* product, const cha
*ipswfile = NULL;
if ((ipsw_get_latest_fw(version_data, product, &fwurl, isha1) < 0) || !fwurl) {
- error("ERROR: can't get URL for latest firmware\n");
+ logger(LL_ERROR, "can't get URL for latest firmware\n");
return -1;
}
char* fwfn = strrchr(fwurl, '/');
if (!fwfn) {
- error("ERROR: can't get local filename for firmware ipsw\n");
+ logger(LL_ERROR, "can't get local filename for firmware ipsw\n");
return -2;
}
fwfn++;
- info("Latest firmware is %s\n", fwfn);
+ logger(LL_INFO, "Latest firmware is %s\n", fwfn);
int res = ipsw_download_fw(fwurl, isha1, todir, ipswfile);
@@ -1192,3 +1422,121 @@ void ipsw_cancel(void)
{
cancel_flag++;
}
+
+ipsw_file_handle_t ipsw_file_open(ipsw_archive_t ipsw, const char* path)
+{
+ ipsw_file_handle_t handle = (ipsw_file_handle_t)calloc(1, sizeof(struct ipsw_file_handle));
+ if (ipsw->zip) {
+ int err = 0;
+ struct zip *zip = zip_open(ipsw->path, 0, &err);
+ if (zip == NULL) {
+ logger(LL_ERROR, "zip_open: %s: %d\n", ipsw->path, err);
+ return NULL;
+ }
+
+ zip_stat_t zst;
+ zip_int64_t zindex = zip_name_locate(zip, path, 0);
+ if (zindex < 0) {
+ logger(LL_ERROR, "zip_name_locate: %s not found\n", path);
+ zip_unchange_all(zip);
+ zip_close(zip);
+ free(handle);
+ return NULL;
+ }
+ handle->zfile = zip_fopen_index(zip, zindex, 0);
+ if (handle->zfile == NULL) {
+ logger(LL_ERROR, "zip_fopen_index: %s could not be opened\n", path);
+ zip_unchange_all(zip);
+ zip_close(zip);
+ free(handle);
+ return NULL;
+ }
+ zip_stat_init(&zst);
+ zip_stat(zip, path, 0, &zst);
+ handle->size = zst.size;
+ handle->seekable = (zst.comp_method == ZIP_CM_STORE);
+ handle->zip = zip;
+ } else {
+ struct stat st;
+ char *filepath = build_path(ipsw->path, path);
+ handle->file = fopen(filepath, "rb");
+ free(filepath);
+ if (!handle->file) {
+ logger(LL_ERROR, "fopen: %s could not be opened\n", path);
+ free(handle);
+ return NULL;
+ }
+ fstat(fileno(handle->file), &st);
+ handle->size = st.st_size;
+ handle->seekable = 1;
+ }
+ return handle;
+}
+
+void ipsw_file_close(ipsw_file_handle_t handle)
+{
+ if (handle && handle->zfile) {
+ zip_fclose(handle->zfile);
+ zip_unchange_all(handle->zip);
+ zip_close(handle->zip);
+ } else if (handle && handle->file) {
+ fclose(handle->file);
+ }
+ free(handle);
+}
+
+uint64_t ipsw_file_size(ipsw_file_handle_t handle)
+{
+ if (handle) {
+ return handle->size;
+ }
+ return 0;
+}
+
+int64_t ipsw_file_read(ipsw_file_handle_t handle, void* buffer, size_t size)
+{
+ if (handle && handle->zfile) {
+ zip_int64_t zr = zip_fread(handle->zfile, buffer, size);
+ return (int64_t)zr;
+ } else if (handle && handle->file) {
+ return fread(buffer, 1, size, handle->file);
+ } else {
+ logger(LL_ERROR, "%s: Invalid file handle\n", __func__);
+ return -1;
+ }
+}
+
+int ipsw_file_seek(ipsw_file_handle_t handle, int64_t offset, int whence)
+{
+ if (handle && handle->zfile) {
+ return zip_fseek(handle->zfile, offset, whence);
+ } else if (handle && handle->file) {
+#ifdef WIN32
+ if (whence == SEEK_SET) {
+ rewind(handle->file);
+ }
+ return (_lseeki64(fileno(handle->file), offset, whence) < 0) ? -1 : 0;
+#else
+ return fseeko(handle->file, offset, whence);
+#endif
+ } else {
+ logger(LL_ERROR, "%s: Invalid file handle\n", __func__);
+ return -1;
+ }
+}
+
+int64_t ipsw_file_tell(ipsw_file_handle_t handle)
+{
+ if (handle && handle->zfile) {
+ return zip_ftell(handle->zfile);
+ } else if (handle && handle->file) {
+#ifdef WIN32
+ return _lseeki64(fileno(handle->file), 0, SEEK_CUR);
+#else
+ return ftello(handle->file);
+#endif
+ } else {
+ logger(LL_ERROR, "%s: Invalid file handle\n", __func__);
+ return -1;
+ }
+}
diff --git a/src/ipsw.h b/src/ipsw.h
index 3b5da80..b22e614 100644
--- a/src/ipsw.h
+++ b/src/ipsw.h
@@ -32,19 +32,48 @@ extern "C" {
#include <plist/plist.h>
#include <sys/stat.h>
+struct ipsw_archive {
+ int zip;
+ char *path;
+};
+typedef struct ipsw_archive* ipsw_archive_t;
+
+ipsw_archive_t ipsw_open(const char* ipsw);
+void ipsw_close(ipsw_archive_t ipsw);
+
int ipsw_print_info(const char* ipsw);
-typedef int (*ipsw_list_cb)(void *ctx, const char* ipsw, const char *name, struct stat *stat);
+typedef int (*ipsw_list_cb)(void *ctx, ipsw_archive_t ipsw, const char *name, struct stat *stat);
+typedef int (*ipsw_send_cb)(void *ctx, const void *data, size_t size, size_t done, size_t total_size);
+
+struct ipsw_file_handle {
+ FILE* file;
+ struct zip* zip;
+ struct zip_file* zfile;
+ uint64_t size;
+ int seekable;
+};
+typedef struct ipsw_file_handle* ipsw_file_handle_t;
+
+ipsw_file_handle_t ipsw_file_open(ipsw_archive_t, const char* path);
+void ipsw_file_close(ipsw_file_handle_t handle);
+
+uint64_t ipsw_file_size(ipsw_file_handle_t handle);
+int64_t ipsw_file_read(ipsw_file_handle_t handle, void* buffer, size_t size);
+int ipsw_file_seek(ipsw_file_handle_t handle, int64_t offset, int whence);
+int64_t ipsw_file_tell(ipsw_file_handle_t handle);
int ipsw_is_directory(const char* ipsw);
-int ipsw_file_exists(const char* ipsw, const char* infile);
-int ipsw_get_file_size(const char* ipsw, const char* infile, uint64_t* size);
-int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfile);
-int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, const char* outfile, int print_progress);
-int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** pbuffer, unsigned int* psize);
-int ipsw_extract_build_manifest(const char* ipsw, plist_t* buildmanifest, int *tss_enabled);
-int ipsw_extract_restore_plist(const char* ipsw, plist_t* restore_plist);
-int ipsw_list_contents(const char* ipsw, ipsw_list_cb cb, void *ctx);
+
+int ipsw_file_exists(ipsw_archive_t ipsw, const char* infile);
+int ipsw_get_file_size(ipsw_archive_t ipsw, const char* infile, uint64_t* size);
+int ipsw_extract_to_file(ipsw_archive_t ipsw, const char* infile, const char* outfile);
+int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile, const char* outfile, int print_progress);
+int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, void** pbuffer, size_t* psize);
+int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ipsw_send_cb send_callback, void* ctx);
+int ipsw_extract_build_manifest(ipsw_archive_t ipsw, plist_t* buildmanifest, int *tss_enabled);
+int ipsw_extract_restore_plist(ipsw_archive_t ipsw, plist_t* restore_plist);
+int ipsw_list_contents(ipsw_archive_t ipsw, ipsw_list_cb cb, void *ctx);
int ipsw_get_signed_firmwares(const char* product, plist_t* firmwares);
int ipsw_download_fw(const char *fwurl, unsigned char* isha1, const char* todir, char** ipswfile);
diff --git a/src/jsmn.c b/src/jsmn.c
deleted file mode 100644
index a56f20a..0000000
--- a/src/jsmn.c
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * jsmn.c
- * Simple JSON parser
- *
- * Copyright (c) 2010 Serge A. Zaitsev
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include <stdlib.h>
-
-#include "jsmn.h"
-
-/**
- * Allocates a fresh unused token from the token pull.
- */
-static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
- jsmntok_t *tokens, size_t num_tokens) {
- jsmntok_t *tok;
- if (parser->toknext >= num_tokens) {
- return NULL;
- }
- tok = &tokens[parser->toknext++];
- tok->start = tok->end = -1;
- tok->size = 0;
-#ifdef JSMN_PARENT_LINKS
- tok->parent = -1;
-#endif
- return tok;
-}
-
-/**
- * Fills token type and boundaries.
- */
-static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
- int start, int end) {
- token->type = type;
- token->start = start;
- token->end = end;
- token->size = 0;
-}
-
-/**
- * Fills next available token with JSON primitive.
- */
-static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js,
- jsmntok_t *tokens, size_t num_tokens) {
- jsmntok_t *token;
- int start;
-
- start = parser->pos;
-
- for (; js[parser->pos] != '\0'; parser->pos++) {
- switch (js[parser->pos]) {
-#ifndef JSMN_STRICT
- /* In strict mode primitive must be followed by "," or "}" or "]" */
- case ':':
-#endif
- case '\t' : case '\r' : case '\n' : case ' ' :
- case ',' : case ']' : case '}' :
- goto found;
- }
- if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
- parser->pos = start;
- return JSMN_ERROR_INVAL;
- }
- }
-#ifdef JSMN_STRICT
- /* In strict mode primitive must be followed by a comma/object/array */
- parser->pos = start;
- return JSMN_ERROR_PART;
-#endif
-
-found:
- token = jsmn_alloc_token(parser, tokens, num_tokens);
- if (token == NULL) {
- parser->pos = start;
- return JSMN_ERROR_NOMEM;
- }
- jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
-#ifdef JSMN_PARENT_LINKS
- token->parent = parser->toksuper;
-#endif
- parser->pos--;
- return JSMN_SUCCESS;
-}
-
-/**
- * Filsl next token with JSON string.
- */
-static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js,
- jsmntok_t *tokens, size_t num_tokens) {
- jsmntok_t *token;
-
- int start = parser->pos;
-
- parser->pos++;
-
- /* Skip starting quote */
- for (; js[parser->pos] != '\0'; parser->pos++) {
- char c = js[parser->pos];
-
- /* Quote: end of string */
- if (c == '\"') {
- token = jsmn_alloc_token(parser, tokens, num_tokens);
- if (token == NULL) {
- parser->pos = start;
- return JSMN_ERROR_NOMEM;
- }
- jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
-#ifdef JSMN_PARENT_LINKS
- token->parent = parser->toksuper;
-#endif
- return JSMN_SUCCESS;
- }
-
- /* Backslash: Quoted symbol expected */
- if (c == '\\') {
- parser->pos++;
- switch (js[parser->pos]) {
- /* Allowed escaped symbols */
- case '\"': case '/' : case '\\' : case 'b' :
- case 'f' : case 'r' : case 'n' : case 't' :
- break;
- /* Allows escaped symbol \uXXXX */
- case 'u':
- /* TODO */
- break;
- /* Unexpected symbol */
- default:
- parser->pos = start;
- return JSMN_ERROR_INVAL;
- }
- }
- }
- parser->pos = start;
- return JSMN_ERROR_PART;
-}
-
-/**
- * Parse JSON string and fill tokens.
- */
-jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, jsmntok_t *tokens,
- unsigned int num_tokens) {
- jsmnerr_t r;
- int i;
- jsmntok_t *token;
-
- for (; js[parser->pos] != '\0'; parser->pos++) {
- char c;
- jsmntype_t type;
-
- c = js[parser->pos];
- switch (c) {
- case '{': case '[':
- token = jsmn_alloc_token(parser, tokens, num_tokens);
- if (token == NULL)
- return JSMN_ERROR_NOMEM;
- if (parser->toksuper != -1) {
- tokens[parser->toksuper].size++;
-#ifdef JSMN_PARENT_LINKS
- token->parent = parser->toksuper;
-#endif
- }
- token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
- token->start = parser->pos;
- parser->toksuper = parser->toknext - 1;
- break;
- case '}': case ']':
- type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
-#ifdef JSMN_PARENT_LINKS
- if (parser->toknext < 1) {
- return JSMN_ERROR_INVAL;
- }
- token = &tokens[parser->toknext - 1];
- for (;;) {
- if (token->start != -1 && token->end == -1) {
- if (token->type != type) {
- return JSMN_ERROR_INVAL;
- }
- token->end = parser->pos + 1;
- parser->toksuper = token->parent;
- break;
- }
- if (token->parent == -1) {
- break;
- }
- token = &tokens[token->parent];
- }
-#else
- for (i = parser->toknext - 1; i >= 0; i--) {
- token = &tokens[i];
- if (token->start != -1 && token->end == -1) {
- if (token->type != type) {
- return JSMN_ERROR_INVAL;
- }
- parser->toksuper = -1;
- token->end = parser->pos + 1;
- break;
- }
- }
- /* Error if unmatched closing bracket */
- if (i == -1) return JSMN_ERROR_INVAL;
- for (; i >= 0; i--) {
- token = &tokens[i];
- if (token->start != -1 && token->end == -1) {
- parser->toksuper = i;
- break;
- }
- }
-#endif
- break;
- case '\"':
- r = jsmn_parse_string(parser, js, tokens, num_tokens);
- if (r < 0) return r;
- if (parser->toksuper != -1)
- tokens[parser->toksuper].size++;
- break;
- case '\t' : case '\r' : case '\n' : case ':' : case ',': case ' ':
- break;
-#ifdef JSMN_STRICT
- /* In strict mode primitives are: numbers and booleans */
- case '-': case '0': case '1' : case '2': case '3' : case '4':
- case '5': case '6': case '7' : case '8': case '9':
- case 't': case 'f': case 'n' :
-#else
- /* In non-strict mode every unquoted value is a primitive */
- default:
-#endif
- r = jsmn_parse_primitive(parser, js, tokens, num_tokens);
- if (r < 0) return r;
- if (parser->toksuper != -1)
- tokens[parser->toksuper].size++;
- break;
-
-#ifdef JSMN_STRICT
- /* Unexpected char in strict mode */
- default:
- return JSMN_ERROR_INVAL;
-#endif
-
- }
- }
-
- for (i = parser->toknext - 1; i >= 0; i--) {
- /* Unmatched opened object or array */
- if (tokens[i].start != -1 && tokens[i].end == -1) {
- return JSMN_ERROR_PART;
- }
- }
-
- return JSMN_SUCCESS;
-}
-
-/**
- * Creates a new parser based over a given buffer with an array of tokens
- * available.
- */
-void jsmn_init(jsmn_parser *parser) {
- parser->pos = 0;
- parser->toknext = 0;
- parser->toksuper = -1;
-}
-
diff --git a/src/jsmn.h b/src/jsmn.h
deleted file mode 100644
index f12dc5a..0000000
--- a/src/jsmn.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * jsmn.h
- * Simple JSON parser (header file)
- *
- * Copyright (c) 2010 Serge A. Zaitsev
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#ifndef __JSMN_H_
-#define __JSMN_H_
-
-/**
- * JSON type identifier. Basic types are:
- * o Object
- * o Array
- * o String
- * o Other primitive: number, boolean (true/false) or null
- */
-typedef enum {
- JSMN_PRIMITIVE = 0,
- JSMN_OBJECT = 1,
- JSMN_ARRAY = 2,
- JSMN_STRING = 3
-} jsmntype_t;
-
-typedef enum {
- /* Not enough tokens were provided */
- JSMN_ERROR_NOMEM = -1,
- /* Invalid character inside JSON string */
- JSMN_ERROR_INVAL = -2,
- /* The string is not a full JSON packet, more bytes expected */
- JSMN_ERROR_PART = -3,
- /* Everything was fine */
- JSMN_SUCCESS = 0
-} jsmnerr_t;
-
-/**
- * JSON token description.
- * @param type type (object, array, string etc.)
- * @param start start position in JSON data string
- * @param end end position in JSON data string
- */
-typedef struct {
- jsmntype_t type;
- int start;
- int end;
- int size;
-#ifdef JSMN_PARENT_LINKS
- int parent;
-#endif
-} jsmntok_t;
-
-/**
- * JSON parser. Contains an array of token blocks available. Also stores
- * the string being parsed now and current position in that string
- */
-typedef struct {
- unsigned int pos; /* offset in the JSON string */
- int toknext; /* next token to allocate */
- int toksuper; /* superior token node, e.g parent object or array */
-} jsmn_parser;
-
-/**
- * Create JSON parser over an array of tokens
- */
-void jsmn_init(jsmn_parser *parser);
-
-/**
- * Run JSON parser. It parses a JSON data string into and array of tokens, each describing
- * a single JSON object.
- */
-jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js,
- jsmntok_t *tokens, unsigned int num_tokens);
-
-#endif /* __JSMN_H_ */
diff --git a/src/json_plist.c b/src/json_plist.c
deleted file mode 100644
index 7bbead0..0000000
--- a/src/json_plist.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * json_plist.c
- * JSON/property list functions
- *
- * Copyright (c) 2013 Nikias Bassen. All Rights Reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <jsmn.h>
-#include <plist/plist.h>
-
-#include "json_plist.h"
-
-static plist_t parse_primitive(const char* js, jsmntok_t* tokens, int* index);
-static plist_t parse_string(const char* js, jsmntok_t* tokens, int* index);
-static plist_t parse_array(const char* js, jsmntok_t* tokens, int* index);
-static plist_t parse_object(const char* js, jsmntok_t* tokens, int* index);
-
-static char* get_string_value(const char* js, jsmntok_t token)
-{
- int len = (token.end - token.start);
- char* str = malloc(len+1);
- memcpy(str, js + token.start, len);
- str[len] = 0;
- return str;
-}
-
-static plist_t parse_primitive(const char* js, jsmntok_t* tokens, int* index)
-{
- if (tokens[*index].type != JSMN_PRIMITIVE) {
- fprintf(stderr, "%s: ERROR: token type != JSMN_PRIMITIVE?!\n", __func__);
- return NULL;
- }
- plist_t val = NULL;
- char* strval = get_string_value(js, tokens[*index]);
- if (strval[0] == 'f') {
- val = plist_new_bool(0);
- } else if (strval[0] == 't') {
- val = plist_new_bool(1);
- } else if ((strval[0] == '-') || ((strval[0] >= '0') && (strval[0] <= '9'))) {
- val = plist_new_uint(strtoll(strval, NULL, 10));
- } else {
- fprintf(stderr, "%s: WARNING: invalid primitive value '%s' encountered, will return as string\n", __func__, strval);
- val = plist_new_string(strval);
- }
- free(strval);
- (*index)++;
- return val;
-}
-
-static plist_t parse_string(const char* js, jsmntok_t* tokens, int* index)
-{
- if (tokens[*index].type != JSMN_STRING) {
- fprintf(stderr, "%s: ERROR: token type != JSMN_STRING?!\n", __func__);
- return NULL;
- }
- char* str = get_string_value(js, tokens[*index]);
- plist_t val = plist_new_string(str);
- free(str);
- (*index)++;
- return val;
-}
-
-static plist_t parse_array(const char* js, jsmntok_t* tokens, int* index)
-{
- if (tokens[*index].type != JSMN_ARRAY) {
- fprintf(stderr, "%s: ERROR: token type != JSMN_ARRAY?!\n", __func__);
- return NULL;
- }
- plist_t arr = plist_new_array();
- int num_tokens = tokens[*index].size;
- int num;
- int j = (*index)+1;
- for (num = 0; num < num_tokens; num++) {
- plist_t val = NULL;
- switch (tokens[j].type) {
- case JSMN_OBJECT:
- val = parse_object(js, tokens, &j);
- break;
- case JSMN_ARRAY:
- val = parse_array(js, tokens, &j);
- break;
- case JSMN_STRING:
- val = parse_string(js, tokens, &j);
- break;
- case JSMN_PRIMITIVE:
- val = parse_primitive(js, tokens, &j);
- break;
- default:
- break;
- }
- if (val) {
- plist_array_append_item(arr, val);
- }
- }
- *(index) = j;
- return arr;
-}
-
-static plist_t parse_object(const char* js, jsmntok_t* tokens, int* index)
-{
- if (tokens[*index].type != JSMN_OBJECT) {
- fprintf(stderr, "%s: ERROR: token type != JSMN_OBJECT?!\n", __func__);
- return NULL;
- }
- plist_t obj = plist_new_dict();
- int num_tokens = tokens[*index].size;
- int num;
- int j = (*index)+1;
- for (num = 0; num < num_tokens; num++) {
- if (tokens[j].type == JSMN_STRING) {
- char* key = get_string_value(js, tokens[j]);
- plist_t val = NULL;
- j++;
- num++;
- switch (tokens[j].type) {
- case JSMN_OBJECT:
- val = parse_object(js, tokens, &j);
- break;
- case JSMN_ARRAY:
- val = parse_array(js, tokens, &j);
- break;
- case JSMN_STRING:
- val = parse_string(js, tokens, &j);
- break;
- case JSMN_PRIMITIVE:
- val = parse_primitive(js, tokens, &j);
- break;
- default:
- break;
- }
- if (val) {
- plist_dict_set_item(obj, key, val);
- }
- free(key);
- } else {
- fprintf(stderr, "%s: keys must be of type STRING\n", __func__);
- return NULL;
- }
- }
- (*index) = j;
- return obj;
-}
-
-plist_t json_to_plist(const char* json_string)
-{
- jsmn_parser parser;
- jsmn_init(&parser);
- int maxtoks = 256;
- jsmntok_t *tokens;
-
- if (!json_string) {
- fprintf(stderr, "%s: ERROR: no JSON string given.\n", __func__);
- return NULL;
- }
-
- tokens = malloc(sizeof(jsmntok_t)*maxtoks);
- if (!tokens) {
- fprintf(stderr, "%s: Out of memory\n", __func__);
- return NULL;
- }
-
- int r = 0;
-reparse:
- r = jsmn_parse(&parser, json_string, tokens, maxtoks);
- if (r == JSMN_ERROR_NOMEM) {
- //printf("not enough tokens (%d), retrying...\n", maxtoks);
- maxtoks+=256;
- jsmntok_t* newtokens = realloc(tokens, sizeof(jsmntok_t)*maxtoks);
- if (newtokens) {
- tokens = newtokens;
- goto reparse;
- }
- }
-
- switch(r) {
- case JSMN_ERROR_NOMEM:
- fprintf(stderr, "%s: ERROR: Out of memory...\n", __func__);
- return NULL;
- case JSMN_ERROR_INVAL:
- fprintf(stderr, "%s: ERROR: Invalid character inside JSON string\n", __func__);
- return NULL;
- case JSMN_ERROR_PART:
- fprintf(stderr, "%s: ERROR: The string is not a full JSON packet, more bytes expected\n", __func__);
- return NULL;
- default:
- break;
- }
-
- int startindex = 0;
- plist_t plist = NULL;
- switch (tokens[startindex].type) {
- case JSMN_PRIMITIVE:
- plist = parse_primitive(json_string, tokens, &startindex);
- break;
- case JSMN_STRING:
- plist = parse_string(json_string, tokens, &startindex);
- break;
- case JSMN_ARRAY:
- plist = parse_array(json_string, tokens, &startindex);
- break;
- case JSMN_OBJECT:
- plist = parse_object(json_string, tokens, &startindex);
- break;
- default:
- break;
- }
-
- free(tokens);
-
- return plist;
-}
-
diff --git a/src/limera1n.c b/src/limera1n.c
index da4a7d5..f205287 100644
--- a/src/limera1n.c
+++ b/src/limera1n.c
@@ -78,7 +78,7 @@ int limera1n_exploit(struct irecv_device *device, irecv_client_t *pclient)
stack_address = 0x84033F98;
shellcode_address = 0x84023001;
} else {
- error("Unsupported ChipID 0x%04x. Can't exploit with limera1n.\n", device->chip_id);
+ logger(LL_ERROR, "Unsupported ChipID 0x%04x. Can't exploit with limera1n.\n", device->chip_id);
return -1;
}
@@ -87,10 +87,10 @@ int limera1n_exploit(struct irecv_device *device, irecv_client_t *pclient)
irecv_client_t client = *pclient;
- debug("Resetting device counters\n");
+ logger(LL_DEBUG, "Resetting device counters\n");
err = irecv_reset_counters(client);
if (err != IRECV_E_SUCCESS) {
- error("%s\n", irecv_strerror(err));
+ logger(LL_ERROR, "%s\n", irecv_strerror(err));
return -1;
}
@@ -103,7 +103,7 @@ int limera1n_exploit(struct irecv_device *device, irecv_client_t *pclient)
heap[3] = stack_address;
}
- debug("Sending chunk headers\n");
+ logger(LL_DEBUG, "Sending chunk headers\n");
irecv_usb_control_transfer(client, 0x21, 1, 0, 0, buf, 0x800, 1000);
memset(buf, 0xCC, 0x800);
@@ -111,32 +111,32 @@ int limera1n_exploit(struct irecv_device *device, irecv_client_t *pclient)
irecv_usb_control_transfer(client, 0x21, 1, 0, 0, buf, 0x800, 1000);
}
- debug("Sending exploit payload\n");
+ logger(LL_DEBUG, "Sending exploit payload\n");
irecv_usb_control_transfer(client, 0x21, 1, 0, 0, shellcode, 0x800, 1000);
- debug("Sending fake data\n");
+ logger(LL_DEBUG, "Sending fake data\n");
memset(buf, 0xBB, 0x800);
irecv_usb_control_transfer(client, 0xA1, 1, 0, 0, buf, 0x800, 1000);
irecv_usb_control_transfer(client, 0x21, 1, 0, 0, buf, 0x800, 10);
- //debug("Executing exploit\n");
+ //logger(LL_DEBUG, "Executing exploit\n");
irecv_usb_control_transfer(client, 0x21, 2, 0, 0, buf, 0, 1000);
irecv_reset(client);
irecv_finish_transfer(client);
- debug("Exploit sent\n");
+ logger(LL_DEBUG, "Exploit sent\n");
- debug("Reconnecting to device\n");
+ logger(LL_DEBUG, "Reconnecting to device\n");
*pclient = irecv_reconnect(client, 7);
if (*pclient == NULL) {
- error("Unable to reconnect\n");
+ logger(LL_ERROR, "Unable to reconnect\n");
return -1;
}
irecv_get_mode((*pclient), &mode);
if (mode != IRECV_K_DFU_MODE) {
- error("Device reconnected in non-DFU mode\n");
+ logger(LL_ERROR, "Device reconnected in non-DFU mode\n");
return -1;
}
diff --git a/src/locking.c b/src/locking.c
index dbbbd7c..05f0e4f 100644
--- a/src/locking.c
+++ b/src/locking.c
@@ -35,7 +35,7 @@ int lock_file(const char* filename, lock_info_t* lockinfo)
#ifdef WIN32
lockinfo->fp = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (lockinfo->fp == INVALID_HANDLE_VALUE) {
- debug("ERROR: could not open or create lockfile '%s'\n", filename);
+ logger(LL_DEBUG, "ERROR: could not open or create lockfile '%s'\n", filename);
return -1;
}
@@ -43,7 +43,7 @@ int lock_file(const char* filename, lock_info_t* lockinfo)
lockinfo->ldata.OffsetHigh = 0;
if (!LockFileEx(lockinfo->fp, LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &lockinfo->ldata)) {
- debug("ERROR: can't lock file, error %d\n", GetLastError());
+ logger(LL_DEBUG, "ERROR: can't lock file, error %d\n", GetLastError());
CloseHandle(lockinfo->fp);
lockinfo->fp = INVALID_HANDLE_VALUE;
return -1;
@@ -52,7 +52,7 @@ int lock_file(const char* filename, lock_info_t* lockinfo)
lockinfo->fp = fopen(filename, "a+");
if (!lockinfo->fp) {
- debug("ERROR: could not open or create lockfile '%s'\n", filename);
+ logger(LL_DEBUG, "ERROR: could not open or create lockfile '%s'\n", filename);
return -1;
}
@@ -62,7 +62,7 @@ int lock_file(const char* filename, lock_info_t* lockinfo)
lockinfo->ldata.l_len = 0;
if (fcntl(fileno(lockinfo->fp), F_SETLKW, &lockinfo->ldata) < 0) {
- debug("ERROR: can't lock file, error %d\n", errno);
+ logger(LL_DEBUG, "ERROR: can't lock file, error %d\n", errno);
fclose(lockinfo->fp);
lockinfo->fp = NULL;
return -1;
@@ -85,7 +85,7 @@ int unlock_file(lock_info_t* lockinfo)
lockinfo->ldata.OffsetHigh = 0;
if (!UnlockFileEx(lockinfo->fp, 0, 1, 0, &lockinfo->ldata)) {
- debug("ERROR: can't unlock file, error %d\n", GetLastError());
+ logger(LL_DEBUG, "ERROR: can't unlock file, error %d\n", GetLastError());
CloseHandle(lockinfo->fp);
lockinfo->fp = INVALID_HANDLE_VALUE;
return -1;
@@ -103,7 +103,7 @@ int unlock_file(lock_info_t* lockinfo)
lockinfo->ldata.l_len = 0;
if (fcntl(fileno(lockinfo->fp), F_SETLK, &lockinfo->ldata) < 0) {
- debug("ERROR: can't unlock file, error %d\n", errno);
+ logger(LL_DEBUG, "ERROR: can't unlock file, error %d\n", errno);
fclose(lockinfo->fp);
lockinfo->fp = NULL;
return -1;
diff --git a/src/log.c b/src/log.c
new file mode 100644
index 0000000..b9c2c51
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,227 @@
+/*
+ * log.c
+ *
+ * Copyright (c) 2024 Nikias Bassen. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <time.h>
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <sys/time.h>
+#endif
+#include <errno.h>
+
+#include <libimobiledevice-glue/thread.h>
+#include <plist/plist.h>
+
+#include "log.h"
+
+static int stderr_enabled = 1;
+
+enum loglevel log_level = LL_VERBOSE;
+enum loglevel print_level = LL_INFO;
+
+static logger_print_func print_func = NULL;
+
+const char *_level_label[6] = {
+ " <Error>",
+ "<Warning>",
+ " <Notice>",
+ " <Info>",
+ "<Verbose>",
+ " <Debug>"
+};
+
+// Reference: https://stackoverflow.com/a/2390626/1806760
+// Initializer/finalizer sample for MSVC and GCC/Clang.
+// 2010-2016 Joe Lowe. Released into the public domain.
+
+#ifdef __cplusplus
+ #define INITIALIZER(f) \
+ static void f(void); \
+ struct f##_t_ { f##_t_(void) { f(); } }; static f##_t_ f##_; \
+ static void f(void)
+#elif defined(_MSC_VER)
+ #pragma section(".CRT$XCU",read)
+ #define INITIALIZER2_(f,p) \
+ static void f(void); \
+ __declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \
+ __pragma(comment(linker,"/include:" p #f "_")) \
+ static void f(void)
+ #ifdef _WIN64
+ #define INITIALIZER(f) INITIALIZER2_(f,"")
+ #else
+ #define INITIALIZER(f) INITIALIZER2_(f,"_")
+ #endif
+#else
+ #define INITIALIZER(f) \
+ static void f(void) __attribute__((__constructor__)); \
+ static void f(void)
+#endif
+
+static mutex_t log_mutex;
+
+static void logger_deinit(void)
+{
+ mutex_destroy(&log_mutex);
+}
+
+INITIALIZER(logger_init)
+{
+ mutex_init(&log_mutex);
+ atexit(logger_deinit);
+}
+
+void logger(enum loglevel level, const char *fmt, ...)
+{
+ va_list ap;
+ va_list ap2;
+ char *fs;
+
+ if (level > log_level)
+ return;
+
+ mutex_lock(&log_mutex);
+
+ size_t fslen = 24 + strlen(fmt);
+ fs = malloc(fslen);
+
+#ifdef _WIN32
+ SYSTEMTIME lt;
+ GetLocalTime(&lt);
+ snprintf(fs, fslen, "%02d:%02d:%02d.%03d %s %s", lt.wHour, lt.wMinute, lt.wSecond, lt.wMilliseconds, _level_label[level], fmt);
+#else
+ struct timeval ts;
+ struct tm *tp;
+
+ gettimeofday(&ts, NULL);
+#ifdef HAVE_LOCALTIME_R
+ struct tm tp_;
+ tp = localtime_r(&ts.tv_sec, &tp_);
+#else
+ tp = localtime(&ts.tv_sec);
+#endif
+
+ strftime(fs, 9, "%H:%M:%S", tp);
+ snprintf(fs+8, fslen-8, ".%03d %s %s", (int)(ts.tv_usec / 1000), _level_label[level], fmt);
+#endif
+
+ va_start(ap, fmt);
+ va_copy(ap2, ap);
+ if (print_func) {
+ if (stderr_enabled) {
+ vfprintf(stderr, fs, ap);
+ fflush(stderr);
+ }
+ if (level <= print_level) {
+ // skip the timestamp and log level string
+ print_func(level, fs+23, ap2);
+ }
+ } else {
+ vprintf(fs, ap);
+ }
+
+ va_end(ap);
+ va_end(ap2);
+
+ free(fs);
+
+ mutex_unlock(&log_mutex);
+}
+
+#if defined(__GNUC__) || defined(__clang__)
+static void print_funcf(enum loglevel level, const char* fmt, ...) __attribute__ ((format (printf, 2, 3)));
+#else
+static void print_funcf(enum loglevel level, const char* fmt, ...);
+#endif
+
+static void print_funcf(enum loglevel level, const char* fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ print_func(level, fmt, ap);
+ va_end(ap);
+}
+
+void logger_dump_hex(enum loglevel level, const void* buf, size_t len)
+{
+ char *fs;
+
+ if (level > log_level)
+ return;
+
+ mutex_lock(&log_mutex);
+
+ fs = (char*)malloc(len * 3 + 1);
+ for (unsigned int i = 0; i < len; i++) {
+ snprintf(fs + i*3, 4, "%02x%c", ((unsigned char*)buf)[i], (i < len-1) ? ' ' : '\n');
+ }
+ if (print_func) {
+ if (stderr_enabled) {
+ fprintf(stderr, "%s", fs);
+ fflush(stderr);
+ }
+ if (level <= print_level) {
+ print_funcf(level, "%s", fs);
+ }
+ } else {
+ printf("%s", fs);
+ }
+ free(fs);
+
+ mutex_unlock(&log_mutex);
+}
+
+void logger_dump_plist(enum loglevel level, plist_t plist, int human_readable)
+{
+ if (level > log_level)
+ return;
+ mutex_lock(&log_mutex);
+ plist_write_to_stream(plist, stderr_enabled ? stderr : stdout, (human_readable) ? PLIST_FORMAT_PRINT : PLIST_FORMAT_XML, PLIST_OPT_NONE);
+ mutex_unlock(&log_mutex);
+}
+
+int logger_set_logfile(const char* path)
+{
+ if (!path || !strcasecmp(path, "NULL") || !strcasecmp(path, "NONE")) {
+ stderr_enabled = 0;
+ return 0;
+ }
+ stderr_enabled = 1;
+ if (strcmp(path, "-")) {
+ FILE* newf = freopen(path, "w", stderr);
+ if (!newf) {
+ logger(LL_ERROR, "Could not open logfile '%s': %s\n", path, strerror(errno));
+ return -1;
+ }
+ }
+ return 0;
+}
+
+void logger_set_print_func(logger_print_func func)
+{
+ print_func = func;
+}
diff --git a/src/json_plist.h b/src/log.h
index d6eec0b..046a8d2 100644
--- a/src/json_plist.h
+++ b/src/log.h
@@ -1,8 +1,7 @@
/*
- * json_plist.h
- * JSON/property list functions (header file)
+ * log.h
*
- * Copyright (c) 2013 Nikias Bassen. All Rights Reserved.
+ * Copyright (c) 2024 Nikias Bassen. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -18,17 +17,29 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef __JSON_PLIST_H
-#define __JSON_PLIST_H
-#ifdef __cplusplus
-extern "C" {
-#endif
+#ifndef LOG_H
+#define LOG_H
-plist_t json_to_plist(const char* json_string);
+#include <plist/plist.h>
-#ifdef __cplusplus
-}
-#endif
+enum loglevel {
+ LL_ERROR = 0,
+ LL_WARNING,
+ LL_NOTICE,
+ LL_INFO,
+ LL_VERBOSE,
+ LL_DEBUG
+};
+
+extern enum loglevel log_level;
+
+typedef void (*logger_print_func)(enum loglevel level, const char*, va_list);
+
+void logger(enum loglevel level, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+int logger_set_logfile(const char* path);
+void logger_set_print_func(logger_print_func func);
+void logger_dump_hex(enum loglevel level, const void* buf, size_t len);
+void logger_dump_plist(enum loglevel level, plist_t plist, int human_readable);
#endif
diff --git a/src/mbn.c b/src/mbn.c
index 101e29f..8d9f7a4 100644
--- a/src/mbn.c
+++ b/src/mbn.c
@@ -1,9 +1,10 @@
/*
* mbn.c
- * support for .mbn file format (found in .bbfw files)
+ * support for Qualcomm MBN (Modem Binary) formats
*
* Copyright (c) 2012 Martin Szulecki. All Rights Reserved.
* Copyright (c) 2012 Nikias Bassen. All Rights Reserved.
+ * Copyright (c) 2025 Visual Ehrmanntraut <visual@chefkiss.dev>. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -25,67 +26,455 @@
#include "mbn.h"
#include "common.h"
-mbn_file* mbn_parse(unsigned char* data, unsigned int size)
+#define MBN_V1_MAGIC "\x0A\x00\x00\x00"
+#define MBN_V1_MAGIC_SIZE 4
+
+#pragma pack(push, 1)
+typedef struct {
+ uint32_t type; // the signed .mbn files have 0xA as value.
+ uint32_t unk_0x04;
+ uint32_t unk_0x08;
+ uint32_t unk_0x0c;
+ uint32_t data_size; // data_size = total_size - sizeof(mbn_header)
+ uint32_t sig_offset; // real offset = enc_sig_offset & 0xFFFFFF00
+ uint32_t unk_0x18;
+ uint32_t unk_0x1c;
+ uint32_t unk_0x20;
+ uint32_t unk_0x24;
+} mbn_header_v1;
+
+#define MBN_V2_MAGIC "\xD1\xDC\x4B\x84\x34\x10\xD7\x73"
+#define MBN_V2_MAGIC_SIZE 8
+
+typedef struct {
+ unsigned char magic1[8];
+ uint32_t unk_0x08;
+ uint32_t unk_0x0c; // 0xFFFFFFFF
+ uint32_t unk_0x10; // 0xFFFFFFFF
+ uint32_t header_size;
+ uint32_t unk_0x18;
+ uint32_t data_size; // data_size = total_size - sizeof(mbn_header_v2)
+ uint32_t sig_offset;
+ uint32_t unk_0x24;
+ uint32_t unk_0x28;
+ uint32_t unk_0x2c;
+ uint32_t unk_0x30;
+ uint32_t unk_0x34; // 0x1
+ uint32_t unk_0x38; // 0x1
+ uint32_t unk_0x3c; // 0xFFFFFFFF
+ uint32_t unk_0x40; // 0xFFFFFFFF
+ uint32_t unk_0x44; // 0xFFFFFFFF
+ uint32_t unk_0x48; // 0xFFFFFFFF
+ uint32_t unk_0x4c; // 0xFFFFFFFF
+} mbn_header_v2;
+
+#define MBN_BIN_MAGIC "\x04\x00\xEA\x6C\x69\x48\x55"
+#define MBN_BIN_MAGIC_SIZE 7
+#define MBN_BIN_MAGIC_OFFSET 1 // we ignore the first byte
+
+typedef struct {
+ unsigned char magic[8];
+ uint32_t unk_0x08;
+ uint32_t version;
+ uint32_t total_size; // size including header
+ uint32_t unk_0x14; // some offset
+} mbn_bin_header;
+
+typedef struct
+{
+ uint32_t reserved;
+ uint32_t version;
+ uint32_t common_metadata_size;
+ uint32_t qti_metadata_size;
+ uint32_t oem_metadata_size;
+ uint32_t hash_table_size;
+ uint32_t qti_signature_size;
+ uint32_t qti_certificate_chain_size;
+ uint32_t oem_signature_size;
+ uint32_t oem_certificate_chain_size;
+} mbn_v7_header;
+
+#define EI_MAG0 0
+#define EI_MAG1 1
+#define EI_MAG2 2
+#define EI_MAG3 3
+#define EI_CLASS 4
+#define EI_DATA 5
+#define EI_VERSION 6
+#define EI_OSABI 7
+#define EI_ABIVERSION 8
+#define EI_PAD 9
+#define EI_NIDENT 16
+
+#define ELFMAG0 0x7F
+#define ELFMAG1 'E'
+#define ELFMAG2 'L'
+#define ELFMAG3 'F'
+#define ELFCLASSNONE 0
+#define ELFCLASS32 1
+#define ELFCLASS64 2
+
+typedef struct
+{
+ uint8_t e_ident[EI_NIDENT];
+ uint16_t e_type;
+ uint16_t e_machine;
+ uint32_t e_version;
+ uint32_t e_entry;
+ uint32_t e_phoff;
+ uint32_t e_shoff;
+ uint32_t e_flags;
+ uint16_t e_ehsize;
+ uint16_t e_phentsize;
+ uint16_t e_phnum;
+ uint16_t e_shentsize;
+ uint16_t e_shnum;
+ uint16_t e_shstrndx;
+} elf32_header;
+
+typedef struct
+{
+ uint8_t e_ident[EI_NIDENT];
+ uint16_t e_type;
+ uint16_t e_machine;
+ uint32_t e_version;
+ uint64_t e_entry;
+ uint64_t e_phoff;
+ uint64_t e_shoff;
+ uint32_t e_flags;
+ uint16_t e_ehsize;
+ uint16_t e_phentsize;
+ uint16_t e_phnum;
+ uint16_t e_shentsize;
+ uint16_t e_shnum;
+ uint16_t e_shstrndx;
+} elf64_header;
+
+typedef struct
+{
+ uint32_t p_type;
+ uint32_t p_offset;
+ uint32_t p_vaddr;
+ uint32_t p_paddr;
+ uint32_t p_filesz;
+ uint32_t p_memsz;
+ uint32_t p_flags;
+ uint32_t p_align;
+} elf32_pheader;
+
+typedef struct
+{
+ uint32_t p_type;
+ uint32_t p_flags;
+ uint64_t p_offset;
+ uint64_t p_vaddr;
+ uint64_t p_paddr;
+ uint64_t p_filesz;
+ uint64_t p_memsz;
+ uint64_t p_align;
+} elf64_pheader;
+#pragma pack(pop)
+
+static int mbn_is_valid_elf(const uint8_t* e_ident, size_t size)
+{
+ return size >= EI_NIDENT && e_ident[EI_MAG0] == ELFMAG0 &&
+ e_ident[EI_MAG1] == ELFMAG1 && e_ident[EI_MAG2] == ELFMAG2 &&
+ e_ident[EI_MAG3] == ELFMAG3 && e_ident[EI_CLASS] != ELFCLASSNONE;
+}
+
+static int mbn_is_64bit_elf(const uint8_t* e_ident)
{
- mbn_file* mbn = (mbn_file*)malloc(sizeof(mbn_file));
- if (!mbn) {
- return NULL;
- }
- memset(mbn, '\0', sizeof(mbn_file));
- mbn->data = malloc(size);
- mbn->size = size;
- memcpy(mbn->data, data, size);
- /* FIXME: header parsing is not big endian safe */
- if (memcmp(data, MBN_V2_MAGIC, MBN_V2_MAGIC_SIZE) == 0) {
- mbn->version = 2;
- memcpy(&mbn->header.v2, data, sizeof(mbn_header_v2));
- mbn->parsed_size = mbn->header.v2.data_size + sizeof(mbn_header_v2);
- } else if (memcmp(data, MBN_V1_MAGIC, MBN_V1_MAGIC_SIZE) == 0) {
- mbn->version = 1;
- memcpy(&mbn->header.v1, data, sizeof(mbn_header_v1));
- mbn->parsed_size = mbn->header.v1.data_size + sizeof(mbn_header_v1);
- } else if (memcmp(data, BIN_MAGIC, BIN_MAGIC_SIZE) == 0) {
- mbn->version = 3;
- memcpy(&mbn->header.bin, data, sizeof(bin_header));
- mbn->parsed_size = mbn->header.bin.total_size;
- } else if (memcmp(data, ELF_MAGIC, ELF_MAGIC_SIZE) == 0) {
- mbn->version = 4;
- memcpy(&mbn->header.elf, data, sizeof(elf_header));
- // we cheat here since we don't parse the actual ELF file
- mbn->parsed_size = mbn->size;
+ return e_ident[EI_CLASS] == ELFCLASS64;
+}
+
+void* mbn_stitch(const void* data, size_t data_size, const void* blob, size_t blob_size)
+{
+ if (!data) {
+ logger(LL_ERROR, "%s: data is NULL\n", __func__);
+ return NULL;
+ }
+
+ if (!data_size) {
+ logger(LL_ERROR, "%s: data size is 0\n", __func__);
+ return NULL;
+ }
+
+ if (!blob) {
+ logger(LL_ERROR, "%s: blob is NULL\n", __func__);
+ return NULL;
+ }
+
+ if (!blob_size) {
+ logger(LL_ERROR, "%s: blob size is 0\n", __func__);
+ return NULL;
+ }
+
+ size_t parsed_size = 0;
+ if (data_size > MBN_V2_MAGIC_SIZE && memcmp(data, MBN_V2_MAGIC, MBN_V2_MAGIC_SIZE) == 0) {
+ parsed_size = ((mbn_header_v2*)data)->data_size + sizeof(mbn_header_v2);
+ logger(LL_DEBUG, "%s: encountered MBN v2 image, parsed_size = 0x%zx\n", __func__, parsed_size);
+ } else if (data_size > MBN_V1_MAGIC_SIZE && memcmp(data, MBN_V1_MAGIC, MBN_V1_MAGIC_SIZE) == 0) {
+ parsed_size = ((mbn_header_v1*)data)->data_size + sizeof(mbn_header_v1);
+ logger(LL_DEBUG, "%s: encountered MBN v1 image, parsed_size = 0x%zx\n", __func__, parsed_size);
+ } else if (data_size > MBN_BIN_MAGIC_SIZE+MBN_BIN_MAGIC_OFFSET && memcmp((uint8_t*)data+MBN_BIN_MAGIC_OFFSET, (uint8_t*)MBN_BIN_MAGIC, MBN_BIN_MAGIC_SIZE) == 0) {
+ parsed_size = ((mbn_bin_header*)data)->total_size;
+ logger(LL_DEBUG, "%s: encountered MBN BIN image, parsed_size = 0x%zx\n", __func__, parsed_size);
+ } else if (mbn_is_valid_elf(data, data_size)) {
+ if (mbn_is_64bit_elf(data)) {
+ const elf64_header* ehdr = data;
+ const elf64_pheader* phdr = data + ehdr->e_phoff;
+ if (ehdr->e_phnum == 0) {
+ logger(LL_ERROR, "%s: ELF has no program sections\n", __func__);
+ return NULL;
+ }
+ uint64_t last_off = 0;
+ uint16_t last_index = 0;
+ for (uint16_t i = 0; i < ehdr->e_phnum; i++) {
+ if (phdr[i].p_offset > last_off) {
+ last_off = phdr[i].p_offset;
+ last_index = i;
+ }
+ }
+ parsed_size = last_off + phdr[last_index].p_filesz;
+ } else {
+ const elf32_header* ehdr = data;
+ const elf32_pheader* phdr = data + ehdr->e_phoff;
+ if (ehdr->e_phnum == 0) {
+ logger(LL_ERROR, "%s: ELF has no program sections\n", __func__);
+ return NULL;
+ }
+ uint32_t last_off = 0;
+ uint16_t last_index = 0;
+ for (uint16_t i = 0; i < ehdr->e_phnum; i++) {
+ if (phdr[i].p_offset > last_off) {
+ last_off = phdr[i].p_offset;
+ last_index = i;
+ }
+ }
+ parsed_size = last_off + phdr[last_index].p_filesz;
+ }
+ logger(LL_DEBUG, "%s: encountered ELF image, parsed_size = 0x%zx\n", __func__, parsed_size);
} else {
- debug("DEBUG: Unknown file format passed to %s\n", __func__);
+ logger(LL_WARNING, "Unknown file format passed to %s\n", __func__);
}
- if (mbn->parsed_size != mbn->size) {
- info("WARNING: size mismatch when parsing MBN file. Continuing anyway.\n");
+ if (parsed_size != data_size) {
+ logger(LL_WARNING, "%s: size mismatch for MBN data, expected 0x%zx, input size 0x%zx\n", __func__, parsed_size, data_size);
}
- return mbn;
+
+ off_t stitch_offset = data_size - blob_size;
+ if (stitch_offset + blob_size > data_size) {
+ logger(LL_ERROR, "%s: stitch offset (0x%lx) + size (0x%zx) is larger than the destination (0x%zx)\n", __func__, (unsigned long)stitch_offset, blob_size, data_size);
+ return NULL;
+ }
+
+ unsigned char* buf = malloc(data_size);
+ if (buf == NULL) {
+ logger(LL_ERROR, "out of memory\n");
+ return NULL;
+ }
+
+ memcpy(buf, data, data_size);
+ logger(LL_DEBUG, "%s: stitching mbn at 0x%llx, size 0x%zx\n", __func__, stitch_offset, blob_size);
+ memcpy(buf + stitch_offset, blob, blob_size);
+
+ return buf;
}
-void mbn_free(mbn_file* mbn)
+// the sum of header size and all sizes inside it must fit within the size of
+// the data
+static int mbn_v7_header_sizes_valid(const mbn_v7_header* header, size_t size)
{
- if (mbn) {
- if (mbn->data) {
- free(mbn->data);
- }
- free(mbn);
- }
+ return (sizeof(*header) + header->common_metadata_size +
+ header->qti_metadata_size + header->oem_metadata_size +
+ header->hash_table_size + header->qti_signature_size +
+ header->qti_certificate_chain_size + header->oem_signature_size +
+ header->oem_certificate_chain_size) <= size;
+}
+
+// 0xE0 == sizeof(mav25_authority_meta_field_t), 0x68 ==
+// kExpectedOEMSignatureSize, 0xD20 == kExpectedOEMCertChainSize
+static int mbn_v7_header_sizes_expected(const mbn_v7_header* header)
+{
+ return (header->qti_metadata_size == 0 || header->qti_metadata_size == 0xE0) &&
+ (header->oem_metadata_size == 0 || header->oem_metadata_size == 0xE0) &&
+ (header->oem_signature_size == 0 || header->oem_signature_size == 0x68) &&
+ (header->oem_certificate_chain_size == 0 || header->oem_certificate_chain_size == 0xD20);
+}
+
+static void mbn_v7_log_header(const mbn_v7_header* header, const char* func, const char* prefix)
+{
+ logger(LL_DEBUG,
+ "%s: %s header {version=0x%x, common_metadata_size=0x%x, "
+ "qti_metadata_size=0x%x, oem_metadata_size=0x%x, hash_table_size=0x%x, "
+ "qti_signature_size=0x%x, qti_certificate_chain_size=0x%x, "
+ "oem_signature_size=0x%x, oem_certificate_chain_size=0x%x}\n",
+ func,
+ prefix,
+ header->version,
+ header->common_metadata_size,
+ header->qti_metadata_size,
+ header->oem_metadata_size,
+ header->hash_table_size,
+ header->qti_signature_size,
+ header->qti_certificate_chain_size,
+ header->oem_signature_size,
+ header->oem_certificate_chain_size
+ );
}
-int mbn_update_sig_blob(mbn_file* mbn, const unsigned char* sigdata, unsigned int siglen)
+void* mbn_mav25_stitch(const void* data, size_t data_size, const void* blob, size_t blob_size)
{
- if (!mbn) {
- error("ERROR: %s: no data\n", __func__);
- return -1;
+ if (!data) {
+ logger(LL_ERROR, "%s: data is NULL\n", __func__);
+ return NULL;
}
- mbn->parsed_sig_offset = mbn->size - siglen;
- if ((mbn->parsed_sig_offset + siglen) > mbn->size) {
- error("ERROR: %s: signature is larger than mbn file size\n", __func__);
- return -1;
+
+ if (!data_size) {
+ logger(LL_ERROR, "%s: data size is 0\n", __func__);
+ return NULL;
}
- memcpy(mbn->data + mbn->parsed_sig_offset, sigdata, siglen);
+ if (!blob) {
+ logger(LL_ERROR, "%s: blob is NULL\n", __func__);
+ return NULL;
+ }
- return 0;
-}
+ if (!blob_size) {
+ logger(LL_ERROR, "%s: blob size is 0\n", __func__);
+ return NULL;
+ }
+
+ if (!mbn_is_valid_elf(data, data_size)) {
+ logger(LL_ERROR, "%s: data is not a valid ELF\n", __func__);
+ return NULL;
+ }
+
+ if (sizeof(mbn_v7_header) > blob_size) {
+ logger(LL_ERROR, "%s: header is bigger than blob\n", __func__);
+ return NULL;
+ }
+
+ const mbn_v7_header* src_header = blob;
+ mbn_v7_log_header(src_header, __func__, "src");
+
+ if (src_header->version != 7) {
+ logger(LL_ERROR, "%s: src header version (0x%x) is incorrect\n", __func__, src_header->version);
+ return NULL;
+ }
+
+ // NOTE: Apple does weird stuff, in this case blob is smaller than
+ // the sizes the header reports, so we can't check their validity.
+ if (!mbn_v7_header_sizes_expected(src_header)) {
+ logger(LL_WARNING, "%s: header sizes in header are unexpected (qti_metadata_size=0x%x, oem_metadata_size=0x%x, oem_signature_size=0x%x, oem_certificate_chain_size=0x%x)\n", __func__, src_header->qti_metadata_size, src_header->oem_metadata_size, src_header->oem_signature_size, src_header->oem_certificate_chain_size);
+ }
+
+ off_t sect_off;
+ size_t sect_size;
+ if (mbn_is_64bit_elf(data)) {
+ const elf64_header* ehdr = data;
+ const elf64_pheader* phdr = data + ehdr->e_phoff;
+ if (ehdr->e_phnum == 0) {
+ logger(LL_ERROR, "%s: ELF has no program sections\n", __func__);
+ return NULL;
+ }
+ if ((ehdr->e_phoff + ehdr->e_phnum * sizeof(elf32_pheader)) > data_size) {
+ logger(LL_ERROR, "%s: Last ELF program section is out of bounds\n", __func__);
+ return NULL;
+ }
+ sect_off = phdr[ehdr->e_phnum-1].p_offset;
+ sect_size = phdr[ehdr->e_phnum-1].p_filesz;
+ } else {
+ const elf32_header* ehdr = data;
+ const elf32_pheader* phdr = data + ehdr->e_phoff;
+ if (ehdr->e_phnum == 0) {
+ logger(LL_ERROR, "%s: ELF has no program sections\n", __func__);
+ return NULL;
+ }
+ if ((ehdr->e_phoff + ehdr->e_phnum * sizeof(elf64_pheader)) > data_size) {
+ logger(LL_ERROR, "%s: Last ELF program section is out of bounds\n", __func__);
+ return NULL;
+ }
+ sect_off = phdr[ehdr->e_phnum-1].p_offset;
+ sect_size = phdr[ehdr->e_phnum-1].p_filesz;
+ }
+
+ if (sect_off == 0) {
+ logger(LL_ERROR, "%s: section has 0 offset\n", __func__);
+ return NULL;
+ }
+
+ if (sect_size == 0) {
+ logger(LL_ERROR, "%s: section has 0 size\n", __func__);
+ return NULL;
+ }
+
+ if (sect_off + sect_size > data_size) {
+ logger(LL_ERROR, "%s: section (0x%lx+0x%zx) is bigger than the data\n", __func__, (unsigned long)sect_off, sect_size);
+ return NULL;
+ }
+ if (sizeof(mbn_v7_header) > sect_size) {
+ logger(LL_ERROR, "%s: dest header is bigger than the section (0x%zx)\n", __func__, sect_size);
+ return NULL;
+ }
+
+ const mbn_v7_header* header = data + sect_off;
+ mbn_v7_log_header(header, __func__, "dest");
+ if (header->version != 7) {
+ logger(LL_ERROR, "%s: dest header version (0x%x) is incorrect\n", __func__, header->version);
+ return NULL;
+ }
+
+ if (!mbn_v7_header_sizes_valid(header, sect_size)) {
+ logger(LL_ERROR, "%s: sizes in dest header are invalid (common_metadata_size=0x%x, qti_metadata_size=0x%x, oem_metadata_size=0x%x, hash_table_size=0x%x, qti_signature_size=0x%x, qti_certificate_chain_size=0x%x, oem_signature_size=0x%x, oem_certificate_chain_size=0x%x)\n", __func__, header->common_metadata_size, header->qti_metadata_size, header->oem_metadata_size, header->hash_table_size, header->qti_signature_size, header->qti_certificate_chain_size, header->oem_signature_size, header->oem_certificate_chain_size);
+ return NULL;
+ }
+
+ if (!mbn_v7_header_sizes_expected(header)) {
+ logger(LL_WARNING, "%s: header sizes in dest header are unexpected (qti_metadata_size=0x%x, oem_metadata_size=0x%x, oem_signature_size=0x%x, oem_certificate_chain_size=0x%x)\n", __func__, header->qti_metadata_size, header->oem_metadata_size, header->oem_signature_size, header->oem_certificate_chain_size);
+ }
+
+ size_t new_metadata_size =
+ sizeof(*src_header) + src_header->common_metadata_size +
+ src_header->qti_metadata_size + src_header->oem_metadata_size;
+ size_t new_metadata_and_hash_table_size =
+ new_metadata_size + src_header->hash_table_size;
+ size_t new_oem_sig_and_cert_chain_size =
+ src_header->oem_signature_size + src_header->oem_certificate_chain_size;
+ off_t new_oem_sig_and_cert_chain_off = new_metadata_and_hash_table_size +
+ header->qti_signature_size + header->qti_certificate_chain_size;
+
+ if (new_metadata_and_hash_table_size > blob_size) {
+ logger(LL_ERROR, "%s: new metadata (0x%zx) and hash table (0x%x) are bigger than the source (0x%zx)\n", __func__, new_metadata_size, src_header->hash_table_size, blob_size);
+ return NULL;
+ }
+
+ if (new_metadata_and_hash_table_size > sect_size) {
+ logger(LL_ERROR, "%s: new metadata (0x%zx) and hash table (0x%x) are bigger than the destination (0x%zx)\n", __func__, new_metadata_size, src_header->hash_table_size, sect_size);
+ return NULL;
+ }
+
+ if (new_metadata_and_hash_table_size + new_oem_sig_and_cert_chain_size > blob_size) {
+ logger(LL_ERROR, "%s: new OEM signature and certificate chain are bigger than the source\n", __func__);
+ return NULL;
+ }
+
+ if (new_oem_sig_and_cert_chain_off + new_oem_sig_and_cert_chain_size > sect_size) {
+ logger(LL_ERROR, "%s: new OEM signature and certificate chain are outside the bounds of the destination\n", __func__);
+ return NULL;
+ }
+
+ unsigned char* buf = malloc(data_size);
+ if (buf == NULL) {
+ logger(LL_ERROR, "out of memory\n");
+ return NULL;
+ }
+
+ memcpy(buf, data, data_size);
+ logger(LL_DEBUG, "%s: stitching mbn at 0x%lx (0x%zx bytes)\n", __func__, (unsigned long)sect_off, new_metadata_and_hash_table_size);
+ memcpy(buf + sect_off, blob, new_metadata_and_hash_table_size);
+ logger(LL_DEBUG, "%s: stitching mbn at 0x%lx (0x%zx bytes)\n", __func__, (unsigned long)(sect_off + new_oem_sig_and_cert_chain_off), new_oem_sig_and_cert_chain_size);
+ memcpy(buf + sect_off + new_oem_sig_and_cert_chain_off, blob + new_metadata_and_hash_table_size, new_oem_sig_and_cert_chain_size);
+
+ return buf;
+}
diff --git a/src/mbn.h b/src/mbn.h
index 008ba61..ff44797 100644
--- a/src/mbn.h
+++ b/src/mbn.h
@@ -1,8 +1,9 @@
/*
* mbn.h
- * support for .mbn file format (found in .bbfw files)
+ * support for Qualcomm MBN (Modem Binary) formats
*
* Copyright (c) 2012 Nikias Bassen. All Rights Reserved.
+ * Copyright (c) 2025 Visual Ehrmanntraut <visual@chefkiss.dev>. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -23,85 +24,7 @@
#include <stdint.h>
-#define MBN_V1_MAGIC "\x0A\x00\x00\x00"
-#define MBN_V1_MAGIC_SIZE 4
-
-struct _mbn_header_v1 {
- uint32_t type; // the signed .mbn files have 0xA as value.
- uint32_t unk_0x04;
- uint32_t unk_0x08;
- uint32_t unk_0x0c;
- uint32_t data_size; // data_size = total_size - sizeof(mbn_header)
- uint32_t sig_offset; // real offset = enc_sig_offset & 0xFFFFFF00
- uint32_t unk_0x18;
- uint32_t unk_0x1c;
- uint32_t unk_0x20;
- uint32_t unk_0x24;
-} __attribute__((packed));
-typedef struct _mbn_header_v1 mbn_header_v1;
-
-#define MBN_V2_MAGIC "\xD1\xDC\x4B\x84\x34\x10\xD7\x73"
-#define MBN_V2_MAGIC_SIZE 8
-
-struct _mbn_header_v2 {
- unsigned char magic1[8];
- uint32_t unk_0x08;
- uint32_t unk_0x0c; // 0xFFFFFFFF
- uint32_t unk_0x10; // 0xFFFFFFFF
- uint32_t header_size;
- uint32_t unk_0x18;
- uint32_t data_size; // data_size = total_size - sizeof(mbn_header_v2)
- uint32_t sig_offset;
- uint32_t unk_0x24;
- uint32_t unk_0x28;
- uint32_t unk_0x2c;
- uint32_t unk_0x30;
- uint32_t unk_0x34; // 0x1
- uint32_t unk_0x38; // 0x1
- uint32_t unk_0x3c; // 0xFFFFFFFF
- uint32_t unk_0x40; // 0xFFFFFFFF
- uint32_t unk_0x44; // 0xFFFFFFFF
- uint32_t unk_0x48; // 0xFFFFFFFF
- uint32_t unk_0x4c; // 0xFFFFFFFF
-} __attribute__((packed));
-typedef struct _mbn_header_v2 mbn_header_v2;
-
-#define BIN_MAGIC "\x7D\x04\x00\xEA\x6C\x69\x48\x55"
-#define BIN_MAGIC_SIZE 8
-
-struct _bin_header {
- unsigned char magic[8];
- uint32_t unk_0x08;
- uint32_t version;
- uint32_t total_size; // size including header
- uint32_t unk_0x14; // some offset
-} __attribute__((packed));
-typedef struct _bin_header bin_header;
-
-#define ELF_MAGIC "\x7F\x45\x4C\x46\x01\x01\x01\x00" // ELF magic, 32bit, little endian, SYSV
-#define ELF_MAGIC_SIZE 8
-
-struct _elf_header {
- unsigned char magic[8];
-} __attribute__((packed));
-typedef struct _elf_header elf_header;
-
-typedef struct {
- uint32_t version;
- union {
- mbn_header_v1 v1;
- mbn_header_v2 v2;
- bin_header bin;
- elf_header elf;
- } header;
- uint32_t parsed_size;
- uint32_t parsed_sig_offset;
- void* data;
- uint32_t size;
-} mbn_file;
-
-mbn_file* mbn_parse(unsigned char* data, unsigned int size);
-void mbn_free(mbn_file* mbn);
-int mbn_update_sig_blob(mbn_file* mbn, const unsigned char* data, unsigned int size);
+void* mbn_stitch(const void* data, size_t data_size, const void* blob, size_t blob_size);
+void* mbn_mav25_stitch(const void* data, size_t data_size, const void* blob, size_t blob_size);
#endif
diff --git a/src/normal.c b/src/normal.c
index 15d3e29..7d689e1 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -29,6 +29,7 @@
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
#include <libimobiledevice/preboard.h>
+#include <usbmuxd.h>
#include "common.h"
#include "normal.h"
@@ -41,18 +42,19 @@ static int normal_idevice_new(struct idevicerestore_client_t* client, idevice_t*
idevice_t dev = NULL;
idevice_error_t device_error;
lockdownd_client_t lockdown = NULL;
+ plist_t node = NULL;
*device = NULL;
if (client->udid) {
device_error = idevice_new(&dev, client->udid);
if (device_error != IDEVICE_E_SUCCESS) {
- debug("%s: can't open device with UDID %s\n", __func__, client->udid);
+ logger(LL_DEBUG, "%s: can't open device with UDID %s\n", __func__, client->udid);
return -1;
}
if (lockdownd_client_new(dev, &lockdown, "idevicerestore") != LOCKDOWN_E_SUCCESS) {
- error("ERROR: %s: can't connect to lockdownd on device with UDID %s\n", __func__, client->udid);
+ logger(LL_ERROR, "%s: can't connect to lockdownd on device with UDID %s\n", __func__, client->udid);
return -1;
}
@@ -65,6 +67,10 @@ static int normal_idevice_new(struct idevicerestore_client_t* client, idevice_t*
return -1;
}
free(type);
+ if (lockdownd_get_value(lockdown, NULL, "UniqueChipID", &node) == LOCKDOWN_E_SUCCESS) {
+ plist_get_uint_val(node, &client->ecid);
+ plist_free(node);
+ }
lockdownd_client_free(lockdown);
lockdown = NULL;
@@ -88,12 +94,12 @@ static int normal_idevice_new(struct idevicerestore_client_t* client, idevice_t*
}
device_error = idevice_new(&dev, devices[j]);
if (device_error != IDEVICE_E_SUCCESS) {
- debug("%s: can't open device with UDID %s\n", __func__, devices[j]);
+ logger(LL_DEBUG, "%s: can't open device with UDID %s\n", __func__, devices[j]);
continue;
}
if (lockdownd_client_new(dev, &lockdown, "idevicerestore") != LOCKDOWN_E_SUCCESS) {
- error("ERROR: %s: can't connect to lockdownd on device with UDID %s\n", __func__, devices[j]);
+ logger(LL_ERROR, "%s: can't connect to lockdownd on device with UDID %s\n", __func__, devices[j]);
continue;
}
@@ -107,7 +113,7 @@ static int normal_idevice_new(struct idevicerestore_client_t* client, idevice_t*
}
free(type);
- plist_t node = NULL;
+ node = NULL;
if ((lockdownd_get_value(lockdown, NULL, "UniqueChipID", &node) != LOCKDOWN_E_SUCCESS) || !node || (plist_get_node_type(node) != PLIST_UINT)){
if (node) {
plist_free(node);
@@ -164,10 +170,7 @@ irecv_device_t normal_get_irecv_device(struct idevicerestore_client_t* client)
lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore");
if (!(client->flags & FLAG_ERASE) && lockdown_error == LOCKDOWN_E_PAIRING_DIALOG_RESPONSE_PENDING) {
- info("*** Device is not paired with this computer. Please trust this computer on the device to continue. ***\n");
- if (client->flags & FLAG_DEBUG) {
- idevice_set_debug_level(0);
- }
+ show_banner("Device is not paired with this computer. Please trust this computer on the device to continue.\n");
while (!(client->flags & FLAG_QUIT)) {
lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore");
if (lockdown_error != LOCKDOWN_E_PAIRING_DIALOG_RESPONSE_PENDING) {
@@ -175,9 +178,7 @@ irecv_device_t normal_get_irecv_device(struct idevicerestore_client_t* client)
}
sleep(1);
}
- if (client->flags & FLAG_DEBUG) {
- idevice_set_debug_level(1);
- }
+ hide_banner();
if (client->flags & FLAG_QUIT) {
return NULL;
}
@@ -217,36 +218,30 @@ int normal_enter_recovery(struct idevicerestore_client_t* client)
device_error = idevice_new(&device, client->udid);
if (device_error != IDEVICE_E_SUCCESS) {
- error("ERROR: Unable to find device\n");
+ logger(LL_ERROR, "Unable to find device\n");
return -1;
}
lockdown_error = lockdownd_client_new(device, &lockdown, "idevicerestore");
if (lockdown_error != LOCKDOWN_E_SUCCESS) {
- error("ERROR: Unable to connect to lockdownd: %s (%d)\n", lockdownd_strerror(lockdown_error), lockdown_error);
+ logger(LL_ERROR, "Unable to connect to lockdownd: %s (%d)\n", lockdownd_strerror(lockdown_error), lockdown_error);
idevice_free(device);
return -1;
}
- /* unpair the device */
- lockdown_error = lockdownd_unpair(lockdown, NULL);
- if (lockdown_error != LOCKDOWN_E_SUCCESS) {
- error("WARNING: Could not unpair device\n");
- }
-
lockdown_error = lockdownd_enter_recovery(lockdown);
if (lockdown_error == LOCKDOWN_E_SESSION_INACTIVE) {
lockdownd_client_free(lockdown);
lockdown = NULL;
if (LOCKDOWN_E_SUCCESS != (lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore"))) {
- error("ERROR: Could not connect to lockdownd: %s (%d)\n", lockdownd_strerror(lockdown_error), lockdown_error);
+ logger(LL_ERROR, "Could not connect to lockdownd: %s (%d)\n", lockdownd_strerror(lockdown_error), lockdown_error);
idevice_free(device);
return -1;
}
lockdown_error = lockdownd_enter_recovery(lockdown);
}
if (lockdown_error != LOCKDOWN_E_SUCCESS) {
- error("ERROR: Unable to place device in recovery mode: %s (%d)\n", lockdownd_strerror(lockdown_error), lockdown_error);
+ logger(LL_ERROR, "Unable to place device in recovery mode: %s (%d)\n", lockdownd_strerror(lockdown_error), lockdown_error);
lockdownd_client_free(lockdown);
idevice_free(device);
return -1;
@@ -258,28 +253,31 @@ int normal_enter_recovery(struct idevicerestore_client_t* client)
device = NULL;
mutex_lock(&client->device_event_mutex);
- debug("DEBUG: Waiting for device to disconnect...\n");
+ logger(LL_DEBUG, "Waiting for device to disconnect...\n");
cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 60000);
if (client->mode == MODE_NORMAL || (client->flags & FLAG_QUIT)) {
mutex_unlock(&client->device_event_mutex);
- error("ERROR: Failed to place device in recovery mode\n");
+ logger(LL_ERROR, "Failed to place device in recovery mode\n");
return -1;
}
- debug("DEBUG: Waiting for device to connect in recovery mode...\n");
+ logger(LL_DEBUG, "Waiting for device to connect in recovery mode...\n");
cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 60000);
if (client->mode != MODE_RECOVERY || (client->flags & FLAG_QUIT)) {
mutex_unlock(&client->device_event_mutex);
- error("ERROR: Failed to enter recovery mode\n");
+ logger(LL_ERROR, "Failed to enter recovery mode\n");
return -1;
}
mutex_unlock(&client->device_event_mutex);
if (recovery_client_new(client) < 0) {
- error("ERROR: Unable to enter recovery mode\n");
+ logger(LL_ERROR, "Unable to enter recovery mode\n");
return -1;
}
+ /* remove pair record for given device */
+ usbmuxd_delete_pair_record(client->udid);
+
return 0;
}
@@ -293,20 +291,20 @@ plist_t normal_get_lockdown_value(struct idevicerestore_client_t* client, const
device_error = idevice_new(&device, client->udid);
if (device_error != IDEVICE_E_SUCCESS) {
- error("ERROR: Unable to connect to device?!\n");
+ logger(LL_ERROR, "Unable to connect to device?!\n");
return NULL;
}
lockdown_error = lockdownd_client_new(device, &lockdown, "idevicerestore");
if (lockdown_error != LOCKDOWN_E_SUCCESS) {
- error("ERROR: Unable to connect to lockdownd\n");
+ logger(LL_ERROR, "Unable to connect to lockdownd\n");
idevice_free(device);
return NULL;
}
lockdown_error = lockdownd_get_value(lockdown, domain, key, &node);
if (lockdown_error != LOCKDOWN_E_SUCCESS) {
- debug("ERROR: Unable to get %s-%s from lockdownd\n", domain, key);
+ logger(LL_DEBUG, "ERROR: Unable to get %s-%s from lockdownd\n", domain, key);
lockdownd_client_free(lockdown);
idevice_free(device);
return NULL;
@@ -320,29 +318,41 @@ plist_t normal_get_lockdown_value(struct idevicerestore_client_t* client, const
return node;
}
-static int normal_get_nonce_by_key(struct idevicerestore_client_t* client, const char* key, unsigned char** nonce, int* nonce_size)
+static int normal_get_nonce_by_key(struct idevicerestore_client_t* client, const char* key, unsigned char** nonce, unsigned int* nonce_size)
{
plist_t nonce_node = normal_get_lockdown_value(client, NULL, key);
if (!nonce_node || plist_get_node_type(nonce_node) != PLIST_DATA) {
- error("Unable to get %s\n", key);
+ logger(LL_ERROR, "Unable to get %s\n", key);
return -1;
}
uint64_t n_size = 0;
plist_get_data_val(nonce_node, (char**)nonce, &n_size);
- *nonce_size = (int)n_size;
+ *nonce_size = (unsigned int)n_size;
plist_free(nonce_node);
return 0;
}
-int normal_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size)
+int normal_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size)
{
+ plist_t node = normal_get_lockdown_value(client, NULL, "ApParameters");
+ if (PLIST_IS_DICT(node)) {
+ plist_t nonce_node = plist_dict_get_item(node, "SepNonce");
+ if (nonce_node) {
+ uint64_t n_size = 0;
+ plist_get_data_val(nonce_node, (char**)nonce, &n_size);
+ *nonce_size = (unsigned int)n_size;
+ plist_free(node);
+ return 0;
+ }
+ }
+ plist_free(node);
return normal_get_nonce_by_key(client, "SEPNonce", nonce, nonce_size);
}
-int normal_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size)
+int normal_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size)
{
return normal_get_nonce_by_key(client, "ApNonce", nonce, nonce_size);
}
@@ -362,28 +372,39 @@ int normal_is_image4_supported(struct idevicerestore_client_t* client)
return bval;
}
-int normal_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid)
+int normal_get_firmware_preflight_info(struct idevicerestore_client_t* client, plist_t *preflight_info)
{
- plist_t unique_chip_node = normal_get_lockdown_value(client, NULL, "UniqueChipID");
- if (!unique_chip_node || plist_get_node_type(unique_chip_node) != PLIST_UINT) {
- error("ERROR: Unable to get ECID\n");
- return -1;
+ uint8_t has_telephony_capability = 0;
+ plist_t node;
+
+ node = normal_get_lockdown_value(client, NULL, "TelephonyCapability");
+ plist_get_bool_val(node, &has_telephony_capability);
+ plist_free(node);
+
+ if (has_telephony_capability) {
+ node = normal_get_lockdown_value(client, NULL, "FirmwarePreflightInfo");
+ if (!node || plist_get_node_type(node) != PLIST_DICT) {
+ logger(LL_ERROR, "Unable to get FirmwarePreflightInfo\n");
+ return -1;
+ }
+ *preflight_info = node;
+ } else {
+ logger(LL_DEBUG, "Device does not have TelephonyCapability, no FirmwarePreflightInfo\n");
+ *preflight_info = NULL;
}
- plist_get_uint_val(unique_chip_node, ecid);
- plist_free(unique_chip_node);
return 0;
}
int normal_get_preflight_info(struct idevicerestore_client_t* client, plist_t *preflight_info)
{
- plist_t node = normal_get_lockdown_value(client, NULL, "FirmwarePreflightInfo");
- if (!node || plist_get_node_type(node) != PLIST_DICT) {
- error("ERROR: Unable to get FirmwarePreflightInfo\n");
- return -1;
+ plist_t node = normal_get_lockdown_value(client, NULL, "PreflightInfo");
+ if (PLIST_IS_DICT(node)) {
+ *preflight_info = node;
+ } else {
+ logger(LL_DEBUG, "No PreflightInfo available.\n");
+ *preflight_info = NULL;
}
- *preflight_info = node;
-
return 0;
}
@@ -401,20 +422,25 @@ int normal_handle_create_stashbag(struct idevicerestore_client_t* client, plist_
device_err = idevice_new(&device, client->udid);
if (device_err != IDEVICE_E_SUCCESS) {
- error("ERROR: Could not connect to device (%d)\n", device_err);
+ logger(LL_ERROR, "Could not connect to device (%d)\n", device_err);
return -1;
}
lerr = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore");
+ if (lerr == LOCKDOWN_E_PASSWORD_PROTECTED) {
+ logger(LL_ERROR, "Device is locked. Unlock device and try again.\n");
+ idevice_free(device);
+ return -1;
+ }
if (lerr != LOCKDOWN_E_SUCCESS) {
- error("ERROR: Could not connect to lockdownd (%d)\n", lerr);
+ logger(LL_ERROR, "Could not connect to lockdownd (%d)\n", lerr);
idevice_free(device);
return -1;
}
lerr = lockdownd_start_service(lockdown, PREBOARD_SERVICE_NAME, &service);
if (lerr == LOCKDOWN_E_PASSWORD_PROTECTED) {
- info("*** Device is locked. Please unlock the device to continue. ***\n");
+ show_banner("Device is locked. Please unlock the device to continue.\n");
while (1) {
lerr = lockdownd_start_service(lockdown, PREBOARD_SERVICE_NAME, &service);
if (lerr != LOCKDOWN_E_PASSWORD_PROTECTED) {
@@ -425,7 +451,7 @@ int normal_handle_create_stashbag(struct idevicerestore_client_t* client, plist_
}
if (lerr != LOCKDOWN_E_SUCCESS) {
- error("ERROR: Could not start preboard service (%d)\n", lerr);
+ logger(LL_ERROR, "Could not start preboard service (%d)\n", lerr);
lockdownd_client_free(lockdown);
idevice_free(device);
return -1;
@@ -435,14 +461,14 @@ int normal_handle_create_stashbag(struct idevicerestore_client_t* client, plist_
lockdownd_service_descriptor_free(service);
lockdownd_client_free(lockdown);
if (perr != PREBOARD_E_SUCCESS) {
- error("ERROR: Could not connect to preboard service (%d)\n", perr);
+ logger(LL_ERROR, "Could not connect to preboard service (%d)\n", perr);
idevice_free(device);
return -1;
}
perr = preboard_create_stashbag(preboard, manifest, NULL, NULL);
if (perr != PREBOARD_E_SUCCESS) {
- error("ERROR: Failed to trigger stashbag creation (%d)\n", perr);
+ logger(LL_ERROR, "Failed to trigger stashbag creation (%d)\n", perr);
preboard_client_free(preboard);
idevice_free(device);
return -1;
@@ -455,25 +481,25 @@ int normal_handle_create_stashbag(struct idevicerestore_client_t* client, plist_
if (perr == PREBOARD_E_TIMEOUT) {
continue;
} else if (perr != PREBOARD_E_SUCCESS) {
- error("ERROR: could not receive from preboard service\n");
+ logger(LL_ERROR, "could not receive from preboard service\n");
break;
} else {
plist_t node;
- if (_plist_dict_get_bool(pl, "Skip")) {
+ if (plist_dict_get_bool(pl, "Skip")) {
result = 0;
- info("Device does not require stashbag.\n");
+ logger(LL_INFO, "Device does not require stashbag.\n");
break;
}
- if (_plist_dict_get_bool(pl, "ShowDialog")) {
- info("Device requires stashbag.\n");
- printf("******************************************************************************\n"
- "* Please enter your passcode on the device. The device will store a token *\n"
- "* that will be used after restore to access the user data partition. This *\n"
- "* prevents an 'Attempting data recovery' process occurring after reboot that *\n"
- "* may take a long time to complete and will _also_ require the passcode. *\n"
- "******************************************************************************\n");
+ if (plist_dict_get_bool(pl, "ShowDialog")) {
+ logger(LL_INFO, "Device requires stashbag.\n");
+ show_banner(
+ "Please enter your passcode on the device. The device will store a token\n"
+ "that will be used after restore to access the user data partition. This\n"
+ "prevents an 'Attempting data recovery' process occurring after reboot that\n"
+ "may take a long time to complete and will _also_ require the passcode."
+ );
plist_free(pl);
continue;
}
@@ -484,27 +510,30 @@ int normal_handle_create_stashbag(struct idevicerestore_client_t* client, plist_
if (node) {
plist_get_string_val(node, &strval);
}
- error("ERROR: Could not create stashbag: %s\n", (strval) ? strval : "(Unknown error)");
+ logger(LL_ERROR, "Could not create stashbag: %s\n", (strval) ? strval : "(Unknown error)");
free(strval);
plist_free(pl);
break;
}
- if (_plist_dict_get_bool(pl, "Timeout")) {
- error("ERROR: Timeout while waiting for user to enter passcode.\n");
+ if (plist_dict_get_bool(pl, "Timeout")) {
+ logger(LL_ERROR, "Timeout while waiting for user to enter passcode.\n");
result = -2;
plist_free(pl);
break;
}
- if (_plist_dict_get_bool(pl, "HideDialog")) {
+ if (plist_dict_get_bool(pl, "HideDialog")) {
plist_free(pl);
/* hide dialog */
result = 1;
- info("Stashbag created.\n");
+ logger(LL_INFO, "Stashbag created.\n");
break;
}
}
plist_free(pl);
}
+
+ hide_banner();
+
preboard_client_free(preboard);
idevice_free(device);
@@ -526,20 +555,20 @@ int normal_handle_commit_stashbag(struct idevicerestore_client_t* client, plist_
device_err = idevice_new(&device, client->udid);
if (device_err != IDEVICE_E_SUCCESS) {
- error("ERROR: Could not connect to device (%d)\n", device_err);
+ logger(LL_ERROR, "Could not connect to device (%d)\n", device_err);
return -1;
}
lerr = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore");
if (lerr != LOCKDOWN_E_SUCCESS) {
- error("ERROR: Could not connect to lockdownd (%d)\n", lerr);
+ logger(LL_ERROR, "Could not connect to lockdownd (%d)\n", lerr);
idevice_free(device);
return -1;
}
lerr = lockdownd_start_service(lockdown, PREBOARD_SERVICE_NAME, &service);
if (lerr == LOCKDOWN_E_PASSWORD_PROTECTED) {
- info("*** Device is locked. Please unlock the device to continue. ***\n");
+ show_banner("Device is locked. Please unlock the device to continue.\n");
while (1) {
lerr = lockdownd_start_service(lockdown, PREBOARD_SERVICE_NAME, &service);
if (lerr != LOCKDOWN_E_PASSWORD_PROTECTED) {
@@ -547,10 +576,11 @@ int normal_handle_commit_stashbag(struct idevicerestore_client_t* client, plist_
}
sleep(1);
}
+ hide_banner();
}
if (lerr != LOCKDOWN_E_SUCCESS) {
- error("ERROR: Could not start preboard service (%d)\n", lerr);
+ logger(LL_ERROR, "Could not start preboard service (%d)\n", lerr);
lockdownd_client_free(lockdown);
idevice_free(device);
return -1;
@@ -560,14 +590,14 @@ int normal_handle_commit_stashbag(struct idevicerestore_client_t* client, plist_
lockdownd_service_descriptor_free(service);
lockdownd_client_free(lockdown);
if (perr != PREBOARD_E_SUCCESS) {
- error("ERROR: Could not connect to preboard service (%d)\n", perr);
+ logger(LL_ERROR, "Could not connect to preboard service (%d)\n", perr);
idevice_free(device);
return -1;
}
perr = preboard_commit_stashbag(preboard, manifest, NULL, NULL);
if (perr != PREBOARD_E_SUCCESS) {
- error("ERROR: Failed to trigger stashbag creation (%d)\n", perr);
+ logger(LL_ERROR, "Failed to trigger stashbag creation (%d)\n", perr);
preboard_client_free(preboard);
idevice_free(device);
return -1;
@@ -575,9 +605,8 @@ int normal_handle_commit_stashbag(struct idevicerestore_client_t* client, plist_
perr = preboard_receive_with_timeout(preboard, &pl, 30000);
if (perr != PREBOARD_E_SUCCESS) {
- error("ERROR: could not receive from preboard service (%d)\n", perr);
+ logger(LL_ERROR, "could not receive from preboard service (%d)\n", perr);
} else {
- int commit_complete = 0;
plist_t node = plist_dict_get_item(pl, "Error");
if (node) {
char *strval = NULL;
@@ -585,14 +614,14 @@ int normal_handle_commit_stashbag(struct idevicerestore_client_t* client, plist_
if (node) {
plist_get_string_val(node, &strval);
}
- error("ERROR: Could not commit stashbag: %s\n", (strval) ? strval : "(Unknown error)");
+ logger(LL_ERROR, "Could not commit stashbag: %s\n", (strval) ? strval : "(Unknown error)");
free(strval);
- } else if (_plist_dict_get_bool(pl, "StashbagCommitComplete")) {
- info("Stashbag committed!\n");
+ } else if (plist_dict_get_bool(pl, "StashbagCommitComplete")) {
+ logger(LL_INFO, "Stashbag committed!\n");
result = 0;
} else {
- error("ERROR: Unexpected reply from preboard service\n");
- debug_plist(pl);
+ logger(LL_ERROR, "Unexpected reply from preboard service\n");
+ logger_dump_plist(LL_VERBOSE, pl, 1);
}
plist_free(pl);
}
diff --git a/src/normal.h b/src/normal.h
index f438f9b..d3d7b0c 100644
--- a/src/normal.h
+++ b/src/normal.h
@@ -35,10 +35,10 @@ extern "C" {
int normal_check_mode(struct idevicerestore_client_t* client);
irecv_device_t normal_get_irecv_device(struct idevicerestore_client_t* client);
int normal_enter_recovery(struct idevicerestore_client_t* client);
-int normal_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid);
int normal_is_image4_supported(struct idevicerestore_client_t* client);
-int normal_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size);
-int normal_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size);
+int normal_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size);
+int normal_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size);
+int normal_get_firmware_preflight_info(struct idevicerestore_client_t* client, plist_t *preflight_info);
int normal_get_preflight_info(struct idevicerestore_client_t* client, plist_t *preflight_info);
plist_t normal_get_lockdown_value(struct idevicerestore_client_t* client, const char* domain, const char* key);
int normal_handle_create_stashbag(struct idevicerestore_client_t* client, plist_t manifest);
diff --git a/src/recovery.c b/src/recovery.c
index b6a6f51..b843f1e 100644
--- a/src/recovery.c
+++ b/src/recovery.c
@@ -29,8 +29,9 @@
#include <libimobiledevice/restore.h>
#include <libimobiledevice/libimobiledevice.h>
+#include <libtatsu/tss.h>
+
#include "idevicerestore.h"
-#include "tss.h"
#include "img3.h"
#include "restore.h"
#include "recovery.h"
@@ -38,14 +39,15 @@
static int recovery_progress_callback(irecv_client_t client, const irecv_event_t* event)
{
if (event->type == IRECV_PROGRESS) {
- //print_progress_bar(event->progress);
+ set_progress('RECV', (double)(event->progress/100.0));
}
return 0;
}
void recovery_client_free(struct idevicerestore_client_t* client)
{
- if(client) {
+ if (client) {
+ finalize_progress('RECV');
if (client->recovery) {
if(client->recovery->client) {
irecv_close(client->recovery->client);
@@ -67,7 +69,7 @@ int recovery_client_new(struct idevicerestore_client_t* client)
if(client->recovery == NULL) {
client->recovery = (struct recovery_client_t*)malloc(sizeof(struct recovery_client_t));
if (client->recovery == NULL) {
- error("ERROR: Out of memory\n");
+ logger(LL_ERROR, "Out of memory\n");
return -1;
}
memset(client->recovery, 0, sizeof(struct recovery_client_t));
@@ -80,19 +82,19 @@ int recovery_client_new(struct idevicerestore_client_t* client)
}
if (i >= attempts) {
- error("ERROR: Unable to connect to device in recovery mode\n");
+ logger(LL_ERROR, "Unable to connect to device in recovery mode\n");
return -1;
}
sleep(4);
- debug("Retrying connection...\n");
+ logger(LL_DEBUG, "Retrying connection...\n");
}
if (client->srnm == NULL) {
const struct irecv_device_info *device_info = irecv_get_device_info(recovery);
if (device_info && device_info->srnm) {
client->srnm = strdup(device_info->srnm);
- info("INFO: device serial number is %s\n", client->srnm);
+ logger(LL_INFO, "INFO: device serial number is %s\n", client->srnm);
}
}
@@ -107,13 +109,13 @@ int recovery_set_autoboot(struct idevicerestore_client_t* client, int enable)
recovery_error = irecv_send_command(client->recovery->client, (enable) ? "setenv auto-boot true" : "setenv auto-boot false");
if (recovery_error != IRECV_E_SUCCESS) {
- error("ERROR: Unable to set auto-boot environmental variable\n");
+ logger(LL_ERROR, "Unable to set auto-boot environmental variable\n");
return -1;
}
recovery_error = irecv_send_command(client->recovery->client, "saveenv");
if (recovery_error != IRECV_E_SUCCESS) {
- error("ERROR: Unable to save environmental variable\n");
+ logger(LL_ERROR, "Unable to save environmental variable\n");
return -1;
}
@@ -122,11 +124,11 @@ int recovery_set_autoboot(struct idevicerestore_client_t* client, int enable)
int recovery_enter_restore(struct idevicerestore_client_t* client, plist_t build_identity)
{
- if (client->build_major >= 8) {
- client->restore_boot_args = strdup("rd=md0 nand-enable-reformat=1 -progress");
- } else if (client->build_major >= 20) {
- client->restore_boot_args = strdup("rd=md0 nand-enable-reformat=1 -progress -restore");
- }
+ if (client->macos_variant) {
+ client->restore_boot_args = strdup("rd=md0 nand-enable-reformat=1 -progress -restore");
+ } else if (client->build_major >= 8) {
+ client->restore_boot_args = strdup("rd=md0 nand-enable-reformat=1 -progress");
+ }
/* upload data to make device boot restore mode */
@@ -140,36 +142,50 @@ int recovery_enter_restore(struct idevicerestore_client_t* client, plist_t build
if (!client->image4supported) {
/* send ApTicket */
if (recovery_send_ticket(client) < 0) {
- error("ERROR: Unable to send APTicket\n");
+ logger(LL_ERROR, "Unable to send APTicket\n");
return -1;
}
}
}
- info("Recovery Mode Environment:\n");
+ logger(LL_INFO, "Recovery Mode Environment:\n");
char* value = NULL;
irecv_getenv(client->recovery->client, "build-version", &value);
- info("iBoot build-version=%s\n", (value) ? value : "(unknown)");
+ logger(LL_INFO, "iBoot build-version=%s\n", (value) ? value : "(unknown)");
free(value);
value = NULL;
irecv_getenv(client->recovery->client, "build-style", &value);
- info("iBoot build-style=%s\n", (value) ? value : "(unknown)");
+ logger(LL_INFO, "iBoot build-style=%s\n", (value) ? value : "(unknown)");
free(value);
value = NULL;
+ unsigned long boot_stage = 0;
+ irecv_getenv(client->recovery->client, "boot-stage", &value);
+ if (value) {
+ boot_stage = strtoul(value, NULL, 0);
+ }
+ if (boot_stage > 0) {
+ logger(LL_INFO, "iBoot boot-stage=%s\n", value);
+ free(value);
+ value = NULL;
+ if (boot_stage != 2) {
+ logger(LL_ERROR, "iBoot should be at boot stage 2, continuing anyway...\n");
+ }
+ }
+
unsigned long radio_error = 0;
irecv_getenv(client->recovery->client, "radio-error", &value);
if (value) {
radio_error = strtoul(value, NULL, 0);
}
if (radio_error > 0) {
- info("radio-error=%s\n", value);
+ logger(LL_INFO, "radio-error=%s\n", value);
free(value);
value = NULL;
irecv_getenv(client->recovery->client, "radio-error-string", &value);
if (value) {
- info("radio-error-string=%s\n", value);
+ logger(LL_INFO, "radio-error-string=%s\n", value);
free(value);
value = NULL;
}
@@ -181,32 +197,32 @@ int recovery_enter_restore(struct idevicerestore_client_t* client, plist_t build
/* send logo and show it */
if (recovery_send_applelogo(client, build_identity) < 0) {
- error("ERROR: Unable to send AppleLogo\n");
+ logger(LL_ERROR, "Unable to send AppleLogo\n");
return -1;
}
/* send components loaded by iBoot */
if (recovery_send_loaded_by_iboot(client, build_identity) < 0) {
- error("ERROR: Unable to send components supposed to be loaded by iBoot\n");
+ logger(LL_ERROR, "Unable to send components supposed to be loaded by iBoot\n");
return -1;
}
/* send ramdisk and run it */
if (recovery_send_ramdisk(client, build_identity) < 0) {
- error("ERROR: Unable to send Ramdisk\n");
+ logger(LL_ERROR, "Unable to send Ramdisk\n");
return -1;
}
/* send devicetree and load it */
if (recovery_send_component_and_command(client, build_identity, "RestoreDeviceTree", "devicetree") < 0) {
- error("ERROR: Unable to send DeviceTree\n");
+ logger(LL_ERROR, "Unable to send DeviceTree\n");
return -1;
}
if (build_identity_has_component(build_identity, "RestoreSEP")) {
/* send rsepfirmware and load it */
if (recovery_send_component_and_command(client, build_identity, "RestoreSEP", "rsepfirmware") < 0) {
- error("ERROR: Unable to send RestoreSEP\n");
+ logger(LL_ERROR, "Unable to send RestoreSEP\n");
return -1;
}
}
@@ -214,15 +230,15 @@ int recovery_enter_restore(struct idevicerestore_client_t* client, plist_t build
mutex_lock(&client->device_event_mutex);
if (recovery_send_kernelcache(client, build_identity) < 0) {
mutex_unlock(&client->device_event_mutex);
- error("ERROR: Unable to send KernelCache\n");
+ logger(LL_ERROR, "Unable to send KernelCache\n");
return -1;
}
- debug("DEBUG: Waiting for device to disconnect...\n");
+ logger(LL_DEBUG, "Waiting for device to disconnect...\n");
cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 30000);
if (client->mode == MODE_RECOVERY || (client->flags & FLAG_QUIT)) {
mutex_unlock(&client->device_event_mutex);
- error("ERROR: Failed to place device in restore mode\n");
+ logger(LL_ERROR, "Failed to place device in restore mode\n");
return -1;
}
mutex_unlock(&client->device_event_mutex);
@@ -233,28 +249,28 @@ int recovery_enter_restore(struct idevicerestore_client_t* client, plist_t build
int recovery_send_ticket(struct idevicerestore_client_t* client)
{
if (!client->tss) {
- error("ERROR: ApTicket requested but no TSS present\n");
+ logger(LL_ERROR, "ApTicket requested but no TSS present\n");
return -1;
}
unsigned char* data = NULL;
uint32_t size = 0;
if (tss_response_get_ap_ticket(client->tss, &data, &size) < 0) {
- error("ERROR: Unable to get ApTicket from TSS request\n");
+ logger(LL_ERROR, "Unable to get ApTicket from TSS request\n");
return -1;
}
- info("Sending APTicket (%d bytes)\n", size);
+ logger(LL_INFO, "Sending APTicket (%d bytes)\n", size);
irecv_error_t err = irecv_send_buffer(client->recovery->client, data, size, 0);
free(data);
if (err != IRECV_E_SUCCESS) {
- error("ERROR: Unable to send APTicket: %s\n", irecv_strerror(err));
+ logger(LL_ERROR, "Unable to send APTicket: %s\n", irecv_strerror(err));
return -1;
}
err = irecv_send_command(client->recovery->client, "ticket");
if (err != IRECV_E_SUCCESS) {
- error("ERROR: Unable to send ticket command\n");
+ logger(LL_ERROR, "Unable to send ticket command\n");
return -1;
}
@@ -263,47 +279,49 @@ int recovery_send_ticket(struct idevicerestore_client_t* client)
int recovery_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component)
{
- unsigned int size = 0;
- unsigned char* data = NULL;
+ size_t size = 0;
+ void* data = NULL;
char* path = NULL;
irecv_error_t err = 0;
if (client->tss) {
if (tss_response_get_path_by_entry(client->tss, component, &path) < 0) {
- debug("NOTE: No path for component %s in TSS, will fetch from build_identity\n", component);
+ logger(LL_DEBUG, "No path for component %s in TSS, will fetch from build_identity\n", component);
}
}
if (!path) {
if (build_identity_get_component_path(build_identity, component, &path) < 0) {
- error("ERROR: Unable to get path for component '%s'\n", component);
+ logger(LL_ERROR, "Unable to get path for component '%s'\n", component);
free(path);
return -1;
}
}
- unsigned char* component_data = NULL;
- unsigned int component_size = 0;
+ void* component_data = NULL;
+ size_t component_size = 0;
int ret = extract_component(client->ipsw, path, &component_data, &component_size);
free(path);
if (ret < 0) {
- error("ERROR: Unable to extract component: %s\n", component);
+ logger(LL_ERROR, "Unable to extract component: %s\n", component);
return -1;
}
- ret = personalize_component(component, component_data, component_size, client->tss, &data, &size);
+ ret = personalize_component(client, component, component_data, component_size, client->tss, &data, &size);
free(component_data);
if (ret < 0) {
- error("ERROR: Unable to get personalized component: %s\n", component);
+ logger(LL_ERROR, "Unable to get personalized component: %s\n", component);
return -1;
}
- info("Sending %s (%d bytes)...\n", component, size);
+ logger(LL_INFO, "Sending %s (%zu bytes)...\n", component, size);
// FIXME: Did I do this right????
+ register_progress('RECV', "Uploading");
err = irecv_send_buffer(client->recovery->client, data, size, 0);
free(data);
+ finalize_progress('RECV');
if (err != IRECV_E_SUCCESS) {
- error("ERROR: Unable to send %s component: %s\n", component, irecv_strerror(err));
+ logger(LL_ERROR, "Unable to send %s component: %s\n", component, irecv_strerror(err));
return -1;
}
@@ -315,13 +333,13 @@ int recovery_send_component_and_command(struct idevicerestore_client_t* client,
irecv_error_t recovery_error = IRECV_E_SUCCESS;
if (recovery_send_component(client, build_identity, component) < 0) {
- error("ERROR: Unable to send %s to device.\n", component);
+ logger(LL_ERROR, "Unable to send %s to device.\n", component);
return -1;
}
recovery_error = irecv_send_command(client->recovery->client, command);
if (recovery_error != IRECV_E_SUCCESS) {
- error("ERROR: Unable to execute %s\n", component);
+ logger(LL_ERROR, "Unable to execute %s\n", component);
return -1;
}
@@ -340,13 +358,13 @@ int recovery_send_ibec(struct idevicerestore_client_t* client, plist_t build_ide
}
if (recovery_send_component(client, build_identity, component) < 0) {
- error("ERROR: Unable to send %s to device.\n", component);
+ logger(LL_ERROR, "Unable to send %s to device.\n", component);
return -1;
}
- recovery_error = irecv_send_command(client->recovery->client, "go");
+ recovery_error = irecv_send_command_breq(client->recovery->client, "go", 1);
if (recovery_error != IRECV_E_SUCCESS) {
- error("ERROR: Unable to execute %s\n", component);
+ logger(LL_ERROR, "Unable to execute %s\n", component);
return -1;
}
irecv_usb_control_transfer(client->recovery->client, 0x21, 1, 0, 0, 0, 0, 5000);
@@ -363,7 +381,7 @@ int recovery_send_applelogo(struct idevicerestore_client_t* client, plist_t buil
return 0;
}
- info("Sending %s...\n", component);
+ logger(LL_INFO, "Sending %s...\n", component);
if (client->recovery == NULL) {
if (recovery_client_new(client) < 0) {
return -1;
@@ -371,19 +389,19 @@ int recovery_send_applelogo(struct idevicerestore_client_t* client, plist_t buil
}
if (recovery_send_component(client, build_identity, component) < 0) {
- error("ERROR: Unable to send %s to device.\n", component);
+ logger(LL_ERROR, "Unable to send %s to device.\n", component);
return -1;
}
recovery_error = irecv_send_command(client->recovery->client, "setpicture 4");
if (recovery_error != IRECV_E_SUCCESS) {
- error("ERROR: Unable to set %s\n", component);
+ logger(LL_ERROR, "Unable to set %s\n", component);
return -1;
}
recovery_error = irecv_send_command(client->recovery->client, "bgcolor 0 0 0");
if (recovery_error != IRECV_E_SUCCESS) {
- error("ERROR: Unable to display %s\n", component);
+ logger(LL_ERROR, "Unable to display %s\n", component);
return -1;
}
@@ -400,7 +418,7 @@ int recovery_send_loaded_by_iboot(struct idevicerestore_client_t* client, plist_
plist_t manifest_node = plist_dict_get_item(build_identity, "Manifest");
if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) {
- error("ERROR: Unable to find manifest node\n");
+ logger(LL_ERROR, "Unable to find manifest node\n");
return -1;
}
@@ -424,9 +442,9 @@ int recovery_send_loaded_by_iboot(struct idevicerestore_client_t* client, plist_
uint8_t b = 0;
plist_get_bool_val(iboot_node, &b);
if (b) {
- debug("DEBUG: %s is loaded by iBoot.\n", key);
+ logger(LL_DEBUG, "%s is loaded by iBoot.\n", key);
if (recovery_send_component_and_command(client, build_identity, key, "firmware") < 0) {
- error("ERROR: Unable to send component '%s' to device.\n", key);
+ logger(LL_ERROR, "Unable to send component '%s' to device.\n", key);
err++;
}
}
@@ -451,12 +469,12 @@ int recovery_send_ramdisk(struct idevicerestore_client_t* client, plist_t build_
char* value = NULL;
irecv_getenv(client->recovery->client, "ramdisk-size", &value);
- info("ramdisk-size=%s\n", (value ? value : "(unknown)"));
+ logger(LL_INFO, "ramdisk-size=%s\n", (value ? value : "(unknown)"));
free(value);
value = NULL;
if (recovery_send_component(client, build_identity, component) < 0) {
- error("ERROR: Unable to send %s to device.\n", component);
+ logger(LL_ERROR, "Unable to send %s to device.\n", component);
return -1;
}
@@ -464,7 +482,7 @@ int recovery_send_ramdisk(struct idevicerestore_client_t* client, plist_t build_
recovery_error = irecv_send_command(client->recovery->client, "ramdisk");
if (recovery_error != IRECV_E_SUCCESS) {
- error("ERROR: Unable to execute %s\n", component);
+ logger(LL_ERROR, "Unable to execute %s\n", component);
return -1;
}
@@ -485,7 +503,7 @@ int recovery_send_kernelcache(struct idevicerestore_client_t* client, plist_t bu
}
if (recovery_send_component(client, build_identity, component) < 0) {
- error("ERROR: Unable to send %s to device.\n", component);
+ logger(LL_ERROR, "Unable to send %s to device.\n", component);
return -1;
}
@@ -498,30 +516,12 @@ int recovery_send_kernelcache(struct idevicerestore_client_t* client, plist_t bu
recovery_error = irecv_send_command(client->recovery->client, setba);
}
- recovery_error = irecv_send_command(client->recovery->client, "bootx");
+ recovery_error = irecv_send_command_breq(client->recovery->client, "bootx", 1);
if (recovery_error != IRECV_E_SUCCESS) {
- error("ERROR: Unable to execute %s\n", component);
- return -1;
- }
-
- return 0;
-}
-
-int recovery_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid)
-{
- if(client->recovery == NULL) {
- if (recovery_client_new(client) < 0) {
- return -1;
- }
- }
-
- const struct irecv_device_info *device_info = irecv_get_device_info(client->recovery->client);
- if (!device_info) {
+ logger(LL_ERROR, "Unable to execute %s\n", component);
return -1;
}
- *ecid = device_info->ecid;
-
return 0;
}
@@ -541,7 +541,7 @@ int recovery_is_image4_supported(struct idevicerestore_client_t* client)
return (device_info->ibfl & IBOOT_FLAG_IMAGE4_AWARE);
}
-int recovery_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size)
+int recovery_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size)
{
if(client->recovery == NULL) {
if (recovery_client_new(client) < 0) {
@@ -566,7 +566,7 @@ int recovery_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char*
return 0;
}
-int recovery_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size)
+int recovery_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size)
{
if(client->recovery == NULL) {
if (recovery_client_new(client) < 0) {
@@ -593,7 +593,7 @@ int recovery_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char
int recovery_send_reset(struct idevicerestore_client_t* client)
{
- irecv_send_command(client->recovery->client, "reset");
+ irecv_send_command_breq(client->recovery->client, "reset", 1);
return 0;
}
diff --git a/src/recovery.h b/src/recovery.h
index 154d7d1..d7413e0 100644
--- a/src/recovery.h
+++ b/src/recovery.h
@@ -54,10 +54,9 @@ int recovery_send_loaded_by_iboot(struct idevicerestore_client_t* client, plist_
int recovery_send_reset(struct idevicerestore_client_t* client);
int recovery_send_ticket(struct idevicerestore_client_t* client);
int recovery_set_autoboot(struct idevicerestore_client_t* client, int enable);
-int recovery_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid);
int recovery_is_image4_supported(struct idevicerestore_client_t* client);
-int recovery_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size);
-int recovery_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size);
+int recovery_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size);
+int recovery_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size);
#ifdef __cplusplus
diff --git a/src/restore.c b/src/restore.c
index 7b61766..12f837c 100644
--- a/src/restore.c
+++ b/src/restore.c
@@ -29,7 +29,11 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <libgen.h>
+#include <math.h>
#include <libimobiledevice/restore.h>
+#include <libimobiledevice/property_list_service.h>
+#include <libimobiledevice-glue/thread.h>
#ifdef HAVE_REVERSE_PROXY
#include <libimobiledevice/reverse_proxy.h>
#else
@@ -37,6 +41,8 @@
#endif
#include <zip.h>
#include <libirecovery.h>
+#include <libtatsu/tss.h>
+#include <curl/curl.h>
#include "idevicerestore.h"
#include "asr.h"
@@ -44,7 +50,6 @@
#include "fls.h"
#include "mbn.h"
#include "ftab.h"
-#include "tss.h"
#include "ipsw.h"
#include "restore.h"
#include "common.h"
@@ -122,7 +127,7 @@ int restore_client_new(struct idevicerestore_client_t* client)
{
struct restore_client_t* restore = (struct restore_client_t*) malloc(sizeof(struct restore_client_t));
if (restore == NULL) {
- error("ERROR: Out of memory\n");
+ logger(LL_ERROR, "Out of memory\n");
return -1;
}
@@ -179,12 +184,12 @@ static int restore_idevice_new(struct idevicerestore_client_t* client, idevice_t
}
device_error = idevice_new(&dev, devices[j]);
if (device_error != IDEVICE_E_SUCCESS) {
- debug("%s: can't open device with UDID %s\n", __func__, devices[j]);
+ logger(LL_DEBUG, "%s: can't open device with UDID %s\n", __func__, devices[j]);
continue;
}
if (restored_client_new(dev, &restore, "idevicerestore") != RESTORE_E_SUCCESS) {
- debug("%s: can't connect to restored on device with UDID %s\n", __func__, devices[j]);
+ logger(LL_DEBUG, "%s: can't connect to restored on device with UDID %s\n", __func__, devices[j]);
continue;
}
@@ -278,25 +283,19 @@ irecv_device_t restore_get_irecv_device(struct idevicerestore_client_t* client)
}
if (client->srnm == NULL) {
- restore_error = restored_get_value(restore, "SerialNumber", &node);
- if (restore_error != RESTORE_E_SUCCESS || !node || plist_get_node_type(node) != PLIST_STRING) {
- error("ERROR: Unable to get SerialNumber from restored\n");
- restored_client_free(restore);
- idevice_free(device);
- return NULL;
+ if (restored_get_value(restore, "SerialNumber", &node) == RESTORE_E_SUCCESS) {
+ plist_get_string_val(node, &client->srnm);
+ logger(LL_INFO, "INFO: device serial number is %s\n", client->srnm);
+ plist_free(node);
+ node = NULL;
}
-
- plist_get_string_val(node, &client->srnm);
- info("INFO: device serial number is %s\n", client->srnm);
- plist_free(node);
- node = NULL;
}
restore_error = restored_get_value(restore, "HardwareModel", &node);
restored_client_free(restore);
idevice_free(device);
if (restore_error != RESTORE_E_SUCCESS || !node || plist_get_node_type(node) != PLIST_STRING) {
- error("ERROR: Unable to get HardwareModel from restored\n");
+ logger(LL_ERROR, "Unable to get HardwareModel from restored\n");
plist_free(node);
return NULL;
}
@@ -317,7 +316,7 @@ int restore_is_image4_supported(struct idevicerestore_client_t* client)
restored_error_t restore_error = RESTORE_E_SUCCESS;
if (idevice_new(&device, client->udid) != IDEVICE_E_SUCCESS) {
- error("ERROR: Could not connect to device %s\n", client->udid);
+ logger(LL_ERROR, "Could not connect to device %s\n", client->udid);
return -1;
}
@@ -352,14 +351,14 @@ int restore_reboot(struct idevicerestore_client_t* client)
{
if(client->restore == NULL) {
if (restore_open_with_timeout(client) < 0) {
- error("ERROR: Unable to open device in restore mode\n");
+ logger(LL_ERROR, "Unable to open device in restore mode\n");
return -1;
}
}
mutex_lock(&client->device_event_mutex);
- info("Rebooting restore mode device...\n");
+ logger(LL_INFO, "Rebooting restore mode device...\n");
restored_reboot(client->restore->client);
restored_client_free(client->restore->client);
@@ -379,8 +378,8 @@ static int restore_is_current_device(struct idevicerestore_client_t* client, con
if (!client) {
return 0;
}
- if (!client->srnm) {
- error("ERROR: %s: no SerialNumber given in client data\n", __func__);
+ if (!client->ecid) {
+ logger(LL_ERROR, "%s: no ECID given in client data\n", __func__);
return 0;
}
@@ -393,55 +392,55 @@ static int restore_is_current_device(struct idevicerestore_client_t* client, con
device_error = idevice_new(&device, udid);
if (device_error != IDEVICE_E_SUCCESS) {
- debug("%s: can't open device with UDID %s\n", __func__, udid);
+ logger(LL_DEBUG, "%s: can't open device with UDID %s\n", __func__, udid);
return 0;
}
restore_error = restored_client_new(device, &restored, "idevicerestore");
if (restore_error != RESTORE_E_SUCCESS) {
- debug("%s: can't connect to restored\n", __func__);
+ logger(LL_DEBUG, "%s: can't connect to restored\n", __func__);
idevice_free(device);
return 0;
}
restore_error = restored_query_type(restored, &type, &version);
if ((restore_error == RESTORE_E_SUCCESS) && type && (strcmp(type, "com.apple.mobile.restored") == 0)) {
- debug("%s: Connected to %s, version %d\n", __func__, type, (int)version);
+ logger(LL_DEBUG, "%s: Connected to %s, version %d\n", __func__, type, (int)version);
} else {
- debug("%s: device %s is not in restore mode\n", __func__, udid);
+ logger(LL_DEBUG, "%s: device %s is not in restore mode\n", __func__, udid);
restored_client_free(restored);
idevice_free(device);
return 0;
}
- plist_t node = NULL;
- restore_error = restored_get_value(restored, "SerialNumber", &node);
- if ((restore_error != RESTORE_E_SUCCESS) || !node || (plist_get_node_type(node) != PLIST_STRING)) {
- error("ERROR: %s: Unable to get SerialNumber from restored\n", __func__);
+ plist_t hwinfo = NULL;
+ restore_error = restored_query_value(restored, "HardwareInfo", &hwinfo);
+ if ((restore_error != RESTORE_E_SUCCESS) || !hwinfo) {
+ logger(LL_ERROR, "%s: Unable to get HardwareInfo from restored\n", __func__);
restored_client_free(restored);
idevice_free(device);
- if (node) {
- plist_free(node);
- }
+ plist_free(hwinfo);
return 0;
}
restored_client_free(restored);
idevice_free(device);
- char* this_srnm = NULL;
- plist_get_string_val(node, &this_srnm);
- plist_free(node);
+ uint64_t this_ecid = 0;
+ plist_t node = plist_dict_get_item(hwinfo, "UniqueChipID");
+ if (node && plist_get_node_type(node) == PLIST_UINT) {
+ plist_get_uint_val(node, &this_ecid);
+ }
+ plist_free(hwinfo);
- if (!this_srnm) {
+ if (this_ecid == 0) {
+ logger(LL_ERROR, "%s: Unable to get ECID from restored\n", __func__);
return 0;
}
- return (strcasecmp(this_srnm, client->srnm) == 0);
+ return (this_ecid == client->ecid);
}
int restore_open_with_timeout(struct idevicerestore_client_t* client)
{
- int i = 0;
- int attempts = 180;
char *type = NULL;
uint64_t version = 0;
idevice_t device = NULL;
@@ -450,20 +449,20 @@ int restore_open_with_timeout(struct idevicerestore_client_t* client)
restored_error_t restore_error = RESTORE_E_SUCCESS;
// no context exists so bail
- if(client == NULL) {
+ if (client == NULL) {
return -1;
}
- if(client->srnm == NULL) {
- error("ERROR: no SerialNumber in client data!\n");
+ if (client->ecid == 0) {
+ logger(LL_ERROR, "no ECID in client data!\n");
return -1;
}
// create our restore client if it doesn't yet exist
- if(client->restore == NULL) {
+ if (client->restore == NULL) {
client->restore = (struct restore_client_t*) malloc(sizeof(struct restore_client_t));
if(client->restore == NULL) {
- error("ERROR: Out of memory\n");
+ logger(LL_ERROR, "Out of memory\n");
return -1;
}
memset(client->restore, '\0', sizeof(struct restore_client_t));
@@ -472,11 +471,11 @@ int restore_open_with_timeout(struct idevicerestore_client_t* client)
restore_device_connected = 0;
if (!restore_is_current_device(client, client->udid)) {
- error("ERROR: Unable to connect to device in restore mode\n");
+ logger(LL_ERROR, "Unable to connect to device in restore mode\n");
return -1;
}
- info("Connecting now...\n");
+ logger(LL_INFO, "Connecting now...\n");
device_error = idevice_new(&device, client->udid);
if (device_error != IDEVICE_E_SUCCESS) {
return -1;
@@ -491,9 +490,9 @@ int restore_open_with_timeout(struct idevicerestore_client_t* client)
restore_error = restored_query_type(restored, &type, &version);
if ((restore_error == RESTORE_E_SUCCESS) && type && (strcmp(type, "com.apple.mobile.restored") == 0)) {
client->restore->protocol_version = version;
- info("Connected to %s, version %d\n", type, (int)version);
+ logger(LL_INFO, "Connected to %s, version %d\n", type, (int)version);
} else {
- error("ERROR: Unable to connect to restored, error=%d\n", restore_error);
+ logger(LL_ERROR, "Unable to connect to restored, error=%d\n", restore_error);
restored_client_free(restored);
idevice_free(device);
return -1;
@@ -638,6 +637,107 @@ const char* restore_progress_string(unsigned int operation)
}
}
+struct restored_service_client {
+
+};
+
+#define SERVICE_TYPE_RESTORED 1
+#define SERVICE_TYPE_PLIST 2
+
+typedef struct restore_service_client {
+ void* client;
+ int type;
+} *restore_service_client_t;
+
+static void* _restore_get_service_client_for_data_request(struct idevicerestore_client_t *client, plist_t message)
+{
+ if (!client || !client->restore || !client->restore->client) return NULL;
+ restore_service_client_t service = (restore_service_client_t)malloc(sizeof(struct restore_service_client));
+ if (!PLIST_IS_DICT(message) || !plist_dict_get_item(message, "DataPort")) {
+ service->client = client->restore->client;
+ service->type = SERVICE_TYPE_RESTORED;
+ return service;
+ }
+ plist_t data_type = plist_dict_get_item(message, "DataType");
+ uint16_t data_port = plist_dict_get_uint(message, "DataPort");
+ const char* data_type_str = plist_get_string_ptr(data_type, NULL);
+
+ struct lockdownd_service_descriptor svcdesc = {
+ data_port,
+ 0,
+ (char*)data_type_str
+ };
+ property_list_service_client_t plclient = NULL;
+ logger(LL_INFO, "Connecting to %s data port %u\n", data_type_str, data_port);
+ if (property_list_service_client_new(client->restore->device, &svcdesc, &plclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
+ logger(LL_ERROR, "Failed to start service connection for %s on port %u\n", data_type_str, data_port);
+ free(service);
+ return NULL;
+ }
+ service->client = plclient;
+ service->type = SERVICE_TYPE_PLIST;
+
+ return service;
+}
+
+static int _restore_service_send(restore_service_client_t service, plist_t plist, plist_format_t fmt)
+{
+ if (!service) {
+ return -1;
+ }
+ switch (service->type) {
+ case SERVICE_TYPE_RESTORED:
+ return restored_send((restored_client_t)service->client, plist);
+ case SERVICE_TYPE_PLIST:
+ if (fmt == PLIST_FORMAT_BINARY) {
+ return property_list_service_send_binary_plist((property_list_service_client_t)service->client, plist);
+ }
+ return property_list_service_send_xml_plist((property_list_service_client_t)service->client, plist);
+ default:
+ break;
+ }
+ return -1;
+}
+
+static int _restore_service_recv_timeout(restore_service_client_t service, plist_t *plist, unsigned int timeout)
+{
+ struct restored_client_private {
+ property_list_service_client_t parent;
+ char *udid;
+ char *label;
+ plist_t info;
+ };
+ if (!service) {
+ return -1;
+ }
+ switch (service->type) {
+ case SERVICE_TYPE_RESTORED:
+ return property_list_service_receive_plist_with_timeout(((struct restored_client_private*)service->client)->parent, plist, timeout);
+ case SERVICE_TYPE_PLIST:
+ return property_list_service_receive_plist_with_timeout((property_list_service_client_t)service->client, plist, timeout);
+ default:
+ break;
+ }
+ return -1;
+}
+
+static void _restore_service_free(restore_service_client_t service)
+{
+ if (!service) {
+ return;
+ }
+ switch (service->type) {
+ case SERVICE_TYPE_RESTORED:
+ break;
+ case SERVICE_TYPE_PLIST:
+ property_list_service_client_free((property_list_service_client_t)service->client);
+ break;
+ default:
+ break;
+ }
+ free(service);
+}
+
static int lastop = 0;
static int restore_handle_previous_restore_log_msg(restored_client_t client, plist_t msg)
@@ -647,12 +747,12 @@ static int restore_handle_previous_restore_log_msg(restored_client_t client, pli
node = plist_dict_get_item(msg, "PreviousRestoreLog");
if (!node || plist_get_node_type(node) != PLIST_STRING) {
- debug("Failed to parse restore log from PreviousRestoreLog plist\n");
+ logger(LL_DEBUG, "Failed to parse restore log from PreviousRestoreLog plist\n");
return -1;
}
plist_get_string_val(node, &restorelog);
- info("Previous Restore Log Received:\n%s\n", restorelog);
+ logger(LL_VERBOSE, "Previous Restore Log Received:\n%s\n", restorelog);
free(restorelog);
return 0;
@@ -666,14 +766,14 @@ int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t
node = plist_dict_get_item(msg, "Operation");
if (!node || plist_get_node_type(node) != PLIST_UINT) {
- debug("Failed to parse operation from ProgressMsg plist\n");
+ logger(LL_DEBUG, "Failed to parse operation from ProgressMsg plist\n");
return -1;
}
plist_get_uint_val(node, &operation);
node = plist_dict_get_item(msg, "Progress");
if (!node || plist_get_node_type(node) != PLIST_UINT) {
- debug("Failed to parse progress from ProgressMsg plist \n");
+ logger(LL_DEBUG, "Failed to parse progress from ProgressMsg plist \n");
return -1;
}
plist_get_uint_val(node, &progress);
@@ -688,9 +788,12 @@ int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t
if ((progress > 0) && (progress <= 100)) {
if ((int)operation != lastop) {
- info("%s (%d)\n", restore_progress_string(adapted_operation), (int)operation);
+ logger(LL_INFO, "%s (%d)\n", restore_progress_string(adapted_operation), (int)operation);
}
switch (adapted_operation) {
+ case RESTORE_IMAGE:
+ idevicerestore_progress(client, RESTORE_STEP_UPLOAD_FS, progress / 100.0);
+ break;
case VERIFY_RESTORE:
idevicerestore_progress(client, RESTORE_STEP_VERIFY_FS, progress / 100.0);
break;
@@ -709,23 +812,23 @@ int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t
case REQUESTING_EAN_DATA:
break;
default:
- debug("Unhandled progress operation %d (%d)\n", adapted_operation, (int)operation);
+ logger(LL_DEBUG, "Unhandled progress operation %d (%d)\n", adapted_operation, (int)operation);
break;
}
} else {
- info("%s (%d)\n", restore_progress_string(adapted_operation), (int)operation);
+ logger(LL_INFO, "%s (%d)\n", restore_progress_string(adapted_operation), (int)operation);
}
lastop = (int)operation;
return 0;
}
-int restore_handle_status_msg(restored_client_t client, plist_t msg)
+int restore_handle_status_msg(struct idevicerestore_client_t* client, plist_t msg)
{
int result = 0;
uint64_t value = 0;
char* log = NULL;
- info("Got status message\n");
+ logger(LL_INFO, "Got status message\n");
// read status code
plist_t node = plist_dict_get_item(msg, "Status");
@@ -733,33 +836,34 @@ int restore_handle_status_msg(restored_client_t client, plist_t msg)
switch(value) {
case 0:
- info("Status: Restore Finished\n");
+ logger(LL_INFO, "Status: Restore Finished\n");
restore_finished = 1;
break;
case 0xFFFFFFFFFFFFFFFFLL:
- info("Status: Verification Error\n");
+ logger(LL_INFO, "Status: Verification Error\n");
break;
case 6:
- info("Status: Disk Failure\n");
+ logger(LL_INFO, "Status: Disk Failure\n");
break;
case 14:
- info("Status: Fail\n");
+ logger(LL_INFO, "Status: Fail\n");
break;
case 27:
- info("Status: Failed to mount filesystems.\n");
+ logger(LL_INFO, "Status: Failed to mount filesystems.\n");
break;
+ case 50:
case 51:
- info("Status: Failed to load SEP Firmware.\n");
+ logger(LL_INFO, "Status: Failed to load SEP Firmware.\n");
break;
case 53:
- info("Status: Failed to recover FDR data.\n");
+ logger(LL_INFO, "Status: Failed to recover FDR data.\n");
break;
case 1015:
- info("Status: X-Gold Baseband Update Failed. Defective Unit?\n");
+ logger(LL_INFO, "Status: X-Gold Baseband Update Failed. Defective Unit?\n");
break;
default:
- info("Unhandled status message (%" PRIu64 ")\n", value);
- debug_plist(msg);
+ logger(LL_INFO, "Unhandled status message (%" PRIu64 ")\n", value);
+ logger_dump_plist(LL_VERBOSE, msg, 1);
break;
}
@@ -777,7 +881,7 @@ int restore_handle_status_msg(restored_client_t client, plist_t msg)
node = plist_dict_get_item(msg, "Log");
if (node && plist_get_node_type(node) == PLIST_STRING) {
plist_get_string_val(node, &log);
- info("Log is available:\n%s\n", log);
+ logger(LL_INFO, "Log is available:\n%s\n", log);
free(log);
log = NULL;
}
@@ -785,10 +889,10 @@ int restore_handle_status_msg(restored_client_t client, plist_t msg)
return result;
}
-static int restore_handle_baseband_updater_output_data(restored_client_t restore, struct idevicerestore_client_t* client, idevice_t device, plist_t msg)
+static int restore_handle_baseband_updater_output_data(struct idevicerestore_client_t* client, plist_t message)
{
int result = -1;
- plist_t node = plist_dict_get_item(msg, "DataPort");
+ plist_t node = plist_dict_get_item(message, "DataPort");
uint64_t u64val = 0;
plist_get_uint_val(node, &u64val);
uint16_t data_port = (uint16_t)u64val;
@@ -797,43 +901,48 @@ static int restore_handle_baseband_updater_output_data(restored_client_t restore
idevice_connection_t connection = NULL;
idevice_error_t device_error = IDEVICE_E_SUCCESS;
- debug("Connecting to baseband updater data port\n");
+ if (!client || !client->restore || !client->restore->build_identity || !client->restore->device) {
+ logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__);
+ return -1;
+ }
+
+ logger(LL_DEBUG, "Connecting to baseband updater data port\n");
while (--attempts > 0) {
- device_error = idevice_connect(device, data_port, &connection);
+ device_error = idevice_connect(client->restore->device, data_port, &connection);
if (device_error == IDEVICE_E_SUCCESS) {
break;
}
sleep(1);
- debug("Retrying connection...\n");
+ logger(LL_DEBUG, "Retrying connection...\n");
}
if (device_error != IDEVICE_E_SUCCESS) {
- error("ERROR: Unable to connect to baseband updater data port\n");
+ logger(LL_ERROR, "Unable to connect to baseband updater data port\n");
return result;
}
int fl = snprintf(NULL, 0, "updater_output-%s.cpio", client->udid);
if (fl < 0) {
idevice_disconnect(connection);
- error("ERROR: snprintf failed?!\n");
+ logger(LL_ERROR, "snprintf failed?!\n");
return result;
}
char* updater_out_fn = malloc(fl+1);
if (!updater_out_fn) {
idevice_disconnect(connection);
- error("ERROR: Could not allocate buffer for filename\n");
+ logger(LL_ERROR, "Could not allocate buffer for filename\n");
return result;
}
snprintf(updater_out_fn, fl+1, "updater_output-%s.cpio", client->udid);
FILE* f = fopen(updater_out_fn, "wb");
if (!f) {
- error("Could not open %s for writing, will not write baseband updater output data.\n", updater_out_fn);
+ logger(LL_ERROR, "Could not open %s for writing, will not write baseband updater output data.\n", updater_out_fn);
}
const int bufsize = 65536;
char* buf = malloc(bufsize);
if (!buf) {
free(updater_out_fn);
idevice_disconnect(connection);
- error("ERROR: Could not allocate buffer\n");
+ logger(LL_ERROR, "Could not allocate buffer\n");
return result;
}
uint32_t size = 0;
@@ -844,7 +953,7 @@ static int restore_handle_baseband_updater_output_data(restored_client_t restore
}
if (f) {
fclose(f);
- info("Wrote baseband updater output data to %s\n", updater_out_fn);
+ logger(LL_INFO, "Wrote baseband updater output data to %s\n", updater_out_fn);
}
free(updater_out_fn);
free(buf);
@@ -854,46 +963,51 @@ static int restore_handle_baseband_updater_output_data(restored_client_t restore
return result;
}
-static int restore_handle_bb_update_status_msg(restored_client_t client, plist_t msg)
+static int restore_handle_bb_update_status_msg(struct idevicerestore_client_t* client, plist_t message)
{
int result = -1;
- plist_t node = plist_dict_get_item(msg, "Accepted");
+ plist_t node = plist_dict_get_item(message, "Accepted");
uint8_t accepted = 0;
plist_get_bool_val(node, &accepted);
if (!accepted) {
- error("ERROR: device didn't accept BasebandData\n");
+ logger(LL_ERROR, "device didn't accept BasebandData\n");
return result;
}
uint8_t done = 0;
- node = plist_access_path(msg, 2, "Output", "done");
+ node = plist_access_path(message, 2, "Output", "done");
if (node && plist_get_node_type(node) == PLIST_BOOLEAN) {
plist_get_bool_val(node, &done);
}
if (done) {
- info("Updating Baseband completed.\n");
- plist_t provisioning = plist_access_path(msg, 2, "Output", "provisioning");
+ logger(LL_INFO, "Updating Baseband completed.\n");
+ plist_t provisioning = plist_access_path(message, 2, "Output", "provisioning");
if (provisioning && plist_get_node_type(provisioning) == PLIST_DICT) {
char* sval = NULL;
node = plist_dict_get_item(provisioning, "IMEI");
if (node && plist_get_node_type(node) == PLIST_STRING) {
plist_get_string_val(node, &sval);
- info("Provisioning:\n");
- info("IMEI:%s\n", sval);
+ logger(LL_INFO, "Provisioning:\n");
+ logger(LL_INFO, "IMEI:%s\n", sval);
free(sval);
sval = NULL;
}
}
} else {
- info("Updating Baseband in progress...\n");
+ logger(LL_INFO, "Updating Baseband in progress...\n");
}
result = 0;
return result;
}
+struct _restore_asr_progress_data {
+ struct idevicerestore_client_t* client;
+ uint32_t tag;
+};
+
static void restore_asr_progress_cb(double progress, void* userdata)
{
struct idevicerestore_client_t* client = (struct idevicerestore_client_t*)userdata;
@@ -902,50 +1016,92 @@ static void restore_asr_progress_cb(double progress, void* userdata)
}
}
-int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device, const char* filesystem)
+int restore_send_filesystem(struct idevicerestore_client_t* client, plist_t message)
{
asr_client_t asr = NULL;
+ ipsw_archive_t ipsw_dummy = NULL;
+ ipsw_file_handle_t file = NULL;
+ char* fsname = NULL;
- info("About to send filesystem...\n");
+ if (!client || !client->restore || !client->restore->build_identity || !client->restore->device) {
+ logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__);
+ return -1;
+ }
- if (asr_open_with_timeout(device, &asr) < 0) {
- error("ERROR: Unable to connect to ASR\n");
+ logger(LL_INFO, "About to send filesystem...\n");
+
+ if (build_identity_get_component_path(client->restore->build_identity, "OS", &fsname) < 0) {
+ logger(LL_ERROR, "Unable to get path for filesystem component\n");
return -1;
}
- info("Connected to ASR\n");
+ if (client->filesystem) {
+ char* path = strdup(client->filesystem);
+ const char* fsname_base = path_get_basename(path);
+ char* parent_dir = dirname(path);
+ ipsw_dummy = ipsw_open(parent_dir);
+ file = ipsw_file_open(ipsw_dummy, fsname_base);
+ free(path);
+ } else {
+ file = ipsw_file_open(client->ipsw, fsname);
+ }
+ if (!file) {
+ logger(LL_ERROR, "Unable to open '%s' in ipsw\n", fsname);
+ free(fsname);
+ }
- asr_set_progress_callback(asr, restore_asr_progress_cb, (void*)client);
+ uint16_t asr_port = (uint16_t)plist_dict_get_uint(message, "DataPort");
+ if (asr_port == 0) {
+ asr_port = ASR_DEFAULT_PORT;
+ }
+ if (asr_open_with_timeout(client->restore->device, &asr, asr_port) < 0) {
+ ipsw_file_close(file);
+ ipsw_close(ipsw_dummy);
+ logger(LL_ERROR, "Unable to connect to ASR\n");
+ return -1;
+ }
+ logger(LL_INFO, "Connected to ASR\n");
// this step sends requested chunks of data from various offsets to asr so
// it can validate the filesystem before installing it
- info("Validating the filesystem\n");
- if (asr_perform_validation(asr, filesystem) < 0) {
- error("ERROR: ASR was unable to validate the filesystem\n");
+ logger(LL_INFO, "Validating the filesystem\n");
+ if (asr_perform_validation(asr, file) < 0) {
+ ipsw_file_close(file);
+ ipsw_close(ipsw_dummy);
+ logger(LL_ERROR, "ASR was unable to validate the filesystem\n");
asr_free(asr);
return -1;
}
- info("Filesystem validated\n");
+ logger(LL_INFO, "Filesystem validated\n");
+
+ if (asr_port == ASR_DEFAULT_PORT) {
+ asr_set_progress_callback(asr, restore_asr_progress_cb, client);
+ }
// once the target filesystem has been validated, ASR then requests the
// entire filesystem to be sent.
- info("Sending filesystem now...\n");
- if (asr_send_payload(asr, filesystem) < 0) {
- error("ERROR: Unable to send payload to ASR\n");
+ logger(LL_INFO, "Sending filesystem now...\n");
+ if (asr_send_payload(asr, file) < 0) {
+ ipsw_file_close(file);
+ ipsw_close(ipsw_dummy);
+ logger(LL_ERROR, "Unable to send payload to ASR\n");
asr_free(asr);
return -1;
}
- info("Done sending filesystem\n");
+ ipsw_file_close(file);
+ ipsw_close(ipsw_dummy);
+
+ logger(LL_INFO, "Done sending filesystem\n");
asr_free(asr);
return 0;
}
-int restore_send_recovery_os_root_ticket(restored_client_t restore, struct idevicerestore_client_t* client)
+int restore_send_recovery_os_root_ticket(struct idevicerestore_client_t* client, plist_t message)
{
restored_error_t restore_error;
plist_t dict;
- info("About to send RecoveryOSRootTicket...\n");
+ logger(LL_INFO, "About to send RecoveryOSRootTicket...\n");
if (client->root_ticket) {
dict = plist_new_dict();
@@ -955,18 +1111,18 @@ int restore_send_recovery_os_root_ticket(restored_client_t restore, struct idevi
unsigned int len = 0;
if (!client->tss_recoveryos_root_ticket && !(client->flags & FLAG_CUSTOM)) {
- error("ERROR: Cannot send RootTicket without TSS\n");
+ logger(LL_ERROR, "Cannot send RootTicket without TSS\n");
return -1;
}
if (client->image4supported) {
if (tss_response_get_ap_img4_ticket(client->tss_recoveryos_root_ticket, &data, &len) < 0) {
- error("ERROR: Unable to get ApImg4Ticket from TSS\n");
+ logger(LL_ERROR, "Unable to get ApImg4Ticket from TSS\n");
return -1;
}
} else {
if (!(client->flags & FLAG_CUSTOM) && (tss_response_get_ap_ticket(client->tss, &data, &len) < 0)) {
- error("ERROR: Unable to get ticket from TSS\n");
+ logger(LL_ERROR, "Unable to get ticket from TSS\n");
return -1;
}
}
@@ -975,30 +1131,37 @@ int restore_send_recovery_os_root_ticket(restored_client_t restore, struct idevi
if (data && (len > 0)) {
plist_dict_set_item(dict, "RootTicketData", plist_new_data((char*)data, len));
} else {
- info("NOTE: not sending RootTicketData (no data present)\n");
+ logger(LL_NOTICE, "Not sending RootTicketData (no data present)\n");
}
free(data);
}
- info("Sending RecoveryOSRootTicket now...\n");
- restore_error = restored_send(restore, dict);
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__);
+ return -1;
+ }
+
+ logger(LL_INFO, "Sending RecoveryOSRootTicket now...\n");
+ restore_error = _restore_service_send(service, dict, 0);
plist_free(dict);
+ _restore_service_free(service);
if (restore_error != RESTORE_E_SUCCESS) {
- error("ERROR: Unable to send RootTicket (%d)\n", restore_error);
+ logger(LL_ERROR, "Unable to send RootTicket (%d)\n", restore_error);
return -1;
}
- info("Done sending RecoveryOS RootTicket\n");
+ logger(LL_INFO, "Done sending RecoveryOS RootTicket\n");
return 0;
}
-int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_client_t* client)
+int restore_send_root_ticket(struct idevicerestore_client_t* client, plist_t message)
{
restored_error_t restore_error;
plist_t dict;
- info("About to send RootTicket...\n");
+ logger(LL_INFO, "About to send RootTicket...\n");
if (client->root_ticket) {
dict = plist_new_dict();
@@ -1008,18 +1171,18 @@ int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_cl
unsigned int len = 0;
if (!client->tss && !(client->flags & FLAG_CUSTOM)) {
- error("ERROR: Cannot send RootTicket without TSS\n");
+ logger(LL_ERROR, "Cannot send RootTicket without TSS\n");
return -1;
}
if (client->image4supported) {
if (tss_response_get_ap_img4_ticket(client->tss, &data, &len) < 0) {
- error("ERROR: Unable to get ApImg4Ticket from TSS\n");
+ logger(LL_ERROR, "Unable to get ApImg4Ticket from TSS\n");
return -1;
}
} else {
if (!(client->flags & FLAG_CUSTOM) && (tss_response_get_ap_ticket(client->tss, &data, &len) < 0)) {
- error("ERROR: Unable to get ticket from TSS\n");
+ logger(LL_ERROR, "Unable to get ticket from TSS\n");
return -1;
}
}
@@ -1028,88 +1191,345 @@ int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_cl
if (data && (len > 0)) {
plist_dict_set_item(dict, "RootTicketData", plist_new_data((char*)data, len));
} else {
- info("NOTE: not sending RootTicketData (no data present)\n");
+ logger(LL_INFO, "Not sending RootTicketData (no data present)\n");
}
free(data);
}
- info("Sending RootTicket now...\n");
- restore_error = restored_send(restore, dict);
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__);
+ return -1;
+ }
+
+ logger(LL_INFO, "Sending RootTicket now...\n");
+ restore_error = _restore_service_send(service, dict, 0);
plist_free(dict);
+ _restore_service_free(service);
if (restore_error != RESTORE_E_SUCCESS) {
- error("ERROR: Unable to send RootTicket (%d)\n", restore_error);
+ logger(LL_ERROR, "Unable to send RootTicket (%d)\n", restore_error);
return -1;
}
- info("Done sending RootTicket\n");
+ logger(LL_INFO, "Done sending RootTicket\n");
return 0;
}
-int restore_send_component(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, const char* component, const char* component_name)
+typedef struct {
+ int length;
+ char* content;
+} query_response;
+
+static size_t _curl_write_callback(char* data, size_t size, size_t nmemb, query_response* response)
+{
+ size_t total = size * nmemb;
+ if (total != 0) {
+ response->content = realloc(response->content, response->length + total + 1);
+ memcpy(response->content + response->length, data, total);
+ response->content[response->length + total] = '\0';
+ response->length += total;
+ }
+
+ return total;
+}
+
+static size_t _curl_header_callback(char* buffer, size_t size, size_t nitems, void* userdata)
+{
+ plist_t header_dict = (plist_t)userdata;
+ size_t len = nitems*size;
+ char* key = NULL;
+ char* val = NULL;
+ size_t i = 0;
+ while (i < len) {
+ if (buffer[i] == ':') {
+ key = malloc(i+1);
+ strncpy(key, buffer, i);
+ key[i] = '\0';
+ i++;
+ while (i < len && (buffer[i] == ' ' || buffer[i] == '\t')) i++;
+ val = malloc(len-i+1);
+ strncpy(val, buffer+i, len-i);
+ val[len-i] = '\0';
+ break;
+ }
+ i++;
+ }
+ if (key && val) {
+ plist_dict_set_item(header_dict, key, plist_new_string(val));
+ }
+ free(key);
+ free(val);
+ return len;
+}
+
+int restore_send_url_asset(struct idevicerestore_client_t* client, plist_t message)
{
- unsigned int size = 0;
- unsigned char* data = NULL;
+ plist_t arguments = plist_dict_get_item(message, "Arguments");
+ if (!PLIST_IS_DICT(arguments)) {
+ logger(LL_ERROR, "%s: Unexpected arguments\n", __func__);
+ logger_dump_plist(LL_VERBOSE, message, 1);
+ return -1;
+ }
+
+ const char* request_method = plist_get_string_ptr(plist_dict_get_item(arguments, "RequestMethod"), NULL);
+ if (!request_method) {
+ logger(LL_ERROR, "%s: Unable to extract RequestMethod from Arguments\n", __func__);
+ return -1;
+ }
+ if (strcmp(request_method, "GET")) {
+ logger(LL_ERROR, "%s: Unexpected RequestMethod '%s' in message\n", __func__, request_method);
+ return -1;
+ }
+ const char* request_url = plist_get_string_ptr(plist_dict_get_item(arguments, "RequestURL"), NULL);
+ if (!request_url) {
+ logger(LL_ERROR, "%s: Unable to extract RequestURL from Arguments\n", __func__);
+ return -1;
+ }
+ logger(LL_INFO, "Requesting URLAsset from %s\n", request_url);
+
+ char curl_error_message[CURL_ERROR_SIZE];
+ CURL* handle = curl_easy_init();
+ /* disable SSL verification to allow download from untrusted https locations */
+ curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0);
+
+ query_response* response = malloc(sizeof(query_response));
+ if (response == NULL) {
+ logger(LL_ERROR, "%s: Unable to allocate sufficient memory\n", __func__);
+ return -1;
+ }
+
+ response->length = 0;
+ response->content = malloc(1);
+ response->content[0] = '\0';
+
+ curl_easy_setopt(handle, CURLOPT_HTTPGET, 1L);
+ curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, curl_error_message);
+ curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, (curl_write_callback)&_curl_write_callback);
+ curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, &_curl_header_callback);
+ plist_t response_headers = plist_new_dict();
+ curl_easy_setopt(handle, CURLOPT_HEADERDATA, response_headers);
+ curl_easy_setopt(handle, CURLOPT_WRITEDATA, response);
+ if (client->debug_level > 0) {
+ curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L);
+ }
+ curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1);
+ curl_easy_setopt(handle, CURLOPT_URL, request_url);
+ curl_easy_perform(handle);
+
+ long http_response = 0;
+ curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &http_response);
+
+ curl_easy_cleanup(handle);
+
+ plist_t dict = plist_new_dict();
+ plist_dict_set_item(dict, "ResponseBody", plist_new_data(response->content, response->length));
+ plist_dict_set_item(dict, "ResponseBodyDone", plist_new_bool(1));
+ plist_dict_set_item(dict, "ResponseHeaders", response_headers);
+ plist_dict_set_item(dict, "ResponseStatus", plist_new_uint(http_response));
+
+ free(response);
+
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__);
+ return -1;
+ }
+
+ _restore_service_send(service, dict, PLIST_FORMAT_BINARY);
+ _restore_service_free(service);
+
+ return 0;
+}
+
+int restore_send_streamed_image_decryption_key(struct idevicerestore_client_t* client, plist_t message)
+{
+ logger(LL_DEBUG, "%s\n", __func__);
+ plist_t arguments = plist_dict_get_item(message, "Arguments");
+ if (!PLIST_IS_DICT(arguments)) {
+ logger(LL_ERROR, "%s: Unexpected arguments\n", __func__);
+ logger_dump_plist(LL_VERBOSE, arguments, 1);
+ return -1;
+ }
+
+ const char* request_method = plist_get_string_ptr(plist_dict_get_item(arguments, "RequestMethod"), NULL);
+ if (!request_method) {
+ logger(LL_ERROR, "%s: Unable to extract RequestMethod from Arguments\n", __func__);
+ return -1;
+ }
+ if (strcmp(request_method, "POST")) {
+ logger(LL_ERROR, "%s: Unexpected RequestMethod '%s' in message\n", __func__, request_method);
+ return -1;
+ }
+ const char* request_url = plist_get_string_ptr(plist_dict_get_item(arguments, "RequestURL"), NULL);
+ if (!request_url) {
+ logger(LL_ERROR, "%s: Unable to extract RequestURL from Arguments\n", __func__);
+ return -1;
+ }
+
+ struct curl_slist* header = NULL;
+
+ plist_t headers = plist_dict_get_item(arguments, "RequestAdditionalHeaders");
+ if (!headers) {
+ logger(LL_ERROR, "%s: Missing 'RequestAdditionalHeaders'\n", __func__);
+ return -1;
+ }
+
+ uint64_t request_body_size = 0;
+ const char* request_body = plist_get_data_ptr(plist_dict_get_item(arguments, "RequestBody"), &request_body_size);
+ if (!request_body) {
+ logger(LL_ERROR, "%s: Missing 'RequestBody'\n", __func__);
+ return -1;
+ }
+
+ logger(LL_INFO, "Requesting image decryption key from %s\n", request_url);
+
+ char curl_error_message[CURL_ERROR_SIZE];
+ char header_tmp[1024];
+ plist_dict_iter iter = NULL;
+ plist_dict_new_iter(headers, &iter);
+ plist_t node = NULL;
+ do {
+ char *key = NULL;
+ plist_dict_next_item(headers, iter, &key, &node);
+ if (!node) break;
+ snprintf(header_tmp, sizeof(header_tmp), "%s: %s", key, plist_get_string_ptr(node, NULL));
+ curl_slist_append(header, header_tmp);
+ } while (node);
+ plist_mem_free(iter);
+
+ CURL* handle = curl_easy_init();
+ /* disable SSL verification to allow download from untrusted https locations */
+ curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0);
+
+ query_response* response = malloc(sizeof(query_response));
+ if (response == NULL) {
+ logger(LL_ERROR, "%s: Unable to allocate sufficient memory\n", __func__);
+ return -1;
+ }
+
+ response->length = 0;
+ response->content = malloc(1);
+ response->content[0] = '\0';
+
+ curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, curl_error_message);
+ curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, (curl_write_callback)&_curl_write_callback);
+ curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, &_curl_header_callback);
+ plist_t response_headers = plist_new_dict();
+ curl_easy_setopt(handle, CURLOPT_HEADERDATA, response_headers);
+ curl_easy_setopt(handle, CURLOPT_WRITEDATA, response);
+ curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header);
+ curl_easy_setopt(handle, CURLOPT_POSTFIELDS, request_body);
+ curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, (long)request_body_size);
+ if (client->debug_level > 0) {
+ curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L);
+ }
+ curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1);
+ curl_easy_setopt(handle, CURLOPT_URL, request_url);
+ curl_easy_perform(handle);
+ curl_slist_free_all(header);
+
+ long http_response = 0;
+ curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &http_response);
+
+ curl_easy_cleanup(handle);
+
+ plist_t dict = plist_new_dict();
+ plist_dict_set_item(dict, "ResponseBody", plist_new_data(response->content, response->length));
+ plist_dict_set_item(dict, "ResponseBodyDone", plist_new_bool(1));
+ plist_dict_set_item(dict, "ResponseHeaders", response_headers);
+ plist_dict_set_item(dict, "ResponseStatus", plist_new_uint(http_response));
+
+ free(response);
+
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__);
+ return -1;
+ }
+
+ _restore_service_send(service, dict, PLIST_FORMAT_BINARY);
+ _restore_service_free(service);
+
+ return 0;
+}
+
+int restore_send_component(struct idevicerestore_client_t* client, plist_t message, const char* component, const char* component_name)
+{
+ size_t size = 0;
+ void* data = NULL;
char* path = NULL;
plist_t blob = NULL;
plist_t dict = NULL;
restored_error_t restore_error = RESTORE_E_SUCCESS;
+ if (!client || !client->restore || !client->restore->build_identity) {
+ logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__);
+ return -1;
+ }
+
if (component_name == NULL) {
component_name = component;
}
- info("About to send %s...\n", component_name);
+ logger(LL_INFO, "About to send %s...\n", component_name);
if (client->tss) {
if (tss_response_get_path_by_entry(client->tss, component, &path) < 0) {
- debug("NOTE: No path for component %s in TSS, will fetch from build identity\n", component);
+ logger(LL_DEBUG, "No path for component %s in TSS, will fetch from build identity\n", component);
}
}
if (!path) {
- if (build_identity_get_component_path(build_identity, component, &path) < 0) {
- error("ERROR: Unable to find %s path from build identity\n", component);
+ if (build_identity_get_component_path(client->restore->build_identity, component, &path) < 0) {
+ logger(LL_ERROR, "Unable to find %s path from build identity\n", component);
return -1;
}
}
- unsigned char* component_data = NULL;
- unsigned int component_size = 0;
+ void* component_data = NULL;
+ size_t component_size = 0;
int ret = extract_component(client->ipsw, path, &component_data, &component_size);
free(path);
path = NULL;
if (ret < 0) {
- error("ERROR: Unable to extract component %s\n", component);
+ logger(LL_ERROR, "Unable to extract component %s\n", component);
return -1;
}
- ret = personalize_component(component, component_data, component_size, client->tss, &data, &size);
+ ret = personalize_component(client, component, component_data, component_size, client->tss, &data, &size);
free(component_data);
component_data = NULL;
if (ret < 0) {
- error("ERROR: Unable to get personalized component %s\n", component);
+ logger(LL_ERROR, "Unable to get personalized component %s\n", component);
return -1;
}
dict = plist_new_dict();
blob = plist_new_data((char*)data, size);
char compkeyname[256];
- sprintf(compkeyname, "%sFile", component_name);
+ snprintf(compkeyname, sizeof(compkeyname), "%sFile", component_name);
plist_dict_set_item(dict, compkeyname, blob);
free(data);
- info("Sending %s now...\n", component_name);
- restore_error = restored_send(restore, dict);
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__);
+ return -1;
+ }
+
+ logger(LL_INFO, "Sending %s now...\n", component_name);
+ restore_error = _restore_service_send(service, dict, 0);
plist_free(dict);
+ _restore_service_free(service);
if (restore_error != RESTORE_E_SUCCESS) {
- error("ERROR: Unable to send component %s data\n", component_name);
+ logger(LL_ERROR, "Unable to send component %s data\n", component_name);
return -1;
}
- info("Done sending %s\n", component_name);
+ logger(LL_INFO, "Done sending %s\n", component_name);
return 0;
}
-int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity)
+int restore_send_nor(struct idevicerestore_client_t* client, plist_t message)
{
char* llb_path = NULL;
char* llb_filename = NULL;
@@ -1117,42 +1537,52 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t*
char* restore_sep_path = NULL;
char firmware_path[PATH_MAX - 9];
char manifest_file[PATH_MAX];
- unsigned int manifest_size = 0;
- unsigned char* manifest_data = NULL;
+ size_t manifest_size = 0;
+ void* manifest_data = NULL;
char firmware_filename[PATH_MAX];
- unsigned int llb_size = 0;
- unsigned char* llb_data = NULL;
+ size_t llb_size = 0;
+ void* llb_data = NULL;
plist_t dict = NULL;
- unsigned int nor_size = 0;
- unsigned char* nor_data = NULL;
+ size_t nor_size = 0;
+ void* nor_data = NULL;
plist_t norimage = NULL;
plist_t firmware_files = NULL;
- uint32_t i;
+ int flash_version_1 = 0;
+
+ if (!client || !client->restore || !client->restore->build_identity) {
+ logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__);
+ return -1;
+ }
- info("About to send NORData...\n");
+ logger(LL_INFO, "About to send NORData...\n");
+
+ plist_t arguments = plist_dict_get_item(message, "Arguments");
+ if (arguments && plist_get_node_type(arguments) == PLIST_DICT) {
+ flash_version_1 = plist_dict_get_item(arguments, "FlashVersion1") ? 1 : 0;
+ }
if (client->tss) {
if (tss_response_get_path_by_entry(client->tss, "LLB", &llb_path) < 0) {
- debug("NOTE: Could not get LLB path from TSS data, will fetch from build identity\n");
+ logger(LL_DEBUG, "Could not get LLB path from TSS data, will fetch from build identity\n");
}
}
if (llb_path == NULL) {
- if (build_identity_get_component_path(build_identity, "LLB", &llb_path) < 0) {
- error("ERROR: Unable to get component path for LLB\n");
+ if (build_identity_get_component_path(client->restore->build_identity, "LLB", &llb_path) < 0) {
+ logger(LL_ERROR, "Unable to get component path for LLB\n");
return -1;
}
}
llb_filename = strstr(llb_path, "LLB");
if (llb_filename == NULL) {
- error("ERROR: Unable to extract firmware path from LLB filename\n");
+ logger(LL_ERROR, "Unable to extract firmware path from LLB filename\n");
free(llb_path);
return -1;
}
memset(firmware_path, '\0', sizeof(firmware_path));
memcpy(firmware_path, llb_path, (llb_filename - 1) - llb_path);
- info("Found firmware path %s\n", firmware_path);
+ logger(LL_INFO, "Found firmware path %s\n", firmware_path);
memset(manifest_file, '\0', sizeof(manifest_file));
snprintf(manifest_file, sizeof(manifest_file), "%s/manifest", firmware_path);
@@ -1162,7 +1592,7 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t*
ipsw_extract_to_memory(client->ipsw, manifest_file, &manifest_data, &manifest_size);
}
if (manifest_data && manifest_size > 0) {
- info("Getting firmware manifest from %s\n", manifest_file);
+ logger(LL_INFO, "Getting firmware manifest from %s\n", manifest_file);
char *manifest_p = (char*)manifest_data;
char *filename = NULL;
while ((filename = strsep(&manifest_p, "\r\n")) != NULL) {
@@ -1175,9 +1605,9 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t*
}
free(manifest_data);
} else {
- info("Getting firmware manifest from build identity\n");
+ logger(LL_INFO, "Getting firmware manifest from build identity\n");
plist_dict_iter iter = NULL;
- plist_t build_id_manifest = plist_dict_get_item(build_identity, "Manifest");
+ plist_t build_id_manifest = plist_dict_get_item(client->restore->build_identity, "Manifest");
if (build_id_manifest) {
plist_dict_new_iter(build_id_manifest, &iter);
}
@@ -1223,36 +1653,34 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t*
}
if (plist_dict_get_size(firmware_files) == 0) {
- error("ERROR: Unable to get list of firmware files.\n");
+ logger(LL_ERROR, "Unable to get list of firmware files.\n");
return -1;
}
const char* component = "LLB";
- unsigned char* component_data = NULL;
- unsigned int component_size = 0;
+ void* component_data = NULL;
+ size_t component_size = 0;
int ret = extract_component(client->ipsw, llb_path, &component_data, &component_size);
free(llb_path);
if (ret < 0) {
- error("ERROR: Unable to extract component: %s\n", component);
+ logger(LL_ERROR, "Unable to extract component: %s\n", component);
return -1;
}
- ret = personalize_component(component, component_data, component_size, client->tss, &llb_data, &llb_size);
+ ret = personalize_component(client, component, component_data, component_size, client->tss, &llb_data, &llb_size);
free(component_data);
component_data = NULL;
component_size = 0;
if (ret < 0) {
- error("ERROR: Unable to get personalized component: %s\n", component);
+ logger(LL_ERROR, "Unable to get personalized component: %s\n", component);
return -1;
}
dict = plist_new_dict();
- plist_dict_set_item(dict, "LlbImageData", plist_new_data((char*)llb_data, (uint64_t) llb_size));
+ plist_dict_set_item(dict, "LlbImageData", plist_new_data((char*)llb_data, llb_size));
free(llb_data);
- if (client->build_major >= 20) {
- // Starting with M1 macs, it seems that NorImageData is now a dict.
- // Sending an array like previous versions results in restore success but the machine will SOS after rebooting.
+ if (flash_version_1) {
norimage = plist_new_dict();
} else {
norimage = plist_new_array();
@@ -1284,38 +1712,38 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t*
}
component_data = NULL;
- unsigned int component_size = 0;
+ component_size = 0;
if (extract_component(client->ipsw, comppath, &component_data, &component_size) < 0) {
free(iter);
free(comp);
free(comppath);
plist_free(firmware_files);
- error("ERROR: Unable to extract component: %s\n", component);
+ logger(LL_ERROR, "Unable to extract component: %s\n", component);
return -1;
}
- if (personalize_component(component, component_data, component_size, client->tss, &nor_data, &nor_size) < 0) {
+ if (personalize_component(client, component, component_data, component_size, client->tss, &nor_data, &nor_size) < 0) {
free(iter);
free(comp);
free(comppath);
free(component_data);
plist_free(firmware_files);
- error("ERROR: Unable to get personalized component: %s\n", component);
+ logger(LL_ERROR, "Unable to get personalized component: %s\n", component);
return -1;
}
free(component_data);
component_data = NULL;
component_size = 0;
- if (client->build_major >= 20) {
- plist_dict_set_item(norimage, component, plist_new_data((char*)nor_data, (uint64_t)nor_size));
+ if (flash_version_1) {
+ plist_dict_set_item(norimage, component, plist_new_data((char*)nor_data, nor_size));
} else {
/* make sure iBoot is the first entry in the array */
if (!strncmp("iBoot", component, 5)) {
- plist_array_insert_item(norimage, plist_new_data((char*)nor_data, (uint64_t)nor_size), 0);
+ plist_array_insert_item(norimage, plist_new_data((char*)nor_data, nor_size), 0);
} else {
- plist_array_append_item(norimage, plist_new_data((char*)nor_data, (uint64_t)nor_size));
+ plist_array_append_item(norimage, plist_new_data((char*)nor_data, nor_size));
}
}
@@ -1329,75 +1757,107 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t*
plist_free(firmware_files);
plist_dict_set_item(dict, "NorImageData", norimage);
- unsigned char* personalized_data = NULL;
- unsigned int personalized_size = 0;
+ void* personalized_data = NULL;
+ size_t personalized_size = 0;
- if (build_identity_has_component(build_identity, "RestoreSEP") &&
- build_identity_get_component_path(build_identity, "RestoreSEP", &restore_sep_path) == 0) {
+ if (build_identity_has_component(client->restore->build_identity, "RestoreSEP") &&
+ build_identity_get_component_path(client->restore->build_identity, "RestoreSEP", &restore_sep_path) == 0) {
component = "RestoreSEP";
ret = extract_component(client->ipsw, restore_sep_path, &component_data, &component_size);
free(restore_sep_path);
if (ret < 0) {
- error("ERROR: Unable to extract component: %s\n", component);
+ logger(LL_ERROR, "Unable to extract component: %s\n", component);
return -1;
}
- ret = personalize_component(component, component_data, component_size, client->tss, &personalized_data, &personalized_size);
+ ret = personalize_component(client, component, component_data, component_size, client->tss, &personalized_data, &personalized_size);
free(component_data);
component_data = NULL;
component_size = 0;
if (ret < 0) {
- error("ERROR: Unable to get personalized component: %s\n", component);
+ logger(LL_ERROR, "Unable to get personalized component: %s\n", component);
return -1;
}
- plist_dict_set_item(dict, "RestoreSEPImageData", plist_new_data((char*)personalized_data, (uint64_t) personalized_size));
+ plist_dict_set_item(dict, "RestoreSEPImageData", plist_new_data((char*)personalized_data, personalized_size));
free(personalized_data);
personalized_data = NULL;
personalized_size = 0;
}
- if (build_identity_has_component(build_identity, "SEP") &&
- build_identity_get_component_path(build_identity, "SEP", &sep_path) == 0) {
+ if (build_identity_has_component(client->restore->build_identity, "SEP") &&
+ build_identity_get_component_path(client->restore->build_identity, "SEP", &sep_path) == 0) {
component = "SEP";
ret = extract_component(client->ipsw, sep_path, &component_data, &component_size);
free(sep_path);
if (ret < 0) {
- error("ERROR: Unable to extract component: %s\n", component);
+ logger(LL_ERROR, "Unable to extract component: %s\n", component);
return -1;
}
- ret = personalize_component(component, component_data, component_size, client->tss, &personalized_data, &personalized_size);
+ ret = personalize_component(client, component, component_data, component_size, client->tss, &personalized_data, &personalized_size);
free(component_data);
component_data = NULL;
component_size = 0;
if (ret < 0) {
- error("ERROR: Unable to get personalized component: %s\n", component);
+ logger(LL_ERROR, "Unable to get personalized component: %s\n", component);
return -1;
}
- plist_dict_set_item(dict, "SEPImageData", plist_new_data((char*)personalized_data, (uint64_t) personalized_size));
+ plist_dict_set_item(dict, "SEPImageData", plist_new_data((char*)personalized_data, personalized_size));
free(personalized_data);
personalized_data = NULL;
personalized_size = 0;
}
- if (idevicerestore_debug)
- debug_plist(dict);
+ if (build_identity_has_component(client->restore->build_identity, "SepStage1") &&
+ build_identity_get_component_path(client->restore->build_identity, "SepStage1", &sep_path) == 0) {
+ component = "SepStage1";
+ ret = extract_component(client->ipsw, sep_path, &component_data, &component_size);
+ free(sep_path);
+ if (ret < 0) {
+ logger(LL_ERROR, "Unable to extract component: %s\n", component);
+ return -1;
+ }
- info("Sending NORData now...\n");
- if (restored_send(restore, dict) != RESTORE_E_SUCCESS) {
- error("ERROR: Unable to send NORData\n");
- plist_free(dict);
+ ret = personalize_component(client, component, component_data, component_size, client->tss, &personalized_data, &personalized_size);
+ free(component_data);
+ component_data = NULL;
+ component_size = 0;
+ if (ret < 0) {
+ logger(LL_ERROR, "Unable to get personalized component: %s\n", component);
+ return -1;
+ }
+
+ plist_dict_set_item(dict, "SEPPatchImageData", plist_new_data((char*)personalized_data, personalized_size));
+ free(personalized_data);
+ personalized_data = NULL;
+ personalized_size = 0;
+ }
+
+ if (client->debug_level > 1)
+ logger_dump_plist(LL_DEBUG, dict, 0);
+
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__);
return -1;
}
- info("Done sending NORData\n");
+ logger(LL_INFO, "Sending NORData now...\n");
+ restored_error_t restore_error = _restore_service_send(service, dict, 0);
plist_free(dict);
+ _restore_service_free(service);
+ if (restore_error != RESTORE_E_SUCCESS) {
+ logger(LL_ERROR, "Unable to send NORData\n");
+ return -1;
+ }
+
+ logger(LL_INFO, "Done sending NORData\n");
return 0;
}
-static const char* restore_get_bbfw_fn_for_element(const char* elem)
+static const char* restore_get_bbfw_fn_for_element(const char* elem, uint32_t bb_chip_id)
{
struct bbfw_fn_elem_t {
const char* element;
@@ -1428,61 +1888,74 @@ static const char* restore_get_bbfw_fn_for_element(const char* elem)
{ NULL, NULL }
};
+ struct bbfw_fn_elem_t bbfw_fn_elem_mav25[] = {
+ // Mav25 Firmware files
+ { "Misc", "multi_image.mbn" },
+ { "RestoreSBL1", "restorexbl_sc.elf" },
+ { "SBL1", "xbl_sc.elf" },
+ { "TME", "signed_firmware_soc_view.elf" },
+ { NULL, NULL }
+ };
+
+ struct bbfw_fn_elem_t* bbfw_fn_elems = (struct bbfw_fn_elem_t*)bbfw_fn_elem;
+ if (bb_chip_id == 0x1F30E1) {
+ bbfw_fn_elems = (struct bbfw_fn_elem_t*)bbfw_fn_elem_mav25;
+ }
+
int i;
- for (i = 0; bbfw_fn_elem[i].element != NULL; i++) {
- if (strcmp(bbfw_fn_elem[i].element, elem) == 0) {
- return bbfw_fn_elem[i].fn;
+ for (i = 0; bbfw_fn_elems[i].element != NULL; i++) {
+ if (strcmp(bbfw_fn_elems[i].element, elem) == 0) {
+ return bbfw_fn_elems[i].fn;
}
}
return NULL;
}
-static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned char* bb_nonce)
+static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned char* bb_nonce, uint32_t bb_chip_id)
{
int res = -1;
// check for BBTicket in result
plist_t bbticket = plist_dict_get_item(bbtss, "BBTicket");
if (!bbticket || plist_get_node_type(bbticket) != PLIST_DATA) {
- error("ERROR: Could not find BBTicket in Baseband TSS response\n");
+ logger(LL_ERROR, "Could not find BBTicket in Baseband TSS response\n");
return -1;
}
plist_t bbfw_dict = plist_dict_get_item(bbtss, "BasebandFirmware");
if (!bbfw_dict || plist_get_node_type(bbfw_dict) != PLIST_DICT) {
- error("ERROR: Could not find BasebandFirmware Dictionary node in Baseband TSS response\n");
+ logger(LL_ERROR, "Could not find BasebandFirmware Dictionary node in Baseband TSS response\n");
return -1;
}
unsigned char* buffer = NULL;
- unsigned char* blob = NULL;
+ const unsigned char* blob = NULL;
unsigned char* fdata = NULL;
uint64_t fsize = 0;
uint64_t blob_size = 0;
int zerr = 0;
- int zindex = -1;
+ int64_t zindex = -1;
struct zip_stat zstat;
struct zip_file* zfile = NULL;
struct zip* za = NULL;
struct zip_source* zs = NULL;
- mbn_file* mbn = NULL;
fls_file* fls = NULL;
za = zip_open(bbfwtmp, 0, &zerr);
if (!za) {
- error("ERROR: Could not open ZIP archive '%s': %d\n", bbfwtmp, zerr);
+ logger(LL_ERROR, "Could not open ZIP archive '%s': %d\n", bbfwtmp, zerr);
goto leave;
}
plist_dict_iter iter = NULL;
plist_dict_new_iter(bbfw_dict, &iter);
if (!iter) {
- error("ERROR: Could not create dict iter for BasebandFirmware Dictionary\n");
+ logger(LL_ERROR, "Could not create dict iter for BasebandFirmware Dictionary\n");
return -1;
}
int is_fls = 0;
- int signed_file_idxs[16];
+ int64_t signed_file_idxs[16];
int signed_file_count = 0;
char* key = NULL;
plist_t node = NULL;
@@ -1493,9 +1966,9 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned
if (node && (strcmp(key + (strlen(key) - 5), "-Blob") == 0) && (plist_get_node_type(node) == PLIST_DATA)) {
char *ptr = strchr(key, '-');
*ptr = '\0';
- const char* signfn = restore_get_bbfw_fn_for_element(key);
+ const char* signfn = restore_get_bbfw_fn_for_element(key, bb_chip_id);
if (!signfn) {
- error("ERROR: can't match element name '%s' to baseband firmware file name.\n", key);
+ logger(LL_ERROR, "can't match element name '%s' to baseband firmware file name.\n", key);
goto leave;
}
char* ext = strrchr(signfn, '.');
@@ -1505,30 +1978,30 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned
zindex = zip_name_locate(za, signfn, 0);
if (zindex < 0) {
- error("ERROR: can't locate '%s' in '%s'\n", signfn, bbfwtmp);
+ logger(LL_ERROR, "can't locate '%s' in '%s'\n", signfn, bbfwtmp);
goto leave;
}
zip_stat_init(&zstat);
if (zip_stat_index(za, zindex, 0, &zstat) != 0) {
- error("ERROR: zip_stat_index failed for index %d\n", zindex);
+ logger(LL_ERROR, "zip_stat_index failed for index %" PRIi64 "\n", zindex);
goto leave;
}
zfile = zip_fopen_index(za, zindex, 0);
if (zfile == NULL) {
- error("ERROR: zip_fopen_index failed for index %d\n", zindex);
+ logger(LL_ERROR, "zip_fopen_index failed for index %" PRIi64 "\n", zindex);
goto leave;
}
buffer = (unsigned char*) malloc(zstat.size + 1);
if (buffer == NULL) {
- error("ERROR: Out of memory\n");
+ logger(LL_ERROR, "Out of memory\n");
goto leave;
}
if (zip_fread(zfile, buffer, zstat.size) != zstat.size) {
- error("ERROR: zip_fread: failed\n");
+ logger(LL_ERROR, "zip_fread: failed\n");
goto leave;
}
buffer[zstat.size] = '\0';
@@ -1539,66 +2012,60 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned
if (is_fls) {
fls = fls_parse(buffer, zstat.size);
if (!fls) {
- error("ERROR: could not parse fls file\n");
- goto leave;
- }
- } else {
- mbn = mbn_parse(buffer, zstat.size);
- if (!mbn) {
- error("ERROR: could not parse mbn file\n");
+ logger(LL_ERROR, "could not parse fls file\n");
goto leave;
}
}
- free(buffer);
- buffer = NULL;
- blob = NULL;
blob_size = 0;
- plist_get_data_val(node, (char**)&blob, &blob_size);
+ blob = (const unsigned char*)plist_get_data_ptr(node, &blob_size);
if (!blob) {
- error("ERROR: could not get %s-Blob data\n", key);
+ logger(LL_ERROR, "could not get %s-Blob data\n", key);
goto leave;
}
+ logger(LL_VERBOSE, "Stitching %s\n", signfn);
if (is_fls) {
- if (fls_update_sig_blob(fls, blob, (unsigned int)blob_size) != 0) {
- error("ERROR: could not sign %s\n", signfn);
+ if (fls_update_sig_blob(fls, blob, (size_t)blob_size) != 0) {
+ logger(LL_ERROR, "Could not stitch %s\n", signfn);
goto leave;
}
- } else {
- if (mbn_update_sig_blob(mbn, blob, (unsigned int)blob_size) != 0) {
- error("ERROR: could not sign %s\n", signfn);
+ fsize = fls->size;
+ fdata = (unsigned char*)malloc(fsize);
+ if (fdata == NULL) {
+ logger(LL_ERROR, "out of memory\n");
goto leave;
}
- }
- free(blob);
- blob = NULL;
-
- fsize = (is_fls ? fls->size : mbn->size);
- fdata = (unsigned char*)malloc(fsize);
- if (fdata == NULL) {
- error("ERROR: out of memory\n");
- goto leave;
- }
- if (is_fls) {
memcpy(fdata, fls->data, fsize);
fls_free(fls);
fls = NULL;
+ } else if (bb_chip_id == 0x1F30E1) { // Mav25 - Qualcomm Snapdragon X80 5G Modem
+ fdata = mbn_mav25_stitch(buffer, zstat.size, blob, (size_t)blob_size);
+ fsize = zstat.size;
+ if (!fdata) {
+ logger(LL_ERROR, "Could not stitch %s\n", signfn);
+ goto leave;
+ }
} else {
- memcpy(fdata, mbn->data, fsize);
- mbn_free(mbn);
- mbn = NULL;
+ fdata = mbn_stitch(buffer, zstat.size, blob, (size_t)blob_size);
+ fsize = zstat.size;
+ if (!fdata) {
+ logger(LL_ERROR, "Could not stitch %s\n", signfn);
+ goto leave;
+ }
}
+ free(buffer);
+ buffer = NULL;
zs = zip_source_buffer(za, fdata, fsize, 1);
if (!zs) {
- error("ERROR: out of memory\n");
+ logger(LL_ERROR, "out of memory\n");
free(fdata);
goto leave;
}
- if (zip_replace(za, zindex, zs) == -1) {
- error("ERROR: could not update signed '%s' in archive\n", signfn);
+ if (zip_file_replace(za, zindex, zs, 0) == -1) {
+ logger(LL_ERROR, "Could not update signed '%s' in archive\n", signfn);
goto leave;
}
@@ -1615,9 +2082,10 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned
free(iter);
// remove everything but required files
- int i, j, keep, numf = zip_get_num_files(za);
+ int64_t i, numf = zip_get_num_entries(za, 0);
for (i = 0; i < numf; i++) {
- keep = 0;
+ int j;
+ int keep = 0;
// check for signed file index
for (j = 0; j < signed_file_count; j++) {
if (i == signed_file_idxs[j]) {
@@ -1626,8 +2094,8 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned
}
}
// check for anything but .mbn and .fls if bb_nonce is set
- if (bb_nonce && !keep) {
- const char* fn = zip_get_name(za, i, 0);
+ const char* fn = zip_get_name(za, i, 0);
+ if (!keep) {
if (fn) {
char* ext = strrchr(fn, '.');
if (ext && (!strcmp(ext, ".fls") || !strcmp(ext, ".mbn") || !strcmp(ext, ".elf") || !strcmp(ext, ".bin"))) {
@@ -1636,39 +2104,42 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned
}
}
if (!keep) {
+ logger(LL_DEBUG, "%s: removing %s from bbfw\n", __func__, fn);
zip_delete(za, i);
+ } else {
+ logger(LL_DEBUG, "%s: keeping %s in bbfw\n", __func__, fn);
}
}
- if (bb_nonce) {
+ if (bbticket) {
if (is_fls) {
// add BBTicket to file ebl.fls
zindex = zip_name_locate(za, "ebl.fls", 0);
if (zindex < 0) {
- error("ERROR: can't locate 'ebl.fls' in '%s'\n", bbfwtmp);
+ logger(LL_ERROR, "can't locate 'ebl.fls' in '%s'\n", bbfwtmp);
goto leave;
}
zip_stat_init(&zstat);
if (zip_stat_index(za, zindex, 0, &zstat) != 0) {
- error("ERROR: zip_stat_index failed for index %d\n", zindex);
+ logger(LL_ERROR, "zip_stat_index failed for index %" PRIi64 "\n", zindex);
goto leave;
}
zfile = zip_fopen_index(za, zindex, 0);
if (zfile == NULL) {
- error("ERROR: zip_fopen_index failed for index %d\n", zindex);
+ logger(LL_ERROR, "zip_fopen_index failed for index %" PRIi64 "\n", zindex);
goto leave;
}
buffer = (unsigned char*) malloc(zstat.size + 1);
if (buffer == NULL) {
- error("ERROR: Out of memory\n");
+ logger(LL_ERROR, "Out of memory\n");
goto leave;
}
if (zip_fread(zfile, buffer, zstat.size) != zstat.size) {
- error("ERROR: zip_fread: failed\n");
+ logger(LL_ERROR, "zip_fread: failed\n");
goto leave;
}
buffer[zstat.size] = '\0';
@@ -1680,29 +2151,26 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned
free(buffer);
buffer = NULL;
if (!fls) {
- error("ERROR: could not parse fls file\n");
+ logger(LL_ERROR, "could not parse fls file\n");
goto leave;
}
- blob = NULL;
blob_size = 0;
- plist_get_data_val(bbticket, (char**)&blob, &blob_size);
+ blob = (const unsigned char*)plist_get_data_ptr(bbticket, &blob_size);
if (!blob) {
- error("ERROR: could not get BBTicket data\n");
+ logger(LL_ERROR, "could not get BBTicket data\n");
goto leave;
}
if (fls_insert_ticket(fls, blob, (unsigned int)blob_size) != 0) {
- error("ERROR: could not insert BBTicket to ebl.fls\n");
+ logger(LL_ERROR, "could not insert BBTicket to ebl.fls\n");
goto leave;
}
- free(blob);
- blob = NULL;
fsize = fls->size;
fdata = (unsigned char*)malloc(fsize);
if (!fdata) {
- error("ERROR: out of memory\n");
+ logger(LL_ERROR, "out of memory\n");
goto leave;
}
memcpy(fdata, fls->data, fsize);
@@ -1711,34 +2179,32 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned
zs = zip_source_buffer(za, fdata, fsize, 1);
if (!zs) {
- error("ERROR: out of memory\n");
+ logger(LL_ERROR, "out of memory\n");
free(fdata);
goto leave;
}
- if (zip_replace(za, zindex, zs) == -1) {
- error("ERROR: could not update archive with ticketed ebl.fls\n");
+ if (zip_file_replace(za, zindex, zs, 0) == -1) {
+ logger(LL_ERROR, "could not update archive with ticketed ebl.fls\n");
goto leave;
}
} else {
// add BBTicket as bbticket.der
- blob = NULL;
blob_size = 0;
- plist_get_data_val(bbticket, (char**)&blob, &blob_size);
+ blob = (const unsigned char*)plist_get_data_ptr(bbticket, &blob_size);
if (!blob) {
- error("ERROR: could not get BBTicket data\n");
+ logger(LL_ERROR, "could not get BBTicket data\n");
goto leave;
}
- zs = zip_source_buffer(za, blob, blob_size, 1);
+ zs = zip_source_buffer(za, blob, blob_size, 0);
if (!zs) {
- error("ERROR: out of memory\n");
+ logger(LL_ERROR, "out of memory\n");
goto leave;
}
- blob = NULL;
- if (zip_add(za, "bbticket.der", zs) == -1) {
- error("ERROR: could not add bbticket.der to archive\n");
+ if (zip_file_add(za, "bbticket.der", zs, ZIP_FL_OVERWRITE) == -1) {
+ logger(LL_ERROR, "could not add bbticket.der to archive\n");
goto leave;
}
}
@@ -1746,7 +2212,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned
// this will write out the modified zip
if (zip_close(za) == -1) {
- error("ERROR: could not close and write modified archive: %s\n", zip_strerror(za));
+ logger(LL_ERROR, "could not close and write modified archive: %s\n", zip_strerror(za));
res = -1;
} else {
res = 0;
@@ -1765,15 +2231,13 @@ leave:
zip_unchange_all(za);
zip_close(za);
}
- mbn_free(mbn);
fls_free(fls);
free(buffer);
- free(blob);
return res;
}
-static int restore_send_baseband_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message)
+static int restore_send_baseband_data(struct idevicerestore_client_t* client, plist_t message)
{
int res = -1;
uint64_t bb_cert_id = 0;
@@ -1787,7 +2251,12 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer
char* bbfwtmp = NULL;
plist_t dict = NULL;
- info("About to send BasebandData...\n");
+ if (!client || !client->restore || !client->restore->build_identity) {
+ logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__);
+ return -1;
+ }
+
+ logger(LL_INFO, "About to send BasebandData...\n");
// NOTE: this function is called 2 or 3 times!
@@ -1823,12 +2292,12 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer
plist_dict_set_item(parameters, "BbGoldCertId", plist_new_uint(bb_cert_id));
plist_dict_set_item(parameters, "BbSNUM", plist_new_data((const char*)bb_snum, bb_snum_size));
- tss_parameters_add_from_manifest(parameters, build_identity);
+ tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true);
/* create baseband request */
plist_t request = tss_request_new(NULL);
if (request == NULL) {
- error("ERROR: Unable to create Baseband TSS request\n");
+ logger(LL_ERROR, "Unable to create Baseband TSS request\n");
plist_free(parameters);
return -1;
}
@@ -1837,7 +2306,7 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer
tss_request_add_common_tags(request, parameters, NULL);
tss_request_add_baseband_tags(request, parameters, NULL);
- plist_t node = plist_access_path(build_identity, 2, "Info", "FDRSupport");
+ plist_t node = plist_access_path(client->restore->build_identity, 2, "Info", "FDRSupport");
if (node && plist_get_node_type(node) == PLIST_BOOLEAN) {
uint8_t b = 0;
plist_get_bool_val(node, &b);
@@ -1846,34 +2315,30 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer
plist_dict_set_item(request, "ApSecurityMode", plist_new_bool(1));
}
}
- if (idevicerestore_debug)
- debug_plist(request);
-
- info("Sending Baseband TSS request...\n");
+ logger(LL_INFO, "Sending Baseband TSS request...\n");
+ logger_dump_plist(LL_DEBUG, request, 0);
response = tss_request_send(request, client->tss_url);
plist_free(request);
plist_free(parameters);
if (response == NULL) {
- error("ERROR: Unable to fetch Baseband TSS\n");
+ logger(LL_ERROR, "Unable to fetch Baseband TSS\n");
return -1;
}
- info("Received Baseband SHSH blobs\n");
-
- if (idevicerestore_debug)
- debug_plist(response);
+ logger(LL_INFO, "Received Baseband SHSH blobs\n");
+ logger_dump_plist(LL_DEBUG, response, 0);
}
// get baseband firmware file path from build identity
- plist_t bbfw_path = plist_access_path(build_identity, 4, "Manifest", "BasebandFirmware", "Info", "Path");
+ plist_t bbfw_path = plist_access_path(client->restore->build_identity, 4, "Manifest", "BasebandFirmware", "Info", "Path");
if (!bbfw_path || plist_get_node_type(bbfw_path) != PLIST_STRING) {
- error("ERROR: Unable to get BasebandFirmware/Info/Path node\n");
+ logger(LL_ERROR, "Unable to get BasebandFirmware/Info/Path node\n");
plist_free(response);
return -1;
}
char* bbfwpath = NULL;
plist_get_string_val(bbfw_path, &bbfwpath);
if (!bbfwpath) {
- error("ERROR: Unable to get baseband path\n");
+ logger(LL_ERROR, "Unable to get baseband path\n");
plist_free(response);
return -1;
}
@@ -1886,10 +2351,10 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer
strcpy(bbfwtmp, "bbfw_");
strncpy(bbfwtmp + 5, client->udid, l);
strcpy(bbfwtmp + 5 + l, ".tmp");
- error("WARNING: Could not generate temporary filename, using %s in current directory\n", bbfwtmp);
+ logger(LL_WARNING, "Could not generate temporary filename, using %s in current directory\n", bbfwtmp);
}
if (ipsw_extract_to_file(client->ipsw, bbfwpath, bbfwtmp) != 0) {
- error("ERROR: Unable to extract baseband firmware from ipsw\n");
+ logger(LL_ERROR, "Unable to extract baseband firmware from ipsw\n");
goto leave;
}
@@ -1899,7 +2364,7 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer
response = NULL;
}
- res = restore_sign_bbfw(bbfwtmp, (client->restore->bbtss) ? client->restore->bbtss : response, bb_nonce);
+ res = restore_sign_bbfw(bbfwtmp, (client->restore->bbtss) ? client->restore->bbtss : response, bb_nonce, bb_chip_id);
if (res != 0) {
goto leave;
}
@@ -1908,30 +2373,44 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer
size_t sz = 0;
if (read_file(bbfwtmp, (void**)&buffer, &sz) < 0) {
- error("ERROR: could not read updated bbfw archive\n");
+ logger(LL_ERROR, "could not read updated bbfw archive\n");
goto leave;
}
// send file
dict = plist_new_dict();
- plist_dict_set_item(dict, "BasebandData", plist_new_data(buffer, (uint64_t)sz));
+ plist_dict_set_item(dict, "BasebandData", plist_new_data(buffer, sz));
free(buffer);
buffer = NULL;
- info("Sending BasebandData now...\n");
- if (restored_send(restore, dict) != RESTORE_E_SUCCESS) {
- error("ERROR: Unable to send BasebandData data\n");
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__);
+ return -1;
+ }
+
+ logger(LL_INFO, "Sending BasebandData now...\n");
+ if (_restore_service_send(service, dict, 0) != RESTORE_E_SUCCESS) {
+ logger(LL_ERROR, "Unable to send BasebandData data\n");
goto leave;
}
- info("Done sending BasebandData\n");
+ _restore_service_free(service);
+
+ logger(LL_INFO, "Done sending BasebandData\n");
res = 0;
leave:
plist_free(dict);
free(buffer);
if (bbfwtmp) {
- remove(bbfwtmp);
+ if (client->flags & FLAG_KEEP_PERS) {
+ const char* bbfwname = path_get_basename(bbfwtmp);
+ logger(LL_VERBOSE, "%s: Keeping personalized BBFW as %s\n", __func__, bbfwname);
+ rename(bbfwtmp, bbfwname);
+ } else {
+ remove(bbfwtmp);
+ }
free(bbfwtmp);
}
plist_free(response);
@@ -1939,32 +2418,39 @@ leave:
return res;
}
-int restore_send_fdr_trust_data(restored_client_t restore, idevice_t device)
+int restore_send_fdr_trust_data(struct idevicerestore_client_t* client, plist_t message)
{
restored_error_t restore_error;
plist_t dict;
- info("About to send FDR Trust data...\n");
+ logger(LL_INFO, "About to send FDR Trust data...\n");
// FIXME: What should we send here?
/* Sending an empty dict makes it continue with FDR
* and this is what iTunes seems to be doing too */
dict = plist_new_dict();
- info("Sending FDR Trust data now...\n");
- restore_error = restored_send(restore, dict);
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__);
+ return -1;
+ }
+
+ logger(LL_INFO, "Sending FDR Trust data now...\n");
+ restore_error = _restore_service_send(service, dict, 0);
plist_free(dict);
+ _restore_service_free(service);
if (restore_error != RESTORE_E_SUCCESS) {
- error("ERROR: During sending FDR Trust data (%d)\n", restore_error);
+ logger(LL_ERROR, "During sending FDR Trust data (%d)\n", restore_error);
return -1;
}
- info("Done sending FDR Trust Data\n");
+ logger(LL_INFO, "Done sending FDR Trust Data\n");
return 0;
}
-static int restore_send_image_data(restored_client_t restore, struct idevicerestore_client_t *client, plist_t build_identity, plist_t message, const char *image_list_k, const char *image_type_k, const char *image_data_k)
+static int restore_send_image_data(struct idevicerestore_client_t *client, plist_t message, const char *image_list_k, const char *image_type_k, const char *image_data_k)
{
restored_error_t restore_error;
plist_t arguments;
@@ -1977,8 +2463,13 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest
char *image_name = NULL;
int want_image_list = 0;
+ if (!client || !client->restore || !client->restore->build_identity) {
+ logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__);
+ return -1;
+ }
+
arguments = plist_dict_get_item(message, "Arguments");
- want_image_list = _plist_dict_get_bool(arguments, image_list_k);
+ want_image_list = plist_dict_get_bool(arguments, image_list_k);
node = plist_dict_get_item(arguments, "ImageName");
if (node) {
plist_get_string_val(node, &image_name);
@@ -1990,12 +2481,12 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest
}
}
if (!image_type_k) {
- error("ERROR: missing ImageType");
+ logger(LL_ERROR, "Missing ImageType\n");
return -1;
}
if (!want_image_list && !image_name) {
- info("About to send %s...\n", image_data_k);
+ logger(LL_INFO, "About to send %s...\n", image_data_k);
}
if (want_image_list) {
@@ -2004,7 +2495,7 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest
data_dict = plist_new_dict();
}
- build_id_manifest = plist_dict_get_item(build_identity, "Manifest");
+ build_id_manifest = plist_dict_get_item(client->restore->build_identity, "Manifest");
if (build_id_manifest) {
plist_dict_new_iter(build_id_manifest, &iter);
}
@@ -2023,34 +2514,34 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest
}
if (is_image_type) {
if (want_image_list) {
- info("Found %s component %s\n", image_type_k, component);
+ logger(LL_INFO, "Found %s component %s\n", image_type_k, component);
plist_array_append_item(matched_images, plist_new_string(component));
} else if (!image_name || !strcmp(image_name, component)) {
char *path = NULL;
- unsigned char* data = NULL;
- unsigned int size = 0;
- unsigned char* component_data = NULL;
- unsigned int component_size = 0;
+ void* data = NULL;
+ size_t size = 0;
+ void* component_data = NULL;
+ size_t component_size = 0;
int ret = -1;
if (!image_name) {
- info("Found %s component '%s'\n", image_type_k, component);
+ logger(LL_INFO, "Found %s component '%s'\n", image_type_k, component);
}
- build_identity_get_component_path(build_identity, component, &path);
+ build_identity_get_component_path(client->restore->build_identity, component, &path);
if (path) {
ret = extract_component(client->ipsw, path, &component_data, &component_size);
}
free(path);
path = NULL;
if (ret < 0) {
- error("ERROR: Unable to extract component: %s\n", component);
+ logger(LL_ERROR, "Unable to extract component: %s\n", component);
}
- ret = personalize_component(component, component_data, component_size, client->tss, &data, &size);
+ ret = personalize_component(client, component, component_data, component_size, client->tss, &data, &size);
free(component_data);
component_data = NULL;
if (ret < 0) {
- error("ERROR: Unable to get personalized component: %s\n", component);
+ logger(LL_ERROR, "Unable to get personalized component: %s\n", component);
}
plist_dict_set_item(data_dict, component, plist_new_data((const char*)data, size));
@@ -2063,10 +2554,16 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest
free(iter);
}
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__);
+ return -1;
+ }
+
dict = plist_new_dict();
if (want_image_list) {
plist_dict_set_item(dict, image_list_k, matched_images);
- info("Sending %s image list\n", image_type_k);
+ logger(LL_INFO, "Sending %s image list\n", image_type_k);
} else {
if (image_name) {
node = plist_dict_get_item(data_dict, image_name);
@@ -2074,24 +2571,25 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest
plist_dict_set_item(dict, image_data_k, plist_copy(node));
}
plist_dict_set_item(dict, "ImageName", plist_new_string(image_name));
- info("Sending %s for %s...\n", image_type_k, image_name);
+ logger(LL_INFO, "Sending %s for %s...\n", image_type_k, image_name);
} else {
plist_dict_set_item(dict, image_data_k, data_dict);
- info("Sending %s now...\n", image_type_k);
+ logger(LL_INFO, "Sending %s now...\n", image_type_k);
}
}
- restore_error = restored_send(restore, dict);
+ restore_error = _restore_service_send(service, dict, 0);
plist_free(dict);
+ _restore_service_free(service);
if (restore_error != RESTORE_E_SUCCESS) {
if (want_image_list) {
- error("ERROR: Failed to send %s image list (%d)\n", image_type_k, restore_error);
+ logger(LL_ERROR, "Failed to send %s image list (%d)\n", image_type_k, restore_error);
} else {
if (image_name) {
- error("ERROR: Failed to send %s for %s (%d)\n", image_type_k, image_name, restore_error);
+ logger(LL_ERROR, "Failed to send %s for %s (%d)\n", image_type_k, image_name, restore_error);
free(image_name);
} else {
- error("ERROR: Failed to send %s (%d)\n", image_type_k, restore_error);
+ logger(LL_ERROR, "Failed to send %s (%d)\n", image_type_k, restore_error);
}
}
return -1;
@@ -2101,62 +2599,86 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest
if (image_name) {
free(image_name);
} else {
- info("Done sending %s\n", image_type_k);
+ logger(LL_INFO, "Done sending %s\n", image_type_k);
}
}
return 0;
}
-static plist_t restore_get_se_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info)
+static int _wants_firmware_data(plist_t arguments)
+{
+ int result = 0;
+ plist_t tags = plist_access_path(arguments, 2, "DeviceGeneratedTags", "ResponseTags");
+ if (tags) {
+ plist_array_iter iter = NULL;
+ plist_array_new_iter(tags, &iter);
+ plist_t node = NULL;
+ do {
+ plist_array_next_item(tags, iter, &node);
+ if (node) {
+ const char* tag = plist_get_string_ptr(node, NULL);
+ if (tag && (strcmp(tag, "FirmwareData") == 0)) {
+ result = 1;
+ }
+ }
+ } while (node);
+ plist_mem_free(iter);
+ }
+ return result;
+}
+
+static plist_t restore_get_se_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments)
{
const char *comp_name = NULL;
char *comp_path = NULL;
- unsigned char* component_data = NULL;
- unsigned int component_size = 0;
+ void* component_data = NULL;
+ size_t component_size = 0;
plist_t parameters = NULL;
plist_t request = NULL;
plist_t response = NULL;
+ plist_t p_dgr = NULL;
int ret;
uint64_t chip_id = 0;
+
+ if (!client || !client->restore || !client->restore->build_identity) {
+ logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__);
+ return NULL;
+ }
+
plist_t node = plist_dict_get_item(p_info, "SE,ChipID");
if (node && plist_get_node_type(node) == PLIST_UINT) {
plist_get_uint_val(node, &chip_id);
}
if (chip_id == 0x20211) {
comp_name = "SE,Firmware";
- } else if (chip_id == 0x73 || chip_id == 0x64 || chip_id == 0xC8 || chip_id == 0xD2) {
+ } else if (chip_id == 0x73 || chip_id == 0x64 || chip_id == 0xC8 || chip_id == 0xD2 || chip_id == 0x2C || chip_id == 0x36 || chip_id == 0x37) {
comp_name = "SE,UpdatePayload";
} else {
- info("WARNING: Unknown SE,ChipID 0x%" PRIx64 " detected. Restore might fail.\n", (uint64_t)chip_id);
- if (build_identity_has_component(build_identity, "SE,UpdatePayload"))
+ logger(LL_WARNING, "Unknown SE,ChipID 0x%" PRIx64 " detected. Restore might fail.\n", (uint64_t)chip_id);
+ if (build_identity_has_component(client->restore->build_identity, "SE,UpdatePayload"))
comp_name = "SE,UpdatePayload";
- else if (build_identity_has_component(build_identity, "SE,Firmware"))
+ else if (build_identity_has_component(client->restore->build_identity, "SE,Firmware"))
comp_name = "SE,Firmware";
else {
- error("ERROR: Neither 'SE,Firmware' nor 'SE,UpdatePayload' found in build identity.\n");
+ logger(LL_ERROR, "Neither 'SE,Firmware' nor 'SE,UpdatePayload' found in build identity.\n");
return NULL;
}
- debug("DEBUG: %s: using %s\n", __func__, comp_name);
+ logger(LL_DEBUG, "%s: using %s\n", __func__, comp_name);
}
- if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) {
- error("ERROR: Unable to get path for '%s' component\n", comp_name);
- return NULL;
- }
-
- ret = extract_component(client->ipsw, comp_path, &component_data, &component_size);
- free(comp_path);
- comp_path = NULL;
- if (ret < 0) {
- error("ERROR: Unable to extract '%s' component\n", comp_name);
+ p_dgr = plist_dict_get_item(arguments, "DeviceGeneratedRequest");
+ if (!p_dgr) {
+ logger(LL_NOTICE, "%s: No DeviceGeneratedRequest in firmware updater data request. Continuing anyway.\n", __func__);
+ } else if (!PLIST_IS_DICT(p_dgr)) {
+ logger(LL_ERROR, "%s: DeviceGeneratedRequest has invalid type!\n", __func__);
return NULL;
}
/* create SE request */
request = tss_request_new(NULL);
if (request == NULL) {
- error("ERROR: Unable to create SE TSS request\n");
+ logger(LL_ERROR, "Unable to create SE TSS request\n");
free(component_data);
return NULL;
}
@@ -2164,32 +2686,55 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id
parameters = plist_new_dict();
/* add manifest for current build_identity to parameters */
- tss_parameters_add_from_manifest(parameters, build_identity);
+ tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true);
/* add SE,* tags from info dictionary to parameters */
plist_dict_merge(&parameters, p_info);
/* add required tags for SE TSS request */
- tss_request_add_se_tags(request, parameters, NULL);
+ tss_request_add_se_tags(request, parameters, p_dgr);
plist_free(parameters);
- info("Sending SE TSS request...\n");
+ logger(LL_INFO, "Sending SE TSS request...\n");
response = tss_request_send(request, client->tss_url);
plist_free(request);
if (response == NULL) {
- error("ERROR: Unable to fetch SE ticket\n");
+ logger(LL_ERROR, "Unable to fetch SE ticket\n");
free(component_data);
return NULL;
}
- if (plist_dict_get_item(response, "SE,Ticket")) {
- info("Received SE ticket\n");
+ if (plist_dict_get_item(response, "SE2,Ticket")) {
+ logger(LL_INFO, "Received SE2,Ticket\n");
+ } else if (plist_dict_get_item(response, "SE,Ticket")) {
+ logger(LL_INFO, "Received SE,Ticket\n");
} else {
- error("ERROR: No 'SE,Ticket' in TSS response, this might not work\n");
+ logger(LL_ERROR, "No 'SE ticket' in TSS response, this might not work\n");
+ }
+
+ /* don't add FirmwareData if not requested via ResponseTags */
+ if (!_wants_firmware_data(arguments)) {
+ logger(LL_DEBUG, "Not adding FirmwareData as it was not requested\n");
+ return response;
+ }
+
+ if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) {
+ plist_free(response);
+ logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name);
+ return NULL;
}
- plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, (uint64_t) component_size));
+ ret = extract_component(client->ipsw, comp_path, &component_data, &component_size);
+ free(comp_path);
+ comp_path = NULL;
+ if (ret < 0) {
+ plist_free(response);
+ logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name);
+ return NULL;
+ }
+
+ plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size));
free(component_data);
component_data = NULL;
component_size = 0;
@@ -2197,64 +2742,81 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id
return response;
}
-static plist_t restore_get_savage_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info)
+static plist_t restore_get_savage_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments)
{
char *comp_name = NULL;
char *comp_path = NULL;
- unsigned char* component_data = NULL;
- unsigned int component_size = 0;
- unsigned char* component_data_tmp = NULL;
+ void* component_data = NULL;
+ size_t component_size = 0;
+ void* component_data_tmp = NULL;
plist_t parameters = NULL;
plist_t request = NULL;
plist_t response = NULL;
- plist_t node = NULL;
int ret;
+ if (!client || !client->restore || !client->restore->build_identity) {
+ logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__);
+ return NULL;
+ }
+
+ plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest");
+ if (device_generated_request && !PLIST_IS_DICT(device_generated_request)) {
+ logger(LL_ERROR, "%s: DeviceGeneratedRequest has invalid type!\n", __func__);
+ return NULL;
+ }
+
/* create Savage request */
request = tss_request_new(NULL);
if (request == NULL) {
- error("ERROR: Unable to create Savage TSS request\n");
+ logger(LL_ERROR, "Unable to create Savage TSS request\n");
return NULL;
}
parameters = plist_new_dict();
/* add manifest for current build_identity to parameters */
- tss_parameters_add_from_manifest(parameters, build_identity);
+ tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true);
/* add Savage,* tags from info dictionary to parameters */
plist_dict_merge(&parameters, p_info);
/* add required tags for Savage TSS request */
- tss_request_add_savage_tags(request, parameters, NULL, &comp_name);
+ tss_request_add_savage_tags(request, parameters, device_generated_request, &comp_name);
plist_free(parameters);
if (!comp_name) {
- error("ERROR: Could not determine Savage firmware component\n");
+ logger(LL_ERROR, "Could not determine Savage firmware component\n");
plist_free(request);
return NULL;
}
- debug("DEBUG: %s: using %s\n", __func__, comp_name);
+ logger(LL_DEBUG, "%s: using %s\n", __func__, comp_name);
- info("Sending Savage TSS request...\n");
+ logger(LL_INFO, "Sending Savage TSS request...\n");
response = tss_request_send(request, client->tss_url);
plist_free(request);
if (response == NULL) {
- error("ERROR: Unable to fetch Savage ticket\n");
+ logger(LL_ERROR, "Unable to fetch Savage ticket\n");
free(comp_name);
return NULL;
}
if (plist_dict_get_item(response, "Savage,Ticket")) {
- info("Received Savage ticket\n");
+ logger(LL_INFO, "Received Savage ticket\n");
} else {
- error("ERROR: No 'Savage,Ticket' in TSS response, this might not work\n");
+ logger(LL_ERROR, "No 'Savage,Ticket' in TSS response, this might not work\n");
+ }
+
+ /* don't add FirmwareData if not requested via ResponseTags */
+ if (!_wants_firmware_data(arguments)) {
+ logger(LL_DEBUG, "Not adding FirmwareData as it was not requested\n");
+ return response;
}
/* now get actual component data */
- if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) {
- error("ERROR: Unable to get path for '%s' component\n", comp_name);
+ if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) {
+ plist_free(response);
+ logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name);
free(comp_name);
return NULL;
}
@@ -2263,7 +2825,8 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc
free(comp_path);
comp_path = NULL;
if (ret < 0) {
- error("ERROR: Unable to extract '%s' component\n", comp_name);
+ plist_free(response);
+ logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name);
free(comp_name);
return NULL;
}
@@ -2273,6 +2836,7 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc
component_data_tmp = realloc(component_data, (size_t)component_size+16);
if (!component_data_tmp) {
free(component_data);
+ plist_free(response);
return NULL;
}
component_data = component_data_tmp;
@@ -2281,7 +2845,7 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc
*(uint32_t*)(component_data + 4) = htole32((uint32_t)component_size);
component_size += 16;
- plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, (uint64_t) component_size));
+ plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size));
free(component_data);
component_data = NULL;
component_size = 0;
@@ -2289,65 +2853,80 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc
return response;
}
-static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info)
+static plist_t restore_get_yonkers_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments)
{
char *comp_name = NULL;
char *comp_path = NULL;
- plist_t comp_node = NULL;
- unsigned char* component_data = NULL;
- unsigned int component_size = 0;
+ void* component_data = NULL;
+ size_t component_size = 0;
plist_t parameters = NULL;
plist_t request = NULL;
plist_t response = NULL;
- plist_t node = NULL;
int ret;
+ if (!client || !client->restore || !client->restore->build_identity) {
+ logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__);
+ return NULL;
+ }
+
+ plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest");
+ if (device_generated_request && !PLIST_IS_DICT(device_generated_request)) {
+ logger(LL_ERROR, "%s: DeviceGeneratedRequest has invalid type!\n", __func__);
+ return NULL;
+ }
+
/* create Yonkers request */
request = tss_request_new(NULL);
if (request == NULL) {
- error("ERROR: Unable to create Yonkers TSS request\n");
- free(component_data);
- free(comp_name);
+ logger(LL_ERROR, "Unable to create Yonkers TSS request\n");
return NULL;
}
parameters = plist_new_dict();
/* add manifest for current build_identity to parameters */
- tss_parameters_add_from_manifest(parameters, build_identity);
+ tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true);
/* add Yonkers,* tags from info dictionary to parameters */
plist_dict_merge(&parameters, p_info);
/* add required tags for Yonkers TSS request */
- tss_request_add_yonkers_tags(request, parameters, NULL, &comp_name);
+ tss_request_add_yonkers_tags(request, parameters, device_generated_request, &comp_name);
plist_free(parameters);
if (!comp_name) {
- error("ERROR: Could not determine Yonkers firmware component\n");
+ logger(LL_ERROR, "Could not determine Yonkers firmware component\n");
plist_free(request);
return NULL;
}
- debug("DEBUG: %s: using %s\n", __func__, comp_name);
+ logger(LL_DEBUG, "%s: using %s\n", __func__, comp_name);
- info("Sending Yonkers TSS request...\n");
+ logger(LL_INFO, "Sending Yonkers TSS request...\n");
response = tss_request_send(request, client->tss_url);
plist_free(request);
if (response == NULL) {
- error("ERROR: Unable to fetch Yonkers ticket\n");
- free(component_data);
+ logger(LL_ERROR, "Unable to fetch Yonkers ticket\n");
+ free(comp_name);
return NULL;
}
if (plist_dict_get_item(response, "Yonkers,Ticket")) {
- info("Received Yonkers ticket\n");
+ logger(LL_INFO, "Received Yonkers ticket\n");
} else {
- error("ERROR: No 'Yonkers,Ticket' in TSS response, this might not work\n");
+ logger(LL_ERROR, "No 'Yonkers,Ticket' in TSS response, this might not work\n");
}
- if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) {
- error("ERROR: Unable to get path for '%s' component\n", comp_name);
+ /* don't add FirmwareData if not requested via ResponseTags */
+ if (!_wants_firmware_data(arguments)) {
+ logger(LL_DEBUG, "Not adding FirmwareData as it was not requested\n");
+ free(comp_name);
+ return response;
+ }
+
+ if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) {
+ plist_free(response);
+ logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name);
free(comp_name);
return NULL;
}
@@ -2357,7 +2936,8 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru
free(comp_path);
comp_path = NULL;
if (ret < 0) {
- error("ERROR: Unable to extract '%s' component\n", comp_name);
+ plist_free(response);
+ logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name);
free(comp_name);
return NULL;
}
@@ -2365,7 +2945,7 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru
comp_name = NULL;
plist_t firmware_data = plist_new_dict();
- plist_dict_set_item(firmware_data, "YonkersFirmware", plist_new_data((char *)component_data, (uint64_t)component_size));
+ plist_dict_set_item(firmware_data, "YonkersFirmware", plist_new_data((char*)component_data, component_size));
plist_dict_set_item(response, "FirmwareData", firmware_data);
free(component_data);
@@ -2375,34 +2955,36 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru
return response;
}
-static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info)
+static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments)
{
char *comp_name = NULL;
char *comp_path = NULL;
- plist_t comp_node = NULL;
- unsigned char* component_data = NULL;
- unsigned int component_size = 0;
+ void* component_data = NULL;
+ size_t component_size = 0;
ftab_t ftab = NULL;
ftab_t rftab = NULL;
uint32_t ftag = 0;
plist_t parameters = NULL;
plist_t request = NULL;
plist_t response = NULL;
- plist_t node = NULL;
int ret;
+ if (!client || !client->restore || !client->restore->build_identity) {
+ logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__);
+ return NULL;
+ }
+
/* create Rose request */
request = tss_request_new(NULL);
if (request == NULL) {
- error("ERROR: Unable to create Rose TSS request\n");
- free(component_data);
+ logger(LL_ERROR, "Unable to create Rose TSS request\n");
return NULL;
}
parameters = plist_new_dict();
/* add manifest for current build_identity to parameters */
- tss_parameters_add_from_manifest(parameters, build_identity);
+ tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true);
plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1));
if (client->image4supported) {
@@ -2412,58 +2994,73 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct
plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(0));
}
- /* add Rap,* tags from info dictionary to parameters */
- plist_dict_merge(&parameters, p_info);
+ plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest");
+ if (device_generated_request) {
+ /* use DeviceGeneratedRequest if present */
+ plist_dict_merge(&request, device_generated_request);
+ } else {
+ /* add Rap,* tags from info dictionary to parameters */
+ plist_dict_merge(&parameters, p_info);
+ }
/* add required tags for Rose TSS request */
tss_request_add_rose_tags(request, parameters, NULL);
plist_free(parameters);
- info("Sending Rose TSS request...\n");
+ logger(LL_INFO, "Sending Rose TSS request...\n");
response = tss_request_send(request, client->tss_url);
plist_free(request);
if (response == NULL) {
- error("ERROR: Unable to fetch Rose ticket\n");
- free(component_data);
+ logger(LL_ERROR, "Unable to fetch Rose ticket\n");
return NULL;
}
if (plist_dict_get_item(response, "Rap,Ticket")) {
- info("Received Rose ticket\n");
+ logger(LL_INFO, "Received Rose ticket\n");
} else {
- error("ERROR: No 'Rap,Ticket' in TSS response, this might not work\n");
+ logger(LL_ERROR, "No 'Rap,Ticket' in TSS response, this might not work\n");
+ }
+
+ /* don't add FirmwareData if not requested via ResponseTags */
+ if (!_wants_firmware_data(arguments)) {
+ logger(LL_DEBUG, "Not adding FirmwareData as it was not requested\n");
+ return response;
}
comp_name = "Rap,RTKitOS";
- if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) {
- error("ERROR: Unable to get path for '%s' component\n", comp_name);
+ if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) {
+ plist_free(response);
+ logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name);
return NULL;
}
ret = extract_component(client->ipsw, comp_path, &component_data, &component_size);
free(comp_path);
comp_path = NULL;
if (ret < 0) {
- error("ERROR: Unable to extract '%s' component\n", comp_name);
+ plist_free(response);
+ logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name);
return NULL;
}
if (ftab_parse(component_data, component_size, &ftab, &ftag) != 0) {
+ plist_free(response);
free(component_data);
- error("ERROR: Failed to parse '%s' component data.\n", comp_name);
+ logger(LL_ERROR, "Failed to parse '%s' component data.\n", comp_name);
return NULL;
}
free(component_data);
component_data = NULL;
component_size = 0;
if (ftag != 'rkos') {
- error("WARNING: Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos');
+ logger(LL_WARNING, "Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos');
}
comp_name = "Rap,RestoreRTKitOS";
- if (build_identity_has_component(build_identity, comp_name)) {
- if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) {
+ if (build_identity_has_component(client->restore->build_identity, comp_name)) {
+ if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) {
ftab_free(ftab);
- error("ERROR: Unable to get path for '%s' component\n", comp_name);
+ plist_free(response);
+ logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name);
return NULL;
}
ret = extract_component(client->ipsw, comp_path, &component_data, &component_size);
@@ -2471,7 +3068,8 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct
comp_path = NULL;
if (ret < 0) {
ftab_free(ftab);
- error("ERROR: Unable to extract '%s' component\n", comp_name);
+ plist_free(response);
+ logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name);
return NULL;
}
@@ -2479,32 +3077,33 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct
if (ftab_parse(component_data, component_size, &rftab, &ftag) != 0) {
free(component_data);
ftab_free(ftab);
- error("ERROR: Failed to parse '%s' component data.\n", comp_name);
+ plist_free(response);
+ logger(LL_ERROR, "Failed to parse '%s' component data.\n", comp_name);
return NULL;
}
free(component_data);
component_data = NULL;
component_size = 0;
if (ftag != 'rkos') {
- error("WARNING: Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos');
+ logger(LL_WARNING, "Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos');
}
if (ftab_get_entry_ptr(rftab, 'rrko', &component_data, &component_size) == 0) {
ftab_add_entry(ftab, 'rrko', component_data, component_size);
} else {
- error("ERROR: Could not find 'rrko' entry in ftab. This will probably break things.\n");
+ logger(LL_ERROR, "Could not find 'rrko' entry in ftab. This will probably break things.\n");
}
ftab_free(rftab);
component_data = NULL;
component_size = 0;
} else {
- info("NOTE: Build identity does not have a '%s' component.\n", comp_name);
+ logger(LL_NOTICE, "Build identity does not have a '%s' component.\n", comp_name);
}
ftab_write(ftab, &component_data, &component_size);
ftab_free(ftab);
- plist_dict_set_item(response, "FirmwareData", plist_new_data((char *)component_data, (uint64_t)component_size));
+ plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size));
free(component_data);
component_data = NULL;
component_size = 0;
@@ -2512,23 +3111,32 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct
return response;
}
-static plist_t restore_get_veridian_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info)
+static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments)
{
char *comp_name = "BMU,FirmwareMap";
char *comp_path = NULL;
- plist_t comp_node = NULL;
- unsigned char* component_data = NULL;
- unsigned int component_size = 0;
+ void* component_data = NULL;
+ size_t component_size = 0;
plist_t parameters = NULL;
plist_t request = NULL;
plist_t response = NULL;
- plist_t node = NULL;
int ret;
+ if (!client || !client->restore || !client->restore->build_identity) {
+ logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__);
+ return NULL;
+ }
+
+ plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest");
+ if (device_generated_request && !PLIST_IS_DICT(device_generated_request)) {
+ logger(LL_ERROR, "%s: DeviceGeneratedRequest has invalid type!\n", __func__);
+ return NULL;
+ }
+
/* create Veridian request */
request = tss_request_new(NULL);
if (request == NULL) {
- error("ERROR: Unable to create Veridian TSS request\n");
+ logger(LL_ERROR, "Unable to create Veridian TSS request\n");
free(component_data);
return NULL;
}
@@ -2536,33 +3144,40 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str
parameters = plist_new_dict();
/* add manifest for current build_identity to parameters */
- tss_parameters_add_from_manifest(parameters, build_identity);
+ tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true);
/* add BMU,* tags from info dictionary to parameters */
plist_dict_merge(&parameters, p_info);
/* add required tags for Veridian TSS request */
- tss_request_add_veridian_tags(request, parameters, NULL);
+ tss_request_add_veridian_tags(request, parameters, device_generated_request);
plist_free(parameters);
- info("Sending Veridian TSS request...\n");
+ logger(LL_INFO, "Sending Veridian TSS request...\n");
response = tss_request_send(request, client->tss_url);
plist_free(request);
if (response == NULL) {
- error("ERROR: Unable to fetch Veridian ticket\n");
+ logger(LL_ERROR, "Unable to fetch Veridian ticket\n");
free(component_data);
return NULL;
}
if (plist_dict_get_item(response, "BMU,Ticket")) {
- info("Received Veridian ticket\n");
+ logger(LL_INFO, "Received Veridian ticket\n");
} else {
- error("ERROR: No 'BMU,Ticket' in TSS response, this might not work\n");
+ logger(LL_ERROR, "No 'BMU,Ticket' in TSS response, this might not work\n");
+ }
+
+ /* don't add FirmwareData if not requested via ResponseTags */
+ if (!_wants_firmware_data(arguments)) {
+ logger(LL_DEBUG, "Not adding FirmwareData as it was not requested\n");
+ return response;
}
- if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) {
- error("ERROR: Unable to get path for '%s' component\n", comp_name);
+ if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) {
+ plist_free(response);
+ logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name);
return NULL;
}
@@ -2571,7 +3186,8 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str
free(comp_path);
comp_path = NULL;
if (ret < 0) {
- error("ERROR: Unable to extract '%s' component\n", comp_name);
+ plist_free(response);
+ logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name);
return NULL;
}
@@ -2586,14 +3202,16 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str
component_size = 0;
if (!fw_map) {
- error("ERROR: Unable to parse '%s' component data as plist\n", comp_name);
+ plist_free(response);
+ logger(LL_ERROR, "Unable to parse '%s' component data as plist\n", comp_name);
return NULL;
}
- plist_t fw_map_digest = plist_access_path(build_identity, 3, "Manifest", comp_name, "Digest");
+ plist_t fw_map_digest = plist_access_path(client->restore->build_identity, 3, "Manifest", comp_name, "Digest");
if (!fw_map_digest) {
plist_free(fw_map);
- error("ERROR: Unable to get Digest for '%s' component\n", comp_name);
+ plist_free(response);
+ logger(LL_ERROR, "Unable to get Digest for '%s' component\n", comp_name);
return NULL;
}
@@ -2604,29 +3222,95 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str
plist_to_bin(fw_map, &bin_plist, &bin_size);
plist_free(fw_map);
- plist_dict_set_item(response, "FirmwareData", plist_new_data(bin_plist, (uint64_t)bin_size));
+ plist_dict_set_item(response, "FirmwareData", plist_new_data(bin_plist, bin_size));
free(bin_plist);
return response;
}
-static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info)
+static plist_t restore_get_generic_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments)
+{
+ plist_t request = NULL;
+ plist_t response = NULL;
+
+ plist_t p_updater_name = plist_dict_get_item(arguments, "MessageArgUpdaterName");
+ const char* s_updater_name = plist_get_string_ptr(p_updater_name, NULL);
+
+ plist_t response_tags = plist_access_path(arguments, 2, "DeviceGeneratedTags", "ResponseTags");
+ const char* response_ticket = NULL;
+ if (PLIST_IS_ARRAY(response_tags)) {
+ plist_t tag0 = plist_array_get_item(response_tags, 0);
+ if (tag0) {
+ response_ticket = plist_get_string_ptr(tag0, NULL);
+ }
+ }
+ if (response_ticket == NULL) {
+ logger(LL_ERROR, "Unable to determine response ticket from device generated tags\n");
+ return NULL;
+ }
+
+ /* create TSS request */
+ request = tss_request_new(NULL);
+ if (request == NULL) {
+ logger(LL_ERROR, "Unable to create %s TSS request\n", s_updater_name);
+ return NULL;
+ }
+
+ /* add device generated request data to request */
+ plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest");
+ if (!device_generated_request) {
+ logger(LL_ERROR, "Could not find DeviceGeneratedRequest in arguments dictionary\n");
+ plist_free(request);
+ return NULL;
+ }
+ plist_dict_merge(&request, device_generated_request);
+
+ logger(LL_INFO, "Sending %s TSS request...\n", s_updater_name);
+ logger_dump_plist(LL_DEBUG, request, 0);
+ response = tss_request_send(request, client->tss_url);
+ plist_free(request);
+ if (response == NULL) {
+ logger(LL_ERROR, "Unable to fetch %s ticket\n", s_updater_name);
+ return NULL;
+ }
+ logger_dump_plist(LL_DEBUG, response, 0);
+
+ if (plist_dict_get_item(response, response_ticket)) {
+ logger(LL_INFO, "Received %s\n", response_ticket);
+ } else {
+ logger(LL_ERROR, "No '%s' in TSS response, this might not work\n", response_ticket);
+ logger_dump_plist(LL_VERBOSE, response, 0);
+ }
+
+ return response;
+}
+
+static plist_t restore_get_tcon_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments)
{
char *comp_name = "Baobab,TCON";
char *comp_path = NULL;
- plist_t comp_node = NULL;
- unsigned char* component_data = NULL;
- unsigned int component_size = 0;
+ void* component_data = NULL;
+ size_t component_size = 0;
plist_t parameters = NULL;
plist_t request = NULL;
plist_t response = NULL;
- plist_t node = NULL;
int ret;
+ if (!client || !client->restore || !client->restore->build_identity) {
+ logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__);
+ return NULL;
+ }
+
+ plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest");
+ if (device_generated_request && !PLIST_IS_DICT(device_generated_request)) {
+ logger(LL_ERROR, "%s: DeviceGeneratedRequest has invalid type!\n", __func__);
+ return NULL;
+ }
+
/* create Baobab request */
request = tss_request_new(NULL);
if (request == NULL) {
- error("ERROR: Unable to create Baobab TSS request\n");
+ logger(LL_ERROR, "Unable to create Baobab TSS request\n");
free(component_data);
return NULL;
}
@@ -2634,33 +3318,40 @@ static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct
parameters = plist_new_dict();
/* add manifest for current build_identity to parameters */
- tss_parameters_add_from_manifest(parameters, build_identity);
+ tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true);
/* add Baobab,* tags from info dictionary to parameters */
plist_dict_merge(&parameters, p_info);
/* add required tags for Baobab TSS request */
- tss_request_add_tcon_tags(request, parameters, NULL);
+ tss_request_add_tcon_tags(request, parameters, device_generated_request);
plist_free(parameters);
- info("Sending Baobab TSS request...\n");
+ logger(LL_INFO, "Sending Baobab TSS request...\n");
response = tss_request_send(request, client->tss_url);
plist_free(request);
if (response == NULL) {
- error("ERROR: Unable to fetch Baobab ticket\n");
+ logger(LL_ERROR, "Unable to fetch Baobab ticket\n");
free(component_data);
return NULL;
}
if (plist_dict_get_item(response, "Baobab,Ticket")) {
- info("Received Baobab ticket\n");
+ logger(LL_INFO, "Received Baobab ticket\n");
} else {
- error("ERROR: No 'Baobab,Ticket' in TSS response, this might not work\n");
+ logger(LL_ERROR, "No 'Baobab,Ticket' in TSS response, this might not work\n");
}
- if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) {
- error("ERROR: Unable to get path for '%s' component\n", comp_name);
+ /* don't add FirmwareData if not requested via ResponseTags */
+ if (!_wants_firmware_data(arguments)) {
+ logger(LL_DEBUG, "Not adding FirmwareData as it was not requested\n");
+ return response;
+ }
+
+ if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) {
+ logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name);
+ plist_free(response);
return NULL;
}
@@ -2669,11 +3360,220 @@ static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct
free(comp_path);
comp_path = NULL;
if (ret < 0) {
- error("ERROR: Unable to extract '%s' component\n", comp_name);
+ logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name);
+ plist_free(response);
+ return NULL;
+ }
+
+ plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size));
+ free(component_data);
+ component_data = NULL;
+ component_size = 0;
+
+ return response;
+}
+
+static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments)
+{
+ char comp_name[64];
+ char *comp_path = NULL;
+ void* component_data = NULL;
+ size_t component_size = 0;
+ ftab_t ftab = NULL;
+ ftab_t rftab = NULL;
+ uint32_t ftag = 0;
+ plist_t parameters = NULL;
+ plist_t request = NULL;
+ plist_t response = NULL;
+ const char* ticket_name = NULL;
+ uint32_t tag = 0;
+ int ret;
+
+ if (!client || !client->restore || !client->restore->build_identity) {
+ logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__);
+ return NULL;
+ }
+
+ plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest");
+ if (device_generated_request && !PLIST_IS_DICT(device_generated_request)) {
+ logger(LL_ERROR, "%s: DeviceGeneratedRequest has invalid type!\n", __func__);
+ return NULL;
+ }
+
+ /* create Timer request */
+ request = tss_request_new(NULL);
+ if (request == NULL) {
+ logger(LL_ERROR, "Unable to create Timer TSS request\n");
return NULL;
}
- plist_dict_set_item(response, "FirmwareData", plist_new_data((char *)component_data, (uint64_t)component_size));
+ parameters = plist_new_dict();
+
+ /* add manifest for current build_identity to parameters */
+ tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true);
+
+ plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1));
+ if (client->image4supported) {
+ plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(1));
+ plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(1));
+ } else {
+ plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(0));
+ }
+
+ /* add Timer,* tags from info dictionary to parameters */
+ plist_t info_array = plist_dict_get_item(p_info, "InfoArray");
+ if (!info_array) {
+ logger(LL_ERROR, "Could not find InfoArray in info dictionary\n");
+ plist_free(parameters);
+ return NULL;
+ } else {
+ plist_t info_dict = plist_array_get_item(info_array, 0);
+ plist_t hwid = plist_dict_get_item(info_dict, "HardwareID");
+ tag = (uint32_t)plist_dict_get_uint(info_dict, "TagNumber");
+ char key[64];
+
+ plist_dict_set_item(parameters, "TagNumber", plist_new_uint(tag));
+ plist_t node = plist_dict_get_item(info_dict, "TicketName");
+ if (node) {
+ ticket_name = plist_get_string_ptr(node, NULL);
+ plist_dict_set_item(parameters, "TicketName", plist_copy(node));
+ }
+
+ snprintf(key, sizeof(key), "Timer,ChipID,%u", tag);
+ plist_dict_copy_uint(parameters, hwid, key, "ChipID");
+
+ snprintf(key, sizeof(key), "Timer,BoardID,%u", tag);
+ plist_dict_copy_uint(parameters, hwid, key, "BoardID");
+
+ snprintf(key, sizeof(key), "Timer,ECID,%u", tag);
+ plist_dict_copy_uint(parameters, hwid, key, "ECID");
+
+ snprintf(key, sizeof(key), "Timer,Nonce,%u", tag);
+ plist_dict_copy_data(parameters, hwid, key, "Nonce");
+
+ snprintf(key, sizeof(key), "Timer,SecurityMode,%u", tag);
+ plist_dict_copy_bool(parameters, hwid, key, "SecurityMode");
+
+ snprintf(key, sizeof(key), "Timer,SecurityDomain,%u", tag);
+ plist_dict_copy_uint(parameters, hwid, key, "SecurityDomain");
+
+ snprintf(key, sizeof(key), "Timer,ProductionMode,%u", tag);
+ plist_dict_copy_uint(parameters, hwid, key, "ProductionStatus");
+ }
+ plist_t ap_info = plist_dict_get_item(p_info, "APInfo");
+ if (!ap_info) {
+ logger(LL_ERROR, "Could not find APInfo in info dictionary\n");
+ plist_free(parameters);
+ return NULL;
+ } else {
+ plist_dict_merge(&parameters, ap_info);
+ }
+
+ /* add required tags for Timer TSS request */
+ tss_request_add_timer_tags(request, parameters, device_generated_request);
+
+ plist_free(parameters);
+
+ logger(LL_INFO, "Sending %s TSS request...\n", ticket_name);
+ response = tss_request_send(request, client->tss_url);
+ plist_free(request);
+ if (response == NULL) {
+ logger(LL_ERROR, "Unable to fetch %s\n", ticket_name);
+ return NULL;
+ }
+
+ if (plist_dict_get_item(response, ticket_name)) {
+ logger(LL_INFO, "Received %s\n", ticket_name);
+ } else {
+ logger(LL_ERROR, "No '%s' in TSS response, this might not work\n", ticket_name);
+ }
+
+ /* don't add FirmwareData if not requested via ResponseTags */
+ if (!_wants_firmware_data(arguments)) {
+ logger(LL_DEBUG, "Not adding FirmwareData as it was not requested\n");
+ return response;
+ }
+
+ snprintf(comp_name, sizeof(comp_name), "Timer,RTKitOS,%u", tag);
+ if (build_identity_has_component(client->restore->build_identity, comp_name)) {
+ if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) {
+ plist_free(response);
+ logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name);
+ return NULL;
+ }
+ ret = extract_component(client->ipsw, comp_path, &component_data, &component_size);
+ free(comp_path);
+ comp_path = NULL;
+ if (ret < 0) {
+ logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name);
+ plist_free(response);
+ return NULL;
+ }
+ if (ftab_parse(component_data, component_size, &ftab, &ftag) != 0) {
+ free(component_data);
+ plist_free(response);
+ logger(LL_ERROR, "Failed to parse '%s' component data.\n", comp_name);
+ return NULL;
+ }
+ free(component_data);
+ component_data = NULL;
+ component_size = 0;
+ if (ftag != 'rkos') {
+ logger(LL_WARNING, "Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos');
+ }
+ } else {
+ logger(LL_NOTICE, "Build identity does not have a '%s' component.\n", comp_name);
+ }
+
+ snprintf(comp_name, sizeof(comp_name), "Timer,RestoreRTKitOS,%u", tag);
+ if (build_identity_has_component(client->restore->build_identity, comp_name)) {
+ if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) {
+ ftab_free(ftab);
+ plist_free(response);
+ logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name);
+ return NULL;
+ }
+ ret = extract_component(client->ipsw, comp_path, &component_data, &component_size);
+ free(comp_path);
+ comp_path = NULL;
+ if (ret < 0) {
+ ftab_free(ftab);
+ plist_free(response);
+ logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name);
+ return NULL;
+ }
+
+ ftag = 0;
+ if (ftab_parse(component_data, component_size, &rftab, &ftag) != 0) {
+ free(component_data);
+ ftab_free(ftab);
+ plist_free(response);
+ logger(LL_ERROR, "Failed to parse '%s' component data.\n", comp_name);
+ return NULL;
+ }
+ free(component_data);
+ component_data = NULL;
+ component_size = 0;
+ if (ftag != 'rkos') {
+ logger(LL_WARNING, "Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos');
+ }
+
+ if (ftab_get_entry_ptr(rftab, 'rrko', &component_data, &component_size) == 0) {
+ ftab_add_entry(ftab, 'rrko', component_data, component_size);
+ } else {
+ logger(LL_ERROR, "Could not find 'rrko' entry in ftab. This will probably break things.\n");
+ }
+ ftab_free(rftab);
+ component_data = NULL;
+ component_size = 0;
+ } else {
+ logger(LL_NOTICE, "Build identity does not have a '%s' component.\n", comp_name);
+ }
+
+ ftab_write(ftab, &component_data, &component_size);
+ ftab_free(ftab);
+
+ plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size));
free(component_data);
component_data = NULL;
component_size = 0;
@@ -2681,7 +3581,133 @@ static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct
return response;
}
-static int restore_send_firmware_updater_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message)
+static plist_t restore_get_cryptex1_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments)
+{
+ plist_t parameters = NULL;
+ plist_t request = NULL;
+ plist_t response = NULL;
+
+ if (!client || !client->restore || !client->restore->build_identity) {
+ logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__);
+ return NULL;
+ }
+
+ plist_t p_updater_name = plist_dict_get_item(arguments, "MessageArgUpdaterName");
+ const char* s_updater_name = plist_get_string_ptr(p_updater_name, NULL);
+
+ plist_t response_tags = plist_access_path(arguments, 2, "DeviceGeneratedTags", "ResponseTags");
+ const char* response_ticket = "Cryptex1,Ticket";
+ if (PLIST_IS_ARRAY(response_tags)) {
+ plist_t tag0 = plist_array_get_item(response_tags, 0);
+ if (tag0) {
+ response_ticket = plist_get_string_ptr(tag0, NULL);
+ }
+ }
+
+ /* create Cryptex1 request */
+ request = tss_request_new(NULL);
+ if (request == NULL) {
+ logger(LL_ERROR, "Unable to create %s TSS request\n", s_updater_name);
+ return NULL;
+ }
+
+ parameters = plist_new_dict();
+
+ /* merge data from MessageArgInfo */
+ plist_dict_merge(&parameters, p_info);
+
+ /* add tags from manifest to parameters */
+ plist_t build_identity_tags = plist_access_path(arguments, 2, "DeviceGeneratedTags", "BuildIdentityTags");
+ if (PLIST_IS_ARRAY(build_identity_tags)) {
+ uint32_t i = 0;
+ for (i = 0; i < plist_array_get_size(build_identity_tags); i++) {
+ plist_t node = plist_array_get_item(build_identity_tags, i);
+ const char* key = plist_get_string_ptr(node, NULL);
+ plist_t item = plist_dict_get_item(client->restore->build_identity, key);
+ if (item) {
+ plist_dict_set_item(parameters, key, plist_copy(item));
+ }
+ }
+ }
+
+ /* make sure we always have these required tags defined */
+ if (!plist_dict_get_item(parameters, "ApProductionMode")) {
+ plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1));
+ }
+ if (!plist_dict_get_item(parameters, "ApSecurityMode")) {
+ plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(1));
+ }
+ if (!plist_dict_get_item(parameters, "ApChipID")) {
+ plist_dict_copy_uint(parameters, client->restore->build_identity, "ApChipID", NULL);
+ }
+ if (!plist_dict_get_item(parameters, "ApBoardID")) {
+ plist_dict_copy_uint(parameters, client->restore->build_identity, "ApBoardID", NULL);
+ }
+
+ /* add device generated request data to parameters */
+ plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest");
+ if (!device_generated_request) {
+ logger(LL_ERROR, "Could not find DeviceGeneratedRequest in arguments dictionary\n");
+ plist_free(parameters);
+ return NULL;
+ }
+ plist_dict_merge(&parameters, device_generated_request);
+
+ /* add Cryptex1 tags to request */
+ tss_request_add_cryptex_tags(request, parameters, NULL);
+
+ plist_free(parameters);
+
+ logger(LL_INFO, "Sending %s TSS request...\n", s_updater_name);
+ response = tss_request_send(request, client->tss_url);
+ plist_free(request);
+ if (response == NULL) {
+ logger(LL_ERROR, "Unable to fetch %s ticket\n", s_updater_name);
+ return NULL;
+ }
+
+ if (plist_dict_get_item(response, response_ticket)) {
+ logger(LL_INFO, "Received %s\n", response_ticket);
+ } else {
+ logger(LL_ERROR, "No '%s' in TSS response, this might not work\n", response_ticket);
+ logger_dump_plist(LL_VERBOSE, response, 0);
+ }
+
+ return response;
+}
+
+static int restore_send_firmware_updater_preflight(struct idevicerestore_client_t* client, plist_t message)
+{
+ plist_t dict = NULL;
+ int restore_error;
+
+ if (client->debug_level > 1) {
+ logger(LL_DEBUG, "%s: Got FirmwareUpdaterPreflight request:\n", __func__);
+ logger_dump_plist(LL_DEBUG, message, 1);
+ }
+
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__);
+ return -1;
+ }
+
+ dict = plist_new_dict();
+
+ logger(LL_INFO, "Sending FirmwareResponsePreflight now...\n");
+ restore_error = _restore_service_send(service, dict, 0);
+ plist_free(dict);
+ _restore_service_free(service);
+ if (restore_error != RESTORE_E_SUCCESS) {
+ logger(LL_ERROR, "Couldn't send FirmwareResponsePreflight data (%d)\n", restore_error);
+ return -1;
+ }
+
+ logger(LL_INFO, "Done sending FirmwareUpdaterPreflight response\n");
+ return 0;
+}
+
+static int restore_send_firmware_updater_data(struct idevicerestore_client_t* client, plist_t message)
{
plist_t arguments;
plist_t p_type, p_updater_name, p_loop_count, p_info;
@@ -2692,26 +3718,31 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct
char *s_updater_name = NULL;
int restore_error;
- if (idevicerestore_debug) {
- debug("DEBUG: %s: Got FirmwareUpdaterData request:\n", __func__);
- debug_plist(message);
+ if (!client || !client->restore || !client->restore->build_identity) {
+ logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__);
+ return -1;
+ }
+
+ if (client->debug_level > 1) {
+ logger(LL_DEBUG, "%s: Got FirmwareUpdaterData request:\n", __func__);
+ logger_dump_plist(LL_DEBUG, message, 1);
}
arguments = plist_dict_get_item(message, "Arguments");
if (!arguments || plist_get_node_type(arguments) != PLIST_DICT) {
- error("ERROR: %s: Arguments missing or has invalid type!\n", __func__);
+ logger(LL_ERROR, "%s: Arguments missing or has invalid type!\n", __func__);
goto error_out;
}
p_type = plist_dict_get_item(arguments, "MessageArgType");
if (!p_type || (plist_get_node_type(p_type) != PLIST_STRING)) {
- error("ERROR: %s: MessageArgType missing or has invalid type!\n", __func__);
+ logger(LL_ERROR, "%s: MessageArgType missing or has invalid type!\n", __func__);
goto error_out;
}
p_updater_name = plist_dict_get_item(arguments, "MessageArgUpdaterName");
if (!p_updater_name || (plist_get_node_type(p_updater_name) != PLIST_STRING)) {
- error("ERROR: %s: MessageArgUpdaterName missing or has invalid type!\n", __func__);
+ logger(LL_ERROR, "%s: MessageArgUpdaterName missing or has invalid type!\n", __func__);
goto error_out;
}
@@ -2723,7 +3754,7 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct
plist_get_string_val(p_type, &s_type);
if (!s_type || strcmp(s_type, "FirmwareResponseData")) {
- error("ERROR: %s: MessageArgType has unexpected value '%s'\n", __func__, s_type);
+ logger(LL_ERROR, "%s: MessageArgType has unexpected value '%s'\n", __func__, s_type);
goto error_out;
}
free(s_type);
@@ -2731,68 +3762,120 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct
p_info = plist_dict_get_item(arguments, "MessageArgInfo");
if (!p_info || (plist_get_node_type(p_info) != PLIST_DICT)) {
- error("ERROR: %s: MessageArgInfo missing or has invalid type!\n", __func__);
+ logger(LL_ERROR, "%s: MessageArgInfo missing or has invalid type!\n", __func__);
goto error_out;
}
plist_get_string_val(p_updater_name, &s_updater_name);
+ logger_dump_plist(LL_DEBUG, p_info, 1);
if (strcmp(s_updater_name, "SE") == 0) {
- fwdict = restore_get_se_firmware_data(restore, client, build_identity, p_info);
+ fwdict = restore_get_se_firmware_data(client, p_info, arguments);
if (fwdict == NULL) {
- error("ERROR: %s: Couldn't get SE firmware data\n", __func__);
+ logger(LL_ERROR, "%s: Couldn't get SE firmware data\n", __func__);
goto error_out;
}
} else if (strcmp(s_updater_name, "Savage") == 0) {
const char *fwtype = "Savage";
- plist_t p_info2 = plist_dict_get_item(p_info, "YonkersDeviceInfo");
- if (p_info2 && plist_get_node_type(p_info2) == PLIST_DICT) {
+ plist_t p_info_yonkers = plist_dict_get_item(p_info, "YonkersDeviceInfo");
+ plist_t p_info_jasmine = plist_dict_get_item(p_info, "JasmineIR1DeviceInfo");
+ if (PLIST_IS_DICT(p_info_yonkers)) {
fwtype = "Yonkers";
- fwdict = restore_get_yonkers_firmware_data(restore, client, build_identity, p_info2);
+ fwdict = restore_get_yonkers_firmware_data(client, p_info_yonkers, arguments);
+ } else if (PLIST_IS_DICT(p_info_jasmine)) {
+ fwtype = "Jasmine";
+ fwdict = restore_get_generic_firmware_data(client, p_info_jasmine, arguments);
} else {
- fwdict = restore_get_savage_firmware_data(restore, client, build_identity, p_info);
+ fwdict = restore_get_savage_firmware_data(client, p_info, arguments);
}
if (fwdict == NULL) {
- error("ERROR: %s: Couldn't get %s firmware data\n", __func__, fwtype);
+ logger(LL_ERROR, "%s: Couldn't get %s firmware data\n", __func__, fwtype);
goto error_out;
}
} else if (strcmp(s_updater_name, "Rose") == 0) {
- fwdict = restore_get_rose_firmware_data(restore, client, build_identity, p_info);
+ fwdict = restore_get_rose_firmware_data(client, p_info, arguments);
if (fwdict == NULL) {
- error("ERROR: %s: Couldn't get Rose firmware data\n", __func__);
+ logger(LL_ERROR, "%s: Couldn't get Rose firmware data\n", __func__);
goto error_out;
}
} else if (strcmp(s_updater_name, "T200") == 0) {
- fwdict = restore_get_veridian_firmware_data(restore, client, build_identity, p_info);
+ fwdict = restore_get_veridian_firmware_data(client, p_info, arguments);
if (fwdict == NULL) {
- error("ERROR: %s: Couldn't get Veridian firmware data\n", __func__);
+ logger(LL_ERROR, "%s: Couldn't get Veridian firmware data\n", __func__);
goto error_out;
}
} else if (strcmp(s_updater_name, "AppleTCON") == 0) {
- fwdict = restore_get_tcon_firmware_data(restore, client, build_identity, p_info);
+ fwdict = restore_get_tcon_firmware_data(client, p_info, arguments);
+ if (fwdict == NULL) {
+ logger(LL_ERROR, "%s: Couldn't get AppleTCON firmware data\n", __func__);
+ goto error_out;
+ }
+ } else if (strcmp(s_updater_name, "PS190") == 0) {
+ fwdict = restore_get_generic_firmware_data(client, p_info, arguments);
+ if (fwdict == NULL) {
+ logger(LL_ERROR, "%s: Couldn't get PCON1 firmware data\n", __func__);
+ goto error_out;
+ }
+ } else if (strcmp(s_updater_name, "AppleTypeCRetimer") == 0) {
+ fwdict = restore_get_timer_firmware_data(client, p_info, arguments);
+ if (fwdict == NULL) {
+ logger(LL_ERROR, "%s: Couldn't get AppleTypeCRetimer firmware data\n", __func__);
+ goto error_out;
+ }
+ } else if ((strcmp(s_updater_name, "Cryptex1") == 0) || (strcmp(s_updater_name, "Cryptex1LocalPolicy") == 0)) {
+ fwdict = restore_get_cryptex1_firmware_data(client, p_info, arguments);
+ if (fwdict == NULL) {
+ logger(LL_ERROR, "%s: Couldn't get %s firmware data\n", __func__, s_updater_name);
+ goto error_out;
+ }
+ } else if (strcmp(s_updater_name, "Ace3") == 0) {
+ fwdict = restore_get_generic_firmware_data(client, p_info, arguments);
if (fwdict == NULL) {
- error("ERROR: %s: Couldn't get AppleTCON firmware data\n", __func__);
+ logger(LL_ERROR, "%s: Couldn't get %s firmware data\n", __func__, s_updater_name);
+ goto error_out;
+ }
+ } else if (strcmp(s_updater_name, "Centauri") == 0) {
+ fwdict = restore_get_generic_firmware_data(client, p_info, arguments);
+ if (fwdict == NULL) {
+ logger(LL_ERROR, "%s: Couldn't get %s firmware data\n", __func__, s_updater_name);
+ goto error_out;
+ }
+ } else if (strcmp(s_updater_name, "Vinyl") == 0) {
+ fwdict = restore_get_generic_firmware_data(client, p_info, arguments);
+ if (fwdict == NULL) {
+ logger(LL_ERROR, "%s: Couldn't get %s firmware data\n", __func__, s_updater_name);
goto error_out;
}
} else {
- error("ERROR: %s: Got unknown updater name '%s'.\n", __func__, s_updater_name);
- goto error_out;
+ logger(LL_ERROR, "%s: Got unknown updater name '%s', trying to discover from device generated request.\n", __func__, s_updater_name);
+ fwdict = restore_get_generic_firmware_data(client, p_info, arguments);
+ if (fwdict == NULL) {
+ logger(LL_ERROR, "%s: Couldn't get %s firmware data\n", __func__, s_updater_name);
+ goto error_out;
+ }
}
free(s_updater_name);
s_updater_name = NULL;
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__);
+ return -1;
+ }
+
dict = plist_new_dict();
plist_dict_set_item(dict, "FirmwareResponseData", fwdict);
- info("Sending FirmwareResponse data now...\n");
- restore_error = restored_send(restore, dict);
+ logger(LL_INFO, "Sending FirmwareResponse data now...\n");
+ restore_error = _restore_service_send(service, dict, 0);
plist_free(dict);
+ _restore_service_free(service);
if (restore_error != RESTORE_E_SUCCESS) {
- error("ERROR: Couldn't send FirmwareResponse data (%d)\n", restore_error);
+ logger(LL_ERROR, "Couldn't send FirmwareResponse data (%d)\n", restore_error);
goto error_out;
}
- info("Done sending FirmwareUpdater data\n");
+ logger(LL_INFO, "Done sending FirmwareUpdater data\n");
return 0;
@@ -2803,6 +3886,49 @@ error_out:
return -1;
}
+static int restore_send_receipt_manifest(struct idevicerestore_client_t* client, plist_t message)
+{
+ plist_t dict;
+ int restore_error;
+
+ if (!client || !client->restore || !client->restore->build_identity) {
+ logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__);
+ return -1;
+ }
+
+ plist_t manifest = plist_dict_get_item(client->restore->build_identity, "Manifest");
+ if (!manifest) {
+ logger(LL_ERROR, "%s: Failed to get Manifest node from build_identity\n", __func__);
+ goto error_out;
+ }
+
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__);
+ return -1;
+ }
+
+ dict = plist_new_dict();
+ plist_dict_set_item(dict, "ReceiptManifest", plist_copy(manifest));
+
+ logger(LL_INFO, "Sending ReceiptManifest data now...\n");
+ restore_error = _restore_service_send(service, dict, 0);
+ plist_free(dict);
+ _restore_service_free(service);
+ if (restore_error != RESTORE_E_SUCCESS) {
+ logger(LL_ERROR, "Couldn't send ReceiptManifest data (%d)\n", restore_error);
+ goto error_out;
+ }
+
+ logger(LL_INFO, "Done sending ReceiptManifest data\n");
+
+ return 0;
+
+error_out:
+ return -1;
+}
+
+
struct cpio_odc_header {
char c_magic[6];
char c_dev[6];
@@ -2848,20 +3974,20 @@ static int cpio_send_file(idevice_connection_t connection, const char *name, str
device_error = idevice_connection_send(connection, (void *)&hdr, sizeof(hdr), &bytes);
if (device_error != IDEVICE_E_SUCCESS || bytes != sizeof(hdr)) {
- error("ERROR: BootabilityBundle unable to send header. (%d) Sent %u of %lu bytes.\n", device_error, bytes, (long)sizeof(hdr));
+ logger(LL_ERROR, "BootabilityBundle unable to send header. (%d) Sent %u of %lu bytes.\n", device_error, bytes, (long)sizeof(hdr));
return -1;
}
device_error = idevice_connection_send(connection, (void *)name, name_len, &bytes);
if (device_error != IDEVICE_E_SUCCESS || bytes != name_len) {
- error("ERROR: BootabilityBundle unable to send filename. (%d) Sent %u of %u bytes.\n", device_error, bytes, name_len);
+ logger(LL_ERROR, "BootabilityBundle unable to send filename. (%d) Sent %u of %u bytes.\n", device_error, bytes, name_len);
return -1;
}
if (st->st_size && data) {
device_error = idevice_connection_send(connection, data, st->st_size, &bytes);
if (device_error != IDEVICE_E_SUCCESS || bytes != st->st_size) {
- error("ERROR: BootabilityBundle unable to send data. (%d) Sent %u of %lu bytes.\n", device_error, bytes, (long)st->st_size);
+ logger(LL_ERROR, "BootabilityBundle unable to send data. (%d) Sent %u of %lu bytes.\n", device_error, bytes, (long)st->st_size);
return -1;
}
}
@@ -2869,7 +3995,7 @@ static int cpio_send_file(idevice_connection_t connection, const char *name, str
return 0;
}
-static int restore_bootability_send_one(void *ctx, const char *ipsw, const char *name, struct stat *stat)
+static int restore_bootability_send_one(void *ctx, ipsw_archive_t ipsw, const char *name, struct stat *stat)
{
idevice_connection_t connection = (idevice_connection_t)ctx;
const char *prefix = "BootabilityBundle/Restore/Bootability/";
@@ -2883,15 +4009,15 @@ static int restore_bootability_send_one(void *ctx, const char *ipsw, const char
subpath = name + strlen(prefix);
}
- debug("DEBUG: BootabilityBundle send m=%07o s=%10ld %s\n", stat->st_mode, (long)stat->st_size, subpath);
+ logger(LL_DEBUG, "BootabilityBundle send m=%07o s=%10ld %s\n", stat->st_mode, (long)stat->st_size, subpath);
- unsigned char *buf = NULL;
- unsigned int size = 0;
+ void *buf = NULL;
+ size_t size = 0;
if ((S_ISLNK(stat->st_mode) || S_ISREG(stat->st_mode)) && stat->st_size != 0) {
ipsw_extract_to_memory(ipsw, name, &buf, &size);
if (size != stat->st_size) {
- error("ERROR: expected %ld bytes but got %d for file %s\n", (long)stat->st_size, size, name);
+ logger(LL_ERROR, "expected %zu bytes but got %zu for file %s\n", (size_t)stat->st_size, size, name);
free(buf);
return -1;
}
@@ -2905,11 +4031,11 @@ static int restore_bootability_send_one(void *ctx, const char *ipsw, const char
return ret;
}
-static int restore_send_bootability_bundle_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message, idevice_t device)
+static int restore_send_bootability_bundle_data(struct idevicerestore_client_t* client, plist_t message)
{
- if (idevicerestore_debug) {
- debug("DEBUG: %s: Got BootabilityBundle request:\n", __func__);
- debug_plist(message);
+ if (client->debug_level > 1) {
+ logger(LL_DEBUG, "%s: Got BootabilityBundle request:\n", __func__);
+ logger_dump_plist(LL_DEBUG, message, 1);
}
plist_t node = plist_dict_get_item(message, "DataPort");
@@ -2921,24 +4047,29 @@ static int restore_send_bootability_bundle_data(restored_client_t restore, struc
idevice_connection_t connection = NULL;
idevice_error_t device_error = IDEVICE_E_SUCCESS;
- debug("Connecting to BootabilityBundle data port\n");
+ if (!client || !client->restore || !client->restore->build_identity || !client->restore->device) {
+ logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__);
+ return -1;
+ }
+
+ logger(LL_DEBUG, "Connecting to BootabilityBundle data port\n");
while (--attempts > 0) {
- device_error = idevice_connect(device, data_port, &connection);
+ device_error = idevice_connect(client->restore->device, data_port, &connection);
if (device_error == IDEVICE_E_SUCCESS) {
break;
}
sleep(1);
- debug("Retrying connection...\n");
+ logger(LL_DEBUG, "Retrying connection...\n");
}
if (device_error != IDEVICE_E_SUCCESS) {
- error("ERROR: Unable to connect to BootabilityBundle data port\n");
+ logger(LL_ERROR, "Unable to connect to BootabilityBundle data port\n");
return -1;
}
int ret = ipsw_list_contents(client->ipsw, restore_bootability_send_one, connection);
if (ret < 0) {
- error("ERROR: Failed to send BootabilityBundle\n");
+ logger(LL_ERROR, "Failed to send BootabilityBundle\n");
return ret;
}
@@ -2950,49 +4081,48 @@ static int restore_send_bootability_bundle_data(restored_client_t restore, struc
return 0;
}
-plist_t restore_get_build_identity(struct idevicerestore_client_t* client, uint8_t is_recover_os)
+plist_t restore_get_build_identity(struct idevicerestore_client_t* client, uint8_t is_recovery_os)
{
const char *variant;
- if (is_recover_os)
- variant = "macOS Customer";
+ if (is_recovery_os)
+ variant = RESTORE_VARIANT_MACOS_RECOVERY_OS;
else if (client->flags & FLAG_ERASE)
- variant = "Customer Erase Install (IPSW)";
+ variant = RESTORE_VARIANT_ERASE_INSTALL;
else
- variant = "Customer Upgrade Install (IPSW)";
+ variant = RESTORE_VARIANT_UPGRADE_INSTALL;
plist_t build_identity = build_manifest_get_build_identity_for_model_with_variant(
client->build_manifest,
client->device->hardware_model,
- variant);
+ variant, 0);
plist_t unique_id_node = plist_dict_get_item(client->build_manifest, "UniqueBuildID");
- debug_plist(unique_id_node);
+ if (unique_id_node) {
+ logger(LL_INFO, "UniqueBuildID: ");
+ plist_write_to_stream(unique_id_node, stdout, PLIST_FORMAT_PRINT, PLIST_OPT_NONE);
+ }
return build_identity;
}
-plist_t restore_get_build_identity_from_request(struct idevicerestore_client_t* client, plist_t msg)
+plist_t restore_get_build_identity_from_request(struct idevicerestore_client_t* client, plist_t message)
{
- plist_t args = plist_dict_get_item(msg, "Arguments");
- plist_t is_recovery_node = plist_dict_get_item(args, "IsRecoveryOS");
- uint8_t is_recovery = 0;
- plist_get_bool_val(is_recovery_node, &is_recovery);
-
- return restore_get_build_identity(client, is_recovery);
+ plist_t args = plist_dict_get_item(message, "Arguments");
+ return restore_get_build_identity(client, plist_dict_get_bool(args, "IsRecoveryOS"));
}
int extract_macos_variant(plist_t build_identity, char** output)
{
plist_t build_info = plist_dict_get_item(build_identity, "Info");
if (!build_info) {
- error("ERROR: build identity does not contain an 'Info' element\n");
+ logger(LL_ERROR, "build identity does not contain an 'Info' element\n");
return -1;
}
plist_t macos_variant_node = plist_dict_get_item(build_info, "MacOSVariant");
if (!macos_variant_node) {
- error("ERROR: build identity info does not contain a MacOSVariant\n");
+ logger(LL_ERROR, "build identity info does not contain a MacOSVariant\n");
return -1;
}
plist_get_string_val(macos_variant_node, output);
@@ -3000,40 +4130,56 @@ int extract_macos_variant(plist_t build_identity, char** output)
return 0;
}
-int extract_global_manifest(struct idevicerestore_client_t* client, plist_t build_identity, unsigned char** pbuffer, unsigned int* psize)
+static char* extract_global_manifest_path(plist_t build_identity, char *variant)
{
plist_t build_info = plist_dict_get_item(build_identity, "Info");
if (!build_info) {
- error("ERROR: build identity does not contain an 'Info' element\n");
- return -1;
+ logger(LL_ERROR, "build identity does not contain an 'Info' element\n");
+ return NULL;
}
plist_t device_class_node = plist_dict_get_item(build_info, "DeviceClass");
if (!device_class_node) {
- error("ERROR: build identity info does not contain a DeviceClass\n");
- return -1;
+ logger(LL_ERROR, "build identity info does not contain a DeviceClass\n");
+ return NULL;
}
char *device_class = NULL;
plist_get_string_val(device_class_node, &device_class);
char *macos_variant = NULL;
- int ret = extract_macos_variant(build_identity, &macos_variant);
- if (ret != 0) {
- free(device_class);
- return -1;
+ int ret;
+ if (variant) {
+ macos_variant = variant;
+ } else {
+ ret = extract_macos_variant(build_identity, &macos_variant);
+ if (ret != 0) {
+ free(device_class);
+ return NULL;
+ }
}
// The path of the global manifest is hardcoded. There's no pointer to in the build manifest.
- char *ticket_path = malloc((42+strlen(macos_variant)+strlen(device_class)+1)*sizeof(char));
- sprintf(ticket_path, "Firmware/Manifests/restore/%s/apticket.%s.im4m", macos_variant, device_class);
+ size_t psize = 42+strlen(macos_variant)+strlen(device_class)+1;
+ char *ticket_path = malloc(psize);
+ snprintf(ticket_path, psize, "Firmware/Manifests/restore/%s/apticket.%s.im4m", macos_variant, device_class);
free(device_class);
free(macos_variant);
- ret = ipsw_extract_to_memory(client->ipsw, ticket_path, pbuffer, psize);
+ return ticket_path;
+}
+
+int extract_global_manifest(struct idevicerestore_client_t* client, plist_t build_identity, char *variant, void** pbuffer, size_t* psize)
+{
+ char* ticket_path = extract_global_manifest_path(build_identity, variant);
+ if (!ticket_path) {
+ logger(LL_ERROR, "failed to get global manifest path\n");
+ return -1;
+ }
+ int ret = ipsw_extract_to_memory(client->ipsw, ticket_path, pbuffer, psize);
if (ret != 0) {
free(ticket_path);
- error("ERROR: failed to read global manifest\n");
+ logger(LL_ERROR, "failed to read global manifest\n");
return -1;
}
free(ticket_path);
@@ -3041,247 +4187,291 @@ int extract_global_manifest(struct idevicerestore_client_t* client, plist_t buil
return 0;
}
-int restore_send_personalized_boot_object_v3(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg, plist_t build_identity)
+struct _restore_send_file_data_ctx {
+ struct idevicerestore_client_t* client;
+ restore_service_client_t service;
+ int last_progress;
+ uint32_t tag;
+};
+
+static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, const void* data, size_t size, size_t done, size_t total_size)
{
- debug_plist(msg);
+ plist_t dict = plist_new_dict();
+ if (data != NULL) {
+ // Send a chunk of file data
+ plist_dict_set_item(dict, "FileData", plist_new_data((char*)data, size));
+ } else {
+ // Send FileDataDone to mark end of transfer
+ plist_dict_set_item(dict, "FileDataDone", plist_new_bool(1));
+ }
+ restored_error_t restore_error = _restore_service_send(rctx->service, dict, 0);
+ if (restore_error != RESTORE_E_SUCCESS) {
+ plist_free(dict);
+ logger(LL_ERROR, "%s: Failed to send data (%d)\n", __func__, restore_error);
+ return -1;
+ }
+ plist_free(dict);
+
+ /* special handling for AEA image format */
+ if (done == 0 && (memcmp(data, "AEA1", 4) == 0)) {
+ logger(LL_VERBOSE, "Encountered First Chunk in AEA image\n");
+ plist_t message = NULL;
+ property_list_service_error_t err = _restore_service_recv_timeout(rctx->service, &message, 3000);
+ if (err == PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT) {
+ logger(LL_VERBOSE, "No URLAsset requested, assuming it is not necessary.\n");
+ } else if (err == PROPERTY_LIST_SERVICE_E_SUCCESS) {
+ if (PLIST_IS_DICT(message) && plist_dict_get_item(message, "Arguments")) {
+ restore_send_url_asset(rctx->client, message);
+ } else {
+ logger(LL_DEBUG, "%s: Unexpected message received\n", __func__);
+ logger_dump_plist(LL_DEBUG, message, 1);
+ }
+ }
+ }
+
+ if (total_size > 0x1000000) {
+ double progress = (double)done / (double)total_size;
+ set_progress(rctx->tag, progress);
+ int progress_int = (int)(progress*100.0);
+ if (progress_int > rctx->last_progress) {
+ idevicerestore_progress(rctx->client, RESTORE_STEP_UPLOAD_IMG, progress);
+ rctx->last_progress = progress_int;
+ }
+ }
+ return 0;
+}
+
+int restore_send_personalized_boot_object_v3(struct idevicerestore_client_t* client, plist_t message)
+{
+ if (client->debug_level > 1) {
+ logger(LL_DEBUG, "%s: Got PersonalizedBootObjectV3 request:\n", __func__);
+ logger_dump_plist(LL_DEBUG, message, 1);
+ }
char *image_name = NULL;
- plist_t node = plist_access_path(msg, 2, "Arguments", "ImageName");
+ plist_t node = plist_access_path(message, 2, "Arguments", "ImageName");
if (!node || plist_get_node_type(node) != PLIST_STRING) {
- debug("Failed to parse arguments from PersonalizedBootObjectV3 plist\n");
+ logger(LL_DEBUG, "Failed to parse arguments from PersonalizedBootObjectV3 plist\n");
return -1;
}
plist_get_string_val(node, &image_name);
if (!image_name) {
- debug("Failed to parse arguments from PersonalizedBootObjectV3 as string\n");
+ logger(LL_DEBUG, "Failed to parse arguments from PersonalizedBootObjectV3 as string\n");
return -1;
}
char *component = image_name;
- unsigned int size = 0;
- unsigned char *data = NULL;
+ size_t size = 0;
+ void *data = NULL;
char *path = NULL;
- plist_t blob = NULL;
- plist_t dict = NULL;
- restored_error_t restore_error = RESTORE_E_SUCCESS;
- char *component_name = component;
- info("About to send %s...\n", component_name);
+ logger(LL_INFO, "About to send %s...\n", component);
if (strcmp(image_name, "__GlobalManifest__") == 0) {
- int ret = extract_global_manifest(client, build_identity, &data, &size);
+ int ret = extract_global_manifest(client, client->restore->build_identity, NULL, &data, &size);
if (ret != 0) {
return -1;
}
} else if (strcmp(image_name, "__RestoreVersion__") == 0) {
int ret = ipsw_extract_to_memory(client->ipsw, "RestoreVersion.plist", &data, &size);
if (ret != 0) {
- error("ERROR: failed to read global manifest\n");
+ logger(LL_ERROR, "failed to read global manifest\n");
return -1;
}
} else if (strcmp(image_name, "__SystemVersion__") == 0) {
int ret = ipsw_extract_to_memory(client->ipsw, "SystemVersion.plist", &data, &size);
if (ret != 0) {
- error("ERROR: failed to read global manifest\n");
+ logger(LL_ERROR, "failed to read global manifest\n");
return -1;
}
} else {
// Get component path
if (client->tss) {
if (tss_response_get_path_by_entry(client->tss, component, &path) < 0) {
- debug("NOTE: No path for component %s in TSS, will fetch from build identity\n", component);
+ logger(LL_DEBUG, "No path for component %s in TSS, will fetch from build identity\n", component);
}
}
if (!path) {
- plist_t build_identity = restore_get_build_identity_from_request(client, msg);
+ plist_t build_identity = restore_get_build_identity_from_request(client, message);
if (!build_identity) {
- error("ERROR: Unable to find a matching build identity\n");
+ logger(LL_ERROR, "Unable to find a matching build identity\n");
return -1;
}
if (build_identity_get_component_path(build_identity, component, &path) < 0) {
- error("ERROR: Unable to find %s path from build identity\n", component);
+ logger(LL_ERROR, "Unable to find %s path from build identity\n", component);
return -1;
}
}
// Extract component
- unsigned char *component_data = NULL;
- unsigned int component_size = 0;
+ void *component_data = NULL;
+ size_t component_size = 0;
int ret = extract_component(client->ipsw, path, &component_data, &component_size);
free(path);
path = NULL;
if (ret < 0) {
- error("ERROR: Unable to extract component %s\n", component);
+ logger(LL_ERROR, "Unable to extract component %s\n", component);
return -1;
}
- // Personalize IMG40
- ret = personalize_component(component, component_data, component_size, client->tss, &data, &size);
+ // Personalize IMG4
+ ret = personalize_component(client, component, component_data, component_size, client->tss, &data, &size);
free(component_data);
component_data = NULL;
if (ret < 0) {
- error("ERROR: Unable to get personalized component %s\n", component);
+ logger(LL_ERROR, "Unable to get personalized component %s\n", component);
return -1;
}
}
- // Make plist
- info("Sending %s now...\n", component_name);
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__);
+ return -1;
+ }
+
+ logger(LL_INFO, "Sending %s now (%" PRIu64 " bytes)...\n", component, (uint64_t)size);
+
+ struct _restore_send_file_data_ctx rctx;
+ rctx.client = client;
+ rctx.service = service;
+ rctx.last_progress = 0;
+ rctx.tag = progress_get_next_tag();
+
+ if (size > 0x2000000) {
+ register_progress(rctx.tag, component);
+ }
int64_t i = size;
while (i > 0) {
int blob_size = i > 8192 ? 8192 : i;
-
- dict = plist_new_dict();
- blob = plist_new_data((char *) (data + size - i), blob_size);
- plist_dict_set_item(dict, "FileData", blob);
-
- restore_error = restored_send(restore, dict);
- if (restore_error != RESTORE_E_SUCCESS) {
- error("ERROR: Unable to send component %s data\n", component_name);
+ if (_restore_send_file_data(&rctx, ((char*)data + size - i), blob_size, size-i, size) < 0) {
+ free(data);
+ _restore_service_free(service);
+ finalize_progress(rctx.tag);
+ logger(LL_ERROR, "Unable to send component %s data\n", component);
return -1;
}
-
- plist_free(dict);
-
i -= blob_size;
}
- debug("\n");
-
- // Send FileDataDone
- dict = plist_new_dict();
- plist_dict_set_item(dict, "FileDataDone", plist_new_bool(1));
+ free(data);
- restore_error = restored_send(restore, dict);
- if (restore_error != RESTORE_E_SUCCESS) {
- error("ERROR: Unable to send component %s data\n", component_name);
- return -1;
- }
+ _restore_send_file_data(&rctx, NULL, 0, size-i, size);
+ finalize_progress(rctx.tag);
- plist_free(dict);
- free(data);
+ _restore_service_free(service);
- info("Done sending %s\n", component_name);
+ logger(LL_INFO, "Done sending %s\n", component);
return 0;
}
-int restore_send_source_boot_object_v4(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg, plist_t build_identity)
+int restore_send_source_boot_object_v4(struct idevicerestore_client_t* client, plist_t message)
{
- debug_plist(msg);
+ if (client->debug_level > 1) {
+ logger(LL_DEBUG, "%s: Got SourceBootObjectV4 request:\n", __func__);
+ logger_dump_plist(LL_DEBUG, message, 1);
+ }
char *image_name = NULL;
- plist_t node = plist_access_path(msg, 2, "Arguments", "ImageName");
+ plist_t node = plist_access_path(message, 2, "Arguments", "ImageName");
if (!node || plist_get_node_type(node) != PLIST_STRING) {
- debug("Failed to parse arguments from SourceBootObjectV4 plist\n");
+ logger(LL_DEBUG, "Failed to parse arguments from SourceBootObjectV4 plist\n");
return -1;
}
plist_get_string_val(node, &image_name);
if (!image_name) {
- debug("Failed to parse arguments from SourceBootObjectV4 as string\n");
+ logger(LL_DEBUG, "Failed to parse arguments from SourceBootObjectV4 as string\n");
return -1;
}
char *component = image_name;
// Fork from restore_send_component
//
- unsigned int size = 0;
- unsigned char *data = NULL;
char *path = NULL;
- plist_t blob = NULL;
- plist_t dict = NULL;
- restored_error_t restore_error = RESTORE_E_SUCCESS;
- char *component_name = component;
- info("About to send %s...\n", component_name);
+ logger(LL_INFO, "About to send %s...\n", component);
if (strcmp(image_name, "__GlobalManifest__") == 0) {
- int ret = extract_global_manifest(client, build_identity, &data, &size);
- if (ret != 0) {
+ char *variant = NULL;
+ plist_t node = plist_access_path(message, 2, "Arguments", "Variant");
+ if (!node || plist_get_node_type(node) != PLIST_STRING) {
+ logger(LL_DEBUG, "Failed to parse arguments from SourceBootObjectV4 plist\n");
return -1;
}
- } else if (strcmp(image_name, "__RestoreVersion__") == 0) {
- int ret = ipsw_extract_to_memory(client->ipsw, "RestoreVersion.plist", &data, &size);
- if (ret != 0) {
- error("ERROR: failed to read global manifest\n");
+ plist_get_string_val(node, &variant);
+ if (!variant) {
+ logger(LL_DEBUG, "Failed to parse arguments from SourceBootObjectV4 as string\n");
return -1;
}
+
+ path = extract_global_manifest_path(client->restore->build_identity, variant);
+ } else if (strcmp(image_name, "__RestoreVersion__") == 0) {
+ path = strdup("RestoreVersion.plist");
} else if (strcmp(image_name, "__SystemVersion__") == 0) {
- int ret = ipsw_extract_to_memory(client->ipsw, "SystemVersion.plist", &data, &size);
- if (ret != 0) {
- error("ERROR: failed to read global manifest\n");
- return -1;
- }
+ path = strdup("SystemVersion.plist");
} else {
// Get component path
if (client->tss) {
if (tss_response_get_path_by_entry(client->tss, component, &path) < 0) {
- debug("NOTE: No path for component %s in TSS, will fetch from build identity\n", component);
+ logger(LL_DEBUG, "No path for component %s in TSS, will fetch from build identity\n", component);
}
}
if (!path) {
- plist_t build_identity = restore_get_build_identity_from_request(client, msg);
+ plist_t build_identity = restore_get_build_identity_from_request(client, message);
if (build_identity_get_component_path(build_identity, component, &path) < 0) {
- error("ERROR: Unable to find %s path from build identity\n", component);
+ logger(LL_ERROR, "Unable to find %s path from build identity\n", component);
return -1;
}
}
-
- int ret = extract_component(client->ipsw, path, &data, &size);
- free(path);
- path = NULL;
- if (ret < 0) {
- error("ERROR: Unable to extract component %s\n", component);
- return -1;
- }
}
- // Make plist
- info("Sending %s now...\n", component_name);
-
- int64_t i = size;
- while (i > 0) {
- int blob_size = i > 8192 ? 8192 : i;
+ if (!path) {
+ logger(LL_ERROR, "Failed to get path for component %s\n", component);
+ return -1;
+ }
- dict = plist_new_dict();
- blob = plist_new_data((char *) (data + size - i), blob_size);
- plist_dict_set_item(dict, "FileData", blob);
+ uint64_t fsize = 0;
+ ipsw_get_file_size(client->ipsw, path, &fsize);
- restore_error = restored_send(restore, dict);
- if (restore_error != RESTORE_E_SUCCESS) {
- error("ERROR: Unable to send component %s data\n", component_name);
- return -1;
- }
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__);
+ return -1;
+ }
- plist_free(dict);
+ logger(LL_INFO, "Sending %s now (%" PRIu64 " bytes)\n", component, fsize);
- i -= blob_size;
- }
- debug("\n");
+ struct _restore_send_file_data_ctx rctx;
+ rctx.client = client;
+ rctx.service = service;
+ rctx.last_progress = 0;
+ rctx.tag = progress_get_next_tag();
- // Send FileDataDone
- dict = plist_new_dict();
- plist_dict_set_item(dict, "FileDataDone", plist_new_bool(1));
+ register_progress(rctx.tag, component);
- restore_error = restored_send(restore, dict);
- if (restore_error != RESTORE_E_SUCCESS) {
- error("ERROR: Unable to send component %s data\n", component_name);
+ if (ipsw_extract_send(client->ipsw, path, 8192, (ipsw_send_cb)_restore_send_file_data, &rctx) < 0) {
+ free(path);
+ _restore_service_free(service);
+ finalize_progress(rctx.tag);
+ logger(LL_ERROR, "Failed to send component %s\n", component);
return -1;
}
+ free(path);
- plist_free(dict);
- free(data);
+ _restore_service_free(service);
+ finalize_progress(rctx.tag);
- info("Done sending %s\n", component_name);
+ logger(LL_INFO, "Done sending %s\n", component);
return 0;
}
-int restore_send_restore_local_policy(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg)
+int restore_send_restore_local_policy(struct idevicerestore_client_t* client, plist_t message)
{
- unsigned int size = 0;
- unsigned char* data = NULL;
+ size_t size = 0;
+ void* data = NULL;
- unsigned char* component_data = NULL;
- unsigned int component_size = 0;
+ void* component_data = NULL;
+ size_t component_size = 0;
char* component = "Ap,LocalPolicy";
@@ -3292,26 +4482,34 @@ int restore_send_restore_local_policy(restored_client_t restore, struct idevicer
// The Update mode does not have a specific build identity for the recovery os.
plist_t build_identity = restore_get_build_identity(client, client->flags & FLAG_ERASE ? 1 : 0);
- int ret = get_recovery_os_local_policy_tss_response(client, build_identity, &client->tss_localpolicy, plist_dict_get_item(msg, "Arguments"));
+ int ret = get_recovery_os_local_policy_tss_response(client, build_identity, &client->tss_localpolicy, plist_dict_get_item(message, "Arguments"));
if (ret < 0) {
- error("ERROR: Unable to get recovery os local policy tss response\n");
+ logger(LL_ERROR, "Unable to get recovery os local policy tss response\n");
return -1;
}
- ret = personalize_component(component, component_data, component_size, client->tss_localpolicy, &data, &size);
+ ret = personalize_component(client, component, component_data, component_size, client->tss_localpolicy, &data, &size);
free(component_data);
component_data = NULL;
if (ret < 0) {
- error("ERROR: Unable to get personalized component %s\n", component);
+ logger(LL_ERROR, "Unable to get personalized component %s\n", component);
return -1;
}
plist_t dict = plist_new_dict();
plist_dict_set_item(dict, "Ap,LocalPolicy", plist_new_data((char*)data, size));
- int restore_error = restored_send(restore, dict);
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__);
+ return -1;
+ }
+
+ int restore_error = 0;
+ restore_error = _restore_service_send(service, dict, 0);
+ _restore_service_free(service);
if (restore_error != RESTORE_E_SUCCESS) {
- error("ERROR: Unable to send component %s data\n", component);
+ logger(LL_ERROR, "Unable to send component %s data\n", component);
return -1;
}
@@ -3321,38 +4519,276 @@ int restore_send_restore_local_policy(restored_client_t restore, struct idevicer
return 0;
}
-int restore_send_buildidentity(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg)
+int restore_send_buildidentity(struct idevicerestore_client_t* client, plist_t message)
{
restored_error_t restore_error;
plist_t dict;
- info("About to send BuildIdentity Dict...\n");
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__);
+ return -1;
+ }
+
+ logger(LL_INFO, "About to send BuildIdentity Dict...\n");
- plist_t build_identity = restore_get_build_identity_from_request(client, msg);
+ plist_t build_identity = restore_get_build_identity_from_request(client, message);
dict = plist_new_dict();
plist_dict_set_item(dict, "BuildIdentityDict", plist_copy(build_identity));
- plist_t node = plist_access_path(msg, 2, "Arguments", "Variant");
+ plist_t node = plist_access_path(message, 2, "Arguments", "Variant");
if(node) {
plist_dict_set_item(dict, "Variant", plist_copy(node));
} else {
plist_dict_set_item(dict, "Variant", plist_new_string("Erase"));
}
- info("Sending BuildIdentityDict now...\n");
- restore_error = restored_send(restore, dict);
+ logger(LL_INFO, "Sending BuildIdentityDict now...\n");
+ restore_error = _restore_service_send(service, dict, 0);
+ _restore_service_free(service);
plist_free(dict);
if (restore_error != RESTORE_E_SUCCESS) {
- error("ERROR: Unable to send BuildIdentityDict (%d)\n", restore_error);
+ logger(LL_ERROR, "Unable to send BuildIdentityDict (%d)\n", restore_error);
+ return -1;
+ }
+
+ logger(LL_INFO, "Done sending BuildIdentityDict\n");
+ return 0;
+}
+
+int restore_send_recovery_os_file_asset_image(struct idevicerestore_client_t* client, plist_t message)
+{
+ char *fw_override_key = NULL;
+ plist_t node = plist_access_path(message, 2, "Arguments", "FWOverrideKey");
+ if (PLIST_IS_STRING(node)) {
+ plist_get_string_val(node, &fw_override_key);
+ }
+ if (!fw_override_key) {
+ logger(LL_ERROR, "Failed to get FWOverrideKey from arguments. Trying to continue anyway.\n");
+ return -1;
+ }
+
+ plist_t dict = plist_new_dict();
+ if (!client->recovery_variant) {
+ logger(LL_ERROR, "no RecoveryOS variant in BuildManifest. Trying to continue anyway.\n");
+ plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1));
+ restored_send(client->restore->client, dict);
+ plist_free(dict);
+ return 0;
+ }
+
+ if (strncmp(fw_override_key, "RecoveryOS", 10) != 0) {
+ logger(LL_ERROR, "FWOVerrideKey has unexpected prefix\n");
+ plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1));
+ restored_send(client->restore->client, dict);
+ plist_free(dict);
+ return 0;
+ }
+
+ const char* component = fw_override_key+10;
+ char* path = NULL;
+ if (build_identity_get_component_path(client->recovery_variant, component, &path) < 0) {
+ logger(LL_ERROR, "Unable to find %s path from recovery build identity. Trying to continue anyway.\n", component);
+ plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1));
+ restored_send(client->restore->client, dict);
+ plist_free(dict);
+ return 0;
+ }
+
+ void* component_data = NULL;
+ size_t component_size = 0;
+ int ret = extract_component(client->ipsw, path, &component_data, &component_size);
+ free(path);
+ path = NULL;
+ if (ret < 0) {
+ logger(LL_ERROR, "Unable to extract component %s. Trying to continue anyway.\n", component);
+ plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1));
+ restored_send(client->restore->client, dict);
+ plist_free(dict);
+ return 0;
+ }
+
+ void* data = NULL;
+ size_t size = 0;
+ ret = personalize_component(client, component, component_data, component_size, client->tss_recoveryos_root_ticket, &data, &size);
+ free(component_data);
+ component_data = NULL;
+ if (ret < 0) {
+ logger(LL_ERROR, "Unable to get personalized component %s. Trying to continue anyway.\n", component);
+ plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1));
+ restored_send(client->restore->client, dict);
+ plist_free(dict);
+ return 0;
+ }
+
+ logger(LL_INFO, "Sending %s\n", fw_override_key);
+
+ plist_dict_set_item(dict, "AdditionalBootImages", plist_new_data((char*)data, size));
+ free(data);
+ restored_send(client->restore->client, dict);
+ plist_free(dict);
+
+ return 0;
+}
+
+int restore_send_recovery_os_iboot_fw_files_images(struct idevicerestore_client_t* client, plist_t message)
+{
+ plist_t build_id_manifest = plist_dict_get_item(client->recovery_variant, "Manifest");
+ if (!build_id_manifest) {
+ logger(LL_ERROR, "Missing Manifest dictionary in build identity?!\n");
+ return -1;
+ }
+
+ plist_t firmware_files = plist_new_dict();
+
+ plist_dict_iter iter = NULL;
+ plist_dict_new_iter(build_id_manifest, &iter);
+ if (iter) {
+ char *component = NULL;
+ plist_t manifest_entry;
+ do {
+ component = NULL;
+ manifest_entry = NULL;
+ plist_dict_next_item(build_id_manifest, iter, &component, &manifest_entry);
+ if (component && PLIST_IS_DICT(manifest_entry)) {
+ uint8_t loaded_by_iboot = 0;
+ uint8_t loaded_by_iboot_stage1 = 0;
+ plist_t fw_node;
+
+ fw_node = plist_access_path(manifest_entry, 2, "Info", "IsLoadedByiBoot");
+ if (fw_node && plist_get_node_type(fw_node) == PLIST_BOOLEAN) {
+ plist_get_bool_val(fw_node, &loaded_by_iboot);
+ }
+ fw_node = plist_access_path(manifest_entry, 2, "Info", "IsLoadedByiBootStage1");
+ if (fw_node && plist_get_node_type(fw_node) == PLIST_BOOLEAN) {
+ plist_get_bool_val(fw_node, &loaded_by_iboot_stage1);
+ }
+ if (loaded_by_iboot || loaded_by_iboot_stage1) {
+ plist_t comp_path = plist_access_path(manifest_entry, 2, "Info", "Path");
+ if (comp_path) {
+ const char* path = plist_get_string_ptr(comp_path, NULL);
+ void* component_data = NULL;
+ size_t component_size = 0;
+ int ret = extract_component(client->ipsw, path, &component_data, &component_size);
+ if (ret == 0) {
+ void* data = NULL;
+ size_t size = 0;
+ ret = personalize_component(client, component, component_data, component_size, client->tss_recoveryos_root_ticket, &data, &size);
+ free(component_data);
+ component_data = NULL;
+ if (ret == 0) {
+ plist_dict_set_item(firmware_files, component, plist_new_data((char*)data, size));
+ free(data);
+ }
+ }
+ }
+ }
+ }
+ free(component);
+ } while (manifest_entry);
+ plist_mem_free(iter);
+ }
+
+ plist_t dict = plist_new_dict();
+
+ if (plist_dict_get_size(firmware_files) == 0) {
+ plist_free(firmware_files);
+ logger(LL_NOTICE, "No iBoot firmware files. Continuing.\n");
+ plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1));
+ restored_send(client->restore->client, dict);
+ plist_free(dict);
+ return 0;
+
+ }
+
+ logger(LL_INFO, "Sending iBoot additional firmware files\n");
+
+ plist_dict_set_item(dict, "AdditionalBootImages", firmware_files);
+ restored_send(client->restore->client, dict);
+ plist_free(dict);
+
+ return 0;
+}
+
+int restore_send_recovery_os_image(struct idevicerestore_client_t* client, plist_t message)
+{
+ const char* component = "OS";
+ char* path = NULL;
+ if (build_identity_get_component_path(client->recovery_variant, component, &path) < 0) {
+ logger(LL_ERROR, "Unable to find %s path from build identity\n", component);
+ return -1;
+ }
+ if (!path) {
+ logger(LL_ERROR, "Failed to get path for component %s\n", component);
+ return -1;
+ }
+
+ uint64_t fsize = 0;
+ ipsw_get_file_size(client->ipsw, path, &fsize);
+
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__);
return -1;
}
- info("Done sending BuildIdentityDict\n");
+ logger(LL_INFO, "Sending %s now (%" PRIu64 " bytes)\n", component, fsize);
+
+ struct _restore_send_file_data_ctx rctx;
+ rctx.client = client;
+ rctx.service = service;
+ rctx.last_progress = 0;
+ rctx.tag = progress_get_next_tag();
+
+ register_progress(rctx.tag, component);
+
+ if (ipsw_extract_send(client->ipsw, path, 8192, (ipsw_send_cb)_restore_send_file_data, &rctx) < 0) {
+ free(path);
+ _restore_service_free(service);
+ finalize_progress(rctx.tag);
+ logger(LL_ERROR, "Failed to send component %s\n", component);
+ return -1;
+ }
+ free(path);
+
+ _restore_service_free(service);
+ finalize_progress(rctx.tag);
+
+ logger(LL_INFO, "Done sending %s\n", component);
+
return 0;
}
-int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t build_identity, const char* filesystem)
+int restore_send_recovery_os_version_data(struct idevicerestore_client_t* client, plist_t message)
+{
+ plist_t build_id_info = plist_dict_get_item(client->recovery_variant, "Info");
+ if (!build_id_info) {
+ logger(LL_ERROR, "Missing Info dictionary in build identity?!\n");
+ return -1;
+ }
+ plist_t version_data = plist_new_dict();
+ plist_dict_copy_item(version_data, build_id_info, "BuildNumber", NULL);
+ plist_dict_copy_item(version_data, build_id_info, "Variant", NULL);
+ plist_dict_copy_item(version_data, build_id_info, "BuildTrain", NULL);
+ plist_dict_copy_item(version_data, build_id_info, "ProductVersion", "ProductMarketingVersion");
+ char *xml = NULL;
+ uint32_t xml_len = 0;
+ plist_to_xml(version_data, &xml, &xml_len);
+ plist_free(version_data);
+
+ logger(LL_INFO, "Sending RecoveryOS version data\n");
+
+ plist_t dict = plist_new_dict();
+ plist_dict_set_item(dict, "RecoveryOSVersionData", plist_new_data(xml, xml_len));
+ plist_mem_free(xml);
+ restored_send(client->restore->client, dict);
+ plist_free(dict);
+
+ return 0;
+}
+
+int restore_handle_data_request_msg(struct idevicerestore_client_t* client, plist_t message)
{
plist_t node = NULL;
@@ -3361,170 +4797,354 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev
node = plist_dict_get_item(message, "DataType");
if (node && PLIST_STRING == plist_get_node_type(node)) {
const char *type = plist_get_string_ptr(node, NULL);
-
+logger(LL_DEBUG, "%s: type = %s\n", __func__, type);
// this request is sent when restored is ready to receive the filesystem
if (!strcmp(type, "SystemImageData")) {
- if(restore_send_filesystem(client, device, filesystem) < 0) {
- error("ERROR: Unable to send filesystem\n");
+ if (restore_send_filesystem(client, message) < 0) {
+ logger(LL_ERROR, "Unable to send filesystem\n");
return -2;
}
}
else if (!strcmp(type, "BuildIdentityDict")) {
- if (restore_send_buildidentity(restore, client, message) < 0) {
- error("ERROR: Unable to send RootTicket\n");
+ if (restore_send_buildidentity(client, message) < 0) {
+ logger(LL_ERROR, "Unable to send RootTicket\n");
return -1;
}
}
else if (!strcmp(type, "PersonalizedBootObjectV3")) {
- if (restore_send_personalized_boot_object_v3(restore, client, message, build_identity) < 0) {
- error("ERROR: Unable to send PersonalizedBootObjectV3\n");
+ if (restore_send_personalized_boot_object_v3(client, message) < 0) {
+ logger(LL_ERROR, "Unable to send PersonalizedBootObjectV3\n");
return -1;
}
}
else if (!strcmp(type, "SourceBootObjectV4")) {
- if (restore_send_source_boot_object_v4(restore, client, message, build_identity) < 0) {
- error("ERROR: Unable to send SourceBootObjectV4\n");
+ if (restore_send_source_boot_object_v4(client, message) < 0) {
+ logger(LL_ERROR, "Unable to send SourceBootObjectV4\n");
return -1;
}
}
else if (!strcmp(type, "RecoveryOSLocalPolicy")) {
- if (restore_send_restore_local_policy(restore, client, message) < 0) {
- error("ERROR: Unable to send RecoveryOSLocalPolicy\n");
+ if (restore_send_restore_local_policy(client, message) < 0) {
+ logger(LL_ERROR, "Unable to send RecoveryOSLocalPolicy\n");
return -1;
}
}
// this request is sent when restored is ready to receive the filesystem
else if (!strcmp(type, "RecoveryOSASRImage")) {
- if(restore_send_filesystem(client, device, filesystem) < 0) {
- error("ERROR: Unable to send filesystem\n");
+ if (restore_send_filesystem(client, message) < 0) {
+ logger(LL_ERROR, "Unable to send filesystem\n");
return -2;
}
}
// Send RecoveryOS RTD
else if(!strcmp(type, "RecoveryOSRootTicketData")) {
- if (restore_send_recovery_os_root_ticket(restore, client) < 0) {
- error("ERROR: Unable to send RootTicket\n");
+ if (restore_send_recovery_os_root_ticket(client, message) < 0) {
+ logger(LL_ERROR, "Unable to send RootTicket\n");
return -1;
}
}
// send RootTicket (== APTicket from the TSS request)
else if (!strcmp(type, "RootTicket")) {
- if (restore_send_root_ticket(restore, client) < 0) {
- error("ERROR: Unable to send RootTicket\n");
+ if (restore_send_root_ticket(client, message) < 0) {
+ logger(LL_ERROR, "Unable to send RootTicket\n");
return -1;
}
}
// send KernelCache
else if (!strcmp(type, "KernelCache")) {
- if (restore_send_component(restore, client, build_identity, "KernelCache", NULL) < 0) {
- error("ERROR: Unable to send kernelcache\n");
+ if (restore_send_component(client, message, "KernelCache", NULL) < 0) {
+ logger(LL_ERROR, "Unable to send kernelcache\n");
return -1;
}
}
else if (!strcmp(type, "DeviceTree")) {
- if (restore_send_component(restore, client, build_identity, "DeviceTree", NULL) < 0) {
- error("ERROR: Unable to send DeviceTree\n");
+ if (restore_send_component(client, message, "DeviceTree", NULL) < 0) {
+ logger(LL_ERROR, "Unable to send DeviceTree\n");
return -1;
}
}
else if (!strcmp(type, "SystemImageRootHash")) {
- if (restore_send_component(restore, client, build_identity, "SystemVolume", type) < 0) {
- error("ERROR: Unable to send SystemImageRootHash data\n");
+ if (restore_send_component(client, message, "SystemVolume", type) < 0) {
+ logger(LL_ERROR, "Unable to send SystemImageRootHash data\n");
return -1;
}
}
else if (!strcmp(type, "SystemImageCanonicalMetadata")) {
- if (restore_send_component(restore, client, build_identity, "Ap,SystemVolumeCanonicalMetadata", type) < 0) {
- error("ERROR: Unable to send SystemImageCanonicalMetadata data\n");
+ if (restore_send_component(client, message, "Ap,SystemVolumeCanonicalMetadata", type) < 0) {
+ logger(LL_ERROR, "Unable to send SystemImageCanonicalMetadata data\n");
return -1;
}
}
else if (!strcmp(type, "NORData")) {
if((client->flags & FLAG_EXCLUDE) == 0) {
- if(restore_send_nor(restore, client, build_identity) < 0) {
- error("ERROR: Unable to send NOR data\n");
+ if(restore_send_nor(client, message) < 0) {
+ logger(LL_ERROR, "Unable to send NOR data\n");
return -1;
}
} else {
- info("Not sending NORData... Quitting...\n");
+ logger(LL_INFO, "Not sending NORData... Quitting...\n");
client->flags |= FLAG_QUIT;
}
}
else if (!strcmp(type, "BasebandData")) {
- if(restore_send_baseband_data(restore, client, build_identity, message) < 0) {
- error("ERROR: Unable to send baseband data\n");
+ if(restore_send_baseband_data(client, message) < 0) {
+ logger(LL_ERROR, "Unable to send baseband data\n");
return -1;
}
}
else if (!strcmp(type, "FDRTrustData")) {
- if(restore_send_fdr_trust_data(restore, device) < 0) {
- error("ERROR: Unable to send FDR Trust data\n");
+ if(restore_send_fdr_trust_data(client, message) < 0) {
+ logger(LL_ERROR, "Unable to send FDR Trust data\n");
return -1;
}
}
else if (!strcmp(type, "FUDData")) {
- if(restore_send_image_data(restore, client, build_identity, message, "FUDImageList", "IsFUDFirmware", "FUDImageData") < 0) {
- error("ERROR: Unable to send FUD data\n");
+ if(restore_send_image_data(client, message, "FUDImageList", "IsFUDFirmware", "FUDImageData") < 0) {
+ logger(LL_ERROR, "Unable to send FUD data\n");
+ return -1;
+ }
+ }
+
+ else if (!strcmp(type, "FirmwareUpdaterPreflight")) {
+ if(restore_send_firmware_updater_preflight(client, message) < 0) {
+ logger(LL_ERROR, "Unable to send FirmwareUpdaterPreflight\n");
return -1;
}
}
else if (!strcmp(type, "FirmwareUpdaterData")) {
- if(restore_send_firmware_updater_data(restore, client, build_identity, message) < 0) {
- error("ERROR: Unable to send FirmwareUpdater data\n");
+ if(restore_send_firmware_updater_data(client, message) < 0) {
+ logger(LL_ERROR, "Unable to send FirmwareUpdater data\n");
return -1;
}
}
else if (!strcmp(type, "PersonalizedData")) {
- if(restore_send_image_data(restore, client, build_identity, message, "ImageList", NULL, "ImageData") < 0) {
- error("ERROR: Unable to send Personalized data\n");
+ if(restore_send_image_data(client, message, "ImageList", NULL, "ImageData") < 0) {
+ logger(LL_ERROR, "Unable to send Personalized data\n");
return -1;
}
}
else if (!strcmp(type, "EANData")) {
- if(restore_send_image_data(restore, client, build_identity, message, "EANImageList", "IsEarlyAccessFirmware", "EANData") < 0) {
- error("ERROR: Unable to send Personalized data\n");
+ if(restore_send_image_data(client, message, "EANImageList", "IsEarlyAccessFirmware", "EANData") < 0) {
+ logger(LL_ERROR, "Unable to send Personalized data\n");
return -1;
}
}
else if (!strcmp(type, "BootabilityBundle")) {
- if (restore_send_bootability_bundle_data(restore, client, build_identity, message, device) < 0) {
- error("ERROR: Unable to send BootabilityBundle data\n");
+ if (restore_send_bootability_bundle_data(client, message) < 0) {
+ logger(LL_ERROR, "Unable to send BootabilityBundle data\n");
+ return -1;
+ }
+ }
+
+ else if (!strcmp(type, "ReceiptManifest")) {
+ if (restore_send_receipt_manifest(client, message) < 0) {
+ logger(LL_ERROR, "Unable to send ReceiptManifest data\n");
+ return -1;
+ }
+ }
+
+ else if (!strcmp(type, "BasebandUpdaterOutputData")) {
+ if (restore_handle_baseband_updater_output_data(client, message) < 0) {
+ logger(LL_ERROR, "Unable to send BasebandUpdaterOutputData data\n");
+ return -1;
+ }
+ }
+
+ else if (!strcmp(type, "URLAsset")) {
+ if (restore_send_url_asset(client, message) < 0) {
+ logger(LL_ERROR, "Unable to send URLAsset data\n");
+ return -1;
+ }
+ }
+
+ else if (!strcmp(type, "StreamedImageDecryptionKey")) {
+ if (restore_send_streamed_image_decryption_key(client, message) < 0) {
+ logger(LL_ERROR, "Unable to send StreamedImageDecryptionKey data\n");
+ return -1;
+ }
+ }
+
+ else if (!strcmp(type, "RecoveryOSFileAssetImage")) {
+ if (restore_send_recovery_os_file_asset_image(client, message) < 0) {
+ logger(LL_ERROR, "Unable to send RecoveryOSFileImageAssetImage data\n");
+ return -1;
+ }
+ }
+
+ else if (!strcmp(type, "RecoveryOSIBootFWFilesImages")) {
+ if (restore_send_recovery_os_iboot_fw_files_images(client, message) < 0) {
+ logger(LL_ERROR, "Unable to send RecoveryOSIBootFWFilesImages data\n");
+ return -1;
+ }
+ }
+
+ else if (!strcmp(type, "RecoveryOSImage")) {
+ if (restore_send_recovery_os_image(client, message) < 0) {
+ logger(LL_ERROR, "Unable to send RecoveryOSImage data\n");
+ return -1;
+ }
+ }
+
+ else if (!strcmp(type, "RecoveryOSVersionData")) {
+ if (restore_send_recovery_os_version_data(client, message) < 0) {
+ logger(LL_ERROR, "Unable to send RecoveryOSVersionData data\n");
return -1;
}
}
else {
// Unknown DataType!!
- error("Unknown data request '%s' received\n", type);
- if (idevicerestore_debug)
- debug_plist(message);
+ logger(LL_ERROR, "Unknown data request '%s' received\n", type);
+ logger_dump_plist(LL_VERBOSE, message, 1);
}
}
return 0;
}
+struct _restore_async_args {
+ struct idevicerestore_client_t* client;
+ plist_t message;
+};
+
+static void* _restore_handle_async_data_request(void* args)
+{
+ struct _restore_async_args* async_args = (struct _restore_async_args*)args;
+ struct idevicerestore_client_t* client = async_args->client;
+ plist_t message = async_args->message;
+ free(async_args);
+
+ int err = restore_handle_data_request_msg(client, message);
+ if (err < 0) {
+ client->async_err = err;
+ client->flags |= FLAG_QUIT;
+ }
+
+ plist_free(message);
+ return NULL;
+}
+
+static int restore_handle_restored_crash(struct idevicerestore_client_t* client, plist_t message)
+{
+ plist_t backtrace = plist_dict_get_item(message, "RestoredBacktrace");
+ logger(LL_INFO, "*** restored crashed, backtrace following ***\n");
+ if (PLIST_IS_STRING(backtrace)) {
+ logger(LL_INFO, "%s\n", plist_get_string_ptr(backtrace, NULL));
+ } else if (PLIST_IS_ARRAY(backtrace)) {
+ uint32_t i = 0;
+ for (i = 0; i < plist_array_get_size(backtrace); i++) {
+ plist_t line = plist_array_get_item(backtrace, i);
+ logger(LL_INFO, "\t%s\n", plist_get_string_ptr(line, NULL));
+ }
+ } else {
+ logger_dump_plist(LL_VERBOSE, message, 1);
+ }
+ return 0;
+}
+
+static int restore_handle_async_wait(struct idevicerestore_client_t* client, plist_t message)
+{
+ logger(LL_DEBUG, "AsyncWait\n");
+ logger_dump_plist(LL_DEBUG, message, 1);
+ return 0;
+}
+
+static int restore_handle_restore_attestation(struct idevicerestore_client_t* client, plist_t message)
+{
+ logger_dump_plist(LL_DEBUG, message, 1);
+ logger(LL_DEBUG, "Sending RestoreShouldAttest: false\n");
+ plist_t dict = plist_new_dict();
+ plist_dict_set_item(dict, "RestoreShouldAttest", plist_new_bool(0));
+ restored_error_t restore_error = restored_send(client->restore->client, dict);
+ plist_free(dict);
+ if (restore_error != RESTORE_E_SUCCESS) {
+ logger(LL_ERROR, "Unable to send RestoreShouldAttest (%d)\n", restore_error);
+ return -1;
+ }
+ return 0;
+}
+
+static void _restore_calculate_recovery_os_partition_size(struct idevicerestore_client_t* client, uint64_t* min_size, uint64_t* max_size)
+{
+ const char* asset_list[] = { "OS", "KernelCache", "DeviceTree", "iBEC", "AppleLogo", "StaticTrustCache", "iBootData", "Diags", "Ap,SystemVolumeCanonicalMetadata", "SystemVolume", "BaseSystemVolume", "Ap,BaseSystemTrustCache", "AVISP1,RTKitOS", NULL };
+
+ if (min_size) *min_size = 356;
+ if (max_size) *max_size = 420;
+
+ double total_size = 0;
+ plist_t firmware_items = plist_new_dict();
+ plist_t build_id_manifest = plist_dict_get_item(client->recovery_variant, "Manifest");
+ plist_dict_iter iter = NULL;
+ plist_dict_new_iter(build_id_manifest, &iter);
+ if (iter) {
+ char *component = NULL;
+ plist_t manifest_entry;
+ do {
+ component = NULL;
+ manifest_entry = NULL;
+ plist_dict_next_item(build_id_manifest, iter, &component, &manifest_entry);
+ if (component && PLIST_IS_DICT(manifest_entry) && plist_dict_get_item(firmware_items, component) == NULL) {
+ int add_image = 0;
+ int i = 0;
+ while (asset_list[i]) {
+ if (!strcmp(asset_list[i], component)) {
+ add_image = 1;
+ break;
+ }
+ i++;
+ }
+ plist_t fw_node;
+ fw_node = plist_access_path(manifest_entry, 2, "Info", "IsLoadedByiBoot");
+ if (fw_node && plist_get_node_type(fw_node) == PLIST_BOOLEAN) {
+ uint8_t loaded_by_iboot = 0;
+ plist_get_bool_val(fw_node, &loaded_by_iboot);
+ if (loaded_by_iboot) {
+ add_image = 1;
+ }
+ }
+ if (add_image) {
+ plist_t p_path = plist_access_path(manifest_entry, 2, "Info", "Path");
+ if (p_path) {
+ const char* path = plist_get_string_ptr(p_path, NULL);
+ uint64_t fsize = 0;
+ if (ipsw_get_file_size(client->ipsw, path, &fsize) == 0) {
+ logger(LL_DEBUG, "%s: Adding %s (%s, %" PRIu64 " bytes)\n", __func__, component, path, fsize);
+ total_size += (double)fsize / 0x100000;
+ }
+ }
+ }
+ }
+ free(component);
+ } while (manifest_entry);
+ plist_mem_free(iter);
+ }
+ total_size = ceil(total_size);
+ if (min_size) *min_size = total_size * 1.05 + 25;
+ if (max_size) *max_size = total_size * 1.25 + 25;
+}
+
// Extracted from ac2
plist_t restore_supported_data_types()
{
plist_t dict = plist_new_dict();
+ plist_dict_set_item(dict, "AuthInstallCACert", plist_new_bool(1));
plist_dict_set_item(dict, "BasebandBootData", plist_new_bool(0));
plist_dict_set_item(dict, "BasebandData", plist_new_bool(0));
plist_dict_set_item(dict, "BasebandStackData", plist_new_bool(0));
@@ -3532,6 +5152,7 @@ plist_t restore_supported_data_types()
plist_dict_set_item(dict, "BootabilityBundle", plist_new_bool(0));
plist_dict_set_item(dict, "BuildIdentityDict", plist_new_bool(0));
plist_dict_set_item(dict, "BuildIdentityDictV2", plist_new_bool(0));
+ plist_dict_set_item(dict, "Cryptex1LocalPolicy", plist_new_bool(1));
plist_dict_set_item(dict, "DataType", plist_new_bool(0));
plist_dict_set_item(dict, "DiagData", plist_new_bool(0));
plist_dict_set_item(dict, "EANData", plist_new_bool(0));
@@ -3541,20 +5162,26 @@ plist_t restore_supported_data_types()
plist_dict_set_item(dict, "FileData", plist_new_bool(0));
plist_dict_set_item(dict, "FileDataDone", plist_new_bool(0));
plist_dict_set_item(dict, "FirmwareUpdaterData", plist_new_bool(0));
+ plist_dict_set_item(dict, "FirmwareUpdaterDataV2", plist_new_bool(0));
+ plist_dict_set_item(dict, "FirmwareUpdaterDataV3", plist_new_bool(1));
+ plist_dict_set_item(dict, "FirmwareUpdaterPreflight", plist_new_bool(1));
plist_dict_set_item(dict, "GrapeFWData", plist_new_bool(0));
plist_dict_set_item(dict, "HPMFWData", plist_new_bool(0));
plist_dict_set_item(dict, "HostSystemTime", plist_new_bool(1));
plist_dict_set_item(dict, "KernelCache", plist_new_bool(0));
+ plist_dict_set_item(dict, "MessageUseStreamedImageFile", plist_new_bool(1));
plist_dict_set_item(dict, "NORData", plist_new_bool(0));
plist_dict_set_item(dict, "NitrogenFWData", plist_new_bool(1));
plist_dict_set_item(dict, "OpalFWData", plist_new_bool(0));
plist_dict_set_item(dict, "OverlayRootDataCount", plist_new_bool(0));
plist_dict_set_item(dict, "OverlayRootDataForKey", plist_new_bool(1));
+ plist_dict_set_item(dict, "OverlayRootDataForKeyIndex", plist_new_bool(1));
plist_dict_set_item(dict, "PeppyFWData", plist_new_bool(1));
plist_dict_set_item(dict, "PersonalizedBootObjectV3", plist_new_bool(0));
plist_dict_set_item(dict, "PersonalizedData", plist_new_bool(1));
plist_dict_set_item(dict, "ProvisioningData", plist_new_bool(0));
plist_dict_set_item(dict, "RamdiskFWData", plist_new_bool(1));
+ plist_dict_set_item(dict, "ReceiptManifest", plist_new_bool(1));
plist_dict_set_item(dict, "RecoveryOSASRImage", plist_new_bool(1));
plist_dict_set_item(dict, "RecoveryOSAppleLogo", plist_new_bool(1));
plist_dict_set_item(dict, "RecoveryOSDeviceTree", plist_new_bool(1));
@@ -3568,6 +5195,7 @@ plist_t restore_supported_data_types()
plist_dict_set_item(dict, "RecoveryOSRootTicketData", plist_new_bool(1));
plist_dict_set_item(dict, "RecoveryOSStaticTrustCache", plist_new_bool(1));
plist_dict_set_item(dict, "RecoveryOSVersionData", plist_new_bool(1));
+ plist_dict_set_item(dict, "RestoreLocalPolicy", plist_new_bool(1));
plist_dict_set_item(dict, "RootData", plist_new_bool(0));
plist_dict_set_item(dict, "RootTicket", plist_new_bool(0));
plist_dict_set_item(dict, "S3EOverride", plist_new_bool(0));
@@ -3578,8 +5206,10 @@ plist_t restore_supported_data_types()
plist_dict_set_item(dict, "SystemImageCanonicalMetadata", plist_new_bool(0));
plist_dict_set_item(dict, "SystemImageData", plist_new_bool(0));
plist_dict_set_item(dict, "SystemImageRootHash", plist_new_bool(0));
+ plist_dict_set_item(dict, "URLAsset", plist_new_bool(1));
plist_dict_set_item(dict, "USBCFWData", plist_new_bool(0));
plist_dict_set_item(dict, "USBCOverride", plist_new_bool(0));
+ plist_dict_set_item(dict, "UpdateVolumeOverlayRootDataCount", plist_new_bool(1));
return dict;
}
@@ -3587,8 +5217,11 @@ plist_t restore_supported_data_types()
plist_t restore_supported_message_types()
{
plist_t dict = plist_new_dict();
+ plist_dict_set_item(dict, "AsyncDataRequestMsg", plist_new_bool(1));
+ plist_dict_set_item(dict, "AsyncWait", plist_new_bool(1));
plist_dict_set_item(dict, "BBUpdateStatusMsg", plist_new_bool(0));
plist_dict_set_item(dict, "CheckpointMsg", plist_new_bool(1));
+ plist_dict_set_item(dict, "CrashLog", plist_new_bool(1));
plist_dict_set_item(dict, "DataRequestMsg", plist_new_bool(0));
plist_dict_set_item(dict, "FDRSubmit", plist_new_bool(1));
plist_dict_set_item(dict, "MsgType", plist_new_bool(0));
@@ -3598,6 +5231,7 @@ plist_t restore_supported_message_types()
plist_dict_set_item(dict, "ProvisioningInfo", plist_new_bool(0));
plist_dict_set_item(dict, "ProvisioningStatusMsg", plist_new_bool(0));
plist_dict_set_item(dict, "ReceivedFinalStatusMsg", plist_new_bool(0));
+ plist_dict_set_item(dict, "RestoreAttestation", plist_new_bool(1));
plist_dict_set_item(dict, "RestoredCrash", plist_new_bool(1));
plist_dict_set_item(dict, "StatusMsg", plist_new_bool(0));
return dict;
@@ -3606,16 +5240,16 @@ plist_t restore_supported_message_types()
#ifdef HAVE_REVERSE_PROXY
static void rp_log_cb(reverse_proxy_client_t client, const char* log_msg, void* user_data)
{
- info("ReverseProxy[%s]: %s\n", (reverse_proxy_get_type(client) == RP_TYPE_CTRL) ? "Ctrl" : "Conn", log_msg);
+ logger(LL_VERBOSE, "ReverseProxy[%s]: %s\n", (reverse_proxy_get_type(client) == RP_TYPE_CTRL) ? "Ctrl" : "Conn", log_msg);
}
static void rp_status_cb(reverse_proxy_client_t client, reverse_proxy_status_t status, const char* status_msg, void* user_data)
{
- info("ReverseProxy[%s]: (status=%d) %s\n", (reverse_proxy_get_type(client) == RP_TYPE_CTRL) ? "Ctrl" : "Conn", status, status_msg);
+ logger(LL_VERBOSE, "ReverseProxy[%s]: (status=%d) %s\n", (reverse_proxy_get_type(client) == RP_TYPE_CTRL) ? "Ctrl" : "Conn", status, status_msg);
}
#endif
-int restore_device(struct idevicerestore_client_t* client, plist_t build_identity, const char* filesystem)
+int restore_device(struct idevicerestore_client_t* client, plist_t build_identity)
{
int err = 0;
char* type = NULL;
@@ -3634,11 +5268,12 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
// open our connection to the device and verify we're in restore mode
err = restore_open_with_timeout(client);
if (err < 0) {
- error("ERROR: Unable to open device in restore mode\n");
+ logger(LL_ERROR, "Unable to open device in restore mode\n");
return (err == -2) ? -1: -2;
}
- info("Device %s has successfully entered restore mode\n", client->udid);
+ logger(LL_INFO, "Device %s has successfully entered restore mode\n", client->udid);
+ client->restore->build_identity = build_identity;
restore = client->restore->client;
device = client->restore->device;
@@ -3646,30 +5281,30 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
if (restore_error == RESTORE_E_SUCCESS) {
uint64_t i = 0;
uint8_t b = 0;
- info("Hardware Information:\n");
+ logger(LL_INFO, "Hardware Information:\n");
node = plist_dict_get_item(hwinfo, "BoardID");
if (node && plist_get_node_type(node) == PLIST_UINT) {
plist_get_uint_val(node, &i);
- info("BoardID: %d\n", (int)i);
+ logger(LL_INFO, "BoardID: %d\n", (int)i);
}
node = plist_dict_get_item(hwinfo, "ChipID");
if (node && plist_get_node_type(node) == PLIST_UINT) {
plist_get_uint_val(node, &i);
- info("ChipID: %d\n", (int)i);
+ logger(LL_INFO, "ChipID: %d\n", (int)i);
}
node = plist_dict_get_item(hwinfo, "UniqueChipID");
if (node && plist_get_node_type(node) == PLIST_UINT) {
plist_get_uint_val(node, &i);
- info("UniqueChipID: %" PRIu64 "\n", i);
+ logger(LL_INFO, "UniqueChipID: %" PRIu64 "\n", i);
}
node = plist_dict_get_item(hwinfo, "ProductionMode");
if (node && plist_get_node_type(node) == PLIST_BOOLEAN) {
plist_get_bool_val(node, &b);
- info("ProductionMode: %s\n", (b==1) ? "true":"false");
+ logger(LL_INFO, "ProductionMode: %s\n", (b==1) ? "true":"false");
}
plist_free(hwinfo);
}
@@ -3681,7 +5316,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
node = plist_dict_get_item(hwinfo, "PreviousExitStatus");
if (node && plist_get_node_type(node) == PLIST_STRING) {
plist_get_string_val(node, &sval);
- info("Previous restore exit status: %s\n", sval);
+ logger(LL_INFO, "Previous restore exit status: %s\n", sval);
free(sval);
sval = NULL;
}
@@ -3689,7 +5324,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
node = plist_dict_get_item(hwinfo, "USBLog");
if (node && plist_get_node_type(node) == PLIST_STRING) {
plist_get_string_val(node, &sval);
- info("USB log is available:\n%s\n", sval);
+ logger(LL_INFO, "USB log is available:\n%s\n", sval);
free(sval);
sval = NULL;
}
@@ -3697,7 +5332,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
node = plist_dict_get_item(hwinfo, "PanicLog");
if (node && plist_get_node_type(node) == PLIST_STRING) {
plist_get_string_val(node, &sval);
- info("Panic log is available:\n%s\n", sval);
+ logger(LL_INFO, "Panic log is available:\n%s\n", sval);
free(sval);
sval = NULL;
}
@@ -3709,42 +5344,42 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
}
#ifdef HAVE_REVERSE_PROXY
- info("Starting Reverse Proxy\n");
+ logger(LL_INFO, "Starting Reverse Proxy\n");
reverse_proxy_client_t rproxy = NULL;
if (reverse_proxy_client_create_with_port(device, &rproxy, REVERSE_PROXY_DEFAULT_PORT) != REVERSE_PROXY_E_SUCCESS) {
- error("Could not create Reverse Proxy\n");
+ logger(LL_ERROR, "Could not create Reverse Proxy\n");
} else {
if (client->flags & FLAG_DEBUG) {
reverse_proxy_client_set_log_callback(rproxy, rp_log_cb, NULL);
}
reverse_proxy_client_set_status_callback(rproxy, rp_status_cb, NULL);
if (reverse_proxy_client_start_proxy(rproxy, 2) != REVERSE_PROXY_E_SUCCESS) {
- error("Device didn't accept new reverse proxy protocol, trying to use old one\n");
+ logger(LL_ERROR, "Device didn't accept new reverse proxy protocol, trying to use old one\n");
reverse_proxy_client_free(rproxy);
rproxy = NULL;
if (reverse_proxy_client_create_with_port(device, &rproxy, REVERSE_PROXY_DEFAULT_PORT) != REVERSE_PROXY_E_SUCCESS) {
- error("Could not create Reverse Proxy\n");
+ logger(LL_ERROR, "Could not create Reverse Proxy\n");
} else {
if (client->flags & FLAG_DEBUG) {
reverse_proxy_client_set_log_callback(rproxy, rp_log_cb, NULL);
}
reverse_proxy_client_set_status_callback(rproxy, rp_status_cb, NULL);
if (reverse_proxy_client_start_proxy(rproxy, 1) != REVERSE_PROXY_E_SUCCESS) {
- error("ReverseProxy: Device didn't accept old protocol, giving up\n");
+ logger(LL_ERROR, "ReverseProxy: Device didn't accept old protocol, giving up\n");
}
}
}
}
#else
fdr_client_t fdr_control_channel = NULL;
- info("Starting FDR listener thread\n");
+ logger(LL_INFO, "Starting FDR listener thread\n");
if (!fdr_connect(device, FDR_CTRL, &fdr_control_channel)) {
if(thread_new(&fdr_thread, fdr_listener_thread, fdr_control_channel)) {
- error("ERROR: Failed to start FDR listener thread\n");
+ logger(LL_ERROR, "Failed to start FDR listener thread\n");
fdr_thread = THREAD_T_NULL; /* undefined after failure */
}
} else {
- error("ERROR: Failed to start FDR Ctrl channel\n");
+ logger(LL_ERROR, "Failed to start FDR Ctrl channel\n");
// FIXME: We might want to return failure here as it will likely fail
}
#endif
@@ -3754,26 +5389,22 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
//plist_dict_set_item(opts, "AuthInstallRestoreBehavior", plist_new_string("Erase"));
plist_dict_set_item(opts, "AutoBootDelay", plist_new_uint(0));
- if (client->preflight_info) {
- plist_t node;
- plist_t bbus = plist_copy(client->preflight_info);
+ if (client->firmware_preflight_info) {
+ plist_t bbus = plist_copy(client->firmware_preflight_info);
plist_dict_remove_item(bbus, "FusingStatus");
plist_dict_remove_item(bbus, "PkHash");
plist_dict_set_item(opts, "BBUpdaterState", bbus);
- node = plist_dict_get_item(client->preflight_info, "Nonce");
- if (node) {
- plist_dict_set_item(opts, "BasebandNonce", plist_copy(node));
- }
+ plist_dict_copy_data(opts, client->firmware_preflight_info, "BasebandNonce", "Nonce");
}
plist_dict_set_item(opts, "SupportedDataTypes", restore_supported_data_types());
plist_dict_set_item(opts, "SupportedMessageTypes", restore_supported_message_types());
// FIXME: Should be adjusted for update behaviors
- if (client->build_major >= 20) {
+ if (client->macos_variant) {
plist_dict_set_item(opts, "AddSystemPartitionPadding", plist_new_bool(1));
plist_dict_set_item(opts, "AllowUntetheredRestore", plist_new_bool(0));
plist_dict_set_item(opts, "AuthInstallEnableSso", plist_new_bool(0));
@@ -3812,7 +5443,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
}
} else {
// FIXME: new on iOS 5 ?
- plist_dict_set_item(opts, "BootImageType", plist_new_string("UserOrInternal"));
+ plist_dict_set_item(opts, "BootImageType", plist_new_string("User"));
// FIXME: required?
//plist_dict_set_item(opts, "BootImageFile", plist_new_string("018-7923-347.dmg"));
plist_dict_set_item(opts, "DFUFileType", plist_new_string("RELEASE"));
@@ -3838,7 +5469,32 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
// FIXME: new on iOS 5 ?
plist_dict_set_item(opts, "SystemImageType", plist_new_string("User"));
// FIXME: does this have any effect actually?
- plist_dict_set_item(opts, "UpdateBaseband", plist_new_bool(0));
+ plist_dict_set_item(opts, "UpdateBaseband", plist_new_bool(1));
+ plist_dict_set_item(opts, "InstallDiags", plist_new_bool(0));
+ if (client->recovery_variant) {
+ plist_dict_set_item(opts, "InstallRecoveryOS", plist_new_bool(1));
+ plist_dict_set_item(opts, "RecoveryOSBundlePath", plist_new_string("/tmp/Per2.tmp"));
+ plist_t recovery_variant = plist_access_path(client->recovery_variant, 2, "Info", "Variant");
+ plist_dict_set_item(opts, "AuthInstallRecoveryOSVariant", plist_copy(recovery_variant));
+ uint64_t max_size = 0;
+ uint64_t min_size = 0;
+ _restore_calculate_recovery_os_partition_size(client, &min_size, &max_size);
+ logger(LL_INFO, "Calculated recoveryOSPartitionSize as %" PRIu64 " MB\n", min_size);
+ logger(LL_INFO, "Calculated recoveryOSMaxPartitionSize as %" PRIu64 " MB\n", max_size);
+ plist_dict_set_item(opts, "recoveryOSMaxPartitionSize", plist_new_uint(max_size));
+ plist_dict_set_item(opts, "recoveryOSPartitionSize", plist_new_uint(min_size));
+ }
+
+ if (plist_dict_get_bool(client->parameters, "RequiresNonceSlot")) {
+ logger(LL_INFO, "Device will use nonce slots.\n");
+ } else {
+ logger(LL_INFO, "Device will not use nonce slots.\n");
+ }
+
+ // Added for iOS 18.0 beta 1
+ plist_dict_set_item(opts, "HostHasFixFor99053849", plist_new_bool(1));
+ plist_dict_set_item(opts, "SystemImageFormat", plist_new_string("AEAWrappedDiskImage"));
+ plist_dict_set_item(opts, "WaitForDeviceConnectionToFinishStateMachine", plist_new_bool(0));
plist_t sep = plist_access_path(build_identity, 3, "Manifest", "SEP", "Info");
if (sep) {
@@ -3846,7 +5502,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
if (node && plist_get_node_type(node) == PLIST_STRING) {
char* sval = NULL;
plist_get_string_val(node, &sval);
- debug("TZ0RequiredCapacity: %s\n", sval);
+ logger(LL_DEBUG, "TZ0RequiredCapacity: %s\n", sval);
plist_dict_set_item(opts, "TZ0RequiredCapacity", plist_copy(node));
free(sval);
sval = NULL;
@@ -3858,6 +5514,15 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
plist_dict_set_item(opts, "PersonalizedDuringPreflight", plist_new_bool(1));
}
+ // Added for iOS 18.0 and macOS 15.0
+ plist_t async_data_types = plist_new_dict();
+ plist_dict_set_item(async_data_types, "BasebandData", plist_new_bool(0));
+ plist_dict_set_item(async_data_types, "RecoveryOSASRImage", plist_new_bool(0));
+ plist_dict_set_item(async_data_types, "StreamedImageDecryptionKey", plist_new_bool(0));
+ plist_dict_set_item(async_data_types, "SystemImageData", plist_new_bool(0));
+ plist_dict_set_item(async_data_types, "URLAsset", plist_new_bool(1));
+ plist_dict_set_item(opts, "SupportedAsyncDataTypes", async_data_types);
+
plist_dict_set_item(opts, "RootToInstall", plist_new_bool(0));
char* guid = generate_guid();
if (guid) {
@@ -3874,10 +5539,14 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
spp = plist_copy(spp);
} else {
spp = plist_new_dict();
+ plist_dict_set_item(spp, "1024", plist_new_uint(1280));
plist_dict_set_item(spp, "128", plist_new_uint(1280));
plist_dict_set_item(spp, "16", plist_new_uint(160));
+ plist_dict_set_item(spp, "256", plist_new_uint(1280));
plist_dict_set_item(spp, "32", plist_new_uint(320));
+ plist_dict_set_item(spp, "512", plist_new_uint(1280));
plist_dict_set_item(spp, "64", plist_new_uint(640));
+ plist_dict_set_item(spp, "768", plist_new_uint(1280));
plist_dict_set_item(spp, "8", plist_new_uint(80));
}
plist_dict_set_item(opts, "SystemPartitionPadding", spp);
@@ -3885,7 +5554,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
// start the restore process
restore_error = restored_start_restore(restore, opts, client->restore->protocol_version);
if (restore_error != RESTORE_E_SUCCESS) {
- error("ERROR: Unable to start the restore process\n");
+ logger(LL_ERROR, "Unable to start the restore process\n");
plist_free(opts);
restore_client_free(client);
return -1;
@@ -3896,31 +5565,31 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
// this is the restore process loop, it reads each message in from
// restored and passes that data on to it's specific handler
while (!(client->flags & FLAG_QUIT)) {
- if (client->flags & FLAG_IGNORE_ERRORS) {
- error("WARNING: Attempting to continue after critical error, restore might fail...\n");
+ if (err != 0 && client->flags & FLAG_IGNORE_ERRORS) {
+ logger(LL_WARNING, "Attempting to continue after critical error, restore might fail...\n");
err = 0;
}
// finally, if any of these message handlers returned -1 then we encountered
// an unrecoverable error, so we need to bail.
if (err < 0) {
- error("ERROR: Unable to successfully restore device\n");
+ logger(LL_ERROR, "Unable to successfully restore device\n");
client->flags |= FLAG_QUIT;
}
restore_error = restored_receive(restore, &message);
#ifdef HAVE_RESTORE_E_RECEIVE_TIMEOUT
if (restore_error == RESTORE_E_RECEIVE_TIMEOUT) {
- debug("No data to read (timeout)\n");
+ logger(LL_DEBUG, "No data to read (timeout)\n");
message = NULL;
continue;
} else if (restore_error != RESTORE_E_SUCCESS) {
- error("ERROR: Could not read data (%d). Aborting.\n", restore_error);
+ logger(LL_ERROR, "Could not read data (%d). Aborting.\n", restore_error);
err = -11;
break;
}
#else
if (restore_error != RESTORE_E_SUCCESS) {
- debug("No data to read\n");
+ logger(LL_DEBUG, "No data to read\n");
message = NULL;
continue;
}
@@ -3929,9 +5598,8 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
// discover what kind of message has been received
node = plist_dict_get_item(message, "MsgType");
if (!node || plist_get_node_type(node) != PLIST_STRING) {
- debug("Unknown message received:\n");
- //if (idevicerestore_debug)
- debug_plist(message);
+ logger(LL_DEBUG, "Unknown message received:\n");
+ logger_dump_plist(LL_DEBUG, message, 1);
plist_free(message);
message = NULL;
continue;
@@ -3942,7 +5610,25 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
// files sent to the server by the client. these data requests include
// SystemImageData, RootTicket, KernelCache, NORData and BasebandData requests
if (!strcmp(type, "DataRequestMsg")) {
- err = restore_handle_data_request_msg(client, device, restore, message, build_identity, filesystem);
+ err = restore_handle_data_request_msg(client, message);
+ }
+
+ // async data request message
+ else if (!strcmp(type, "AsyncDataRequestMsg")) {
+ THREAD_T t = THREAD_T_NULL;
+ struct _restore_async_args* args = (struct _restore_async_args*)malloc(sizeof(struct _restore_async_args));
+ args->client = client;
+ args->message = plist_copy(message);
+ if (thread_new(&t, _restore_handle_async_data_request, args) < 0) {
+ free(args);
+ logger(LL_ERROR, "Failed to start async data request handler thread!\n");
+ err = -1;
+ if (client->flags & FLAG_IGNORE_ERRORS) {
+ client->flags &= ~FLAG_IGNORE_ERRORS;
+ }
+ } else {
+ thread_detach(t);
+ }
}
// restore logs are available if a previous restore failed
@@ -3959,7 +5645,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
// status messages usually indicate the current state of the restored
// process or often to signal an error has been encountered
else if (!strcmp(type, "StatusMsg")) {
- err = restore_handle_status_msg(restore, message);
+ err = restore_handle_status_msg(client, message);
if (restore_finished) {
plist_t dict = plist_new_dict();
plist_dict_set_item(dict, "MsgType", plist_new_string("ReceivedFinalStatusMsg"));
@@ -3971,53 +5657,87 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
else if (!strcmp(type, "CheckpointMsg")) {
uint64_t ckpt_id;
- uint64_t ckpt_res;
+ int64_t ckpt_res;
uint8_t ckpt_complete = 0;
+ const char* ckpt_name = NULL;
// Get checkpoint id
node = plist_dict_get_item(message, "CHECKPOINT_ID");
- if (!node || plist_get_node_type(node) != PLIST_UINT) {
- debug("Failed to parse checkpoint id from checkpoint plist\n");
- return -1;
+ if (!node || plist_get_node_type(node) != PLIST_INT) {
+ logger(LL_DEBUG, "Failed to parse checkpoint id from checkpoint plist\n");
+ err = -1;
+ break;
}
plist_get_uint_val(node, &ckpt_id);
+ // Get checkpoint_name
+ node = plist_dict_get_item(message, "CHECKPOINT_NAME");
+ ckpt_name = (node) ? plist_get_string_ptr(node, NULL) : "unknown";
// Get checkpoint result
node = plist_dict_get_item(message, "CHECKPOINT_RESULT");
- if (!node || plist_get_node_type(node) != PLIST_UINT) {
- debug("Failed to parse checkpoint result from checkpoint plist\n");
- return -1;
+ if (!node || plist_get_node_type(node) != PLIST_INT) {
+ logger(LL_DEBUG, "Failed to parse checkpoint result from checkpoint plist\n");
+ err = -1;
+ break;
}
- plist_get_uint_val(node, &ckpt_res);
+ plist_get_int_val(node, &ckpt_res);
// Get checkpoint complete
node = plist_dict_get_item(message, "CHECKPOINT_COMPLETE");
if (PLIST_IS_BOOLEAN(node)) {
plist_get_bool_val(node, &ckpt_complete);
}
- if (ckpt_complete)
- info("Checkpoint %" PRIu64 " complete with code %" PRIu64 "\n", ckpt_id, ckpt_res);
+
+ if (ckpt_complete) {
+ logger(LL_VERBOSE, "Checkpoint completed id: 0x%" PRIX64 " (%s) result=%" PRIi64 "\n", ckpt_id, ckpt_name, ckpt_res);
+ } else {
+ logger(LL_VERBOSE, "Checkpoint started id: 0x%" PRIX64 " (%s)\n", ckpt_id, ckpt_name);
+ }
+ node = plist_dict_get_item(message, "CHECKPOINT_WARNING");
+ if (node) {
+ logger(LL_VERBOSE, "Checkpoint WARNING id: 0x%" PRIX64 " result=%" PRIi64 ": %s\n", ckpt_id, ckpt_res, plist_get_string_ptr(node, NULL));
+ }
+ node = plist_dict_get_item(message, "CHECKPOINT_ERROR");
+ if (node) {
+ logger(LL_VERBOSE, "Checkpoint FAILURE id: 0x%" PRIX64 " result=%" PRIi64 ": %s\n", ckpt_id, ckpt_res, plist_get_string_ptr(node, NULL));
+ }
}
// baseband update message
else if (!strcmp(type, "BBUpdateStatusMsg")) {
- err = restore_handle_bb_update_status_msg(restore, message);
+ err = restore_handle_bb_update_status_msg(client, message);
}
// baseband updater output data request
else if (!strcmp(type, "BasebandUpdaterOutputData")) {
- err = restore_handle_baseband_updater_output_data(restore, client, device, message);
+ err = restore_handle_baseband_updater_output_data(client, message);
+ }
+
+ // handle restored crash, print backtrace
+ else if (!strcmp(type, "RestoredCrash")) {
+ err = restore_handle_restored_crash(client, message);
+ }
+
+ // handle async wait
+ else if (!strcmp(type, "AsyncWait")) {
+ err = restore_handle_async_wait(client, message);
+ }
+
+ else if (!strcmp(type, "RestoreAttestation")) {
+ err = restore_handle_restore_attestation(client, message);
}
// there might be some other message types i'm not aware of, but I think
// at least the "previous error logs" messages usually end up here
else {
- debug("Unknown message type received\n");
- //if (idevicerestore_debug)
- debug_plist(message);
+ logger(LL_DEBUG, "Unknown message type received\n");
+ logger_dump_plist(LL_DEBUG, message, 1);
}
free(type);
plist_free(message);
message = NULL;
}
+ if (client->async_err != 0) {
+ err = client->async_err;
+ }
#ifdef HAVE_REVERSE_PROXY
reverse_proxy_client_free(rproxy);
diff --git a/src/restore.h b/src/restore.h
index c93e325..763331d 100644
--- a/src/restore.h
+++ b/src/restore.h
@@ -38,9 +38,9 @@ struct restore_client_t {
idevice_t device;
char* udid;
unsigned int operation;
- const char* filesystem;
uint64_t protocol_version;
restored_client_t client;
+ plist_t build_identity;
};
int restore_check_mode(struct idevicerestore_client_t* client);
@@ -50,16 +50,16 @@ void restore_client_free(struct idevicerestore_client_t* client);
int restore_is_image4_supported(struct idevicerestore_client_t* client);
int restore_reboot(struct idevicerestore_client_t* client);
const char* restore_progress_string(unsigned int operation);
-int restore_handle_status_msg(restored_client_t client, plist_t msg);
-int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t msg);
-int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t build_identity, const char* filesystem);
-int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity);
-int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_client_t* client);
-int restore_send_component(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, const char* component, const char* component_name);
-int restore_device(struct idevicerestore_client_t* client, plist_t build_identity, const char* filesystem);
+int restore_handle_status_msg(struct idevicerestore_client_t* client, plist_t message);
+int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t message);
+int restore_handle_data_request_msg(struct idevicerestore_client_t* client, plist_t message);
+int restore_send_nor(struct idevicerestore_client_t* client, plist_t message);
+int restore_send_root_ticket(struct idevicerestore_client_t* client, plist_t message);
+int restore_send_component(struct idevicerestore_client_t* client, plist_t message, const char* component, const char* component_name);
+int restore_device(struct idevicerestore_client_t* client, plist_t build_identity);
int restore_open_with_timeout(struct idevicerestore_client_t* client);
-int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device, const char* filesystem);
-int restore_send_fdr_trust_data(restored_client_t restore, idevice_t device);
+int restore_send_filesystem(struct idevicerestore_client_t* client, plist_t message);
+int restore_send_fdr_trust_data(struct idevicerestore_client_t* client, plist_t message);
#ifdef __cplusplus
}
diff --git a/src/sha1.c b/src/sha1.c
deleted file mode 100644
index 02557ff..0000000
--- a/src/sha1.c
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
-SHA-1 in C
-By Steve Reid <steve@edmweb.com>
-100% Public Domain
-Test Vectors (from FIPS PUB 180-1)
-"abc"
- A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
-"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
- 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
-A million repetitions of "a"
- 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
-*/
-
-/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
-/* #define SHA1HANDSOFF * Copies data before messing with it. */
-
-#define SHA1HANDSOFF
-
-#include <stdio.h>
-#include <string.h>
-
-/* for uint32_t */
-#include <stdint.h>
-
-#include "sha1.h"
-
-
-#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
-
-/* blk0() and blk() perform the initial expand. */
-/* I got the idea of expanding during the round function from SSLeay */
-#if BYTE_ORDER == LITTLE_ENDIAN
-#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
- |(rol(block->l[i],8)&0x00FF00FF))
-#elif BYTE_ORDER == BIG_ENDIAN
-#define blk0(i) block->l[i]
-#else
-#error "Endianness not defined!"
-#endif
-#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
- ^block->l[(i+2)&15]^block->l[i&15],1))
-
-/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
-#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
-#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
-#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
-#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
-#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
-
-
-/* Hash a single 512-bit block. This is the core of the algorithm. */
-
-void SHA1Transform(
- uint32_t state[5],
- const unsigned char buffer[64]
-)
-{
- uint32_t a, b, c, d, e;
-
- typedef union
- {
- unsigned char c[64];
- uint32_t l[16];
- } CHAR64LONG16;
-
-#ifdef SHA1HANDSOFF
- CHAR64LONG16 block[1]; /* use array to appear as a pointer */
-
- memcpy(block, buffer, 64);
-#else
- /* The following had better never be used because it causes the
- * pointer-to-const buffer to be cast into a pointer to non-const.
- * And the result is written through. I threw a "const" in, hoping
- * this will cause a diagnostic.
- */
- CHAR64LONG16 *block = (const CHAR64LONG16 *) buffer;
-#endif
- /* Copy context->state[] to working vars */
- a = state[0];
- b = state[1];
- c = state[2];
- d = state[3];
- e = state[4];
- /* 4 rounds of 20 operations each. Loop unrolled. */
- R0(a, b, c, d, e, 0);
- R0(e, a, b, c, d, 1);
- R0(d, e, a, b, c, 2);
- R0(c, d, e, a, b, 3);
- R0(b, c, d, e, a, 4);
- R0(a, b, c, d, e, 5);
- R0(e, a, b, c, d, 6);
- R0(d, e, a, b, c, 7);
- R0(c, d, e, a, b, 8);
- R0(b, c, d, e, a, 9);
- R0(a, b, c, d, e, 10);
- R0(e, a, b, c, d, 11);
- R0(d, e, a, b, c, 12);
- R0(c, d, e, a, b, 13);
- R0(b, c, d, e, a, 14);
- R0(a, b, c, d, e, 15);
- R1(e, a, b, c, d, 16);
- R1(d, e, a, b, c, 17);
- R1(c, d, e, a, b, 18);
- R1(b, c, d, e, a, 19);
- R2(a, b, c, d, e, 20);
- R2(e, a, b, c, d, 21);
- R2(d, e, a, b, c, 22);
- R2(c, d, e, a, b, 23);
- R2(b, c, d, e, a, 24);
- R2(a, b, c, d, e, 25);
- R2(e, a, b, c, d, 26);
- R2(d, e, a, b, c, 27);
- R2(c, d, e, a, b, 28);
- R2(b, c, d, e, a, 29);
- R2(a, b, c, d, e, 30);
- R2(e, a, b, c, d, 31);
- R2(d, e, a, b, c, 32);
- R2(c, d, e, a, b, 33);
- R2(b, c, d, e, a, 34);
- R2(a, b, c, d, e, 35);
- R2(e, a, b, c, d, 36);
- R2(d, e, a, b, c, 37);
- R2(c, d, e, a, b, 38);
- R2(b, c, d, e, a, 39);
- R3(a, b, c, d, e, 40);
- R3(e, a, b, c, d, 41);
- R3(d, e, a, b, c, 42);
- R3(c, d, e, a, b, 43);
- R3(b, c, d, e, a, 44);
- R3(a, b, c, d, e, 45);
- R3(e, a, b, c, d, 46);
- R3(d, e, a, b, c, 47);
- R3(c, d, e, a, b, 48);
- R3(b, c, d, e, a, 49);
- R3(a, b, c, d, e, 50);
- R3(e, a, b, c, d, 51);
- R3(d, e, a, b, c, 52);
- R3(c, d, e, a, b, 53);
- R3(b, c, d, e, a, 54);
- R3(a, b, c, d, e, 55);
- R3(e, a, b, c, d, 56);
- R3(d, e, a, b, c, 57);
- R3(c, d, e, a, b, 58);
- R3(b, c, d, e, a, 59);
- R4(a, b, c, d, e, 60);
- R4(e, a, b, c, d, 61);
- R4(d, e, a, b, c, 62);
- R4(c, d, e, a, b, 63);
- R4(b, c, d, e, a, 64);
- R4(a, b, c, d, e, 65);
- R4(e, a, b, c, d, 66);
- R4(d, e, a, b, c, 67);
- R4(c, d, e, a, b, 68);
- R4(b, c, d, e, a, 69);
- R4(a, b, c, d, e, 70);
- R4(e, a, b, c, d, 71);
- R4(d, e, a, b, c, 72);
- R4(c, d, e, a, b, 73);
- R4(b, c, d, e, a, 74);
- R4(a, b, c, d, e, 75);
- R4(e, a, b, c, d, 76);
- R4(d, e, a, b, c, 77);
- R4(c, d, e, a, b, 78);
- R4(b, c, d, e, a, 79);
- /* Add the working vars back into context.state[] */
- state[0] += a;
- state[1] += b;
- state[2] += c;
- state[3] += d;
- state[4] += e;
- /* Wipe variables */
- a = b = c = d = e = 0;
-#ifdef SHA1HANDSOFF
- memset(block, '\0', sizeof(block));
-#endif
-}
-
-
-/* SHA1Init - Initialize new context */
-
-void SHA1Init(
- SHA1_CTX * context
-)
-{
- /* SHA1 initialization constants */
- context->state[0] = 0x67452301;
- context->state[1] = 0xEFCDAB89;
- context->state[2] = 0x98BADCFE;
- context->state[3] = 0x10325476;
- context->state[4] = 0xC3D2E1F0;
- context->count[0] = context->count[1] = 0;
-}
-
-
-/* Run your data through this. */
-
-void SHA1Update(
- SHA1_CTX * context,
- const unsigned char *data,
- size_t len
-)
-{
- size_t i;
-
- size_t j;
-
- j = context->count[0];
- if ((context->count[0] += len << 3) < j)
- context->count[1]++;
- context->count[1] += (len >> 29);
- j = (j >> 3) & 63;
- if ((j + len) > 63)
- {
- memcpy(&context->buffer[j], data, (i = 64 - j));
- SHA1Transform(context->state, context->buffer);
- for (; i + 63 < len; i += 64)
- {
- SHA1Transform(context->state, &data[i]);
- }
- j = 0;
- }
- else
- i = 0;
- memcpy(&context->buffer[j], &data[i], len - i);
-}
-
-
-/* Add padding and return the message digest. */
-
-void SHA1Final(
- unsigned char digest[20],
- SHA1_CTX * context
-)
-{
- unsigned i;
-
- unsigned char finalcount[8];
-
- unsigned char c;
-
-#if 0 /* untested "improvement" by DHR */
- /* Convert context->count to a sequence of bytes
- * in finalcount. Second element first, but
- * big-endian order within element.
- * But we do it all backwards.
- */
- unsigned char *fcp = &finalcount[8];
-
- for (i = 0; i < 2; i++)
- {
- uint32_t t = context->count[i];
-
- int j;
-
- for (j = 0; j < 4; t >>= 8, j++)
- *--fcp = (unsigned char) t}
-#else
- for (i = 0; i < 8; i++)
- {
- finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); /* Endian independent */
- }
-#endif
- c = 0200;
- SHA1Update(context, &c, 1);
- while ((context->count[0] & 504) != 448)
- {
- c = 0000;
- SHA1Update(context, &c, 1);
- }
- SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
- for (i = 0; i < 20; i++)
- {
- digest[i] = (unsigned char)
- ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
- }
- /* Wipe variables */
- memset(context, '\0', sizeof(*context));
- memset(&finalcount, '\0', sizeof(finalcount));
-}
-
-void SHA1(
- const unsigned char *str,
- size_t len,
- unsigned char *hash_out
-)
-{
- SHA1_CTX ctx;
- size_t ii;
-
- SHA1Init(&ctx);
- for (ii=0; ii<len; ii+=1)
- SHA1Update(&ctx, str + ii, 1);
- SHA1Final(hash_out, &ctx);
-}
diff --git a/src/sha1.h b/src/sha1.h
deleted file mode 100644
index c8e9f68..0000000
--- a/src/sha1.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef SHA1_H
-#define SHA1_H
-
-/*
- SHA-1 in C
- By Steve Reid <steve@edmweb.com>
- 100% Public Domain
- */
-
-#include "stdint.h"
-
-typedef struct
-{
- uint32_t state[5];
- uint32_t count[2];
- unsigned char buffer[64];
-} SHA1_CTX;
-
-void SHA1Transform(
- uint32_t state[5],
- const unsigned char buffer[64]
- );
-
-void SHA1Init(
- SHA1_CTX * context
- );
-
-void SHA1Update(
- SHA1_CTX * context,
- const unsigned char *data,
- size_t len
- );
-
-void SHA1Final(
- unsigned char digest[20],
- SHA1_CTX * context
- );
-
-void SHA1(
- const unsigned char *str,
- size_t len,
- unsigned char *hash_out);
-
-#endif /* SHA1_H */
diff --git a/src/sha512.c b/src/sha512.c
deleted file mode 100644
index 8f7c59d..0000000
--- a/src/sha512.c
+++ /dev/null
@@ -1,314 +0,0 @@
-/* LibTomCrypt, modular cryptographic library -- Tom St Denis
- *
- * LibTomCrypt is a library that provides various cryptographic
- * algorithms in a highly modular and flexible manner.
- *
- * The library is free for all purposes without any express
- * guarantee it works.
- *
- * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
- */
-
-#include "fixedint.h"
-#include "sha512.h"
-
-/* the K array */
-static const uint64_t K[80] = {
- UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd),
- UINT64_C(0xb5c0fbcfec4d3b2f), UINT64_C(0xe9b5dba58189dbbc),
- UINT64_C(0x3956c25bf348b538), UINT64_C(0x59f111f1b605d019),
- UINT64_C(0x923f82a4af194f9b), UINT64_C(0xab1c5ed5da6d8118),
- UINT64_C(0xd807aa98a3030242), UINT64_C(0x12835b0145706fbe),
- UINT64_C(0x243185be4ee4b28c), UINT64_C(0x550c7dc3d5ffb4e2),
- UINT64_C(0x72be5d74f27b896f), UINT64_C(0x80deb1fe3b1696b1),
- UINT64_C(0x9bdc06a725c71235), UINT64_C(0xc19bf174cf692694),
- UINT64_C(0xe49b69c19ef14ad2), UINT64_C(0xefbe4786384f25e3),
- UINT64_C(0x0fc19dc68b8cd5b5), UINT64_C(0x240ca1cc77ac9c65),
- UINT64_C(0x2de92c6f592b0275), UINT64_C(0x4a7484aa6ea6e483),
- UINT64_C(0x5cb0a9dcbd41fbd4), UINT64_C(0x76f988da831153b5),
- UINT64_C(0x983e5152ee66dfab), UINT64_C(0xa831c66d2db43210),
- UINT64_C(0xb00327c898fb213f), UINT64_C(0xbf597fc7beef0ee4),
- UINT64_C(0xc6e00bf33da88fc2), UINT64_C(0xd5a79147930aa725),
- UINT64_C(0x06ca6351e003826f), UINT64_C(0x142929670a0e6e70),
- UINT64_C(0x27b70a8546d22ffc), UINT64_C(0x2e1b21385c26c926),
- UINT64_C(0x4d2c6dfc5ac42aed), UINT64_C(0x53380d139d95b3df),
- UINT64_C(0x650a73548baf63de), UINT64_C(0x766a0abb3c77b2a8),
- UINT64_C(0x81c2c92e47edaee6), UINT64_C(0x92722c851482353b),
- UINT64_C(0xa2bfe8a14cf10364), UINT64_C(0xa81a664bbc423001),
- UINT64_C(0xc24b8b70d0f89791), UINT64_C(0xc76c51a30654be30),
- UINT64_C(0xd192e819d6ef5218), UINT64_C(0xd69906245565a910),
- UINT64_C(0xf40e35855771202a), UINT64_C(0x106aa07032bbd1b8),
- UINT64_C(0x19a4c116b8d2d0c8), UINT64_C(0x1e376c085141ab53),
- UINT64_C(0x2748774cdf8eeb99), UINT64_C(0x34b0bcb5e19b48a8),
- UINT64_C(0x391c0cb3c5c95a63), UINT64_C(0x4ed8aa4ae3418acb),
- UINT64_C(0x5b9cca4f7763e373), UINT64_C(0x682e6ff3d6b2b8a3),
- UINT64_C(0x748f82ee5defb2fc), UINT64_C(0x78a5636f43172f60),
- UINT64_C(0x84c87814a1f0ab72), UINT64_C(0x8cc702081a6439ec),
- UINT64_C(0x90befffa23631e28), UINT64_C(0xa4506cebde82bde9),
- UINT64_C(0xbef9a3f7b2c67915), UINT64_C(0xc67178f2e372532b),
- UINT64_C(0xca273eceea26619c), UINT64_C(0xd186b8c721c0c207),
- UINT64_C(0xeada7dd6cde0eb1e), UINT64_C(0xf57d4f7fee6ed178),
- UINT64_C(0x06f067aa72176fba), UINT64_C(0x0a637dc5a2c898a6),
- UINT64_C(0x113f9804bef90dae), UINT64_C(0x1b710b35131c471b),
- UINT64_C(0x28db77f523047d84), UINT64_C(0x32caab7b40c72493),
- UINT64_C(0x3c9ebe0a15c9bebc), UINT64_C(0x431d67c49c100d4c),
- UINT64_C(0x4cc5d4becb3e42b6), UINT64_C(0x597f299cfc657e2a),
- UINT64_C(0x5fcb6fab3ad6faec), UINT64_C(0x6c44198c4a475817)
-};
-
-/* Various logical functions */
-
-#define ROR64c(x, y) \
- ( ((((x)&UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)(y)&UINT64_C(63))) | \
- ((x)<<((uint64_t)(64-((y)&UINT64_C(63)))))) & UINT64_C(0xFFFFFFFFFFFFFFFF))
-
-#define STORE64H(x, y) \
- { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
- (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
- (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
- (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
-
-#define LOAD64H(x, y) \
- { x = (((uint64_t)((y)[0] & 255))<<56)|(((uint64_t)((y)[1] & 255))<<48) | \
- (((uint64_t)((y)[2] & 255))<<40)|(((uint64_t)((y)[3] & 255))<<32) | \
- (((uint64_t)((y)[4] & 255))<<24)|(((uint64_t)((y)[5] & 255))<<16) | \
- (((uint64_t)((y)[6] & 255))<<8)|(((uint64_t)((y)[7] & 255))); }
-
-
-#define Ch(x,y,z) (z ^ (x & (y ^ z)))
-#define Maj(x,y,z) (((x | y) & z) | (x & y))
-#define S(x, n) ROR64c(x, n)
-#define R(x, n) (((x) &UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)n))
-#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
-#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
-#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))
-#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6))
-#ifndef MIN
- #define MIN(x, y) ( ((x)<(y))?(x):(y) )
-#endif
-
-/* compress 1024-bits */
-static int sha512_compress(sha512_context *md, unsigned char *buf)
-{
- uint64_t S[8], W[80], t0, t1;
- int i;
-
- /* copy state into S */
- for (i = 0; i < 8; i++) {
- S[i] = md->state[i];
- }
-
- /* copy the state into 1024-bits into W[0..15] */
- for (i = 0; i < 16; i++) {
- LOAD64H(W[i], buf + (8*i));
- }
-
- /* fill W[16..79] */
- for (i = 16; i < 80; i++) {
- W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
- }
-
-/* Compress */
- #define RND(a,b,c,d,e,f,g,h,i) \
- t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
- t1 = Sigma0(a) + Maj(a, b, c);\
- d += t0; \
- h = t0 + t1;
-
- for (i = 0; i < 80; i += 8) {
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0);
- RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1);
- RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2);
- RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3);
- RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4);
- RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5);
- RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6);
- RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7);
- }
-
- #undef RND
-
-
-
- /* feedback */
- for (i = 0; i < 8; i++) {
- md->state[i] = md->state[i] + S[i];
- }
-
- return 0;
-}
-
-
-/**
- Initialize the hash state
- @param md The hash state you wish to initialize
- @return 0 if successful
-*/
-int sha512_init(sha512_context * md) {
- if (md == NULL) return 1;
-
- md->curlen = 0;
- md->length = 0;
- md->state[0] = UINT64_C(0x6a09e667f3bcc908);
- md->state[1] = UINT64_C(0xbb67ae8584caa73b);
- md->state[2] = UINT64_C(0x3c6ef372fe94f82b);
- md->state[3] = UINT64_C(0xa54ff53a5f1d36f1);
- md->state[4] = UINT64_C(0x510e527fade682d1);
- md->state[5] = UINT64_C(0x9b05688c2b3e6c1f);
- md->state[6] = UINT64_C(0x1f83d9abfb41bd6b);
- md->state[7] = UINT64_C(0x5be0cd19137e2179);
- md->num_qwords = 8;
-
- return 0;
-}
-
-/**
- Process a block of memory though the hash
- @param md The hash state
- @param in The data to hash
- @param inlen The length of the data (octets)
- @return 0 if successful
-*/
-int sha512_update (sha512_context * md, const unsigned char *in, size_t inlen)
-{
- size_t n;
- size_t i;
- int err;
- if (md == NULL) return 1;
- if (in == NULL) return 1;
- if (md->curlen > sizeof(md->buf)) {
- return 1;
- }
- while (inlen > 0) {
- if (md->curlen == 0 && inlen >= 128) {
- if ((err = sha512_compress (md, (unsigned char *)in)) != 0) {
- return err;
- }
- md->length += 128 * 8;
- in += 128;
- inlen -= 128;
- } else {
- n = MIN(inlen, (128 - md->curlen));
-
- for (i = 0; i < n; i++) {
- md->buf[i + md->curlen] = in[i];
- }
-
-
- md->curlen += n;
- in += n;
- inlen -= n;
- if (md->curlen == 128) {
- if ((err = sha512_compress (md, md->buf)) != 0) {
- return err;
- }
- md->length += 8*128;
- md->curlen = 0;
- }
- }
- }
- return 0;
-}
-
-/**
- Terminate the hash to get the digest
- @param md The hash state
- @param out [out] The destination of the hash (64 bytes)
- @return 0 if successful
-*/
-int sha512_final(sha512_context * md, unsigned char *out)
-{
- int i;
-
- if (md == NULL) return 1;
- if (out == NULL) return 1;
-
- if (md->curlen >= sizeof(md->buf)) {
- return 1;
- }
-
- /* increase the length of the message */
- md->length += md->curlen * UINT64_C(8);
-
- /* append the '1' bit */
- md->buf[md->curlen++] = (unsigned char)0x80;
-
- /* if the length is currently above 112 bytes we append zeros
- * then compress. Then we can fall back to padding zeros and length
- * encoding like normal.
- */
- if (md->curlen > 112) {
- while (md->curlen < 128) {
- md->buf[md->curlen++] = (unsigned char)0;
- }
- sha512_compress(md, md->buf);
- md->curlen = 0;
- }
-
- /* pad upto 120 bytes of zeroes
- * note: that from 112 to 120 is the 64 MSB of the length. We assume that you won't hash
- * > 2^64 bits of data... :-)
- */
- while (md->curlen < 120) {
- md->buf[md->curlen++] = (unsigned char)0;
- }
-
- /* store length */
- STORE64H(md->length, md->buf+120);
- sha512_compress(md, md->buf);
-
- /* copy output */
- for (i = 0; i < md->num_qwords; i++) {
- STORE64H(md->state[i], out+(8*i));
- }
-
- return 0;
-}
-
-int sha512(const unsigned char *message, size_t message_len, unsigned char *out)
-{
- sha512_context ctx;
- int ret;
- if ((ret = sha512_init(&ctx))) return ret;
- if ((ret = sha512_update(&ctx, message, message_len))) return ret;
- if ((ret = sha512_final(&ctx, out))) return ret;
- return 0;
-}
-
-int sha384_init(sha384_context * md) {
- if (md == NULL) return 1;
-
- md->curlen = 0;
- md->length = 0;
- md->state[0] = UINT64_C(0xcbbb9d5dc1059ed8);
- md->state[1] = UINT64_C(0x629a292a367cd507);
- md->state[2] = UINT64_C(0x9159015a3070dd17);
- md->state[3] = UINT64_C(0x152fecd8f70e5939);
- md->state[4] = UINT64_C(0x67332667ffc00b31);
- md->state[5] = UINT64_C(0x8eb44a8768581511);
- md->state[6] = UINT64_C(0xdb0c2e0d64f98fa7);
- md->state[7] = UINT64_C(0x47b5481dbefa4fa4);
- md->num_qwords = 6;
-
- return 0;
-}
-
-int sha384_final(sha384_context * md, unsigned char* out)
-{
- return sha512_final(md, out);
-}
-
-int sha384_update(sha384_context * md, const unsigned char *in, size_t inlen)
-{
- return sha512_update(md, in, inlen);
-}
-
-int sha384(const unsigned char *message, size_t message_len, unsigned char *out)
-{
- sha384_context ctx;
- int ret;
- if ((ret = sha384_init(&ctx))) return ret;
- if ((ret = sha384_update(&ctx, message, message_len))) return ret;
- if ((ret = sha384_final(&ctx, out))) return ret;
- return 0;
-}
diff --git a/src/sha512.h b/src/sha512.h
deleted file mode 100644
index 72db47b..0000000
--- a/src/sha512.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef SHA512_H
-#define SHA512_H
-
-#include <stddef.h>
-
-#include "fixedint.h"
-
-/* state */
-typedef struct sha512_context_ {
- uint64_t length, state[8];
- size_t curlen;
- unsigned char buf[128];
- int num_qwords;
-} sha512_context;
-
-#define SHA512_DIGEST_LENGTH 64
-
-int sha512_init(sha512_context * md);
-int sha512_final(sha512_context * md, unsigned char *out);
-int sha512_update(sha512_context * md, const unsigned char *in, size_t inlen);
-int sha512(const unsigned char *message, size_t message_len, unsigned char *out);
-
-typedef sha512_context sha384_context;
-
-#define SHA384_DIGEST_LENGTH 48
-
-int sha384_init(sha384_context * md);
-int sha384_final(sha384_context * md, unsigned char *out);
-int sha384_update(sha384_context * md, const unsigned char *in, size_t inlen);
-int sha384(const unsigned char *message, size_t message_len, unsigned char *out);
-
-#endif
diff --git a/src/tss.c b/src/tss.c
deleted file mode 100644
index 084ad10..0000000
--- a/src/tss.c
+++ /dev/null
@@ -1,2113 +0,0 @@
-/*
- * tss.c
- * Functions for communicating with Apple's TSS server
- *
- * Copyright (c) 2010-2013 Martin Szulecki. All Rights Reserved.
- * Copyright (c) 2012 Nikias Bassen. All Rights Reserved.
- * Copyright (c) 2010 Joshua Hill. All Rights Reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <curl/curl.h>
-#include <plist/plist.h>
-
-#include "tss.h"
-#include "img3.h"
-#include "common.h"
-#include "idevicerestore.h"
-
-#include "endianness.h"
-
-#define AUTH_VERSION "850.0.2"
-
-#ifdef WIN32
-#define TSS_CLIENT_VERSION_STRING "libauthinstall_Win-"AUTH_VERSION""
-#else
-#define TSS_CLIENT_VERSION_STRING "libauthinstall-"AUTH_VERSION""
-#endif
-#define ECID_STRSIZE 0x20
-
-typedef struct {
- int length;
- char* content;
-} tss_response;
-
-char* ecid_to_string(uint64_t ecid) {
- char* ecid_string = malloc(ECID_STRSIZE);
- memset(ecid_string, '\0', ECID_STRSIZE);
- if (ecid == 0) {
- error("ERROR: Invalid ECID passed.\n");
- return NULL;
- }
- snprintf(ecid_string, ECID_STRSIZE, "%"PRIu64, ecid);
- return ecid_string;
-}
-
-plist_t tss_request_new(plist_t overrides) {
-
- plist_t request = plist_new_dict();
-
- plist_dict_set_item(request, "@BBTicket", plist_new_bool(1));
- plist_dict_set_item(request, "@HostPlatformInfo",
-#ifdef WIN32
- plist_new_string("windows")
-#else
- plist_new_string("mac")
-#endif
- );
-
- plist_dict_set_item(request, "@VersionInfo", plist_new_string(TSS_CLIENT_VERSION_STRING));
- char* guid = generate_guid();
- if (guid) {
- plist_dict_set_item(request, "@UUID", plist_new_string(guid));
- free(guid);
- }
-
- /* apply overrides */
- if (overrides) {
- plist_dict_merge(&request, overrides);
- }
-
- return request;
-}
-
-int tss_request_add_local_policy_tags(plist_t request, plist_t parameters)
-{
- plist_t node = NULL;
-
- plist_dict_set_item(request, "@ApImg4Ticket", plist_new_bool(1));
-
- /* Ap,LocalBoot */
- node = plist_dict_get_item(parameters, "Ap,LocalBoot");
- if (!node || plist_get_node_type(node) != PLIST_BOOLEAN) {
- error("ERROR: Unable to find required Ap,LocalBoot in parameters\n");
- return -1;
- }
- plist_dict_set_item(request, "Ap,LocalBoot", plist_copy(node));
- node = NULL;
-
- /* Ap,LocalPolicy */
- node = plist_dict_get_item(parameters, "Ap,LocalPolicy");
- if (!node || plist_get_node_type(node) != PLIST_DICT) {
- error("ERROR: Unable to find required Ap,LocalPolicy in parameters\n");
- return -1;
- }
- plist_dict_set_item(request, "Ap,LocalPolicy", plist_copy(node));
- node = NULL;
-
- /* Ap,NextStageIM4MHash */
- node = plist_dict_get_item(parameters, "Ap,NextStageIM4MHash");
- if (!node || plist_get_node_type(node) != PLIST_DATA) {
- error("ERROR: Unable to find required Ap,NextStageIM4MHash in parameters\n");
- return -1;
- }
- plist_dict_set_item(request, "Ap,NextStageIM4MHash", plist_copy(node));
- node = NULL;
-
- /* Ap,RecoveryOSPolicyNonceHash */
- node = plist_dict_get_item(parameters, "Ap,RecoveryOSPolicyNonceHash");
- if (node) {
- plist_dict_set_item(request, "Ap,RecoveryOSPolicyNonceHash", plist_copy(node));
- }
- node = NULL;
-
- /* Ap,VolumeUUID */
- node = plist_dict_get_item(parameters, "Ap,VolumeUUID");
- if (node) {
- plist_dict_set_item(request, "Ap,VolumeUUID", plist_copy(node));
- }
- node = NULL;
-
- /* ApECID */
- node = plist_dict_get_item(parameters, "ApECID");
- if (node) {
- plist_dict_set_item(request, "ApECID", plist_copy(node));
- }
- node = NULL;
-
- /* ApChipID */
- node = plist_dict_get_item(parameters, "ApChipID");
- if (node) {
- plist_dict_set_item(request, "ApChipID", plist_copy(node));
- }
- node = NULL;
-
- /* ApBoardID */
- node = plist_dict_get_item(parameters, "ApBoardID");
- if (node) {
- plist_dict_set_item(request, "ApBoardID", plist_copy(node));
- }
- node = NULL;
-
- /* ApSecurityDomain */
- node = plist_dict_get_item(parameters, "ApSecurityDomain");
- if (node) {
- plist_dict_set_item(request, "ApSecurityDomain", plist_copy(node));
- }
- node = NULL;
-
- /* ApNonce */
- node = plist_dict_get_item(parameters, "ApNonce");
- if (node) {
- plist_dict_set_item(request, "ApNonce", plist_copy(node));
- }
- node = NULL;
-
- /* ApSecurityMode */
- node = plist_dict_get_item(request, "ApSecurityMode");
- if (!node) {
- /* copy from parameters if available */
- node = plist_dict_get_item(parameters, "ApSecurityMode");
- if (!node || plist_get_node_type(node) != PLIST_BOOLEAN) {
- error("ERROR: Unable to find required ApSecurityMode in parameters\n");
- return -1;
- }
- plist_dict_set_item(request, "ApSecurityMode", plist_copy(node));
- node = NULL;
- }
-
- node = plist_dict_get_item(request, "ApProductionMode");
- if (!node) {
- /* ApProductionMode */
- node = plist_dict_get_item(parameters, "ApProductionMode");
- if (!node || plist_get_node_type(node) != PLIST_BOOLEAN) {
- error("ERROR: Unable to find required ApProductionMode in parameters\n");
- return -1;
- }
- plist_dict_set_item(request, "ApProductionMode", plist_copy(node));
- node = NULL;
- }
-
- return 0;
-}
-
-int tss_parameters_add_from_manifest(plist_t parameters, plist_t build_identity)
-{
- plist_t node = NULL;
- char* string = NULL;
-
- /* UniqueBuildID */
- node = plist_dict_get_item(build_identity, "UniqueBuildID");
- if (!node || plist_get_node_type(node) != PLIST_DATA) {
- error("ERROR: Unable to find UniqueBuildID node\n");
- return -1;
- }
- plist_dict_set_item(parameters, "UniqueBuildID", plist_copy(node));
- node = NULL;
-
- /* Ap,OSLongVersion */
- node = plist_dict_get_item(build_identity, "Ap,OSLongVersion");
- if (node) {
- plist_dict_set_item(parameters, "Ap,OSLongVersion", plist_copy(node));
- }
-
- /* ApChipID */
- int chip_id = 0;
- node = plist_dict_get_item(build_identity, "ApChipID");
- if (!node || plist_get_node_type(node) != PLIST_STRING) {
- error("ERROR: Unable to find ApChipID node\n");
- return -1;
- }
- plist_get_string_val(node, &string);
- sscanf(string, "%x", &chip_id);
- plist_dict_set_item(parameters, "ApChipID", plist_new_uint(chip_id));
- free(string);
- string = NULL;
- node = NULL;
-
- /* ApBoardID */
- int board_id = 0;
- node = plist_dict_get_item(build_identity, "ApBoardID");
- if (!node || plist_get_node_type(node) != PLIST_STRING) {
- error("ERROR: Unable to find ApBoardID node\n");
- return -1;
- }
- plist_get_string_val(node, &string);
- sscanf(string, "%x", &board_id);
- plist_dict_set_item(parameters, "ApBoardID", plist_new_uint(board_id));
- free(string);
- string = NULL;
- node = NULL;
-
- /* ApSecurityDomain */
- int security_domain = 0;
- node = plist_dict_get_item(build_identity, "ApSecurityDomain");
- if (!node || plist_get_node_type(node) != PLIST_STRING) {
- error("ERROR: Unable to find ApSecurityDomain node\n");
- return -1;
- }
- plist_get_string_val(node, &string);
- sscanf(string, "%x", &security_domain);
- plist_dict_set_item(parameters, "ApSecurityDomain", plist_new_uint(security_domain));
- free(string);
- string = NULL;
- node = NULL;
-
- /* BMU,BoardID */
- node = plist_dict_get_item(build_identity, "BMU,BoardID");
- if (node) {
- plist_dict_set_item(parameters, "BMU,BoardID", plist_copy(node));
- }
-
- /* BMU,ChipID */
- node = plist_dict_get_item(build_identity, "BMU,ChipID");
- if (node) {
- plist_dict_set_item(parameters, "BMU,ChipID", plist_copy(node));
- }
-
- /* BbChipID */
- int bb_chip_id = 0;
- char* bb_chip_id_string = NULL;
- node = plist_dict_get_item(build_identity, "BbChipID");
- if (node && plist_get_node_type(node) == PLIST_STRING) {
- plist_get_string_val(node, &bb_chip_id_string);
- sscanf(bb_chip_id_string, "%x", &bb_chip_id);
- plist_dict_set_item(parameters, "BbChipID", plist_new_uint(bb_chip_id));
- } else {
- debug("NOTE: Unable to find BbChipID node\n");
- }
- node = NULL;
-
- /* BbProvisioningManifestKeyHash */
- node = plist_dict_get_item(build_identity, "BbProvisioningManifestKeyHash");
- if (node && plist_get_node_type(node) == PLIST_DATA) {
- plist_dict_set_item(parameters, "BbProvisioningManifestKeyHash", plist_copy(node));
- } else {
- debug("NOTE: Unable to find BbProvisioningManifestKeyHash node\n");
- }
- node = NULL;
-
- /* BbActivationManifestKeyHash - Used by Qualcomm MDM6610 */
- node = plist_dict_get_item(build_identity, "BbActivationManifestKeyHash");
- if (node && plist_get_node_type(node) == PLIST_DATA) {
- plist_dict_set_item(parameters, "BbActivationManifestKeyHash", plist_copy(node));
- } else {
- debug("NOTE: Unable to find BbActivationManifestKeyHash node\n");
- }
- node = NULL;
-
- node = plist_dict_get_item(build_identity, "BbCalibrationManifestKeyHash");
- if (node && plist_get_node_type(node) == PLIST_DATA) {
- plist_dict_set_item(parameters, "BbCalibrationManifestKeyHash", plist_copy(node));
- } else {
- debug("NOTE: Unable to find BbCalibrationManifestKeyHash node\n");
- }
- node = NULL;
-
- /* BbFactoryActivationManifestKeyHash */
- node = plist_dict_get_item(build_identity, "BbFactoryActivationManifestKeyHash");
- if (node && plist_get_node_type(node) == PLIST_DATA) {
- plist_dict_set_item(parameters, "BbFactoryActivationManifestKeyHash", plist_copy(node));
- } else {
- debug("NOTE: Unable to find BbFactoryActivationManifestKeyHash node\n");
- }
- node = NULL;
-
- /* BbFDRSecurityKeyHash */
- node = plist_dict_get_item(build_identity, "BbFDRSecurityKeyHash");
- if (node && plist_get_node_type(node) == PLIST_DATA) {
- plist_dict_set_item(parameters, "BbFDRSecurityKeyHash", plist_copy(node));
- } else {
- debug("NOTE: Unable to find BbFDRSecurityKeyHash node\n");
- }
- node = NULL;
-
- /* BbSkeyId - Used by XMM 6180/GSM */
- node = plist_dict_get_item(build_identity, "BbSkeyId");
- if (node && plist_get_node_type(node) == PLIST_DATA) {
- plist_dict_set_item(parameters, "BbSkeyId", plist_copy(node));
- } else {
- debug("NOTE: Unable to find BbSkeyId node\n");
- }
- node = NULL;
-
- /* SE,ChipID - Used for SE firmware request */
- node = plist_dict_get_item(build_identity, "SE,ChipID");
- if (node) {
- if (plist_get_node_type(node) == PLIST_STRING) {
- char *strval = NULL;
- int intval = 0;
- plist_get_string_val(node, &strval);
- sscanf(strval, "%x", &intval);
- plist_dict_set_item(parameters, "SE,ChipID", plist_new_uint(intval));
- } else {
- plist_dict_set_item(parameters, "SE,ChipID", plist_copy(node));
- }
- }
- node = NULL;
-
- /* Savage,ChipID - Used for Savage firmware request */
- node = plist_dict_get_item(build_identity, "Savage,ChipID");
- if (node) {
- if (plist_get_node_type(node) == PLIST_STRING) {
- char *strval = NULL;
- int intval = 0;
- plist_get_string_val(node, &strval);
- sscanf(strval, "%x", &intval);
- plist_dict_set_item(parameters, "Savage,ChipID", plist_new_uint(intval));
- } else {
- plist_dict_set_item(parameters, "Savage,ChipID", plist_copy(node));
- }
- }
- node = NULL;
-
- /* add Savage,PatchEpoch - Used for Savage firmware request */
- node = plist_dict_get_item(build_identity, "Savage,PatchEpoch");
- if (node) {
- if (plist_get_node_type(node) == PLIST_STRING) {
- char *strval = NULL;
- int intval = 0;
- plist_get_string_val(node, &strval);
- sscanf(strval, "%x", &intval);
- plist_dict_set_item(parameters, "Savage,PatchEpoch", plist_new_uint(intval));
- } else {
- plist_dict_set_item(parameters, "Savage,PatchEpoch", plist_copy(node));
- }
- }
- node = NULL;
-
- /* Yonkers,BoardID - Used for Yonkers firmware request */
- node = plist_dict_get_item(build_identity, "Yonkers,BoardID");
- if (node) {
- if (plist_get_node_type(node) == PLIST_STRING) {
- char *strval = NULL;
- int intval = 0;
- plist_get_string_val(node, &strval);
- sscanf(strval, "%x", &intval);
- plist_dict_set_item(parameters, "Yonkers,BoardID", plist_new_uint(intval));
- } else {
- plist_dict_set_item(parameters, "Yonkers,BoardID", plist_copy(node));
- }
- }
- node = NULL;
-
- /* Yonkers,ChipID - Used for Yonkers firmware request */
- node = plist_dict_get_item(build_identity, "Yonkers,ChipID");
- if (node) {
- if (plist_get_node_type(node) == PLIST_STRING) {
- char *strval = NULL;
- int intval = 0;
- plist_get_string_val(node, &strval);
- sscanf(strval, "%x", &intval);
- plist_dict_set_item(parameters, "Yonkers,ChipID", plist_new_uint(intval));
- } else {
- plist_dict_set_item(parameters, "Yonkers,ChipID", plist_copy(node));
- }
- }
- node = NULL;
-
- /* add Yonkers,PatchEpoch - Used for Yonkers firmware request */
- node = plist_dict_get_item(build_identity, "Yonkers,PatchEpoch");
- if (node) {
- if (plist_get_node_type(node) == PLIST_STRING) {
- char *strval = NULL;
- int intval = 0;
- plist_get_string_val(node, &strval);
- sscanf(strval, "%x", &intval);
- plist_dict_set_item(parameters, "Yonkers,PatchEpoch", plist_new_uint(intval));
- } else {
- plist_dict_set_item(parameters, "Yonkers,PatchEpoch", plist_copy(node));
- }
- }
- node = NULL;
-
- /* add Rap,BoardID */
- node = plist_dict_get_item(build_identity, "Rap,BoardID");
- if (node) {
- plist_dict_set_item(parameters, "Rap,BoardID", plist_copy(node));
- }
- node = NULL;
-
- /* add Rap,ChipID */
- node = plist_dict_get_item(build_identity, "Rap,ChipID");
- if (node) {
- plist_dict_set_item(parameters, "Rap,ChipID", plist_copy(node));
- }
- node = NULL;
-
- /* add Rap,SecurityDomain */
- node = plist_dict_get_item(build_identity, "Rap,SecurityDomain");
- if (node) {
- plist_dict_set_item(parameters, "Rap,SecurityDomain", plist_copy(node));
- }
- node = NULL;
-
- /* add Baobab,BoardID */
- node = plist_dict_get_item(build_identity, "Baobab,BoardID");
- if (node) {
- plist_dict_set_item(parameters, "Baobab,BoardID", plist_copy(node));
- }
- node = NULL;
-
- /* add Baobab,ChipID */
- node = plist_dict_get_item(build_identity, "Baobab,ChipID");
- if (node) {
- plist_dict_set_item(parameters, "Baobab,ChipID", plist_copy(node));
- }
- node = NULL;
-
- /* add Baobab,ManifestEpoch */
- node = plist_dict_get_item(build_identity, "Baobab,ManifestEpoch");
- if (node) {
- plist_dict_set_item(parameters, "Baobab,ManifestEpoch", plist_copy(node));
- }
- node = NULL;
-
- /* add Baobab,SecurityDomain */
- node = plist_dict_get_item(build_identity, "Baobab,SecurityDomain");
- if (node) {
- plist_dict_set_item(parameters, "Baobab,SecurityDomain", plist_copy(node));
- }
- node = NULL;
-
- /* add eUICC,ChipID */
- node = plist_dict_get_item(build_identity, "eUICC,ChipID");
- if (node) {
- plist_dict_set_item(parameters, "eUICC,ChipID", plist_copy(node));
- }
- node = NULL;
-
- node = plist_dict_get_item(build_identity, "PearlCertificationRootPub");
- if (node) {
- plist_dict_set_item(parameters, "PearlCertificationRootPub", plist_copy(node));
- }
- node = NULL;
-
- /* add build identity manifest dictionary */
- node = plist_dict_get_item(build_identity, "Manifest");
- if (!node || plist_get_node_type(node) != PLIST_DICT) {
- error("ERROR: Unable to find Manifest node\n");
- return -1;
- }
- plist_dict_set_item(parameters, "Manifest", plist_copy(node));
-
- return 0;
-}
-
-int tss_request_add_ap_img4_tags(plist_t request, plist_t parameters) {
- plist_t node = NULL;
-
- if (!parameters) {
- error("ERROR: Missing required AP parameters\n");
- return -1;
- }
-
- /* Ap,OSLongVersion */
- node = plist_dict_get_item(parameters, "Ap,OSLongVersion");
- if (node) {
- plist_dict_set_item(request, "Ap,OSLongVersion", plist_copy(node));
- }
-
- /* ApNonce */
- node = plist_dict_get_item(parameters, "ApNonce");
- if (!node || plist_get_node_type(node) != PLIST_DATA) {
- error("ERROR: Unable to find required ApNonce in parameters\n");
- return -1;
- }
- plist_dict_set_item(request, "ApNonce", plist_copy(node));
- node = NULL;
-
- plist_dict_set_item(request, "@ApImg4Ticket", plist_new_bool(1));
-
- /* ApSecurityMode */
- node = plist_dict_get_item(request, "ApSecurityMode");
- if (!node) {
- /* copy from parameters if available */
- node = plist_dict_get_item(parameters, "ApSecurityMode");
- if (!node || plist_get_node_type(node) != PLIST_BOOLEAN) {
- error("ERROR: Unable to find required ApSecurityMode in parameters\n");
- return -1;
- }
- plist_dict_set_item(request, "ApSecurityMode", plist_copy(node));
- node = NULL;
- }
-
- node = plist_dict_get_item(request, "ApProductionMode");
- if (!node) {
- /* ApProductionMode */
- node = plist_dict_get_item(parameters, "ApProductionMode");
- if (!node || plist_get_node_type(node) != PLIST_BOOLEAN) {
- error("ERROR: Unable to find required ApProductionMode in parameters\n");
- return -1;
- }
- plist_dict_set_item(request, "ApProductionMode", plist_copy(node));
- node = NULL;
- }
-
- /* ApSepNonce */
- node = plist_dict_get_item(parameters, "ApSepNonce");
- if (!node || plist_get_node_type(node) != PLIST_DATA) {
- error("ERROR: Unable to find required ApSepNonce in parameters\n");
- return -1;
- }
- plist_dict_set_item(request, "SepNonce", plist_copy(node));
- node = NULL;
-
- /* PearlCertificationRootPub */
- node = plist_dict_get_item(parameters, "PearlCertificationRootPub");
- if (node) {
- plist_dict_set_item(request, "PearlCertificationRootPub", plist_copy(node));
- }
-
- return 0;
-}
-
-int tss_request_add_ap_img3_tags(plist_t request, plist_t parameters) {
- plist_t node = NULL;
-
- if (!parameters) {
- error("ERROR: Missing required AP parameters\n");
- return -1;
- }
-
- /* ApNonce */
- node = plist_dict_get_item(parameters, "ApNonce");
- if (node) {
- if (plist_get_node_type(node) != PLIST_DATA) {
- error("ERROR: Unable to find required ApNonce in parameters\n");
- return -1;
- }
- plist_dict_set_item(request, "ApNonce", plist_copy(node));
- node = NULL;
- }
-
- /* @APTicket */
- plist_dict_set_item(request, "@APTicket", plist_new_bool(1));
-
- /* ApBoardID */
- node = plist_dict_get_item(request, "ApBoardID");
- if (!node || plist_get_node_type(node) != PLIST_UINT) {
- error("ERROR: Unable to find required ApBoardID in request\n");
- return -1;
- }
- node = NULL;
-
- /* ApChipID */
- node = plist_dict_get_item(request, "ApChipID");
- if (!node || plist_get_node_type(node) != PLIST_UINT) {
- error("ERROR: Unable to find required ApChipID in request\n");
- return -1;
- }
- node = NULL;
-
- /* ApSecurityDomain */
- node = plist_dict_get_item(request, "ApSecurityDomain");
- if (!node || plist_get_node_type(node) != PLIST_UINT) {
- error("ERROR: Unable to find required ApSecurityDomain in request\n");
- return -1;
- }
- node = NULL;
-
- /* ApProductionMode */
- node = plist_dict_get_item(parameters, "ApProductionMode");
- if (!node || plist_get_node_type(node) != PLIST_BOOLEAN) {
- error("ERROR: Unable to find required ApProductionMode in parameters\n");
- return -1;
- }
- plist_dict_set_item(request, "ApProductionMode", plist_copy(node));
- node = NULL;
-
- return 0;
-}
-
-int tss_request_add_common_tags(plist_t request, plist_t parameters, plist_t overrides) {
- plist_t node = NULL;
-
- /* ApECID */
- node = plist_dict_get_item(parameters, "ApECID");
- if (node) {
- plist_dict_set_item(request, "ApECID", plist_copy(node));
- }
- node = NULL;
-
- /* UniqueBuildID */
- node = plist_dict_get_item(parameters, "UniqueBuildID");
- if (node) {
- plist_dict_set_item(request, "UniqueBuildID", plist_copy(node));
- }
- node = NULL;
-
- /* ApChipID */
- node = plist_dict_get_item(parameters, "ApChipID");
- if (node) {
- plist_dict_set_item(request, "ApChipID", plist_copy(node));
- }
- node = NULL;
-
- /* ApBoardID */
- node = plist_dict_get_item(parameters, "ApBoardID");
- if (node) {
- plist_dict_set_item(request, "ApBoardID", plist_copy(node));
- }
- node = NULL;
-
- /* ApSecurityDomain */
- node = plist_dict_get_item(parameters, "ApSecurityDomain");
- if (node) {
- plist_dict_set_item(request, "ApSecurityDomain", plist_copy(node));
- }
- node = NULL;
-
- /* apply overrides */
- if (overrides) {
- plist_dict_merge(&request, overrides);
- }
-
- return 0;
-}
-
-static void tss_entry_apply_restore_request_rules(plist_t tss_entry, plist_t parameters, plist_t rules)
-{
- if (!tss_entry || !rules) {
- return;
- }
- if (plist_get_node_type(tss_entry) != PLIST_DICT) {
- return;
- }
- if (plist_get_node_type(rules) != PLIST_ARRAY) {
- return;
- }
-
- uint32_t i;
- for (i = 0; i < plist_array_get_size(rules); i++) {
- plist_t rule = plist_array_get_item(rules, i);
- plist_t conditions = plist_dict_get_item(rule, "Conditions");
- plist_dict_iter iter = NULL;
- plist_dict_new_iter(conditions, &iter);
- char* key = NULL;
- plist_t value = NULL;
- plist_t value2 = NULL;
- int conditions_fulfilled = 1;
- while (conditions_fulfilled) {
- plist_dict_next_item(conditions, iter, &key, &value);
- if (key == NULL)
- break;
- if (!strcmp(key, "ApRawProductionMode")) {
- value2 = plist_dict_get_item(parameters, "ApProductionMode");
- } else if (!strcmp(key, "ApCurrentProductionMode")) {
- value2 = plist_dict_get_item(parameters, "ApProductionMode");
- } else if (!strcmp(key, "ApRawSecurityMode")) {
- value2 = plist_dict_get_item(parameters, "ApSecurityMode");
- } else if (!strcmp(key, "ApRequiresImage4")) {
- value2 = plist_dict_get_item(parameters, "ApSupportsImg4");
- } else if (!strcmp(key, "ApDemotionPolicyOverride")) {
- value2 = plist_dict_get_item(parameters, "DemotionPolicy");
- } else if (!strcmp(key, "ApInRomDFU")) {
- value2 = plist_dict_get_item(parameters, "ApInRomDFU");
- } else {
- error("WARNING: Unhandled condition '%s' while parsing RestoreRequestRules\n", key);
- value2 = NULL;
- }
- if (value2) {
- conditions_fulfilled = plist_compare_node_value(value, value2);
- } else {
- conditions_fulfilled = 0;
- }
- free(key);
- }
- free(iter);
- iter = NULL;
-
- if (!conditions_fulfilled) {
- continue;
- }
-
- plist_t actions = plist_dict_get_item(rule, "Actions");
- plist_dict_new_iter(actions, &iter);
- while (1) {
- plist_dict_next_item(actions, iter, &key, &value);
- if (key == NULL)
- break;
- uint8_t bv = 255;
- plist_get_bool_val(value, &bv);
- if (bv != 255) {
- value2 = plist_dict_get_item(tss_entry, key);
- if (value2) {
- plist_dict_remove_item(tss_entry, key);
- }
- debug("DEBUG: Adding %s=%s to TSS entry\n", key, (bv) ? "true" : "false");
- plist_dict_set_item(tss_entry, key, plist_new_bool(bv));
- }
- free(key);
- }
- }
-}
-
-int tss_request_add_ap_recovery_tags(plist_t request, plist_t parameters, plist_t overrides) {
- /* loop over components from build manifest */
- plist_t manifest_node = plist_dict_get_item(parameters, "Manifest");
- if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) {
- error("ERROR: Unable to find restore manifest\n");
- return -1;
- }
-
- /* add components to request */
- char* key = NULL;
- plist_t manifest_entry = NULL;
- plist_dict_iter iter = NULL;
- plist_dict_new_iter(manifest_node, &iter);
- while (1) {
- free(key);
- key = NULL;
- plist_dict_next_item(manifest_node, iter, &key, &manifest_entry);
- if (key == NULL)
- break;
- if (!manifest_entry || plist_get_node_type(manifest_entry) != PLIST_DICT) {
- error("ERROR: Unable to fetch BuildManifest entry\n");
- free(key);
- return -1;
- }
-
- /* do not populate BaseBandFirmware, only in basebaseband request */
- if ((strcmp(key, "BasebandFirmware") == 0)) {
- continue;
- }
-
- // Compared to ac2, not needed for RecoveryOSRootTicket
- if ((strcmp(key, "SE,UpdatePayload") == 0)) {
- continue;
- }
- if ((strcmp(key, "BaseSystem") == 0)) {
- continue;
- }
- if ((strcmp(key, "ANS") == 0)) {
- continue;
- }
- if ((strcmp(key, "Ap,AudioBootChime") == 0)) {
- continue;
- }
- if ((strcmp(key, "Ap,CIO") == 0)) {
- continue;
- }
- if ((strcmp(key, "Ap,RestoreCIO") == 0)) {
- continue;
- }
- if ((strcmp(key, "Ap,RestoreTMU") == 0)) {
- continue;
- }
- if ((strcmp(key, "Ap,TMU") == 0)) {
- continue;
- }
- if ((strcmp(key, "Ap,rOSLogo1") == 0)) {
- continue;
- }
- if ((strcmp(key, "Ap,rOSLogo2") == 0)) {
- continue;
- }
- if ((strcmp(key, "AppleLogo") == 0)) {
- continue;
- }
- if ((strcmp(key, "DCP") == 0)) {
- continue;
- }
- if ((strcmp(key, "LLB") == 0)) {
- continue;
- }
- if ((strcmp(key, "RecoveryMode") == 0)) {
- continue;
- }
- if ((strcmp(key, "RestoreANS") == 0)) {
- continue;
- }
- if ((strcmp(key, "RestoreDCP") == 0)) {
- continue;
- }
- if ((strcmp(key, "RestoreDeviceTree") == 0)) {
- continue;
- }
- if ((strcmp(key, "RestoreKernelCache") == 0)) {
- continue;
- }
- if ((strcmp(key, "RestoreLogo") == 0)) {
- continue;
- }
- if ((strcmp(key, "RestoreRamDisk") == 0)) {
- continue;
- }
- if ((strcmp(key, "RestoreSEP") == 0)) {
- continue;
- }
- if ((strcmp(key, "SEP") == 0)) {
- continue;
- }
- if ((strcmp(key, "ftap") == 0)) {
- continue;
- }
- if ((strcmp(key, "ftsp") == 0)) {
- continue;
- }
- if ((strcmp(key, "iBEC") == 0)) {
- continue;
- }
- if ((strcmp(key, "iBSS") == 0)) {
- continue;
- }
- if ((strcmp(key, "rfta") == 0)) {
- continue;
- }
- if ((strcmp(key, "rfts") == 0)) {
- continue;
- }
-
- /* FIXME: only used with diagnostics firmware */
- if (strcmp(key, "Diags") == 0) {
- continue;
- }
-
- plist_t info_dict = plist_dict_get_item(manifest_entry, "Info");
- if (!info_dict) {
- continue;
- }
-
- if (_plist_dict_get_bool(parameters, "_OnlyFWComponents")) {
- if (!_plist_dict_get_bool(manifest_entry, "Trusted")) {
- debug("DEBUG: %s: Skipping '%s' as it is not trusted\n", __func__, key);
- continue;
- }
-
- if (!_plist_dict_get_bool(info_dict, "IsFirmwarePayload") && !_plist_dict_get_bool(info_dict, "IsSecondaryFirmwarePayload") && !_plist_dict_get_bool(info_dict, "IsFUDFirmware")) {
- debug("DEBUG: %s: Skipping '%s' as it is neither firmware nor secondary nor FUD firmware payload\n", __func__, key);
- continue;
- }
- }
-
- /* copy this entry */
- plist_t tss_entry = plist_copy(manifest_entry);
-
- /* remove obsolete Info node */
- plist_dict_remove_item(tss_entry, "Info");
-
- /* handle RestoreRequestRules */
- plist_t rules = plist_access_path(manifest_entry, 2, "Info", "RestoreRequestRules");
- if (rules) {
- debug("DEBUG: Applying restore request rules for entry %s\n", key);
- tss_entry_apply_restore_request_rules(tss_entry, parameters, rules);
- }
-
- /* Make sure we have a Digest key for Trusted items even if empty */
- plist_t node = plist_dict_get_item(manifest_entry, "Trusted");
- if (node && plist_get_node_type(node) == PLIST_BOOLEAN) {
- uint8_t trusted;
- plist_get_bool_val(node, &trusted);
- if (trusted && !plist_access_path(manifest_entry, 1, "Digest")) {
- debug("DEBUG: No Digest data, using empty value for entry %s\n", key);
- plist_dict_set_item(tss_entry, "Digest", plist_new_data(NULL, 0));
- }
- }
-
- /* finally add entry to request */
- plist_dict_set_item(request, key, tss_entry);
- }
- free(key);
- free(iter);
-
- /* apply overrides */
- if (overrides) {
- plist_dict_merge(&request, overrides);
- }
-
- return 0;
-}
-
-int tss_request_add_ap_tags(plist_t request, plist_t parameters, plist_t overrides) {
- /* loop over components from build manifest */
- plist_t manifest_node = plist_dict_get_item(parameters, "Manifest");
- if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) {
- error("ERROR: Unable to find restore manifest\n");
- return -1;
- }
-
- /* add components to request */
- char* key = NULL;
- plist_t manifest_entry = NULL;
- plist_dict_iter iter = NULL;
- plist_dict_new_iter(manifest_node, &iter);
- while (1) {
- free(key);
- key = NULL;
- plist_dict_next_item(manifest_node, iter, &key, &manifest_entry);
- if (key == NULL)
- break;
- if (!manifest_entry || plist_get_node_type(manifest_entry) != PLIST_DICT) {
- error("ERROR: Unable to fetch BuildManifest entry\n");
- free(key);
- return -1;
- }
-
- /* do not populate BaseBandFirmware, only in basebaseband request */
- if ((strcmp(key, "BasebandFirmware") == 0)) {
- continue;
- }
-
- // Compared to ac2, not needed
- if ((strcmp(key, "SE,UpdatePayload") == 0)) {
- continue;
- }
-
- // Compared to ac2, not needed
- if ((strcmp(key, "BaseSystem") == 0)) {
- continue;
- }
-
- /* FIXME: only used with diagnostics firmware */
- if (strcmp(key, "Diags") == 0) {
- continue;
- }
-
- plist_t info_dict = plist_dict_get_item(manifest_entry, "Info");
- if (!info_dict) {
- continue;
- }
-
- if (_plist_dict_get_bool(parameters, "ApSupportsImg4")) {
- if (!plist_dict_get_item(info_dict, "RestoreRequestRules")) {
- debug("DEBUG: %s: Skipping '%s' as it doesn't have RestoreRequestRules\n", __func__, key);
- continue;
- }
- }
-
- if (_plist_dict_get_bool(parameters, "_OnlyFWComponents")) {
- if (!_plist_dict_get_bool(manifest_entry, "Trusted")) {
- debug("DEBUG: %s: Skipping '%s' as it is not trusted\n", __func__, key);
- continue;
- }
-
- if (!_plist_dict_get_bool(info_dict, "IsFirmwarePayload") && !_plist_dict_get_bool(info_dict, "IsSecondaryFirmwarePayload") && !_plist_dict_get_bool(info_dict, "IsFUDFirmware")) {
- debug("DEBUG: %s: Skipping '%s' as it is neither firmware nor secondary nor FUD firmware payload\n", __func__, key);
- continue;
- }
- }
-
- /* copy this entry */
- plist_t tss_entry = plist_copy(manifest_entry);
-
- /* remove obsolete Info node */
- plist_dict_remove_item(tss_entry, "Info");
-
- /* handle RestoreRequestRules */
- plist_t rules = plist_access_path(manifest_entry, 2, "Info", "RestoreRequestRules");
- if (rules) {
- debug("DEBUG: Applying restore request rules for entry %s\n", key);
- tss_entry_apply_restore_request_rules(tss_entry, parameters, rules);
- }
-
- /* Make sure we have a Digest key for Trusted items even if empty */
- plist_t node = plist_dict_get_item(manifest_entry, "Trusted");
- if (node && plist_get_node_type(node) == PLIST_BOOLEAN) {
- uint8_t trusted;
- plist_get_bool_val(node, &trusted);
- if (trusted && !plist_access_path(manifest_entry, 1, "Digest")) {
- debug("DEBUG: No Digest data, using empty value for entry %s\n", key);
- plist_dict_set_item(tss_entry, "Digest", plist_new_data(NULL, 0));
- }
- }
-
- /* finally add entry to request */
- plist_dict_set_item(request, key, tss_entry);
- }
- free(key);
- free(iter);
-
- /* apply overrides */
- if (overrides) {
- plist_dict_merge(&request, overrides);
- }
-
- return 0;
-}
-
-int tss_request_add_baseband_tags(plist_t request, plist_t parameters, plist_t overrides) {
- plist_t node = NULL;
-
- /* BbChipID */
- uint64_t bb_chip_id = _plist_dict_get_uint(parameters, "BbChipID");
- if (bb_chip_id) {
- plist_dict_set_item(request, "BbChipID", plist_new_uint(bb_chip_id));
- }
-
- /* BbProvisioningManifestKeyHash */
- node = plist_dict_get_item(parameters, "BbProvisioningManifestKeyHash");
- if (node) {
- plist_dict_set_item(request, "BbProvisioningManifestKeyHash", plist_copy(node));
- }
- node = NULL;
-
- /* BbActivationManifestKeyHash - Used by Qualcomm MDM6610 */
- node = plist_dict_get_item(parameters, "BbActivationManifestKeyHash");
- if (node) {
- plist_dict_set_item(request, "BbActivationManifestKeyHash", plist_copy(node));
- }
- node = NULL;
-
- node = plist_dict_get_item(parameters, "BbCalibrationManifestKeyHash");
- if (node) {
- plist_dict_set_item(request, "BbCalibrationManifestKeyHash", plist_copy(node));
- }
- node = NULL;
-
- /* BbFactoryActivationManifestKeyHash */
- node = plist_dict_get_item(parameters, "BbFactoryActivationManifestKeyHash");
- if (node) {
- plist_dict_set_item(request, "BbFactoryActivationManifestKeyHash", plist_copy(node));
- }
- node = NULL;
-
- /* BbFDRSecurityKeyHash */
- node = plist_dict_get_item(parameters, "BbFDRSecurityKeyHash");
- if (node) {
- plist_dict_set_item(request, "BbFDRSecurityKeyHash", plist_copy(node));
- }
- node = NULL;
-
- /* BbSkeyId - Used by XMM 6180/GSM */
- node = plist_dict_get_item(parameters, "BbSkeyId");
- if (node) {
- plist_dict_set_item(request, "BbSkeyId", plist_copy(node));
- }
- node = NULL;
-
- /* BbNonce */
- node = plist_dict_get_item(parameters, "BbNonce");
- if (node) {
- plist_dict_set_item(request, "BbNonce", plist_copy(node));
- }
- node = NULL;
-
- /* @BBTicket */
- plist_dict_set_item(request, "@BBTicket", plist_new_bool(1));
-
- /* BbGoldCertId */
- node = plist_dict_get_item(parameters, "BbGoldCertId");
- if (!node || plist_get_node_type(node) != PLIST_UINT) {
- error("ERROR: Unable to find required BbGoldCertId in parameters\n");
- return -1;
- }
- node = plist_copy(node);
- uint64_t val;
- plist_get_uint_val(node, &val);
- int32_t bb_cert_id = (int32_t)val;
- plist_set_uint_val(node, bb_cert_id);
- plist_dict_set_item(request, "BbGoldCertId", node);
- node = NULL;
-
- /* BbSNUM */
- node = plist_dict_get_item(parameters, "BbSNUM");
- if (!node || plist_get_node_type(node) != PLIST_DATA) {
- error("ERROR: Unable to find required BbSNUM in parameters\n");
- return -1;
- }
- plist_dict_set_item(request, "BbSNUM", plist_copy(node));
- node = NULL;
-
- /* BasebandFirmware */
- node = plist_access_path(parameters, 2, "Manifest", "BasebandFirmware");
- if (!node || plist_get_node_type(node) != PLIST_DICT) {
- error("ERROR: Unable to get BasebandFirmware node\n");
- return -1;
- }
- plist_t bbfwdict = plist_copy(node);
- node = NULL;
- if (plist_dict_get_item(bbfwdict, "Info")) {
- plist_dict_remove_item(bbfwdict, "Info");
- }
-
- if (bb_chip_id == 0x68) {
- /* depending on the BasebandCertId remove certain nodes */
- if (bb_cert_id == 0x26F3FACC || bb_cert_id == 0x5CF2EC4E || bb_cert_id == 0x8399785A) {
- plist_dict_remove_item(bbfwdict, "PSI2-PartialDigest");
- plist_dict_remove_item(bbfwdict, "RestorePSI2-PartialDigest");
- } else {
- plist_dict_remove_item(bbfwdict, "PSI-PartialDigest");
- plist_dict_remove_item(bbfwdict, "RestorePSI-PartialDigest");
- }
- }
-
- plist_dict_set_item(request, "BasebandFirmware", bbfwdict);
-
- /* apply overrides */
- if (overrides) {
- plist_dict_merge(&request, overrides);
- }
-
- return 0;
-}
-
-int tss_request_add_se_tags(plist_t request, plist_t parameters, plist_t overrides)
-{
- plist_t node = NULL;
-
- plist_t manifest_node = plist_dict_get_item(parameters, "Manifest");
- if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) {
- error("ERROR: %s: Unable to get restore manifest from parameters\n", __func__);
- return -1;
- }
-
- /* add tags indicating we want to get the SE,Ticket */
- plist_dict_set_item(request, "@BBTicket", plist_new_bool(1));
- plist_dict_set_item(request, "@SE,Ticket", plist_new_bool(1));
-
- /* add SE,ChipID */
- node = plist_dict_get_item(parameters, "SE,ChipID");
- if (!node || plist_get_node_type(node) != PLIST_UINT) {
- error("ERROR: %s: Unable to find required SE,ChipID in parameters\n", __func__);
- return -1;
- }
- plist_dict_set_item(request, "SE,ChipID", plist_copy(node));
- node = NULL;
-
- /* add SE,ID */
- node = plist_dict_get_item(parameters, "SE,ID");
- if (!node) {
- error("ERROR: %s: Unable to find required SE,ID in parameters\n", __func__);
- return -1;
- }
- plist_dict_set_item(request, "SE,ID", plist_copy(node));
- node = NULL;
-
- /* add SE,Nonce */
- node = plist_dict_get_item(parameters, "SE,Nonce");
- if (!node) {
- error("ERROR: %s: Unable to find required SE,Nonce in parameters\n", __func__);
- return -1;
- }
- plist_dict_set_item(request, "SE,Nonce", plist_copy(node));
- node = NULL;
-
- /* add SE,RootKeyIdentifier */
- node = plist_dict_get_item(parameters, "SE,RootKeyIdentifier");
- if (!node) {
- error("ERROR: %s: Unable to find required SE,RootKeyIdentifier in parameters\n", __func__);
- return -1;
- }
- plist_dict_set_item(request, "SE,RootKeyIdentifier", plist_copy(node));
- node = NULL;
-
- /* 'IsDev' determines whether we have Production or Development */
- uint8_t is_dev = 0;
- node = plist_dict_get_item(parameters, "SE,IsDev");
- if (node && plist_get_node_type(node) == PLIST_BOOLEAN) {
- plist_get_bool_val(node, &is_dev);
- }
-
- /* add SE,* components from build manifest to request */
- char* key = NULL;
- plist_t manifest_entry = NULL;
- plist_dict_iter iter = NULL;
- plist_dict_new_iter(manifest_node, &iter);
- while (1) {
- free(key);
- key = NULL;
- plist_dict_next_item(manifest_node, iter, &key, &manifest_entry);
- if (key == NULL)
- break;
- if (!manifest_entry || plist_get_node_type(manifest_entry) != PLIST_DICT) {
- error("ERROR: Unable to fetch BuildManifest entry\n");
- free(key);
- return -1;
- }
-
- if (strncmp(key, "SE,", 3)) {
- continue;
- }
-
- /* copy this entry */
- plist_t tss_entry = plist_copy(manifest_entry);
-
- /* remove Info node */
- plist_dict_remove_item(tss_entry, "Info");
-
- /* remove Development or Production key/hash node */
- if (is_dev) {
- if (plist_dict_get_item(tss_entry, "ProductionCMAC"))
- plist_dict_remove_item(tss_entry, "ProductionCMAC");
- if (plist_dict_get_item(tss_entry, "ProductionUpdatePayloadHash"))
- plist_dict_remove_item(tss_entry, "ProductionUpdatePayloadHash");
- } else {
- if (plist_dict_get_item(tss_entry, "DevelopmentCMAC"))
- plist_dict_remove_item(tss_entry, "DevelopmentCMAC");
- if (plist_dict_get_item(tss_entry, "DevelopmentUpdatePayloadHash"))
- plist_dict_remove_item(tss_entry, "DevelopmentUpdatePayloadHash");
- }
-
- /* add entry to request */
- plist_dict_set_item(request, key, tss_entry);
- }
- free(key);
- free(iter);
-
- /* apply overrides */
- if (overrides) {
- plist_dict_merge(&request, overrides);
- }
-
- return 0;
-}
-
-int tss_request_add_savage_tags(plist_t request, plist_t parameters, plist_t overrides, char **component_name)
-{
- plist_t node = NULL;
-
- plist_t manifest_node = plist_dict_get_item(parameters, "Manifest");
- if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) {
- error("ERROR: %s: Unable to get restore manifest from parameters\n", __func__);
- return -1;
- }
-
- /* add tags indicating we want to get the Savage,Ticket */
- plist_dict_set_item(request, "@BBTicket", plist_new_bool(1));
- plist_dict_set_item(request, "@Savage,Ticket", plist_new_bool(1));
-
- /* add Savage,UID */
- node = plist_dict_get_item(parameters, "Savage,UID");
- if (!node) {
- error("ERROR: %s: Unable to find required Savage,UID in parameters\n", __func__);
- return -1;
- }
- plist_dict_set_item(request, "Savage,UID", plist_copy(node));
- node = NULL;
-
- /* add SEP */
- node = plist_access_path(manifest_node, 2, "SEP", "Digest");
- if (!node) {
- error("ERROR: Unable to get SEP digest from manifest\n");
- return -1;
- }
- plist_t dict = plist_new_dict();
- plist_dict_set_item(dict, "Digest", plist_copy(node));
- plist_dict_set_item(request, "SEP", dict);
-
- /* add Savage,PatchEpoch */
- node = plist_dict_get_item(parameters, "Savage,PatchEpoch");
- if (!node) {
- error("ERROR: %s: Unable to find required Savage,PatchEpoch in parameters\n", __func__);
- return -1;
- }
- plist_dict_set_item(request, "Savage,PatchEpoch", plist_copy(node));
- node = NULL;
-
- /* add Savage,ChipID */
- node = plist_dict_get_item(parameters, "Savage,ChipID");
- if (!node) {
- error("ERROR: %s: Unable to find required Savage,ChipID in parameters\n", __func__);
- return -1;
- }
- plist_dict_set_item(request, "Savage,ChipID", plist_copy(node));
- node = NULL;
-
- /* add Savage,AllowOfflineBoot */
- node = plist_dict_get_item(parameters, "Savage,AllowOfflineBoot");
- if (!node) {
- error("ERROR: %s: Unable to find required Savage,AllowOfflineBoot in parameters\n", __func__);
- return -1;
- }
- plist_dict_set_item(request, "Savage,AllowOfflineBoot", plist_copy(node));
- node = NULL;
-
- /* add Savage,ReadFWKey */
- node = plist_dict_get_item(parameters, "Savage,ReadFWKey");
- if (!node) {
- error("ERROR: %s: Unable to find required Savage,ReadFWKey in parameters\n", __func__);
- return -1;
- }
- plist_dict_set_item(request, "Savage,ReadFWKey", plist_copy(node));
- node = NULL;
-
- /* add Savage,ProductionMode */
- node = plist_dict_get_item(parameters, "Savage,ProductionMode");
- if (!node) {
- error("ERROR: %s: Unable to find required Savage,ProductionMode in parameters\n", __func__);
- return -1;
- }
- plist_dict_set_item(request, "Savage,ProductionMode", plist_copy(node));
- const char *comp_name = NULL;
- uint8_t isprod = 0;
- plist_get_bool_val(node, &isprod);
- node = NULL;
-
- /* get the right component name */
- comp_name = (isprod) ? "Savage,B0-Prod-Patch" : "Savage,B0-Dev-Patch";
- node = plist_dict_get_item(parameters, "Savage,Revision");
- if (node && (plist_get_node_type(node) == PLIST_DATA)) {
- unsigned char *savage_rev = NULL;
- uint64_t savage_rev_len = 0;
- plist_get_data_val(node, (char**)&savage_rev, &savage_rev_len);
- if (savage_rev_len > 0) {
- if (((savage_rev[0] | 0x10) & 0xF0) == 0x30) {
- comp_name = (isprod) ? "Savage,B2-Prod-Patch" : "Savage,B2-Dev-Patch";
- } else if ((savage_rev[0] & 0xF0) == 0xA0) {
- comp_name = (isprod) ? "Savage,BA-Prod-Patch" : "Savage,BA-Dev-Patch";
- }
- }
- free(savage_rev);
- }
-
- /* add Savage,B?-*-Patch */
- node = plist_dict_get_item(manifest_node, comp_name);
- if (!node) {
- error("ERROR: Unable to get %s entry from manifest\n", comp_name);
- return -1;
- }
- dict = plist_copy(node);
- plist_dict_remove_item(dict, "Info");
- plist_dict_set_item(request, comp_name, dict);
-
- if (component_name) {
- *component_name = strdup(comp_name);
- }
-
- /* add Savage,Nonce */
- node = plist_dict_get_item(parameters, "Savage,Nonce");
- if (!node) {
- error("ERROR: %s: Unable to find required Savage,Nonce in parameters\n", __func__);
- return -1;
- }
- plist_dict_set_item(request, "Savage,Nonce", plist_copy(node));
- node = NULL;
-
- /* add Savage,ReadECKey */
- node = plist_dict_get_item(parameters, "Savage,ReadECKey");
- if (!node) {
- error("ERROR: %s: Unable to find required Savage,ReadECKey in parameters\n", __func__);
- return -1;
- }
- plist_dict_set_item(request, "Savage,ReadECKey", plist_copy(node));
- node = NULL;
-
- /* apply overrides */
- if (overrides) {
- plist_dict_merge(&request, overrides);
- }
-
- return 0;
-}
-
-int tss_request_add_yonkers_tags(plist_t request, plist_t parameters, plist_t overrides, char **component_name)
-{
- plist_t node = NULL;
-
- plist_t manifest_node = plist_dict_get_item(parameters, "Manifest");
- if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) {
- error("ERROR: %s: Unable to get restore manifest from parameters\n", __func__);
- return -1;
- }
-
- /* add tags indicating we want to get the Savage,Ticket */
- plist_dict_set_item(request, "@BBTicket", plist_new_bool(1));
- plist_dict_set_item(request, "@Yonkers,Ticket", plist_new_bool(1));
-
- /* add SEP */
- node = plist_access_path(manifest_node, 2, "SEP", "Digest");
- if (!node) {
- error("ERROR: Unable to get SEP digest from manifest\n");
- return -1;
- }
- plist_t dict = plist_new_dict();
- plist_dict_set_item(dict, "Digest", plist_copy(node));
- plist_dict_set_item(request, "SEP", dict);
-
- {
- static const char *keys[] = {"Yonkers,AllowOfflineBoot", "Yonkers,BoardID", "Yonkers,ChipID", "Yonkers,ECID", "Yonkers,Nonce", "Yonkers,PatchEpoch", "Yonkers,ProductionMode", "Yonkers,ReadECKey", "Yonkers,ReadFWKey", };
- int i;
- for (i = 0; i < (int)(sizeof(keys) / sizeof(keys[0])); ++i) {
- node = plist_dict_get_item(parameters, keys[i]);
- if (!node) {
- error("ERROR: %s: Unable to find required %s in parameters\n", __func__, keys[i]);
- }
- plist_dict_set_item(request, keys[i], plist_copy(node));
- node = NULL;
- }
- }
-
- char *comp_name = NULL;
- plist_t comp_node = NULL;
- uint8_t isprod = 1;
- uint64_t fabrevision = (uint64_t)-1;
-
- node = plist_dict_get_item(parameters, "Yonkers,ProductionMode");
- if (node && (plist_get_node_type(node) == PLIST_BOOLEAN)) {
- plist_get_bool_val(node, &isprod);
- }
-
- node = plist_dict_get_item(parameters, "Yonkers,FabRevision");
- if (node && (plist_get_node_type(node) == PLIST_UINT)) {
- plist_get_uint_val(node, &fabrevision);
- }
-
- plist_dict_iter iter = NULL;
- plist_dict_new_iter(manifest_node, &iter);
- while (iter) {
- node = NULL;
- comp_name = NULL;
- plist_dict_next_item(manifest_node, iter, &comp_name, &node);
- if (comp_name == NULL) {
- node = NULL;
- break;
- }
- if (strncmp(comp_name, "Yonkers,", 8) == 0) {
- int target_node = 1;
- plist_t sub_node;
- if ((sub_node = plist_dict_get_item(node, "EPRO")) != NULL && plist_get_node_type(sub_node) == PLIST_BOOLEAN) {
- uint8_t b = 0;
- plist_get_bool_val(sub_node, &b);
- target_node &= ((isprod) ? b : !b);
- }
- if ((sub_node = plist_dict_get_item(node, "FabRevision")) != NULL && plist_get_node_type(sub_node) == PLIST_UINT) {
- uint64_t v = 0;
- plist_get_uint_val(sub_node, &v);
- target_node &= (v == fabrevision);
- }
- if (target_node) {
- comp_node = node;
- break;
- }
- }
- free(comp_name);
- }
- free(iter);
-
- if (comp_name == NULL) {
- error("ERROR: No Yonkers node for %s/%lu\n", (isprod) ? "Production" : "Development", (unsigned long)fabrevision);
- return -1;
- }
-
- /* add Yonkers,SysTopPatch* */
- if (comp_node != NULL) {
- plist_t comp_dict = plist_copy(comp_node);
- plist_dict_remove_item(comp_dict, "Info");
- plist_dict_set_item(request, comp_name, comp_dict);
- }
-
- if (component_name) {
- *component_name = comp_name;
- } else {
- free(comp_name);
- }
-
- /* apply overrides */
- if (overrides) {
- plist_dict_merge(&request, overrides);
- }
-
- return 0;
-}
-
-int tss_request_add_vinyl_tags(plist_t request, plist_t parameters, plist_t overrides)
-{
- plist_t node = NULL;
-
- plist_t manifest_node = plist_dict_get_item(parameters, "Manifest");
- if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) {
- error("ERROR: %s: Unable to get restore manifest from parameters\n", __func__);
- return -1;
- }
-
- /* add tags indicating we want to get the eUICC,Ticket */
- plist_dict_set_item(request, "@BBTicket", plist_new_bool(1));
- plist_dict_set_item(request, "@eUICC,Ticket", plist_new_bool(1));
-
- node = plist_dict_get_item(parameters, "eUICC,ChipID");
- if (node) {
- plist_dict_set_item(request, "eUICC,ChipID", plist_copy(node));
- }
- node = plist_dict_get_item(parameters, "eUICC,EID");
- if (node) {
- plist_dict_set_item(request, "eUICC,EID", plist_copy(node));
- }
- node = plist_dict_get_item(parameters, "eUICC,RootKeyIdentifier");
- if (node) {
- plist_dict_set_item(request, "eUICC,RootKeyIdentifier", plist_copy(node));
- }
-
- /* set Nonce for eUICC,Gold component */
- node = plist_dict_get_item(parameters, "EUICCGoldNonce");
- if (node) {
- plist_t n = plist_dict_get_item(request, "eUICC,Gold");
- if (n) {
- plist_dict_set_item(n, "Nonce", plist_copy(node));
- }
- }
-
- /* set Nonce for eUICC,Main component */
- node = plist_dict_get_item(parameters, "EUICCMainNonce");
- if (node) {
- plist_t n = plist_dict_get_item(request, "eUICC,Main");
- if (n) {
- plist_dict_set_item(n, "Nonce", plist_copy(node));
- }
- }
-
- /* apply overrides */
- if (overrides) {
- plist_dict_merge(&request, overrides);
- }
-
- return 0;
-}
-
-int tss_request_add_rose_tags(plist_t request, plist_t parameters, plist_t overrides)
-{
- plist_t node = NULL;
-
- plist_t manifest_node = plist_dict_get_item(parameters, "Manifest");
- if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) {
- error("ERROR: %s: Unable to get restore manifest from parameters\n", __func__);
- return -1;
- }
-
- /* add tags indicating we want to get the Rap,Ticket */
- plist_dict_set_item(request, "@BBTicket", plist_new_bool(1));
- plist_dict_set_item(request, "@Rap,Ticket", plist_new_bool(1));
-
- uint64_t u64val = 0;
- uint8_t bval = 0;
-
- u64val = _plist_dict_get_uint(parameters, "Rap,BoardID");
- plist_dict_set_item(request, "Rap,BoardID", plist_new_uint(u64val));
-
- u64val = _plist_dict_get_uint(parameters, "Rap,ChipID");
- plist_dict_set_item(request, "Rap,ChipID", plist_new_uint(u64val));
-
- u64val = _plist_dict_get_uint(parameters, "Rap,ECID");
- plist_dict_set_item(request, "Rap,ECID", plist_new_uint(u64val));
-
- node = plist_dict_get_item(parameters, "Rap,Nonce");
- if (node) {
- plist_dict_set_item(request, "Rap,Nonce", plist_copy(node));
- }
-
- bval = _plist_dict_get_bool(parameters, "Rap,ProductionMode");
- plist_dict_set_item(request, "Rap,ProductionMode", plist_new_bool(bval));
-
- u64val = _plist_dict_get_uint(parameters, "Rap,SecurityDomain");
- plist_dict_set_item(request, "Rap,SecurityDomain", plist_new_uint(u64val));
-
- bval = _plist_dict_get_bool(parameters, "Rap,SecurityMode");
- plist_dict_set_item(request, "Rap,SecurityMode", plist_new_bool(bval));
-
- char *comp_name = NULL;
- plist_dict_iter iter = NULL;
- plist_dict_new_iter(manifest_node, &iter);
- while (iter) {
- node = NULL;
- comp_name = NULL;
- plist_dict_next_item(manifest_node, iter, &comp_name, &node);
- if (comp_name == NULL) {
- node = NULL;
- break;
- }
- if (strncmp(comp_name, "Rap,", 4) == 0) {
- plist_t manifest_entry = plist_copy(node);
-
- /* handle RestoreRequestRules */
- plist_t rules = plist_access_path(manifest_entry, 2, "Info", "RestoreRequestRules");
- if (rules) {
- debug("DEBUG: Applying restore request rules for entry %s\n", comp_name);
- tss_entry_apply_restore_request_rules(manifest_entry, parameters, rules);
- }
-
- /* Make sure we have a Digest key for Trusted items even if empty */
- plist_t node = plist_dict_get_item(manifest_entry, "Trusted");
- if (node && plist_get_node_type(node) == PLIST_BOOLEAN) {
- uint8_t trusted;
- plist_get_bool_val(node, &trusted);
- if (trusted && !plist_access_path(manifest_entry, 1, "Digest")) {
- debug("DEBUG: No Digest data, using empty value for entry %s\n", comp_name);
- plist_dict_set_item(manifest_entry, "Digest", plist_new_data(NULL, 0));
- }
- }
-
- plist_dict_remove_item(manifest_entry, "Info");
-
- /* finally add entry to request */
- plist_dict_set_item(request, comp_name, manifest_entry);
- }
- free(comp_name);
- }
- free(iter);
-
- /* apply overrides */
- if (overrides) {
- plist_dict_merge(&request, overrides);
- }
-
- return 0;
-}
-
-int tss_request_add_veridian_tags(plist_t request, plist_t parameters, plist_t overrides)
-{
- plist_t node = NULL;
-
- plist_t manifest_node = plist_dict_get_item(parameters, "Manifest");
- if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) {
- error("ERROR: %s: Unable to get restore manifest from parameters\n", __func__);
- return -1;
- }
-
- /* add tags indicating we want to get the BMU,Ticket */
- plist_dict_set_item(request, "@BBTicket", plist_new_bool(1));
- plist_dict_set_item(request, "@BMU,Ticket", plist_new_bool(1));
-
- uint64_t u64val = 0;
- uint8_t bval = 0;
-
- u64val = _plist_dict_get_uint(parameters, "BMU,BoardID");
- plist_dict_set_item(request, "BMU,BoardID", plist_new_uint(u64val));
-
- u64val = _plist_dict_get_uint(parameters, "ChipID");
- plist_dict_set_item(request, "BMU,ChipID", plist_new_uint(u64val));
-
- node = plist_dict_get_item(parameters, "Nonce");
- if (node) {
- plist_dict_set_item(request, "BMU,Nonce", plist_copy(node));
- }
-
- bval = _plist_dict_get_bool(parameters, "ProductionMode");
- plist_dict_set_item(request, "BMU,ProductionMode", plist_new_bool(bval));
-
- u64val = _plist_dict_get_uint(parameters, "UniqueID");
- plist_dict_set_item(request, "BMU,UniqueID", plist_new_uint(u64val));
-
- char *comp_name = NULL;
- plist_dict_iter iter = NULL;
- plist_dict_new_iter(manifest_node, &iter);
- while (iter) {
- node = NULL;
- comp_name = NULL;
- plist_dict_next_item(manifest_node, iter, &comp_name, &node);
- if (comp_name == NULL) {
- node = NULL;
- break;
- }
- if (strncmp(comp_name, "BMU,", 4) == 0) {
- plist_t manifest_entry = plist_copy(node);
-
- /* handle RestoreRequestRules */
- plist_t rules = plist_access_path(manifest_entry, 2, "Info", "RestoreRequestRules");
- if (rules) {
- debug("DEBUG: Applying restore request rules for entry %s\n", comp_name);
- tss_entry_apply_restore_request_rules(manifest_entry, parameters, rules);
- }
-
- /* Make sure we have a Digest key for Trusted items even if empty */
- plist_t node = plist_dict_get_item(manifest_entry, "Trusted");
- if (node && plist_get_node_type(node) == PLIST_BOOLEAN) {
- uint8_t trusted;
- plist_get_bool_val(node, &trusted);
- if (trusted && !plist_access_path(manifest_entry, 1, "Digest")) {
- debug("DEBUG: No Digest data, using empty value for entry %s\n", comp_name);
- plist_dict_set_item(manifest_entry, "Digest", plist_new_data(NULL, 0));
- }
- }
-
- plist_dict_remove_item(manifest_entry, "Info");
-
- /* finally add entry to request */
- plist_dict_set_item(request, comp_name, manifest_entry);
- }
- free(comp_name);
- }
- free(iter);
-
- /* apply overrides */
- if (overrides) {
- plist_dict_merge(&request, overrides);
- }
-
- return 0;
-}
-
-int tss_request_add_tcon_tags(plist_t request, plist_t parameters, plist_t overrides)
-{
- plist_t node = NULL;
-
- plist_t manifest_node = plist_dict_get_item(parameters, "Manifest");
- if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) {
- error("ERROR: %s: Unable to get restore manifest from parameters\n", __func__);
- return -1;
- }
-
- /* add tags indicating we want to get the Baobab,Ticket */
- plist_dict_set_item(request, "@BBTicket", plist_new_bool(1));
- plist_dict_set_item(request, "@Baobab,Ticket", plist_new_bool(1));
-
- uint64_t u64val = 0;
- uint8_t bval = 0;
- uint8_t isprod = 0;
-
- u64val = _plist_dict_get_uint(parameters, "Baobab,BoardID");
- plist_dict_set_item(request, "Baobab,BoardID", plist_new_uint(u64val));
-
- u64val = _plist_dict_get_uint(parameters, "Baobab,ChipID");
- plist_dict_set_item(request, "Baobab,ChipID", plist_new_uint(u64val));
-
- node = plist_dict_get_item(parameters, "Baobab,ECID");
- if (node) {
- plist_dict_set_item(request, "Baobab,ECID", plist_copy(node));
- }
-
- u64val = _plist_dict_get_uint(parameters, "Baobab,Life");
- plist_dict_set_item(request, "Baobab,Life", plist_new_uint(u64val));
-
- u64val = _plist_dict_get_uint(parameters, "Baobab,ManifestEpoch");
- plist_dict_set_item(request, "Baobab,ManifestEpoch", plist_new_uint(u64val));
-
- isprod = _plist_dict_get_bool(parameters, "Baobab,ProductionMode");
- plist_dict_set_item(request, "Baobab,ProductionMode", plist_new_bool(isprod));
-
- u64val = _plist_dict_get_uint(parameters, "Baobab,SecurityDomain");
- plist_dict_set_item(request, "Baobab,SecurityDomain", plist_new_uint(u64val));
-
- node = plist_dict_get_item(parameters, "Baobab,UpdateNonce");
- if (node) {
- plist_dict_set_item(request, "Baobab,UpdateNonce", plist_copy(node));
- }
-
- char *comp_name = NULL;
- plist_dict_iter iter = NULL;
- plist_dict_new_iter(manifest_node, &iter);
- while (iter) {
- node = NULL;
- comp_name = NULL;
- plist_dict_next_item(manifest_node, iter, &comp_name, &node);
- if (comp_name == NULL) {
- node = NULL;
- break;
- }
- if (strncmp(comp_name, "Baobab,", 7) == 0) {
- plist_t manifest_entry = plist_copy(node);
-
- plist_dict_remove_item(manifest_entry, "Info");
- plist_dict_set_item(manifest_entry, "EPRO", plist_new_bool(isprod));
-
- /* finally add entry to request */
- plist_dict_set_item(request, comp_name, manifest_entry);
- }
- free(comp_name);
- }
- free(iter);
-
- /* apply overrides */
- if (overrides) {
- plist_dict_merge(&request, overrides);
- }
- return 0;
-}
-
-static size_t tss_write_callback(char* data, size_t size, size_t nmemb, tss_response* response) {
- size_t total = size * nmemb;
- if (total != 0) {
- response->content = realloc(response->content, response->length + total + 1);
- memcpy(response->content + response->length, data, total);
- response->content[response->length + total] = '\0';
- response->length += total;
- }
-
- return total;
-}
-
-plist_t tss_request_send(plist_t tss_request, const char* server_url_string) {
-
- if (idevicerestore_debug) {
- debug_plist(tss_request);
- }
-
- char* request = NULL;
- int status_code = -1;
- int retry = 0;
- int max_retries = 15;
- unsigned int size = 0;
- char curl_error_message[CURL_ERROR_SIZE];
-
- const char* urls[6] = {
- "https://gs.apple.com/TSS/controller?action=2",
- "https://17.171.36.30/TSS/controller?action=2",
- "https://17.151.36.30/TSS/controller?action=2",
- "http://gs.apple.com/TSS/controller?action=2",
- "http://17.171.36.30/TSS/controller?action=2",
- "http://17.151.36.30/TSS/controller?action=2"
- };
-
- plist_to_xml(tss_request, &request, &size);
-
- tss_response* response = NULL;
- memset(curl_error_message, '\0', CURL_ERROR_SIZE);
-
- while (retry++ < max_retries) {
- response = NULL;
- CURL* handle = curl_easy_init();
- if (handle == NULL) {
- break;
- }
- struct curl_slist* header = NULL;
- header = curl_slist_append(header, "Cache-Control: no-cache");
- header = curl_slist_append(header, "Content-type: text/xml; charset=\"utf-8\"");
- header = curl_slist_append(header, "Expect:");
-
- response = malloc(sizeof(tss_response));
- if (response == NULL) {
- fprintf(stderr, "Unable to allocate sufficient memory\n");
- return NULL;
- }
-
- response->length = 0;
- response->content = malloc(1);
- response->content[0] = '\0';
-
- /* disable SSL verification to allow download from untrusted https locations */
- curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0);
-
- curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, curl_error_message);
- curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, (curl_write_callback)&tss_write_callback);
- curl_easy_setopt(handle, CURLOPT_WRITEDATA, response);
- curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header);
- curl_easy_setopt(handle, CURLOPT_POSTFIELDS, request);
- curl_easy_setopt(handle, CURLOPT_USERAGENT, USER_AGENT_STRING);
- curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, strlen(request));
- if (server_url_string) {
- curl_easy_setopt(handle, CURLOPT_URL, server_url_string);
- } else {
- int url_index = (retry - 1) % 6;
- curl_easy_setopt(handle, CURLOPT_URL, urls[url_index]);
- info("Request URL set to %s\n", urls[url_index]);
- }
-
- info("Sending TSS request attempt %d... ", retry);
-
- curl_easy_perform(handle);
- curl_slist_free_all(header);
- curl_easy_cleanup(handle);
-
- if (strstr(response->content, "MESSAGE=SUCCESS")) {
- status_code = 0;
- info("response successfully received\n");
- break;
- }
-
- if (response->length > 0) {
- error("TSS server returned: %s\n", response->content);
- }
-
- char* status = strstr(response->content, "STATUS=");
- if (status) {
- sscanf(status+7, "%d&%*s", &status_code);
- }
- if (status_code == -1) {
- error("%s\n", curl_error_message);
- // no status code in response. retry
- free(response->content);
- free(response);
- response = NULL;
- sleep(2);
- continue;
- } else if (status_code == 8) {
- // server error (invalid bb request?)
- break;
- } else if (status_code == 49) {
- // server error (invalid bb data, e.g. BbSNUM?)
- break;
- } else if (status_code == 69 || status_code == 94) {
- // This device isn't eligible for the requested build.
- break;
- } else if (status_code == 100) {
- // server error, most likely the request was malformed
- break;
- } else if (status_code == 126) {
- // An internal error occured, most likely the request was malformed
- break;
- } else {
- error("ERROR: tss_send_request: Unhandled status code %d\n", status_code);
- }
- }
-
- if (status_code != 0) {
- if (response && strstr(response->content, "MESSAGE=") != NULL) {
- char* message = strstr(response->content, "MESSAGE=") + strlen("MESSAGE=");
- error("ERROR: TSS request failed (status=%d, message=%s)\n", status_code, message);
- } else {
- error("ERROR: TSS request failed: %s (status=%d)\n", curl_error_message, status_code);
- }
- free(request);
- if (response) free(response->content);
- if (response) free(response);
- return NULL;
- }
-
- char* tss_data = strstr(response->content, "<?xml");
- if (tss_data == NULL) {
- error("ERROR: Incorrectly formatted TSS response\n");
- free(request);
- free(response->content);
- free(response);
- return NULL;
- }
-
- uint32_t tss_size = 0;
- plist_t tss_response = NULL;
- tss_size = response->length - (tss_data - response->content);
- plist_from_xml(tss_data, tss_size, &tss_response);
- free(response->content);
- free(response);
-
- if (idevicerestore_debug) {
- debug_plist(tss_response);
- }
-
- free(request);
-
- return tss_response;
-}
-
-static int tss_response_get_data_by_key(plist_t response, const char* name, unsigned char** buffer, unsigned int* length) {
-
- plist_t node = plist_dict_get_item(response, name);
- if (!node || plist_get_node_type(node) != PLIST_DATA) {
- debug("DEBUG: %s: No entry '%s' in TSS response\n", __func__, name);
- return -1;
- }
-
- char *data = NULL;
- uint64_t len = 0;
- plist_get_data_val(node, &data, &len);
- if (data) {
- *length = (unsigned int)len;
- *buffer = (unsigned char*)data;
- return 0;
- } else {
- error("ERROR: Unable to get %s data from TSS response\n", name);
- return -1;
- }
-}
-
-int tss_response_get_ap_img4_ticket(plist_t response, unsigned char** ticket, unsigned int* length) {
- return tss_response_get_data_by_key(response, "ApImg4Ticket", ticket, length);
-}
-
-int tss_response_get_ap_ticket(plist_t response, unsigned char** ticket, unsigned int* length) {
- return tss_response_get_data_by_key(response, "APTicket", ticket, length);
-}
-
-int tss_response_get_baseband_ticket(plist_t response, unsigned char** ticket, unsigned int* length) {
- return tss_response_get_data_by_key(response, "BBTicket", ticket, length);
-}
-
-int tss_response_get_path_by_entry(plist_t response, const char* entry, char** path) {
- char* path_string = NULL;
- plist_t path_node = NULL;
- plist_t entry_node = NULL;
-
- *path = NULL;
-
- entry_node = plist_dict_get_item(response, entry);
- if (!entry_node || plist_get_node_type(entry_node) != PLIST_DICT) {
- debug("DEBUG: %s: No entry '%s' in TSS response\n", __func__, entry);
- return -1;
- }
-
- path_node = plist_dict_get_item(entry_node, "Path");
- if (!path_node || plist_get_node_type(path_node) != PLIST_STRING) {
- debug("NOTE: Unable to find %s path in TSS entry\n", entry);
- return -1;
- }
- plist_get_string_val(path_node, &path_string);
-
- *path = path_string;
- return 0;
-}
-
-int tss_response_get_blob_by_path(plist_t tss, const char* path, unsigned char** blob) {
- uint32_t i = 0;
- uint32_t tss_size = 0;
- uint64_t blob_size = 0;
- char* entry_key = NULL;
- char* blob_data = NULL;
- char* entry_path = NULL;
- plist_t tss_entry = NULL;
- plist_t blob_node = NULL;
- plist_t path_node = NULL;
- plist_dict_iter iter = NULL;
-
- *blob = NULL;
-
- plist_dict_new_iter(tss, &iter);
- tss_size = plist_dict_get_size(tss);
- for (i = 0; i < tss_size; i++) {
- plist_dict_next_item(tss, iter, &entry_key, &tss_entry);
- if (entry_key == NULL)
- break;
-
- if (!tss_entry || plist_get_node_type(tss_entry) != PLIST_DICT) {
- continue;
- }
-
- path_node = plist_dict_get_item(tss_entry, "Path");
- if (!path_node || plist_get_node_type(path_node) != PLIST_STRING) {
- error("ERROR: Unable to find TSS path node in entry %s\n", entry_key);
- free(iter);
- return -1;
- }
-
- plist_get_string_val(path_node, &entry_path);
- if (strcmp(path, entry_path) == 0) {
- blob_node = plist_dict_get_item(tss_entry, "Blob");
- if (!blob_node || plist_get_node_type(blob_node) != PLIST_DATA) {
- error("ERROR: Unable to find TSS blob node in entry %s\n", entry_key);
- free(iter);
- return -1;
- }
- plist_get_data_val(blob_node, &blob_data, &blob_size);
- break;
- }
-
- free(entry_key);
- }
- free(iter);
-
- if (blob_data == NULL || blob_size <= 0) {
- return -1;
- }
-
- *blob = (unsigned char*)blob_data;
- return 0;
-}
-
-int tss_response_get_blob_by_entry(plist_t response, const char* entry, unsigned char** blob) {
- uint64_t blob_size = 0;
- char* blob_data = NULL;
- plist_t blob_node = NULL;
- plist_t tss_entry = NULL;
-
- *blob = NULL;
-
- tss_entry = plist_dict_get_item(response, entry);
- if (!tss_entry || plist_get_node_type(tss_entry) != PLIST_DICT) {
- debug("DEBUG: %s: No entry '%s' in TSS response\n", __func__, entry);
- return -1;
- }
-
- blob_node = plist_dict_get_item(tss_entry, "Blob");
- if (!blob_node || plist_get_node_type(blob_node) != PLIST_DATA) {
- error("ERROR: Unable to find blob in %s entry\n", entry);
- return -1;
- }
- plist_get_data_val(blob_node, &blob_data, &blob_size);
-
- *blob = (unsigned char*)blob_data;
- return 0;
-}
diff --git a/src/tss.h b/src/tss.h
deleted file mode 100644
index 3590aed..0000000
--- a/src/tss.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * tss.h
- * Definitions for communicating with Apple's TSS server.
- *
- * Copyright (c) 2013 Martin Szulecki. All Rights Reserved.
- * Copyright (c) 2012 Nikias Bassen. All Rights Reserved.
- * Copyright (c) 2010 Joshua Hill. All Rights Reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef IDEVICERESTORE_TSS_H
-#define IDEVICERESTORE_TSS_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <plist/plist.h>
-
-/* parameters */
-int tss_parameters_add_from_manifest(plist_t parameters, plist_t build_identity);
-
-/* request */
-plist_t tss_request_new(plist_t overrides);
-
-int tss_request_add_local_policy_tags(plist_t request, plist_t parameters);
-int tss_request_add_common_tags(plist_t request, plist_t parameters, plist_t overrides);
-int tss_request_add_ap_tags(plist_t request, plist_t parameters, plist_t overrides);
-int tss_request_add_ap_recovery_tags(plist_t request, plist_t parameters, plist_t overrides);
-int tss_request_add_baseband_tags(plist_t request, plist_t parameters, plist_t overrides);
-int tss_request_add_se_tags(plist_t request, plist_t parameters, plist_t overrides);
-int tss_request_add_savage_tags(plist_t request, plist_t parameters, plist_t overrides, char **component_name);
-int tss_request_add_yonkers_tags(plist_t request, plist_t parameters, plist_t overrides, char **component_name);
-int tss_request_add_vinyl_tags(plist_t request, plist_t parameters, plist_t overrides);
-int tss_request_add_rose_tags(plist_t request, plist_t parameters, plist_t overrides);
-int tss_request_add_veridian_tags(plist_t request, plist_t parameters, plist_t overrides);
-int tss_request_add_tcon_tags(plist_t request, plist_t parameters, plist_t overrides);
-
-int tss_request_add_ap_img4_tags(plist_t request, plist_t parameters);
-int tss_request_add_ap_img3_tags(plist_t request, plist_t parameters);
-
-/* i/o */
-plist_t tss_request_send(plist_t request, const char* server_url_string);
-
-/* response */
-int tss_response_get_ap_img4_ticket(plist_t response, unsigned char** ticket, unsigned int* length);
-int tss_response_get_ap_ticket(plist_t response, unsigned char** ticket, unsigned int* length);
-int tss_response_get_baseband_ticket(plist_t response, unsigned char** ticket, unsigned int* length);
-int tss_response_get_path_by_entry(plist_t response, const char* entry, char** path);
-int tss_response_get_blob_by_path(plist_t response, const char* path, unsigned char** blob);
-int tss_response_get_blob_by_entry(plist_t response, const char* entry, unsigned char** blob);
-
-/* helpers */
-char* ecid_to_string(uint64_t ecid);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif