summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am12
-rw-r--r--src/ace3.c59
-rw-r--r--src/ace3.h2
-rw-r--r--src/asr.c138
-rw-r--r--src/asr.h6
-rw-r--r--src/common.c577
-rw-r--r--src/common.h63
-rw-r--r--src/dfu.c131
-rw-r--r--src/dfu.h4
-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.c851
-rw-r--r--src/idevicerestore.h9
-rw-r--r--src/img3.c80
-rw-r--r--src/img3.h16
-rw-r--r--src/img4.c298
-rw-r--r--src/img4.h2
-rw-r--r--src/ipsw.c457
-rw-r--r--src/ipsw.h7
-rw-r--r--src/limera1n.c22
-rw-r--r--src/locking.c12
-rw-r--r--src/log.c227
-rw-r--r--src/log.h45
-rw-r--r--src/mbn.c489
-rw-r--r--src/mbn.h85
-rw-r--r--src/normal.c150
-rw-r--r--src/normal.h1
-rw-r--r--src/recovery.c128
-rw-r--r--src/restore.c2717
-rw-r--r--src/restore.h17
-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.c1796
-rw-r--r--src/tss.h76
42 files changed, 4554 insertions, 4924 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 722487a..2b7084e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -6,9 +6,9 @@ AM_CFLAGS = \
$(libusbmuxd_CFLAGS) \
$(libplist_CFLAGS) \
$(limd_glue_CFLAGS) \
+ $(libtatsu_CFLAGS) \
$(libzip_CFLAGS) \
$(zlib_CFLAGS) \
- $(openssl_CFLAGS) \
$(libcurl_CFLAGS)
AM_LDFLAGS = \
@@ -18,9 +18,9 @@ AM_LDFLAGS = \
$(libusbmuxd_LIBS) \
$(libplist_LIBS) \
$(limd_glue_LIBS) \
+ $(libtatsu_LIBS) \
$(libzip_LIBS) \
$(zlib_LIBS) \
- $(openssl_LIBS) \
$(libcurl_LIBS)
AM_LDADD = $(AC_LDADD)
@@ -29,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 \
@@ -45,12 +45,10 @@ idevicerestore_SOURCES = \
asr.c asr.h \
fdr.c fdr.h \
ace3.c ace3.h \
- limera1n_payload.h \
- limera1n.c limera1n.h \
download.c download.h \
locking.c locking.h
-if USE_INTERNAL_SHA
-idevicerestore_SOURCES += sha1.c sha1.h sha512.c sha512.h fixedint.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
index b96e6b4..d51613d 100644
--- a/src/ace3.c
+++ b/src/ace3.c
@@ -50,11 +50,39 @@ static uint32_t crc_buffer(const unsigned char* buffer, unsigned int bufsize, un
return result;
}
-int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t bdid, unsigned int prev, plist_t tss, unsigned char** bin_out, size_t* bin_size)
+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 unk4; // 0x00203400
+ uint32_t version; // ace3 version, e.g. 0x00203400
uint32_t unk8; // 0x00002800
uint32_t header_size; // 0x00000040
uint32_t data1_size;
@@ -84,10 +112,7 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t
struct uarp_toc_entry {
uint32_t this_size; // BE usually 0x28
uint32_t fourcc; // 'PT01' or similar
- uint32_t index; // BE starting with 0, increment+1 for each entry
- uint32_t unk_0c; // BE usually not zero
- uint32_t unk_10; // BE usually 0
- uint32_t unk_14; // BE usually 0
+ 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
@@ -142,6 +167,7 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t
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");
@@ -163,6 +189,7 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t
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);
@@ -174,11 +201,11 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t
plist_mem_free(iter);
}
if (!payload_4cc) {
- printf("Failed to get payload 4cc\n");
+ logger(LL_ERROR, "Failed to get payload 4cc\n");
return -1;
}
if (!data_payload_4ccs) {
- printf("Failed to get data payload 4ccs\n");
+ logger(LL_ERROR, "Failed to get data payload 4ccs\n");
return -1;
}
@@ -187,20 +214,26 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t
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_offset = be32toh(uarp_hdr->toc_offset);
uint32_t toc_size = be32toh(uarp_hdr->toc_size);
- const unsigned char* p = uarp_fw + uarp_hdr_size;
- while (p < uarp_fw + 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);
@@ -210,10 +243,10 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t
uint32_t content_size = data1_size + data2_size + im4m_size + dl_size;
- *bin_out = (unsigned char*)malloc(0x40 + content_size);
+ *bin_out = malloc(0x40 + content_size);
struct ace3bin_header* hdr = (struct ace3bin_header*)(*bin_out);
hdr->magic = htole32(0xACE00003);
- hdr->unk4 = htole32(0x00203400);
+ hdr->version = htole32(data1_version);
hdr->unk8 = htole32(0x00002800);
hdr->header_size = htole32(0x40);
hdr->data1_size = htole32(data1_size);
diff --git a/src/ace3.h b/src/ace3.h
index 2ef65a7..6c93e1e 100644
--- a/src/ace3.h
+++ b/src/ace3.h
@@ -8,7 +8,7 @@ extern "C" {
#include <stdint.h>
#include <plist/plist.h>
-int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t bdid, unsigned int prev, plist_t tss, unsigned char** bin_out, size_t* bin_size);
+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
}
diff --git a/src/asr.c b/src/asr.c
index bf15dc2..e140980 100644
--- a/src/asr.c
+++ b/src/asr.c
@@ -30,15 +30,8 @@
#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"
@@ -47,7 +40,6 @@
#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
@@ -55,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;
@@ -68,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));
@@ -92,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;
@@ -103,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;
@@ -142,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;
}
@@ -156,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;
}
@@ -170,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;
}
@@ -180,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;
}
@@ -206,23 +201,13 @@ void asr_free(asr_client_t asr)
}
}
-int asr_perform_validation(asr_client_t asr, ipsw_file_handle_t file)
+int asr_send_validation_packet_info(asr_client_t asr, uint64_t ipsw_size)
{
- 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;
-
- length = ipsw_file_size(file);
-
- 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));
}
@@ -234,21 +219,39 @@ int asr_perform_validation(asr_client_t asr, ipsw_file_handle_t file)
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;
@@ -259,11 +262,30 @@ int asr_perform_validation(asr_client_t asr, ipsw_file_handle_t file)
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);
@@ -274,7 +296,7 @@ int asr_perform_validation(asr_client_t asr, ipsw_file_handle_t file)
break;
} else {
- error("ERROR: Unknown command received from ASR\n");
+ logger(LL_ERROR, "Unknown command received from ASR\n");
plist_free(packet);
return -1;
}
@@ -293,38 +315,38 @@ int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, ipsw_file_hand
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;
}
if (ipsw_file_seek(file, oob_offset, SEEK_SET) < 0) {
- error("ERROR: Unable to seek to OOB offset 0x%" PRIx64 "\n", oob_offset);
+ 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) {
- error("ERROR: Unable to read OOB data from filesystem offset 0x%" PRIx64 ", oob_length %" PRIu64 ", read returned %" PRIi64"\n", oob_offset, oob_length, ir);
+ 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;
}
@@ -343,12 +365,6 @@ int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file)
data = (char*)malloc(ASR_PAYLOAD_CHUNK_SIZE + 20);
- SHA_CTX sha1;
-
- if (asr->checksum_chunks) {
- SHA1_Init(&sha1);
- }
-
i = length;
int retry = 3;
while(i > 0 && retry >= 0) {
@@ -360,18 +376,18 @@ int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file)
}
if (ipsw_file_read(file, data, size) != (int64_t)size) {
- error("Error reading filesystem\n");
+ 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, sendsize) < 0) {
- error("ERROR: Unable to send filesystem payload\n");
+ logger(LL_ERROR, "Unable to send filesystem payload chunk, retrying...\n");
retry--;
continue;
}
@@ -387,5 +403,5 @@ int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file)
}
free(data);
- return 0;
+ return (i == 0) ? 0 : -1;
}
diff --git a/src/asr.h b/src/asr.h
index 0d9534c..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 {
@@ -44,11 +46,11 @@ typedef struct asr_client *asr_client_t;
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);
+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, ipsw_file_handle_t file);
int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file);
diff --git a/src/common.c b/src/common.c
index 499509d..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" },
@@ -68,102 +77,17 @@ struct idevicerestore_mode_t idevicerestore_modes[] = {
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;
}
@@ -171,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;
}
@@ -185,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;
}
@@ -212,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;
}
@@ -222,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 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 print_progress_bar(double progress) {
-#ifndef WIN32
- if (info_disabled) return;
+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)
@@ -469,7 +669,7 @@ void idevicerestore_progress(struct idevicerestore_client_t* client, int step, d
} 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) || (step == RESTORE_STEP_UPLOAD_IMG)) {
- print_progress_bar(100.0 * progress);
+ print_progress_bar(NULL, progress);
}
}
}
@@ -558,145 +758,6 @@ 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 uintval;
- }
- 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)
-{
- 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);
- }
- break;
- default:
- break;
- }
- return bval;
-}
-
-int _plist_dict_copy_uint(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key)
-{
- if (plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key) == NULL) {
- return -1;
- }
- uint64_t u64val = _plist_dict_get_uint(source_dict, (alt_source_key) ? alt_source_key : key);
- plist_dict_set_item(target_dict, key, plist_new_uint(u64val));
- return 0;
-}
-
-int _plist_dict_copy_bool(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key)
-{
- if (plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key) == NULL) {
- return -1;
- }
- uint64_t bval = _plist_dict_get_bool(source_dict, (alt_source_key) ? alt_source_key : key);
- plist_dict_set_item(target_dict, key, plist_new_bool(bval));
- return 0;
-}
-
-int _plist_dict_copy_data(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key)
-{
- plist_t node = plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key);
- if (!PLIST_IS_DATA(node)) {
- return -1;
- }
- plist_dict_set_item(target_dict, key, plist_copy(node));
- return 0;
-}
-
-int _plist_dict_copy_string(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key)
-{
- plist_t node = plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key);
- if (!PLIST_IS_STRING(node)) {
- return -1;
- }
- plist_dict_set_item(target_dict, key, plist_copy(node));
- return 0;
-}
-
-int _plist_dict_copy_item(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key)
-{
- plist_t node = plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key);
- if (!node) {
- return -1;
- }
- plist_dict_set_item(target_dict, key, plist_copy(node));
- return 0;
-}
-
const char* path_get_basename(const char* path)
{
#ifdef WIN32
diff --git a/src/common.h b/src/common.h
index 9b3c1e3..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
@@ -81,16 +82,6 @@ struct idevicerestore_mode_t {
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;
@@ -104,7 +95,9 @@ 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;
ipsw_archive_t ipsw;
@@ -112,7 +105,6 @@ struct idevicerestore_client_t {
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;
@@ -131,24 +123,49 @@ struct idevicerestore_client_t {
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);
@@ -191,14 +208,6 @@ 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);
-int _plist_dict_copy_uint(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key);
-int _plist_dict_copy_bool(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key);
-int _plist_dict_copy_data(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key);
-int _plist_dict_copy_string(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key);
-int _plist_dict_copy_item(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key);
-
const char* path_get_basename(const char* path);
#ifdef __cplusplus
diff --git a/src/dfu.c b/src/dfu.c
index cc8e1fb..6ba23e7 100644
--- a/src/dfu.c
+++ b/src/dfu.c
@@ -27,15 +27,16 @@
#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;
}
@@ -48,13 +49,13 @@ int dfu_client_new(struct idevicerestore_client_t* client)
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;
}
}
if (irecv_open_with_ecid_and_attempts(&dfu, client->ecid, 10) != IRECV_E_SUCCESS) {
- error("ERROR: Unable to connect to device in DFU mode\n");
+ logger(LL_ERROR, "Unable to connect to device in DFU mode\n");
return -1;
}
@@ -66,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);
@@ -83,7 +85,6 @@ 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_and_attempts(&dfu, client->ecid, 10) != IRECV_E_SUCCESS) {
return NULL;
}
@@ -103,22 +104,22 @@ irecv_device_t dfu_get_irecv_device(struct idevicerestore_client_t* client)
return device;
}
-int dfu_send_buffer_with_options(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size, unsigned int irecv_options)
+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, irecv_options);
+ 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, unsigned char* buffer, unsigned int size)
+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);
}
@@ -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);
+ 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;
}
@@ -366,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;
}
@@ -384,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;
}
@@ -398,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;
}
@@ -422,12 +425,12 @@ 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 and iBoot.\n", key);
+ logger(LL_DEBUG, "%s is loaded by iBoot Stage 1 and iBoot.\n", key);
} else {
- debug("DEBUG: %s is loaded by iBoot Stage 1 but not iBoot...\n", key);
+ 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) {
- error("ERROR: Unable to send component '%s' to device.\n", key);
+ logger(LL_ERROR, "Unable to send component '%s' to device.\n", key);
err++;
}
}
@@ -443,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;
}
@@ -458,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;
@@ -467,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;
}
@@ -493,7 +496,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide
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;
}
@@ -508,29 +511,25 @@ 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);
@@ -540,7 +539,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide
// 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;
@@ -553,17 +552,17 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide
boot_stage = strtoul(value, NULL, 0);
}
if (boot_stage > 0) {
- info("iBoot boot-stage=%s\n", value);
+ logger(LL_INFO, "iBoot boot-stage=%s\n", value);
free(value);
value = NULL;
if (boot_stage != 1) {
- error("ERROR: iBoot should be at boot stage 1, continuing anyway...\n");
+ 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;
@@ -571,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;
@@ -579,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;
@@ -587,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;
@@ -595,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;
@@ -603,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;
@@ -611,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;
@@ -621,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;
@@ -631,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;
}
@@ -642,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 4590dbd..7b1d092 100644
--- a/src/dfu.h
+++ b/src/dfu.h
@@ -40,8 +40,8 @@ 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_with_options(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size, unsigned int irecv_options);
+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);
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 ca9b7c7..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 trying 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 fdb340e..04070a1 100644
--- a/src/idevicerestore.c
+++ b/src/idevicerestore.c
@@ -38,18 +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"
@@ -60,7 +55,9 @@
#include "recovery.h"
#include "idevicerestore.h"
+#ifdef HAVE_LIMERA1N
#include "limera1n.h"
+#endif
#include "locking.h"
@@ -79,7 +76,9 @@ static struct option longopts[] = {
{ "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' },
@@ -91,11 +90,17 @@ static struct option longopts[] = {
{ "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" \
@@ -130,7 +135,9 @@ 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"
@@ -140,7 +147,7 @@ static void usage(int argc, char* argv[], int err)
" -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" \
@@ -164,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) {
@@ -196,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 {
@@ -210,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;
}
@@ -220,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;
@@ -261,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);
@@ -311,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);
}
@@ -319,7 +330,7 @@ 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
@@ -344,29 +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->debug_level > 0) {
idevicerestore_debug = 1;
if (client->debug_level > 1) {
- idevice_set_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);
@@ -374,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);
@@ -413,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");
}
@@ -444,14 +464,14 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
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);
@@ -462,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);
@@ -471,20 +491,20 @@ 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) {
- error("ERROR: Unable to determine ECID\n");
+ logger(LL_ERROR, "Unable to determine ECID\n");
return -1;
}
- info("ECID: %" PRIu64 "\n", client->ecid);
+ 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;
}
@@ -500,39 +520,41 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
plist_free(pver);
}
}
- info("Device Product Version: %s\n", (client->device_version) ? client->device_version : "N/A");
- info("Device Product Build: %s\n", (client->device_build) ? client->device_build : "N/A");
+ 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;
}
if (limera1n_is_supported(client->device)) {
- info("exploiting with limera1n...\n");
+ 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);
return -1;
}
dfu_client_free(client);
- info("Device should be in pwned DFU state now.\n");
+ logger(LL_INFO, "Device should be in pwned DFU state now.\n");
return 0;
}
else {
dfu_client_free(client);
- error("ERROR: This device is not supported by the limera1n exploit");
+ logger(LL_ERROR, "This device is not supported by the limera1n exploit");
return -1;
}
+#endif
}
if (client->flags & FLAG_LATEST) {
@@ -542,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];
@@ -589,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;
@@ -621,13 +631,13 @@ 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;
}
@@ -639,7 +649,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
} else {
client->ipsw = ipsw_open(ipsw);
if (!client->ipsw) {
- error("ERROR: Failed to open ipsw '%s'\n", ipsw);
+ logger(LL_ERROR, "Failed to open ipsw '%s'\n", ipsw);
free(ipsw);
return -1;
}
@@ -654,15 +664,15 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
// extract buildmanifest
if (client->flags & FLAG_CUSTOM) {
- info("Extracting Restore.plist from IPSW\n");
+ logger(LL_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->path);
+ logger(LL_ERROR, "Unable to extract Restore.plist from %s. Firmware file might be corrupt.\n", client->ipsw->path);
return -1;
}
} else {
- info("Extracting BuildManifest from IPSW\n");
+ logger(LL_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->path);
+ logger(LL_ERROR, "Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", client->ipsw->path);
return -1;
}
}
@@ -670,13 +680,13 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
if (client->flags & FLAG_CUSTOM) {
// prevent attempt to sign custom firmware
tss_enabled = 0;
- info("Custom firmware requested; TSS has been disabled.\n");
+ logger(LL_INFO, "Custom firmware requested; TSS has been disabled.\n");
}
if (client->mode == MODE_RESTORE) {
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;
}
@@ -685,10 +695,10 @@ 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);
}
}
@@ -699,73 +709,74 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
unsigned int prev = 0;
if (dfu_get_bdid(client, &pdfu_bdid) < 0) {
- error("ERROR: Failed to get bdid for Port DFU device!\n");
+ logger(LL_ERROR, "Failed to get bdid for Port DFU device!\n");
return -1;
}
if (dfu_get_cpid(client, &pdfu_cpid) < 0) {
- error("ERROR: Failed to get cpid for Port DFU device!\n");
+ logger(LL_ERROR, "Failed to get cpid for Port DFU device!\n");
return -1;
}
if (dfu_get_prev(client, &prev) < 0) {
- error("ERROR: Failed to get PREV for Port DFU device!\n");
+ 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) {
- error("ERROR: Failed to get nonce for Port DFU device!\n");
+ 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) {
- error("ERORR: Failed to get build identity\n");
+ 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");
+ unsigned int b_pdfu_cpid = (unsigned int)plist_dict_get_uint(build_identity, "USBPortController1,ChipID");
if (b_pdfu_cpid != pdfu_cpid) {
- error("ERROR: cpid 0x%02x doesn't match USBPortController1,ChipID in build identity (0x%02x)\n", pdfu_cpid, b_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");
+ unsigned int b_pdfu_bdid = (unsigned int)plist_dict_get_uint(build_identity, "USBPortController1,BoardID");
if (b_pdfu_bdid != pdfu_bdid) {
- error("ERROR: bdid 0x%x doesn't match USBPortController1,BoardID in build identity (0x%x)\n", pdfu_bdid, b_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_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);
- error("ERROR: Unable to find USBPortController1,USBFirmware in build identity\n");
+ 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);
- error("ERROR: Unable to find path of USBPortController1,USBFirmware component\n");
+ 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);
- error("ERROR: Unable to get path of USBPortController1,USBFirmware component\n");
+ logger(LL_ERROR, "Unable to get path of USBPortController1,USBFirmware component\n");
return -1;
}
- unsigned char* uarp_buf = NULL;
- unsigned int uarp_size = 0;
+ 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);
- error("ERROR: Unable to extract '%s' from IPSW\n", fwpath);
+ logger(LL_ERROR, "Unable to extract '%s' from IPSW\n", fwpath);
return -1;
}
usbf = plist_copy(usbf);
@@ -776,7 +787,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
plist_t request = tss_request_new(NULL);
if (request == NULL) {
plist_free(parameters);
- error("ERROR: Unable to create TSS request\n");
+ logger(LL_ERROR, "Unable to create TSS request\n");
return -1;
}
plist_dict_merge(&request, parameters);
@@ -786,56 +797,60 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
plist_t response = tss_request_send(request, client->tss_url);
plist_free(request);
if (response == NULL) {
- error("ERROR: Unable to send TSS request\n");
+ logger(LL_ERROR, "Unable to send TSS request\n");
return -1;
}
- info("Received USBPortController1,Ticket\n");
+ logger(LL_INFO, "Received USBPortController1,Ticket\n");
- info("Creating Ace3Binary\n");
- unsigned char* ace3bin = NULL;
+ 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) {
- error("ERROR: Could not create Ace3Binary\n");
+ logger(LL_ERROR, "Could not create Ace3Binary\n");
return -1;
}
plist_free(response);
free(uarp_buf);
- if (idevicerestore_keep_pers) {
- write_file("Ace3Binary", (const char*)ace3bin, ace3bin_size);
+ 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) {
- error("ERROR: Could not send Ace3Buffer to device\n");
+ logger(LL_ERROR, "Could not send Ace3Buffer to device\n");
return -1;
}
- 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, 5000);
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. Port DFU failed.\n");
+ logger(LL_ERROR, "Device did not disconnect. Port DFU failed.\n");
}
return -2;
}
- debug("Waiting for device to reconnect in DFU mode...\n");
- cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 5000);
+ 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)) {
- error("ERROR: Device did not reconnect in DFU mode. Port DFU failed.\n");
+ 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) {
- info("Port DFU restore successful.\n");
+ logger(LL_INFO, "Port DFU restore successful.\n");
return 0;
} else {
- info("Port DFU restore successful. Continuing.\n");
+ logger(LL_INFO, "Port DFU restore successful. Continuing.\n");
}
}
@@ -843,18 +858,18 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
/* 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("IPSW Product Version: %s\n", client->version);
- info("IPSW 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");
+ 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;
@@ -879,16 +894,16 @@ 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;
}
@@ -921,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]);
@@ -929,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();
@@ -937,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();
@@ -991,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));
@@ -1024,7 +1039,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
}
}
if (build_identity == NULL) {
- error("ERROR: Unable to find a matching build identity\n");
+ logger(LL_ERROR, "Unable to find a matching build identity\n");
return -1;
}
@@ -1034,47 +1049,37 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
build_identity_print_information(build_identity);
if (client->macos_variant) {
- info("Performing macOS restore\n");
+ logger(LL_INFO, "Performing macOS restore\n");
}
if (client->mode == MODE_NORMAL && !(client->flags & FLAG_ERASE) && !(client->flags & FLAG_SHSHONLY)) {
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(client->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",
- client->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;
}
}
}
}
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"
@@ -1099,22 +1104,23 @@ 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->path);
+ 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 OS (filesystem) name from build identity */
char* os_path = NULL;
if (build_identity_get_component_path(build_identity, "OS", &os_path) < 0) {
- error("ERROR: Unable to get path for filesystem component\n");
+ logger(LL_ERROR, "Unable to get path for filesystem component\n");
return -1;
}
@@ -1159,16 +1165,16 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
memset(&st, '\0', sizeof(struct stat));
if (stat(tmpf, &st) == 0) {
if ((fssize > 0) && ((uint64_t)st.st_size == fssize)) {
- info("Using cached filesystem from '%s'\n", tmpf);
+ logger(LL_INFO, "Using cached filesystem from '%s'\n", tmpf);
client->filesystem = tmpf;
}
}
if (!client->filesystem) {
- info("Extracting filesystem from IPSW: %s\n", os_path);
+ 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) {
- error("ERROR: Unable to extract filesystem from IPSW\n");
- info("Removing %s\n", tmpf);
+ logger(LL_ERROR, "Unable to extract filesystem from IPSW\n");
+ logger(LL_INFO, "Removing %s\n", tmpf);
unlink(tmpf);
free(tmpf);
return -1;
@@ -1190,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) {
@@ -1217,7 +1223,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
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)) {
@@ -1229,6 +1235,27 @@ 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) {
@@ -1236,44 +1263,58 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
}
if (client->mode == MODE_RESTORE && client->root_ticket) {
- plist_t ap_ticket = plist_new_data(client->root_ticket, client->root_ticket_len);
+ plist_t ap_ticket = plist_new_data((char*)client->root_ticket, client->root_ticket_len);
if (!ap_ticket) {
- error("ERROR: Failed to create ApImg4Ticket node value.\n");
+ logger(LL_ERROR, "Failed to create ApImg4Ticket node value.\n");
return -1;
}
client->tss = plist_new_dict();
if (!client->tss) {
- error("ERROR: Failed to create ApImg4Ticket node.\n");
+ 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) {
- 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->macos_variant) {
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");
+ 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) {
- error("ERROR: Unable to get SHSH blobs for this device (recovery OS Root Ticket)\n");
+ 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;
}
}
@@ -1284,11 +1325,11 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
}
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;
@@ -1303,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;
@@ -1324,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;
}
@@ -1339,9 +1380,9 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
// 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;
@@ -1357,22 +1398,24 @@ 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) {
return -1;
}
- info("exploiting with limera1n\n");
+ 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);
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);
return -2;
@@ -1383,7 +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");
+ logger(LL_ERROR, "Unable to send APTicket\n");
return -2;
}
}
@@ -1394,27 +1437,28 @@ 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");
+ logger(LL_ERROR, "Unable to send iBEC\n");
return -2;
}
recovery_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, 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");
}
return -2;
}
- debug("Waiting for device to reconnect in recovery mode...\n");
+ 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");
}
return -2;
}
@@ -1431,7 +1475,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
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);
return -2;
}
@@ -1451,11 +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");
+ 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);
@@ -1469,7 +1513,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
// now finally do the magic to put the device into restore mode
if (client->mode == MODE_RECOVERY) {
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);
return -2;
@@ -1480,12 +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");
+ 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);
@@ -1494,14 +1542,14 @@ 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");
+ logger(LL_INFO, "About to restore device... \n");
result = restore_device(client, build_identity);
if (result < 0) {
- error("ERROR: Unable to restore device\n");
+ logger(LL_ERROR, "Unable to restore device\n");
return result;
}
}
@@ -1512,17 +1560,18 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
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_needs_free)
@@ -1535,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));
@@ -1600,6 +1649,9 @@ 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);
}
@@ -1675,6 +1727,7 @@ static void handle_signal(int sig)
{
if (idevicerestore_client) {
idevicerestore_client->flags |= FLAG_QUIT;
+ global_quit_flag++;
ipsw_cancel();
}
}
@@ -1685,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;
}
@@ -1721,7 +1809,13 @@ int main(int argc, char* argv[]) {
client->flags |= FLAG_INTERACTIVE;
}
- while ((opt = getopt_long(argc, argv, "dhces:xtpli: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);
@@ -1730,6 +1824,9 @@ 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':
@@ -1742,7 +1839,7 @@ int main(int argc, char* argv[]) {
case 's': {
if (!*optarg) {
- error("ERROR: URL argument for --server must not be empty!\n");
+ logger(LL_ERROR, "URL argument for --server must not be empty!\n");
usage(argc, argv, 1);
return EXIT_FAILURE;
}
@@ -1757,14 +1854,15 @@ int main(int argc, char* argv[]) {
if (!p || *(p+1) == '\0') {
// no path component, add default path
const char default_path[] = "/TSS/controller?action=2";
- char* newurl = malloc(strlen(optarg)+sizeof(default_path));
- sprintf(newurl, "%s%s", optarg, (p) ? default_path+1 : default_path);
+ 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 {
- error("ERROR: URL argument for --server is invalid, must start with http:// or https://\n");
+ logger(LL_ERROR, "URL argument for --server is invalid, must start with http:// or https://\n");
usage(argc, argv, 1);
return EXIT_FAILURE;
}
@@ -1787,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;
}
}
@@ -1795,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;
}
@@ -1807,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;
@@ -1828,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':
@@ -1839,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': {
@@ -1850,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;
}
@@ -1867,6 +1969,15 @@ int main(int argc, char* argv[]) {
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;
@@ -1875,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;
}
@@ -1893,24 +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;
}
- info("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
+ 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) {
// verify if ipsw file exists
client->ipsw = ipsw_open(ipsw);
if (!client->ipsw) {
- error("ERROR: Firmware file %s cannot be opened.\n", 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);
@@ -1968,7 +2096,7 @@ 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;
@@ -1981,46 +2109,40 @@ int get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce,
*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;
}
@@ -2032,46 +2154,40 @@ int get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce,
*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;
}
@@ -2080,7 +2196,7 @@ plist_t build_manifest_get_build_identity_for_model_with_variant(plist_t build_m
{
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;
}
@@ -2156,24 +2272,24 @@ int get_preboard_manifest(struct idevicerestore_client_t* client, plist_t build_
/* 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;
}
- plist_dict_set_item(parameters, "_OnlyFWOrTrustedComponents", plist_new_bool(1));
+ plist_dict_set_item(parameters, "_OnlyFWComponents", plist_new_bool(1));
/* 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;
@@ -2198,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) {
@@ -2220,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;
@@ -2245,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;
- 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);
+ 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));
@@ -2287,14 +2407,14 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident
/* 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;
@@ -2302,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;
@@ -2311,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;
@@ -2319,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;
@@ -2329,40 +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_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");
-
- /* 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);
+ 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);
+ }
}
}
+ 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);
@@ -2416,7 +2542,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie
/* 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;
}
@@ -2424,7 +2550,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie
/* add common tags from manifest */
/* 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;
@@ -2432,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;
@@ -2441,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;
@@ -2450,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);
@@ -2494,14 +2620,14 @@ int get_recovery_os_local_policy_tss_response(
// 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_dict_copy_data(parameters, args, "Ap,NextStageIM4MHash", NULL);
- _plist_dict_copy_data(parameters, args, "Ap,RecoveryOSPolicyNonceHash", NULL);
+ 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;
@@ -2509,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;
}
@@ -2523,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;
@@ -2539,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);
@@ -2589,7 +2715,7 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_
// 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));
@@ -2602,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;
@@ -2624,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);
@@ -2675,13 +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;
}
return plist_array_get_size(build_identities_array);
}
-int extract_component(ipsw_archive_t 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) {
@@ -2694,39 +2820,38 @@ int extract_component(ipsw_archive_t ipsw, const char* path, unsigned char** com
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->path);
+ 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 && plist_dict_get_item(tss_response, "ApImg4Ticket")) {
/* stitch ApImg4Ticket into IMG4 file */
- img4_stitch_component(component_name, component_data, component_size, tss_response, &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;
@@ -2736,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);
}
@@ -2750,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);
@@ -2780,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);
@@ -2803,25 +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);
+ logger(LL_INFO, "Variant: %s\n", value);
if (strstr(value, RESTORE_VARIANT_UPGRADE_INSTALL))
- info("This restore will update the device without erasing user data.\n");
+ logger(LL_INFO, "This restore will update the device without erasing user data.\n");
else if (strstr(value, RESTORE_VARIANT_ERASE_INSTALL))
- info("This restore will erase all device data.\n");
+ logger(LL_INFO, "This restore will erase all device data.\n");
else
- info("Unknown Variant '%s'\n", value);
+ logger(LL_INFO, "Unknown Variant '%s'\n", value);
free(value);
@@ -2851,7 +2976,7 @@ int build_identity_check_components_in_ipsw(plist_t build_identity, ipsw_archive
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);
@@ -2884,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;
@@ -2892,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;
@@ -2900,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;
@@ -2908,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;
@@ -2953,6 +3078,6 @@ const char* get_component_name(const char* filename)
}
i++;
}
- error("WARNING: Unhandled component '%s'", filename);
+ logger(LL_WARNING, "Unhandled component '%s'", filename);
return NULL;
}
diff --git a/src/idevicerestore.h b/src/idevicerestore.h
index 5afcf1a..ce8686f 100644
--- a/src/idevicerestore.h
+++ b/src/idevicerestore.h
@@ -46,6 +46,8 @@ 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)"
@@ -83,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);
@@ -114,8 +113,8 @@ void build_identity_print_information(plist_t build_identity);
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(ipsw_archive_t ipsw, plist_t build_identity, char** filesystem);
-int extract_component(ipsw_archive_t 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 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 56b0496..732ef69 100644
--- a/src/img4.c
+++ b/src/img4.c
@@ -22,9 +22,11 @@
#include <stdlib.h>
#include <string.h>
+#include <libtatsu/tss.h>
+
#include "common.h"
#include "img4.h"
-#include "tss.h"
+#include "endianness.h"
#define ASN1_PRIVATE 0xc0
#define ASN1_PRIMITIVE_TAG 0x1f
@@ -202,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\n", __func__, type);
+ logger(LL_ERROR, "%s: type %02x is not implemented\n", __func__, type);
return;
}
}
@@ -289,6 +291,7 @@ static const char *_img4_get_component_tag(const char *compname)
{ "Ap,AudioPowerAttachChime", "aupr" },
{ "Ap,BootabilityBrainTrustCache", "trbb" },
{ "Ap,CIO", "ciof" },
+ { "Ap,DCP2", "dcp2" },
{ "Ap,HapticAssets", "hpas" },
{ "Ap,LocalBoot", "lobo" },
{ "Ap,LocalPolicy", "lpol" },
@@ -298,8 +301,13 @@ static const char *_img4_get_component_tag(const char *compname)
{ "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" },
@@ -394,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, plist_t tss_response, 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;
@@ -413,130 +421,212 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo
}
if (tss_response_get_ap_img4_ticket(tss_response, &blob, &blob_size) != 0) {
- error("ERROR: %s: Failed to get ApImg4Ticket from TSS response\n", __func__);
+ 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);
- sprintf(tbm_key, "%s-TBM", component_name);
+ 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) {
- error("ERROR: %s: Missing ucon node in %s-TBM dictionary\n", __func__, component_name);
+ logger(LL_ERROR, "%s: Missing ucon node in %s-TBM dictionary\n", __func__, component_name);
return -1;
}
- uint64_t ucon_size = 0;
- const char* ucon_data = plist_get_data_ptr(dt, &ucon_size);
+ ucon_data = plist_get_data_ptr(dt, &ucon_size);
if (!ucon_data) {
- error("ERROR: %s: Missing ucon data in %s-TBM dictionary\n", __func__, component_name);
+ 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) {
- error("ERROR: %s: Missing ucer data node in %s-TBM dictionary\n", __func__, component_name);
+ logger(LL_ERROR, "%s: Missing ucer data node in %s-TBM dictionary\n", __func__, component_name);
return -1;
}
- uint64_t ucer_size = 0;
- const char* ucer_data = plist_get_data_ptr(dt, &ucer_size);
+ ucer_data = plist_get_data_ptr(dt, &ucer_size);
if (!ucer_data) {
- error("ERROR: %s: Missing ucer data in %s-TBM dictionary\n", __func__, component_name);
+ 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"));
- unsigned char *im4rset = (unsigned char*)malloc(16 + 8 + 8 + ucon_size + 16 + 8 + 8 + ucer_size + 16);
+ 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 ------------
- // write priv ucon element
- asn1_write_priv_element(&p_im4rset, &im4rlen, *(uint32_t*)"nocu");
-
- // write ucon IA5STRING and ucon data
- unsigned char ucon_seq[16];
- unsigned char *p_ucon_seq = &ucon_seq[0];
- unsigned int ucon_seq_hdr_len = 0;
- asn1_write_element(&p_ucon_seq, &ucon_seq_hdr_len, ASN1_IA5_STRING, (void*)"ucon", -1);
- asn1_write_element_header(ASN1_OCTET_STRING, ucon_size, &p_ucon_seq, &ucon_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, ucon_seq_hdr_len + ucon_size, &p, &seq_hdr_len);
-
- // add size to priv ucon element
- asn1_write_size(ucon_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, ucon_seq, ucon_seq_hdr_len);
- p_im4rset += ucon_seq_hdr_len;
- im4rlen += ucon_seq_hdr_len;
- memcpy(p_im4rset, ucon_data, ucon_size);
- p_im4rset += ucon_size;
- im4rlen += ucon_size;
+ 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 ------------
- // write priv ucer element
- asn1_write_priv_element(&p_im4rset, &im4rlen, *(uint32_t*)"recu");
-
- // write ucon IA5STRING and ucer data
- unsigned char ucer_seq[16];
- unsigned char *p_ucer_seq = &ucer_seq[0];
- unsigned int ucer_seq_hdr_len = 0;
- asn1_write_element(&p_ucer_seq, &ucer_seq_hdr_len, ASN1_IA5_STRING, (void*)"ucer", -1);
- asn1_write_element_header(ASN1_OCTET_STRING, ucer_size, &p_ucer_seq, &ucer_seq_hdr_len);
-
- p = &elem_seq[0];
- seq_hdr_len = 0;
- asn1_write_element_header(ASN1_SEQUENCE | ASN1_CONSTRUCTED, ucer_seq_hdr_len + ucer_size, &p, &seq_hdr_len);
-
- // add size to priv ucer element
- asn1_write_size(ucer_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, ucer_seq, ucer_seq_hdr_len);
- p_im4rset += ucer_seq_hdr_len;
- im4rlen += ucer_seq_hdr_len;
- memcpy(p_im4rset, ucer_data, ucer_size);
- p_im4rset += ucer_size;
- im4rlen += ucer_size;
+ 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
@@ -605,7 +695,7 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo
free(img4header);
}
free(additional_data);
- error("ERROR: out of memory when personalizing IMG4 component %s\n", component_name);
+ logger(LL_ERROR, "out of memory when personalizing IMG4 component %s\n", component_name);
return -1;
}
p = outbuf;
@@ -705,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");
@@ -740,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";
@@ -750,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);
@@ -798,22 +884,22 @@ int img4_create_local_manifest(plist_t request, plist_t build_identity, plist_t*
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 */
@@ -844,10 +930,10 @@ int img4_create_local_manifest(plist_t request, plist_t build_identity, plist_t*
comp = _img4_get_component_tag(key);
}
if (!comp) {
- debug("DEBUG: %s: Unhandled component '%s'\n", __func__, key);
+ logger(LL_DEBUG, "%s: Unhandled component '%s'\n", __func__, key);
_manifest_write_component(&p, &length, key, val);
} else {
- debug("DEBUG: found component %s (%s)\n", comp, key);
+ logger(LL_DEBUG, "found component %s (%s)\n", comp, key);
_manifest_write_component(&p, &length, comp, val);
}
}
diff --git a/src/img4.h b/src/img4.h
index 1056fa6..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, plist_t tss_response, 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 c25f61d..cebfa49 100644
--- a/src/ipsw.c
+++ b/src/ipsw.c
@@ -34,16 +34,8 @@
#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>
@@ -77,52 +69,52 @@ 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) {
ipsw_archive_t ipsw = ipsw_open(thepath);
- unsigned int rlen = 0;
- if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", (unsigned char**)&plist_buf, &rlen) < 0) {
+ size_t rlen = 0;
+ if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", &plist_buf, &rlen) < 0) {
ipsw_close(ipsw);
- error("ERROR: Failed to extract BuildManifest.plist from IPSW!\n");
+ 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;
@@ -308,26 +300,27 @@ int ipsw_print_info(const char* path)
ipsw_archive_t ipsw_open(const char* ipsw)
{
int err = 0;
- ipsw_archive_t archive = (ipsw_archive_t)malloc(sizeof(struct 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;
}
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;
@@ -337,10 +330,6 @@ void ipsw_close(ipsw_archive_t ipsw)
{
if (ipsw != NULL) {
free(ipsw->path);
- if (ipsw->zip) {
- zip_unchange_all(ipsw->zip);
- zip_close(ipsw->zip);
- }
free(ipsw);
}
}
@@ -358,23 +347,35 @@ int ipsw_is_directory(const char* ipsw)
int ipsw_get_file_size(ipsw_archive_t ipsw, const char* infile, uint64_t* size)
{
if (ipsw == NULL) {
- error("ERROR: Invalid archive\n");
+ logger(LL_ERROR, "Invalid archive\n");
return -1;
}
if (ipsw->zip) {
- int zindex = zip_name_locate(ipsw->zip, infile, 0);
+ 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);
+ 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(ipsw->zip, zindex, 0, &zstat) != 0) {
- error("ERROR: zip_stat_index: %s\n", infile);
+ 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 {
@@ -397,48 +398,67 @@ int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile,
int ret = 0;
if (!ipsw || !infile || !outfile) {
- error("ERROR: Invalid argument\n");
+ logger(LL_ERROR, "Invalid argument\n");
return -1;
}
cancel_flag = 0;
if (ipsw->zip) {
- int zindex = zip_name_locate(ipsw->zip, infile, 0);
+ 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(ipsw->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(ipsw->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;
@@ -447,25 +467,33 @@ int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile,
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: Writing to '%s' failed: %s\n", outfile, strerror(errno));
+ 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(ipsw->path, infile);
char actual_filepath[PATH_MAX+1];
@@ -475,7 +503,7 @@ int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile,
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 {
@@ -489,21 +517,21 @@ int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile,
}
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;
}
@@ -511,34 +539,39 @@ int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile,
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: Writing to '%s' failed: %s\n", actual_outfile, strerror(errno));
+ 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);
@@ -566,7 +599,15 @@ int ipsw_file_exists(ipsw_archive_t ipsw, const char* infile)
}
if (ipsw->zip) {
- int zindex = zip_name_locate(ipsw->zip, infile, 0);
+ 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) {
return 0;
}
@@ -582,53 +623,83 @@ int ipsw_file_exists(ipsw_archive_t ipsw, const char* infile)
return 1;
}
-int ipsw_extract_to_memory(ipsw_archive_t 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;
if (ipsw == NULL) {
- error("ERROR: Invalid archive\n");
+ logger(LL_ERROR, "Invalid archive\n");
return -1;
}
if (ipsw->zip) {
- int zindex = zip_name_locate(ipsw->zip, infile, 0);
+ 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);
+ 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(ipsw->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;
}
- struct zip_file* zfile = zip_fopen_index(ipsw->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;
}
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);
+ 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);
return -1;
}
buffer[size] = '\0';
-
- zip_fclose(zfile);
} else {
char *filepath = build_path(ipsw->path, infile);
struct stat fst;
@@ -637,14 +708,19 @@ int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, unsigned cha
#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);
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);
return -1;
}
@@ -652,7 +728,7 @@ int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, unsigned cha
#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);
return -1;
@@ -661,14 +737,14 @@ int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, unsigned cha
#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);
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);
return -1;
@@ -694,35 +770,50 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip
size_t total_size = 0;
if (ipsw == NULL) {
- error("ERROR: Invalid archive\n");
+ logger(LL_ERROR, "Invalid archive\n");
return -1;
}
if (ipsw->zip) {
- int zindex = zip_name_locate(ipsw->zip, infile, 0);
+ 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);
+ 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(ipsw->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;
}
- struct zip_file* zfile = zip_fopen_index(ipsw->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;
}
total_size = zstat.size;
buffer = (unsigned char*) malloc(blocksize);
if (buffer == NULL) {
- error("ERROR: Out of memory\n");
zip_fclose(zfile);
+ zip_unchange_all(zip);
+ zip_close(zip);
+ logger(LL_ERROR, "Out of memory\n");
return -1;
}
@@ -731,19 +822,22 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip
if (size > blocksize) size = blocksize;
zip_int64_t zr = zip_fread(zfile, buffer, size);
if (zr < 0) {
- error("ERROR: %s: zip_fread: %s\n", __func__, infile);
+ 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) {
- error("ERROR: %s: send failed\n", __func__);
+ 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;
@@ -752,14 +846,14 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip
#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);
return -1;
}
total_size = fst.st_size;
buffer = (unsigned char*)malloc(blocksize);
if (buffer == NULL) {
- error("ERROR: Out of memory\n");
+ logger(LL_ERROR, "Out of memory\n");
free(filepath);
return -1;
}
@@ -768,7 +862,7 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip
if (S_ISLNK(fst.st_mode)) {
ssize_t rl = readlink(filepath, (char*)buffer, (total_size > blocksize) ? blocksize : total_size);
if (rl < 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);
return -1;
@@ -778,7 +872,7 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip
#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);
return -2;
@@ -789,11 +883,11 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip
if (size > blocksize) size = blocksize;
size_t fr = fread(buffer, 1, size, f);
if (fr != size) {
- 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));
break;
}
if (send_callback(ctx, buffer, fr, done, total_size) < 0) {
- error("ERROR: %s: send failed\n", __func__);
+ logger(LL_ERROR, "%s: send failed\n", __func__);
break;
}
done += fr;
@@ -807,7 +901,7 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip
}
if (done < total_size) {
- error("ERROR: %s: Sending file data for %s failed (sent %" PRIu64 "/%" PRIu64 ")\n", __func__, infile, (uint64_t)done, (uint64_t)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;
}
@@ -819,15 +913,15 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip
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;
}
@@ -839,7 +933,7 @@ int ipsw_extract_build_manifest(ipsw_archive_t ipsw, plist_t* buildmanifest, int
/* 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;
}
@@ -849,11 +943,11 @@ int ipsw_extract_build_manifest(ipsw_archive_t ipsw, plist_t* buildmanifest, int
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;
}
@@ -869,7 +963,7 @@ static int ipsw_list_contents_recurse(ipsw_archive_t ipsw, const char *path, ips
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;
}
@@ -896,7 +990,7 @@ static int ipsw_list_contents_recurse(ipsw_archive_t ipsw, const char *path, ips
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;
@@ -921,14 +1015,21 @@ int ipsw_list_contents(ipsw_archive_t ipsw, ipsw_list_cb cb, void *ctx)
int ret = 0;
if (ipsw == NULL) {
- error("ERROR: Invalid IPSW archive\n");
+ logger(LL_ERROR, "Invalid IPSW archive\n");
return -1;
}
if (ipsw->zip) {
- int64_t entries = zip_get_num_entries(ipsw->zip, 0);
+ 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");
+ logger(LL_ERROR, "zip_get_num_entries failed\n");
return -1;
}
@@ -936,21 +1037,21 @@ int ipsw_list_contents(ipsw_archive_t ipsw, ipsw_list_cb cb, void *ctx)
zip_stat_t stat;
zip_stat_init(&stat);
- if (zip_stat_index(ipsw->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(ipsw->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;
}
@@ -984,7 +1085,7 @@ 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;
@@ -999,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;
}
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;
}
@@ -1057,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;
@@ -1085,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;
}
@@ -1108,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;
}
@@ -1124,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;
}
}
@@ -1142,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;
}
@@ -1175,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;
}
@@ -1191,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;
@@ -1217,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 {
@@ -1233,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;
}
}
@@ -1266,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;
@@ -1280,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);
@@ -1308,30 +1427,42 @@ 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(ipsw->zip, path, 0);
+ zip_int64_t zindex = zip_name_locate(zip, path, 0);
if (zindex < 0) {
- error("ERROR: zip_name_locate: %s not found\n", path);
+ 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(ipsw->zip, zindex, 0);
+ handle->zfile = zip_fopen_index(zip, zindex, 0);
if (handle->zfile == NULL) {
- error("ERROR: zip_fopen_index: %s could not be opened\n", path);
+ 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(ipsw->zip, path, 0, &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) {
- error("ERROR: fopen: %s could not be opened\n", path);
+ logger(LL_ERROR, "fopen: %s could not be opened\n", path);
free(handle);
return NULL;
}
@@ -1346,6 +1477,8 @@ 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);
}
@@ -1368,7 +1501,7 @@ int64_t ipsw_file_read(ipsw_file_handle_t handle, void* buffer, size_t size)
} else if (handle && handle->file) {
return fread(buffer, 1, size, handle->file);
} else {
- error("ERROR: %s: Invalid file handle\n", __func__);
+ logger(LL_ERROR, "%s: Invalid file handle\n", __func__);
return -1;
}
}
@@ -1387,7 +1520,7 @@ int ipsw_file_seek(ipsw_file_handle_t handle, int64_t offset, int whence)
return fseeko(handle->file, offset, whence);
#endif
} else {
- error("ERROR: %s: Invalid file handle\n", __func__);
+ logger(LL_ERROR, "%s: Invalid file handle\n", __func__);
return -1;
}
}
@@ -1403,7 +1536,7 @@ int64_t ipsw_file_tell(ipsw_file_handle_t handle)
return ftello(handle->file);
#endif
} else {
- error("ERROR: %s: Invalid file handle\n", __func__);
+ logger(LL_ERROR, "%s: Invalid file handle\n", __func__);
return -1;
}
}
diff --git a/src/ipsw.h b/src/ipsw.h
index f0e11a1..b22e614 100644
--- a/src/ipsw.h
+++ b/src/ipsw.h
@@ -33,7 +33,7 @@ extern "C" {
#include <sys/stat.h>
struct ipsw_archive {
- struct zip* zip;
+ int zip;
char *path;
};
typedef struct ipsw_archive* ipsw_archive_t;
@@ -44,10 +44,11 @@ void ipsw_close(ipsw_archive_t ipsw);
int ipsw_print_info(const char* ipsw);
typedef int (*ipsw_list_cb)(void *ctx, ipsw_archive_t ipsw, const char *name, struct stat *stat);
-typedef int (*ipsw_send_cb)(void *ctx, void *data, size_t size, size_t done, size_t total_size);
+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;
@@ -68,7 +69,7 @@ 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, unsigned char** pbuffer, unsigned int* psize);
+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);
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/log.h b/src/log.h
new file mode 100644
index 0000000..046a8d2
--- /dev/null
+++ b/src/log.h
@@ -0,0 +1,45 @@
+/*
+ * log.h
+ *
+ * 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
+ */
+
+#ifndef LOG_H
+#define LOG_H
+
+#include <plist/plist.h>
+
+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 efe8f03..7d689e1 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -49,12 +49,12 @@ static int normal_idevice_new(struct idevicerestore_client_t* client, idevice_t*
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;
}
@@ -94,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;
}
@@ -170,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) {
@@ -181,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;
}
@@ -223,13 +218,13 @@ 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;
}
@@ -239,14 +234,14 @@ int normal_enter_recovery(struct idevicerestore_client_t* client)
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,25 +253,25 @@ 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;
}
@@ -296,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;
@@ -328,7 +323,7 @@ static int normal_get_nonce_by_key(struct idevicerestore_client_t* client, const
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;
}
@@ -342,6 +337,18 @@ static int normal_get_nonce_by_key(struct idevicerestore_client_t* client, const
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);
}
@@ -365,7 +372,7 @@ int normal_is_image4_supported(struct idevicerestore_client_t* client)
return bval;
}
-int normal_get_preflight_info(struct idevicerestore_client_t* client, plist_t *preflight_info)
+int normal_get_firmware_preflight_info(struct idevicerestore_client_t* client, plist_t *preflight_info)
{
uint8_t has_telephony_capability = 0;
plist_t node;
@@ -377,18 +384,30 @@ int normal_get_preflight_info(struct idevicerestore_client_t* client, plist_t *p
if (has_telephony_capability) {
node = normal_get_lockdown_value(client, NULL, "FirmwarePreflightInfo");
if (!node || plist_get_node_type(node) != PLIST_DICT) {
- error("ERROR: Unable to get FirmwarePreflightInfo\n");
+ logger(LL_ERROR, "Unable to get FirmwarePreflightInfo\n");
return -1;
}
*preflight_info = node;
} else {
- debug("DEBUG: Device does not have TelephonyCapability, no FirmwarePreflightInfo\n");
+ logger(LL_DEBUG, "Device does not have TelephonyCapability, no FirmwarePreflightInfo\n");
*preflight_info = NULL;
}
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, "PreflightInfo");
+ if (PLIST_IS_DICT(node)) {
+ *preflight_info = node;
+ } else {
+ logger(LL_DEBUG, "No PreflightInfo available.\n");
+ *preflight_info = NULL;
+ }
+ return 0;
+}
+
int normal_handle_create_stashbag(struct idevicerestore_client_t* client, plist_t manifest)
{
int result = -1;
@@ -403,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) {
@@ -427,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;
@@ -437,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;
@@ -457,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;
}
@@ -486,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);
@@ -528,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) {
@@ -549,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;
@@ -562,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;
@@ -577,7 +605,7 @@ 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 {
plist_t node = plist_dict_get_item(pl, "Error");
if (node) {
@@ -586,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 7741ac5..d3d7b0c 100644
--- a/src/normal.h
+++ b/src/normal.h
@@ -38,6 +38,7 @@ int normal_enter_recovery(struct idevicerestore_client_t* client);
int normal_is_image4_supported(struct idevicerestore_client_t* client);
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 e3fb4d1..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->macos_variant) {
- 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,21 +142,21 @@ 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;
@@ -164,11 +166,11 @@ int recovery_enter_restore(struct idevicerestore_client_t* client, plist_t build
boot_stage = strtoul(value, NULL, 0);
}
if (boot_stage > 0) {
- info("iBoot boot-stage=%s\n", value);
+ logger(LL_INFO, "iBoot boot-stage=%s\n", value);
free(value);
value = NULL;
if (boot_stage != 2) {
- error("ERROR: iBoot should be at boot stage 2, continuing anyway...\n");
+ logger(LL_ERROR, "iBoot should be at boot stage 2, continuing anyway...\n");
}
}
@@ -178,12 +180,12 @@ int recovery_enter_restore(struct idevicerestore_client_t* client, plist_t build
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;
}
@@ -195,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;
}
}
@@ -228,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);
@@ -247,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;
}
@@ -277,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;
}
@@ -329,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;
}
@@ -354,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_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);
@@ -377,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;
@@ -385,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;
}
@@ -414,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;
}
@@ -438,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++;
}
}
@@ -465,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;
}
@@ -478,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;
}
@@ -499,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;
}
@@ -514,7 +518,7 @@ int recovery_send_kernelcache(struct idevicerestore_client_t* client, plist_t bu
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);
+ logger(LL_ERROR, "Unable to execute %s\n", component);
return -1;
}
diff --git a/src/restore.c b/src/restore.c
index 1261147..12f837c 100644
--- a/src/restore.c
+++ b/src/restore.c
@@ -30,7 +30,10 @@
#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
@@ -38,6 +41,8 @@
#endif
#include <zip.h>
#include <libirecovery.h>
+#include <libtatsu/tss.h>
+#include <curl/curl.h>
#include "idevicerestore.h"
#include "asr.h"
@@ -45,7 +50,6 @@
#include "fls.h"
#include "mbn.h"
#include "ftab.h"
-#include "tss.h"
#include "ipsw.h"
#include "restore.h"
#include "common.h"
@@ -123,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;
}
@@ -180,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;
}
@@ -281,7 +285,7 @@ irecv_device_t restore_get_irecv_device(struct idevicerestore_client_t* client)
if (client->srnm == NULL) {
if (restored_get_value(restore, "SerialNumber", &node) == RESTORE_E_SUCCESS) {
plist_get_string_val(node, &client->srnm);
- info("INFO: device serial number is %s\n", client->srnm);
+ logger(LL_INFO, "INFO: device serial number is %s\n", client->srnm);
plist_free(node);
node = NULL;
}
@@ -291,7 +295,7 @@ irecv_device_t restore_get_irecv_device(struct idevicerestore_client_t* client)
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;
}
@@ -312,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;
}
@@ -347,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);
@@ -375,7 +379,7 @@ static int restore_is_current_device(struct idevicerestore_client_t* client, con
return 0;
}
if (!client->ecid) {
- error("ERROR: %s: no ECID given in client data\n", __func__);
+ logger(LL_ERROR, "%s: no ECID given in client data\n", __func__);
return 0;
}
@@ -388,21 +392,21 @@ 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;
@@ -411,7 +415,7 @@ static int restore_is_current_device(struct idevicerestore_client_t* client, con
plist_t hwinfo = NULL;
restore_error = restored_query_value(restored, "HardwareInfo", &hwinfo);
if ((restore_error != RESTORE_E_SUCCESS) || !hwinfo) {
- error("ERROR: %s: Unable to get HardwareInfo from restored\n", __func__);
+ logger(LL_ERROR, "%s: Unable to get HardwareInfo from restored\n", __func__);
restored_client_free(restored);
idevice_free(device);
plist_free(hwinfo);
@@ -428,7 +432,7 @@ static int restore_is_current_device(struct idevicerestore_client_t* client, con
plist_free(hwinfo);
if (this_ecid == 0) {
- error("ERROR: %s: Unable to get ECID from restored\n", __func__);
+ logger(LL_ERROR, "%s: Unable to get ECID from restored\n", __func__);
return 0;
}
@@ -450,7 +454,7 @@ int restore_open_with_timeout(struct idevicerestore_client_t* client)
}
if (client->ecid == 0) {
- error("ERROR: no ECID in client data!\n");
+ logger(LL_ERROR, "no ECID in client data!\n");
return -1;
}
@@ -458,7 +462,7 @@ int restore_open_with_timeout(struct idevicerestore_client_t* client)
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));
@@ -467,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;
@@ -486,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;
@@ -633,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)
@@ -642,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;
@@ -661,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);
@@ -683,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;
@@ -704,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");
@@ -728,34 +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;
}
@@ -773,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;
}
@@ -781,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;
@@ -793,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;
@@ -840,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);
@@ -850,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;
@@ -898,17 +1016,22 @@ static void restore_asr_progress_cb(double progress, void* userdata)
}
}
-int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device, plist_t build_identity)
+int restore_send_filesystem(struct idevicerestore_client_t* client, plist_t message)
{
asr_client_t asr = NULL;
-
- info("About to send filesystem...\n");
-
ipsw_archive_t ipsw_dummy = NULL;
ipsw_file_handle_t file = NULL;
char* fsname = NULL;
- if (build_identity_get_component_path(build_identity, "OS", &fsname) < 0) {
- error("ERROR: Unable to get path for filesystem component\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_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;
}
if (client->filesystem) {
@@ -922,57 +1045,63 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t de
file = ipsw_file_open(client->ipsw, fsname);
}
if (!file) {
- error("ERROR: Unable to open '%s' in ipsw\n", fsname);
+ logger(LL_ERROR, "Unable to open '%s' in ipsw\n", fsname);
free(fsname);
}
- if (asr_open_with_timeout(device, &asr) < 0) {
+ 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);
- error("ERROR: Unable to connect to ASR\n");
+ logger(LL_ERROR, "Unable to connect to ASR\n");
return -1;
}
- info("Connected to ASR\n");
-
- asr_set_progress_callback(asr, restore_asr_progress_cb, (void*)client);
+ 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");
+ logger(LL_INFO, "Validating the filesystem\n");
if (asr_perform_validation(asr, file) < 0) {
ipsw_file_close(file);
ipsw_close(ipsw_dummy);
- error("ERROR: ASR was unable to validate the filesystem\n");
+ 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");
+ logger(LL_INFO, "Sending filesystem now...\n");
if (asr_send_payload(asr, file) < 0) {
ipsw_file_close(file);
ipsw_close(ipsw_dummy);
- error("ERROR: Unable to send payload to ASR\n");
+ logger(LL_ERROR, "Unable to send payload to ASR\n");
asr_free(asr);
return -1;
}
ipsw_file_close(file);
ipsw_close(ipsw_dummy);
- info("Done sending filesystem\n");
+ 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();
@@ -982,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;
}
}
@@ -1002,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();
@@ -1035,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;
}
}
@@ -1055,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;
+}
+
+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)
+{
+ 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(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, const char* component, const char* component_name)
+int restore_send_component(struct idevicerestore_client_t* client, plist_t message, const char* component, const char* component_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;
+ 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, plist_t message)
+int restore_send_nor(struct idevicerestore_client_t* client, plist_t message)
{
char* llb_path = NULL;
char* llb_filename = NULL;
@@ -1144,19 +1537,24 @@ 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;
int flash_version_1 = 0;
- info("About to send NORData...\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 NORData...\n");
plist_t arguments = plist_dict_get_item(message, "Arguments");
if (arguments && plist_get_node_type(arguments) == PLIST_DICT) {
@@ -1165,26 +1563,26 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t*
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);
@@ -1194,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) {
@@ -1207,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);
}
@@ -1255,31 +1653,31 @@ 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 (flash_version_1) {
@@ -1314,24 +1712,24 @@ 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);
@@ -1339,13 +1737,13 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t*
component_size = 0;
if (flash_version_1) {
- plist_dict_set_item(norimage, component, plist_new_data((char*)nor_data, (uint64_t)nor_size));
+ 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));
}
}
@@ -1359,100 +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 (build_identity_has_component(build_identity, "SepStage1") &&
- build_identity_get_component_path(build_identity, "SepStage1", &sep_path) == 0) {
+ 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) {
- 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, "SEPPatchImageData", plist_new_data((char*)personalized_data, (uint64_t) personalized_size));
+ plist_dict_set_item(dict, "SEPPatchImageData", plist_new_data((char*)personalized_data, personalized_size));
free(personalized_data);
personalized_data = NULL;
personalized_size = 0;
}
- if (idevicerestore_debug)
- debug_plist(dict);
+ if (client->debug_level > 1)
+ logger_dump_plist(LL_DEBUG, dict, 0);
- info("Sending NORData now...\n");
- if (restored_send(restore, dict) != RESTORE_E_SUCCESS) {
- error("ERROR: Unable to send NORData\n");
- plist_free(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;
}
- 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;
@@ -1483,34 +1888,48 @@ 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;
@@ -1520,19 +1939,18 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned
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;
}
@@ -1548,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, '.');
@@ -1560,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 %" PRIi64 "\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 %" PRIi64 "\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';
@@ -1594,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_file_replace(za, zindex, zs, 0) == -1) {
- error("ERROR: could not update signed '%s' in archive\n", signfn);
+ logger(LL_ERROR, "Could not update signed '%s' in archive\n", signfn);
goto leave;
}
@@ -1682,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"))) {
@@ -1692,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 %" PRIi64 "\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 %" PRIi64 "\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';
@@ -1736,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);
@@ -1767,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_file_replace(za, zindex, zs, 0) == -1) {
- error("ERROR: could not update archive with ticketed ebl.fls\n");
+ 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_file_add(za, "bbticket.der", zs, ZIP_FL_OVERWRITE) == -1) {
- error("ERROR: could not add bbticket.der to archive\n");
+ logger(LL_ERROR, "could not add bbticket.der to archive\n");
goto leave;
}
}
@@ -1802,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;
@@ -1821,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;
@@ -1843,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!
@@ -1879,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, true);
+ 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;
}
@@ -1893,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);
@@ -1902,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;
}
@@ -1942,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;
}
@@ -1955,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;
}
@@ -1964,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);
@@ -1995,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;
@@ -2033,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);
@@ -2046,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) {
@@ -2060,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);
}
@@ -2079,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));
@@ -2119,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);
@@ -2130,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;
@@ -2157,71 +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, plist_t arguments)
+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 || chip_id == 0x2C || chip_id == 0x36) {
+ } 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);
}
p_dgr = plist_dict_get_item(arguments, "DeviceGeneratedRequest");
if (!p_dgr) {
- info("NOTE: %s: No DeviceGeneratedRequest in firmware updater data request. Continuing anyway.\n", __func__);
+ logger(LL_NOTICE, "%s: No DeviceGeneratedRequest in firmware updater data request. Continuing anyway.\n", __func__);
} else if (!PLIST_IS_DICT(p_dgr)) {
- error("ERROR: %s: DeviceGeneratedRequest has invalid type!\n", __func__);
- return NULL;
- }
-
- 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);
+ 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;
}
@@ -2229,7 +2686,7 @@ 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, true);
+ 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);
@@ -2239,24 +2696,45 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id
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, "SE2,Ticket")) {
- info("Received SE2,Ticket\n");
+ logger(LL_INFO, "Received SE2,Ticket\n");
} else if (plist_dict_get_item(response, "SE,Ticket")) {
- info("Received SE,Ticket\n");
+ 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;
+ }
+
+ 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, (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;
@@ -2264,63 +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;
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, true);
+ 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;
}
@@ -2329,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;
}
@@ -2339,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;
@@ -2347,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;
@@ -2355,63 +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;
- 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;
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, true);
+ 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;
}
@@ -2421,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;
}
@@ -2429,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);
@@ -2439,12 +2955,12 @@ 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, plist_t arguments)
+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;
- 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;
@@ -2453,18 +2969,22 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct
plist_t response = 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, true);
+ tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true);
plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1));
if (client->image4supported) {
@@ -2488,56 +3008,59 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct
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");
}
- /* skip FirmwareData for newer versions */
- if (client->build_major >= 20) {
- debug("DEBUG: Not adding FirmwareData.\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);
@@ -2545,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;
}
@@ -2553,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;
@@ -2586,21 +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;
- 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;
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;
}
@@ -2608,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, true);
+ 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");
}
- 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) {
+ plist_free(response);
+ logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name);
return NULL;
}
@@ -2643,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;
}
@@ -2658,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;
}
@@ -2676,13 +3222,13 @@ 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_generic_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info, plist_t arguments)
+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;
@@ -2699,59 +3245,72 @@ static plist_t restore_get_generic_firmware_data(restored_client_t restore, stru
}
}
if (response_ticket == NULL) {
- error("ERROR: Unable to determine response ticket from device generated tags");
+ 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) {
- error("ERROR: Unable to create %s TSS request\n", s_updater_name);
+ 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) {
- error("ERROR: Could not find DeviceGeneratedRequest in arguments dictionary\n");
+ logger(LL_ERROR, "Could not find DeviceGeneratedRequest in arguments dictionary\n");
plist_free(request);
return NULL;
}
plist_dict_merge(&request, device_generated_request);
- info("Sending %s TSS request...\n", s_updater_name);
+ 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) {
- error("ERROR: Unable to fetch %s ticket\n", s_updater_name);
+ 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)) {
- info("Received %s\n", response_ticket);
+ logger(LL_INFO, "Received %s\n", response_ticket);
} else {
- error("ERROR: No '%s' in TSS response, this might not work\n", response_ticket);
- debug_plist(response);
+ 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(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info)
+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;
- 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;
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;
}
@@ -2759,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, true);
+ 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;
}
@@ -2794,11 +3360,12 @@ 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, (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;
@@ -2806,12 +3373,12 @@ static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct
return response;
}
-static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info)
+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;
- 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;
@@ -2822,17 +3389,28 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct
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) {
- error("ERROR: Unable to create Timer TSS request\n");
+ logger(LL_ERROR, "Unable to create Timer 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, true);
+ tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true);
plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1));
if (client->image4supported) {
@@ -2845,13 +3423,13 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct
/* add Timer,* tags from info dictionary to parameters */
plist_t info_array = plist_dict_get_item(p_info, "InfoArray");
if (!info_array) {
- error("ERROR: Could not find InfoArray in info dictionary\n");
+ 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");
+ tag = (uint32_t)plist_dict_get_uint(info_dict, "TagNumber");
char key[64];
plist_dict_set_item(parameters, "TagNumber", plist_new_uint(tag));
@@ -2861,30 +3439,30 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct
plist_dict_set_item(parameters, "TicketName", plist_copy(node));
}
- sprintf(key, "Timer,ChipID,%u", tag);
- _plist_dict_copy_uint(parameters, hwid, key, "ChipID");
+ snprintf(key, sizeof(key), "Timer,ChipID,%u", tag);
+ plist_dict_copy_uint(parameters, hwid, key, "ChipID");
- sprintf(key, "Timer,BoardID,%u", tag);
- _plist_dict_copy_uint(parameters, hwid, key, "BoardID");
+ snprintf(key, sizeof(key), "Timer,BoardID,%u", tag);
+ plist_dict_copy_uint(parameters, hwid, key, "BoardID");
- sprintf(key, "Timer,ECID,%u", tag);
- _plist_dict_copy_uint(parameters, hwid, key, "ECID");
+ snprintf(key, sizeof(key), "Timer,ECID,%u", tag);
+ plist_dict_copy_uint(parameters, hwid, key, "ECID");
- sprintf(key, "Timer,Nonce,%u", tag);
- _plist_dict_copy_data(parameters, hwid, key, "Nonce");
+ snprintf(key, sizeof(key), "Timer,Nonce,%u", tag);
+ plist_dict_copy_data(parameters, hwid, key, "Nonce");
- sprintf(key, "Timer,SecurityMode,%u", tag);
- _plist_dict_copy_bool(parameters, hwid, key, "SecurityMode");
+ snprintf(key, sizeof(key), "Timer,SecurityMode,%u", tag);
+ plist_dict_copy_bool(parameters, hwid, key, "SecurityMode");
- sprintf(key, "Timer,SecurityDomain,%u", tag);
- _plist_dict_copy_uint(parameters, hwid, key, "SecurityDomain");
+ snprintf(key, sizeof(key), "Timer,SecurityDomain,%u", tag);
+ plist_dict_copy_uint(parameters, hwid, key, "SecurityDomain");
- sprintf(key, "Timer,ProductionMode,%u", tag);
- _plist_dict_copy_uint(parameters, hwid, key, "ProductionStatus");
+ 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) {
- error("ERROR: Could not find APInfo in info dictionary\n");
+ logger(LL_ERROR, "Could not find APInfo in info dictionary\n");
plist_free(parameters);
return NULL;
} else {
@@ -2892,57 +3470,67 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct
}
/* add required tags for Timer TSS request */
- tss_request_add_timer_tags(request, parameters, NULL);
+ tss_request_add_timer_tags(request, parameters, device_generated_request);
plist_free(parameters);
- info("Sending %s TSS request...\n", ticket_name);
+ logger(LL_INFO, "Sending %s TSS request...\n", ticket_name);
response = tss_request_send(request, client->tss_url);
plist_free(request);
if (response == NULL) {
- error("ERROR: Unable to fetch %s\n", ticket_name);
+ logger(LL_ERROR, "Unable to fetch %s\n", ticket_name);
return NULL;
}
if (plist_dict_get_item(response, ticket_name)) {
- info("Received %s\n", ticket_name);
+ logger(LL_INFO, "Received %s\n", ticket_name);
} else {
- error("ERROR: No '%s' in TSS response, this might not work\n", ticket_name);
+ logger(LL_ERROR, "No '%s' in TSS response, this might not work\n", ticket_name);
}
- sprintf(comp_name, "Timer,RTKitOS,%u", tag);
- if (build_identity_has_component(build_identity, 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);
+ /* 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) {
- 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;
}
if (ftab_parse(component_data, component_size, &ftab, &ftag) != 0) {
free(component_data);
- 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');
}
} 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);
}
- sprintf(comp_name, "Timer,RestoreRTKitOS,%u", tag);
- if (build_identity_has_component(build_identity, comp_name)) {
- if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) {
+ 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);
- 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);
@@ -2950,7 +3538,8 @@ static plist_t restore_get_timer_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;
}
@@ -2958,32 +3547,33 @@ static plist_t restore_get_timer_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;
@@ -2991,12 +3581,17 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct
return response;
}
-static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info, plist_t arguments)
+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);
@@ -3012,7 +3607,7 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str
/* create Cryptex1 request */
request = tss_request_new(NULL);
if (request == NULL) {
- error("ERROR: Unable to create %s TSS request\n", s_updater_name);
+ logger(LL_ERROR, "Unable to create %s TSS request\n", s_updater_name);
return NULL;
}
@@ -3028,7 +3623,7 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str
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(build_identity, key);
+ plist_t item = plist_dict_get_item(client->restore->build_identity, key);
if (item) {
plist_dict_set_item(parameters, key, plist_copy(item));
}
@@ -3043,16 +3638,16 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str
plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(1));
}
if (!plist_dict_get_item(parameters, "ApChipID")) {
- _plist_dict_copy_uint(parameters, build_identity, "ApChipID", NULL);
+ plist_dict_copy_uint(parameters, client->restore->build_identity, "ApChipID", NULL);
}
if (!plist_dict_get_item(parameters, "ApBoardID")) {
- _plist_dict_copy_uint(parameters, build_identity, "ApBoardID", NULL);
+ 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) {
- error("ERROR: Could not find DeviceGeneratedRequest in arguments dictionary\n");
+ logger(LL_ERROR, "Could not find DeviceGeneratedRequest in arguments dictionary\n");
plist_free(parameters);
return NULL;
}
@@ -3063,49 +3658,56 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str
plist_free(parameters);
- info("Sending %s TSS request...\n", s_updater_name);
+ 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) {
- error("ERROR: Unable to fetch %s ticket\n", s_updater_name);
+ logger(LL_ERROR, "Unable to fetch %s ticket\n", s_updater_name);
return NULL;
}
if (plist_dict_get_item(response, response_ticket)) {
- info("Received %s\n", response_ticket);
+ logger(LL_INFO, "Received %s\n", response_ticket);
} else {
- error("ERROR: No '%s' in TSS response, this might not work\n", response_ticket);
- debug_plist(response);
+ 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(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message)
+static int restore_send_firmware_updater_preflight(struct idevicerestore_client_t* client, plist_t message)
{
plist_t dict = NULL;
int restore_error;
- if (idevicerestore_debug) {
- debug("DEBUG: %s: Got FirmwareUpdaterPreflight request:\n", __func__);
- debug_plist(message);
+ 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();
- info("Sending FirmwareResponsePreflight now...\n");
- restore_error = restored_send(restore, 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) {
- error("ERROR: Couldn't send FirmwareResponsePreflight data (%d)\n", restore_error);
+ logger(LL_ERROR, "Couldn't send FirmwareResponsePreflight data (%d)\n", restore_error);
return -1;
}
- info("Done sending FirmwareUpdaterPreflight response\n");
+ logger(LL_INFO, "Done sending FirmwareUpdaterPreflight response\n");
return 0;
}
-static int restore_send_firmware_updater_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message)
+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;
@@ -3116,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;
}
@@ -3147,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);
@@ -3155,96 +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, arguments);
+ 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, arguments);
+ 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) {
- error("ERROR: %s: Couldn't get AppleTCON firmware data\n", __func__);
+ 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(restore, client, build_identity, p_info, arguments);
+ fwdict = restore_get_generic_firmware_data(client, p_info, arguments);
if (fwdict == NULL) {
- error("ERROR: %s: Couldn't get PCON1 firmware data\n", __func__);
+ 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(restore, client, build_identity, p_info);
+ fwdict = restore_get_timer_firmware_data(client, p_info, arguments);
if (fwdict == NULL) {
- error("ERROR: %s: Couldn't get AppleTypeCRetimer firmware data\n", __func__);
+ 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(restore, client, build_identity, p_info, arguments);
+ fwdict = restore_get_cryptex1_firmware_data(client, p_info, arguments);
if (fwdict == NULL) {
- error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name);
+ 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(restore, client, build_identity, p_info, arguments);
+ fwdict = restore_get_generic_firmware_data(client, p_info, arguments);
if (fwdict == NULL) {
- error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name);
+ 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', trying to discover from device generated request.\n", __func__, s_updater_name);
- fwdict = restore_get_generic_firmware_data(restore, client, build_identity, p_info, arguments);
+ 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) {
- error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name);
+ 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;
@@ -3255,29 +3886,41 @@ error_out:
return -1;
}
-static int restore_send_receipt_manifest(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity)
+static int restore_send_receipt_manifest(struct idevicerestore_client_t* client, plist_t message)
{
plist_t dict;
int restore_error;
- plist_t manifest = plist_dict_get_item(build_identity, "Manifest");
+ 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) {
- error("failed to get Manifest node from build_identity");
+ 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));
- info("Sending ReceiptManifest data now...\n");
- restore_error = restored_send(restore, dict);
+ 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) {
- error("ERROR: Couldn't send ReceiptManifest data (%d)\n", restore_error);
+ logger(LL_ERROR, "Couldn't send ReceiptManifest data (%d)\n", restore_error);
goto error_out;
}
- info("Done sending ReceiptManifest data\n");
+ logger(LL_INFO, "Done sending ReceiptManifest data\n");
return 0;
@@ -3331,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;
}
}
@@ -3366,15 +4009,15 @@ static int restore_bootability_send_one(void *ctx, ipsw_archive_t ipsw, const ch
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;
}
@@ -3388,11 +4031,11 @@ static int restore_bootability_send_one(void *ctx, ipsw_archive_t ipsw, const ch
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");
@@ -3404,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;
}
@@ -3451,30 +4099,30 @@ plist_t restore_get_build_identity(struct idevicerestore_client_t* client, uint8
plist_t unique_id_node = plist_dict_get_item(client->build_manifest, "UniqueBuildID");
if (unique_id_node) {
- printf("UniqueBuildID: ");
+ 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");
- return restore_get_build_identity(client, _plist_dict_get_bool(args, "IsRecoveryOS"));
+ 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);
@@ -3486,13 +4134,13 @@ 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");
+ 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");
+ logger(LL_ERROR, "build identity info does not contain a DeviceClass\n");
return NULL;
}
char *device_class = NULL;
@@ -3511,8 +4159,9 @@ static char* extract_global_manifest_path(plist_t build_identity, char *variant)
}
// 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);
@@ -3520,17 +4169,17 @@ static char* extract_global_manifest_path(plist_t build_identity, char *variant)
return ticket_path;
}
-int extract_global_manifest(struct idevicerestore_client_t* client, plist_t build_identity, char *variant, unsigned char** pbuffer, unsigned int* psize)
+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) {
- error("ERROR: failed to get global manifest path\n");
+ 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);
@@ -3540,11 +4189,12 @@ int extract_global_manifest(struct idevicerestore_client_t* client, plist_t buil
struct _restore_send_file_data_ctx {
struct idevicerestore_client_t* client;
- restored_client_t restore;
+ restore_service_client_t service;
int last_progress;
+ uint32_t tag;
};
-static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, void* data, size_t size, size_t done, size_t total_size)
+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)
{
plist_t dict = plist_new_dict();
if (data != NULL) {
@@ -3554,15 +4204,34 @@ static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, voi
// Send FileDataDone to mark end of transfer
plist_dict_set_item(dict, "FileDataDone", plist_new_bool(1));
}
- restored_error_t restore_error = restored_send(rctx->restore, dict);
+ restored_error_t restore_error = _restore_service_send(rctx->service, dict, 0);
if (restore_error != RESTORE_E_SUCCESS) {
plist_free(dict);
- error("ERROR: %s: Failed to send data (%d)\n", __func__, restore_error);
+ 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);
@@ -3572,105 +4241,115 @@ static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, voi
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)
+int restore_send_personalized_boot_object_v3(struct idevicerestore_client_t* client, plist_t message)
{
- if (idevicerestore_debug) {
- debug("DEBUG: %s: Got PersonalizedBootObjectV3 request:\n", __func__);
- debug_plist(msg);
+ 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;
- info("About to send %s...\n", component);
+ logger(LL_INFO, "About to send %s...\n", component);
if (strcmp(image_name, "__GlobalManifest__") == 0) {
- int ret = extract_global_manifest(client, build_identity, NULL, &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 IMG4
- 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;
}
}
- info("Sending %s now (%" PRIu64 " bytes)...\n", component, (uint64_t)size);
+ 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.restore = restore;
+ 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;
- if (_restore_send_file_data(&rctx, (data + size - i), blob_size, size-i, size) < 0) {
+ if (_restore_send_file_data(&rctx, ((char*)data + size - i), blob_size, size-i, size) < 0) {
free(data);
- error("ERROR: Unable to send component %s data\n", component);
+ _restore_service_free(service);
+ finalize_progress(rctx.tag);
+ logger(LL_ERROR, "Unable to send component %s data\n", component);
return -1;
}
i -= blob_size;
@@ -3678,56 +4357,54 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i
free(data);
_restore_send_file_data(&rctx, NULL, 0, size-i, size);
+ finalize_progress(rctx.tag);
+
+ _restore_service_free(service);
- info("Done sending %s\n", component);
+ 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)
{
- if (idevicerestore_debug) {
- debug("DEBUG: %s: Got SourceBootObjectV4 request:\n", __func__);
- 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;
- info("About to send %s...\n", component);
+ logger(LL_INFO, "About to send %s...\n", component);
if (strcmp(image_name, "__GlobalManifest__") == 0) {
char *variant = NULL;
- plist_t node = plist_access_path(msg, 2, "Arguments", "Variant");
+ plist_t node = plist_access_path(message, 2, "Arguments", "Variant");
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, &variant);
if (!variant) {
- debug("Failed to parse arguments from SourceBootObjectV4 as string\n");
+ logger(LL_DEBUG, "Failed to parse arguments from SourceBootObjectV4 as string\n");
return -1;
}
- path = extract_global_manifest_path(build_identity, variant);
+ 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) {
@@ -3736,51 +4413,65 @@ int restore_send_source_boot_object_v4(restored_client_t restore, struct idevice
// 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;
}
}
}
if (!path) {
- error("ERROR: Failed to get path for component %s\n", component);
+ 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);
- info("Sending %s now (%" PRIu64 " bytes)\n", component, 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;
+ }
+
+ logger(LL_INFO, "Sending %s now (%" PRIu64 " bytes)\n", component, fsize);
struct _restore_send_file_data_ctx rctx;
rctx.client = client;
- rctx.restore = restore;
+ 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);
- error("ERROR: Failed to send component %s\n", component);
+ _restore_service_free(service);
+ finalize_progress(rctx.tag);
+ logger(LL_ERROR, "Failed to send component %s\n", component);
return -1;
}
free(path);
- info("Done sending %s\n", component);
+ _restore_service_free(service);
+ finalize_progress(rctx.tag);
+
+ 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";
@@ -3791,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;
}
@@ -3820,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)
+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;
@@ -3860,191 +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, build_identity) < 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, build_identity) < 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, message) < 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(restore, client, build_identity, message) < 0) {
- error("ERROR: Unable to send FirmwareUpdaterPreflight\n");
+ 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(restore, client, build_identity) < 0) {
- error("ERROR: Unable to send ReceiptManifest data\n");
+ 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(restore, client, device, message) < 0) {
- error("ERROR: Unable to send BasebandUpdaterOutputData data\n");
+ 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));
@@ -4062,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));
@@ -4089,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));
@@ -4099,14 +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, "FirmwareUpdaterPreflight", plist_new_bool(1));
- plist_dict_set_item(dict, "ReceiptManifest", plist_new_bool(1));
- plist_dict_set_item(dict, "FirmwareUpdaterDataV2", plist_new_bool(0));
- plist_dict_set_item(dict, "RestoreLocalPolicy", plist_new_bool(1));
- plist_dict_set_item(dict, "AuthInstallCACert", plist_new_bool(1));
- plist_dict_set_item(dict, "OverlayRootDataForKeyIndex", plist_new_bool(1));
+ plist_dict_set_item(dict, "UpdateVolumeOverlayRootDataCount", plist_new_bool(1));
return dict;
}
@@ -4114,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));
@@ -4125,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;
@@ -4133,12 +5240,12 @@ 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
@@ -4161,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;
@@ -4173,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);
}
@@ -4208,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;
}
@@ -4216,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;
}
@@ -4224,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;
}
@@ -4236,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
@@ -4281,15 +5389,15 @@ 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 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);
- _plist_dict_copy_data(opts, client->preflight_info, "BasebandNonce", "Nonce");
+ plist_dict_copy_data(opts, client->firmware_preflight_info, "BasebandNonce", "Nonce");
}
plist_dict_set_item(opts, "SupportedDataTypes", restore_supported_data_types());
@@ -4335,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"));
@@ -4361,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) {
@@ -4369,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;
@@ -4381,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) {
@@ -4397,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);
@@ -4408,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;
@@ -4420,30 +5566,30 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
// restored and passes that data on to it's specific handler
while (!(client->flags & FLAG_QUIT)) {
if (err != 0 && client->flags & FLAG_IGNORE_ERRORS) {
- error("WARNING: Attempting to continue after critical error, restore might fail...\n");
+ 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;
}
@@ -4452,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;
@@ -4465,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);
+ 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
@@ -4482,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"));
@@ -4500,8 +5663,9 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
// Get checkpoint id
node = plist_dict_get_item(message, "CHECKPOINT_ID");
if (!node || plist_get_node_type(node) != PLIST_INT) {
- debug("Failed to parse checkpoint id from checkpoint plist\n");
- return -1;
+ 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
@@ -4510,8 +5674,9 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
// Get checkpoint result
node = plist_dict_get_item(message, "CHECKPOINT_RESULT");
if (!node || plist_get_node_type(node) != PLIST_INT) {
- debug("Failed to parse checkpoint result from checkpoint plist\n");
- return -1;
+ logger(LL_DEBUG, "Failed to parse checkpoint result from checkpoint plist\n");
+ err = -1;
+ break;
}
plist_get_int_val(node, &ckpt_res);
// Get checkpoint complete
@@ -4521,42 +5686,58 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
}
if (ckpt_complete) {
- info("Checkpoint completed id: 0x%" PRIX64 " (%s) result=%" PRIi64 "\n", ckpt_id, ckpt_name, ckpt_res);
+ logger(LL_VERBOSE, "Checkpoint completed id: 0x%" PRIX64 " (%s) result=%" PRIi64 "\n", ckpt_id, ckpt_name, ckpt_res);
} else {
- info("Checkpoint started id: 0x%" PRIX64 " (%s)\n", ckpt_id, ckpt_name);
+ logger(LL_VERBOSE, "Checkpoint started id: 0x%" PRIX64 " (%s)\n", ckpt_id, ckpt_name);
}
node = plist_dict_get_item(message, "CHECKPOINT_WARNING");
if (node) {
- info("Checkpoint WARNING id: 0x%" PRIX64 " result=%" PRIi64 ": %s\n", ckpt_id, ckpt_res, plist_get_string_ptr(node, NULL));
+ 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) {
- info("Checkpoint FAILURE id: 0x%" PRIX64 " result=%" PRIi64 ": %s\n", ckpt_id, ckpt_res, plist_get_string_ptr(node, NULL));
+ 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 765f374..763331d 100644
--- a/src/restore.h
+++ b/src/restore.h
@@ -40,6 +40,7 @@ struct restore_client_t {
unsigned int operation;
uint64_t protocol_version;
restored_client_t client;
+ plist_t build_identity;
};
int restore_check_mode(struct idevicerestore_client_t* client);
@@ -49,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);
-int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message);
-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_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, plist_t build_identity);
-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 80591e7..0000000
--- a/src/tss.c
+++ /dev/null
@@ -1,1796 +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 "973.40.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, "@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_dict_set_item(request, "@ApImg4Ticket", plist_new_bool(1));
-
- if (_plist_dict_copy_bool(request, parameters, "Ap,LocalBoot", NULL) < 0) {
- error("ERROR: Unable to find required Ap,LocalBoot in parameters\n");
- return -1;
- }
-
- if (_plist_dict_copy_item(request, parameters, "Ap,LocalPolicy", NULL) < 0) {
- error("ERROR: Unable to find required Ap,LocalPolicy in parameters\n");
- return -1;
- }
-
- if (_plist_dict_copy_data(request, parameters, "Ap,NextStageIM4MHash", NULL) < 0) {
- error("ERROR: Unable to find required Ap,NextStageIM4MHash in parameters\n");
- return -1;
- }
-
- _plist_dict_copy_data(request, parameters, "Ap,RecoveryOSPolicyNonceHash", NULL);
- _plist_dict_copy_data(request, parameters, "Ap,VolumeUUID", NULL);
- _plist_dict_copy_uint(request, parameters, "ApECID", NULL);
- _plist_dict_copy_uint(request, parameters, "ApChipID", NULL);
- _plist_dict_copy_uint(request, parameters, "ApBoardID", NULL);
- _plist_dict_copy_uint(request, parameters, "ApSecurityDomain", NULL);
- _plist_dict_copy_data(request, parameters, "ApNonce", NULL);
-
- if (!plist_dict_get_item(request, "ApSecurityMode")) {
- /* copy from parameters if available */
- if (_plist_dict_copy_bool(request, parameters, "ApSecurityMode", NULL) < 0) {
- error("ERROR: Unable to find required ApSecurityMode in parameters\n");
- return -1;
- }
- }
- if (!plist_dict_get_item(request, "ApProductionMode")) {
- /* copy from parameters if available */
- if (_plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL) < 0) {
- error("ERROR: Unable to find required ApProductionMode in parameters\n");
- return -1;
- }
- }
-
- return 0;
-}
-
-int tss_parameters_add_from_manifest(plist_t parameters, plist_t build_identity, bool include_manifest)
-{
- plist_t node = NULL;
-
- if (_plist_dict_copy_data(parameters, build_identity, "UniqueBuildID", NULL) < 0) {
- error("ERROR: Unable to find UniqueBuildID node\n");
- return -1;
- }
-
- _plist_dict_copy_string(parameters, build_identity, "Ap,OSLongVersion", NULL);
-
- if (_plist_dict_copy_uint(parameters, build_identity, "ApChipID", NULL) < 0) {;
- error("ERROR: Unable to find ApChipID node\n");
- return -1;
- }
-
- if (_plist_dict_copy_uint(parameters, build_identity, "ApBoardID", NULL) < 0) {
- error("ERROR: Unable to find ApBoardID node\n");
- return -1;
- }
-
- _plist_dict_copy_uint(parameters, build_identity, "ApSecurityDomain", NULL);
- _plist_dict_copy_uint(parameters, build_identity, "BMU,BoardID", NULL);
- _plist_dict_copy_uint(parameters, build_identity, "BMU,ChipID", NULL);
-
- if (_plist_dict_copy_uint(parameters, build_identity, "BbChipID", NULL) < 0) {
- debug("NOTE: Unable to find BbChipID node\n");
- }
-
- if (_plist_dict_copy_data(parameters, build_identity, "BbProvisioningManifestKeyHash", NULL) < 0) {
- debug("NOTE: Unable to find BbProvisioningManifestKeyHash node\n");
- }
-
- if (_plist_dict_copy_data(parameters, build_identity, "BbActivationManifestKeyHash", NULL) < 0) {
- debug("NOTE: Unable to find BbActivationManifestKeyHash node\n");
- }
-
- if (_plist_dict_copy_data(parameters, build_identity, "BbCalibrationManifestKeyHash", NULL) < 0) {
- debug("NOTE: Unable to find BbCalibrationManifestKeyHash node\n");
- }
-
- if (_plist_dict_copy_data(parameters, build_identity, "BbFactoryActivationManifestKeyHash", NULL) < 0) {
- debug("NOTE: Unable to find BbFactoryActivationManifestKeyHash node\n");
- }
-
- if (_plist_dict_copy_data(parameters, build_identity, "BbFDRSecurityKeyHash", NULL) < 0) {
- debug("NOTE: Unable to find BbFDRSecurityKeyHash node\n");
- }
-
- /* BbSkeyId - Used by XMM 6180/GSM */
- if (_plist_dict_copy_data(parameters, build_identity, "BbSkeyId", NULL) < 0) {
- debug("NOTE: Unable to find BbSkeyId node\n");
- }
-
- /* SE,ChipID - Used for SE firmware request */
- _plist_dict_copy_uint(parameters, build_identity, "SE,ChipID", NULL);
-
- /* Savage,ChipID - Used for Savage firmware request */
- _plist_dict_copy_uint(parameters, build_identity, "Savage,ChipID", NULL);
-
- /* add Savage,PatchEpoch - Used for Savage firmware request */
- _plist_dict_copy_uint(parameters, build_identity, "Savage,PatchEpoch", NULL);
-
- /* Yonkers,BoardID - Used for Yonkers firmware request */
- _plist_dict_copy_uint(parameters, build_identity, "Yonkers,BoardID", NULL);
-
- /* Yonkers,ChipID - Used for Yonkers firmware request */
- _plist_dict_copy_uint(parameters, build_identity, "Yonkers,ChipID", NULL);
-
- /* add Yonkers,PatchEpoch - Used for Yonkers firmware request */
- _plist_dict_copy_uint(parameters, build_identity, "Yonkers,PatchEpoch", NULL);
-
- _plist_dict_copy_uint(parameters, build_identity, "Rap,BoardID", NULL);
- _plist_dict_copy_uint(parameters, build_identity, "Rap,ChipID", NULL);
- _plist_dict_copy_uint(parameters, build_identity, "Rap,SecurityDomain", NULL);
-
- _plist_dict_copy_uint(parameters, build_identity, "Baobab,BoardID", NULL);
- _plist_dict_copy_uint(parameters, build_identity, "Baobab,ChipID", NULL);
- _plist_dict_copy_uint(parameters, build_identity, "Baobab,ManifestEpoch", NULL);
- _plist_dict_copy_uint(parameters, build_identity, "Baobab,SecurityDomain", NULL);
-
- _plist_dict_copy_uint(parameters, build_identity, "eUICC,ChipID", NULL);
-
- _plist_dict_copy_uint(parameters, build_identity, "NeRDEpoch", NULL);
- _plist_dict_copy_data(parameters, build_identity, "PearlCertificationRootPub", NULL);
-
- _plist_dict_copy_uint(parameters, build_identity, "Timer,BoardID,1", NULL);
- _plist_dict_copy_uint(parameters, build_identity, "Timer,BoardID,2", NULL);
- _plist_dict_copy_uint(parameters, build_identity, "Timer,ChipID,1", NULL);
- _plist_dict_copy_uint(parameters, build_identity, "Timer,ChipID,2", NULL);
- _plist_dict_copy_uint(parameters, build_identity, "Timer,SecurityDomain,1", NULL);
- _plist_dict_copy_uint(parameters, build_identity, "Timer,SecurityDomain,2", NULL);
-
- _plist_dict_copy_item(parameters, build_identity, "Cryptex1,ChipID", NULL);
- _plist_dict_copy_item(parameters, build_identity, "Cryptex1,Type", NULL);
- _plist_dict_copy_item(parameters, build_identity, "Cryptex1,SubType", NULL);
- _plist_dict_copy_item(parameters, build_identity, "Cryptex1,ProductClass", NULL);
- _plist_dict_copy_item(parameters, build_identity, "Cryptex1,UseProductClass", NULL);
- _plist_dict_copy_item(parameters, build_identity, "Cryptex1,NonceDomain", NULL);
- _plist_dict_copy_item(parameters, build_identity, "Cryptex1,Version", NULL);
- _plist_dict_copy_item(parameters, build_identity, "Cryptex1,PreauthorizationVersion", NULL);
- _plist_dict_copy_item(parameters, build_identity, "Cryptex1,FakeRoot", NULL);
- _plist_dict_copy_item(parameters, build_identity, "Cryptex1,SystemOS", NULL);
- _plist_dict_copy_item(parameters, build_identity, "Cryptex1,SystemVolume", NULL);
- _plist_dict_copy_item(parameters, build_identity, "Cryptex1,SystemTrustCache", NULL);
- _plist_dict_copy_item(parameters, build_identity, "Cryptex1,AppOS", NULL);
- _plist_dict_copy_item(parameters, build_identity, "Cryptex1,AppVolume", NULL);
- _plist_dict_copy_item(parameters, build_identity, "Cryptex1,AppTrustCache", NULL);
- _plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainOS", NULL);
- _plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainVolume", NULL);
- _plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainTrustCache", NULL);
-
- _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);
-
- node = plist_dict_get_item(build_identity, "Info");
- if (node) {
- _plist_dict_copy_bool(parameters, node, "RequiresUIDMode", NULL);
- }
-
- if (include_manifest) {
- /* 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)
-{
- if (!parameters) {
- error("ERROR: Missing required AP parameters\n");
- return -1;
- }
-
- _plist_dict_copy_string(request, parameters, "Ap,OSLongVersion", NULL);
-
- if (_plist_dict_copy_data(request, parameters, "ApNonce", NULL) < 0) {
- error("ERROR: Unable to find required ApNonce in parameters\n");
- return -1;
- }
-
- plist_dict_set_item(request, "@ApImg4Ticket", plist_new_bool(1));
-
- if (!plist_dict_get_item(request, "ApSecurityMode")) {
- /* copy from parameters if available */
- if (_plist_dict_copy_bool(request, parameters, "ApSecurityMode", NULL) < 0) {
- error("ERROR: Unable to find required ApSecurityMode in parameters\n");
- return -1;
- }
- }
- if (!plist_dict_get_item(request, "ApProductionMode")) {
- /* ApProductionMode */
- if (_plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL) < 0) {
- error("ERROR: Unable to find required ApProductionMode in parameters\n");
- return -1;
- }
- }
-
- _plist_dict_copy_data(request, parameters, "SepNonce", "ApSepNonce");
- _plist_dict_copy_uint(request, parameters, "NeRDEpoch", NULL);
- _plist_dict_copy_data(request, parameters, "PearlCertificationRootPub", NULL);
-
- if (plist_dict_get_item(parameters, "UID_MODE")) {
- _plist_dict_copy_item(request, parameters, "UID_MODE", NULL);
- } else if (_plist_dict_get_bool(parameters, "RequiresUIDMode")) {
- // The logic here is missing why this value is expected to be 'false'
- plist_dict_set_item(request, "UID_MODE", plist_new_bool(0));
- }
-
- // FIXME: I didn't understand yet when this value is set, so for now we use a workaround
- if (plist_dict_get_item(parameters, "ApSikaFuse")) {
- _plist_dict_copy_item(request, parameters, "Ap,SikaFuse", "ApSikaFuse");
- } else if (_plist_dict_get_bool(parameters, "RequiresUIDMode")) {
- // Workaround: We have only seen Ap,SikaFuse together with UID_MODE
- plist_dict_set_item(request, "Ap,SikaFuse", plist_new_int(0));
- }
-
- return 0;
-}
-
-int tss_request_add_ap_img3_tags(plist_t request, plist_t parameters)
-{
- if (!parameters) {
- error("ERROR: Missing required AP parameters\n");
- return -1;
- }
-
- if (_plist_dict_copy_data(request, parameters, "ApNonce", NULL) < 0) {
- error("WARNING: Unable to find ApNonce in parameters\n");
- }
-
- plist_dict_set_item(request, "@APTicket", plist_new_bool(1));
-
- if (_plist_dict_copy_uint(request, parameters, "ApBoardID", NULL) < 0) {
- error("ERROR: Unable to find required ApBoardID in request\n");
- return -1;
- }
-
- if (_plist_dict_copy_uint(request, parameters, "ApChipID", NULL) < 0) {
- error("ERROR: Unable to find required ApChipID in request\n");
- return -1;
- }
-
- if (_plist_dict_copy_uint(request, parameters, "ApSecurityDomain", NULL) < 0) {
- error("ERROR: Unable to find required ApSecurityDomain in request\n");
- return -1;
- }
-
- if (_plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL) < 0) {
- error("ERROR: Unable to find required ApProductionMode in parameters\n");
- return -1;
- }
-
- return 0;
-}
-
-int tss_request_add_common_tags(plist_t request, plist_t parameters, plist_t overrides)
-{
- _plist_dict_copy_uint(request, parameters, "ApECID", NULL);
- _plist_dict_copy_data(request, parameters, "UniqueBuildID", NULL);
- _plist_dict_copy_uint(request, parameters, "ApChipID", NULL);
- _plist_dict_copy_uint(request, parameters, "ApBoardID", NULL);
- _plist_dict_copy_uint(request, parameters, "ApSecurityDomain", 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")
- && !_plist_dict_get_bool(info_dict, "IsLoadedByiBoot")
- && !_plist_dict_get_bool(info_dict, "IsEarlyAccessFirmware")
- && !_plist_dict_get_bool(info_dict, "IsiBootEANFirmware")
- && !_plist_dict_get_bool(info_dict, "IsiBootNonEssentialFirmware"))
- {
- debug("DEBUG: %s: Skipping '%s' as it is not a 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 */
- if (_plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "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;
- }
- }
-
- int is_fw_payload = _plist_dict_get_bool(info_dict, "IsFirmwarePayload")
- || _plist_dict_get_bool(info_dict, "IsSecondaryFirmwarePayload")
- || _plist_dict_get_bool(info_dict, "IsFUDFirmware")
- || _plist_dict_get_bool(info_dict, "IsLoadedByiBoot")
- || _plist_dict_get_bool(info_dict, "IsEarlyAccessFirmware")
- || _plist_dict_get_bool(info_dict, "IsiBootEANFirmware")
- || _plist_dict_get_bool(info_dict, "IsiBootNonEssentialFirmware");
-
- if (_plist_dict_get_bool(parameters, "_OnlyFWOrTrustedComponents")) {
- if (!_plist_dict_get_bool(manifest_entry, "Trusted") && !is_fw_payload) {
- debug("DEBUG: %s: Skipping '%s' as it is neither firmware payload nor trusted\n", __func__, key);
- continue;
- }
- } else 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 (!is_fw_payload) {
- debug("DEBUG: %s: Skipping '%s' as it is not a firmware payload\n", __func__, key);
- continue;
- }
- }
-
- /* skip components with IsFTAB:true */
- if (_plist_dict_get_bool(info_dict, "IsFTAB")) {
- debug("DEBUG: %s: Skipping FTAB component '%s'\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 */
- if (_plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "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;
-
- plist_dict_set_item(request, "@BBTicket", plist_new_bool(1));
-
- _plist_dict_copy_uint(request, parameters, "BbChipID", NULL);
- _plist_dict_copy_data(request, parameters, "BbProvisioningManifestKeyHash", NULL);
- /* BbActivationManifestKeyHash - Used by Qualcomm MDM6610 */
- _plist_dict_copy_data(request, parameters, "BbActivationManifestKeyHash", NULL);
- _plist_dict_copy_data(request, parameters, "BbCalibrationManifestKeyHash", NULL);
- _plist_dict_copy_data(request, parameters, "BbFactoryActivationManifestKeyHash", NULL);
- _plist_dict_copy_data(request, parameters, "BbFDRSecurityKeyHash", NULL);
- /* BbSkeyId - Used by XMM 6180/GSM */
- _plist_dict_copy_data(request, parameters, "BbSkeyId", NULL);
- _plist_dict_copy_data(request, parameters, "BbNonce", NULL);
- _plist_dict_copy_uint(request, parameters, "BbGoldCertId", NULL);
-
- uint64_t bb_chip_id = _plist_dict_get_uint(request, "BbChipID");
- int32_t bb_cert_id = (int32_t)_plist_dict_get_uint(request, "BbGoldCertId");
-
- if (_plist_dict_copy_data(request, parameters, "BbSNUM", NULL) < 0) {
- error("ERROR: Unable to find required BbSNUM in parameters\n");
- return -1;
- }
-
- /* 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 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;
- }
-
- plist_dict_set_item(request, "@BBTicket", plist_new_bool(1));
-
- if (_plist_dict_copy_uint(request, parameters, "SE,ChipID", NULL) < 0) {
- error("ERROR: %s: Unable to find required SE,ChipID in parameters\n", __func__);
- return -1;
- }
-
- if (_plist_dict_copy_data(request, parameters, "SE,ID", NULL) < 0) {
- error("ERROR: %s: Unable to find required SE,ID in parameters\n", __func__);
- return -1;
- }
-
- if (_plist_dict_copy_data(request, parameters, "SE,Nonce", NULL) < 0) {
- error("ERROR: %s: Unable to find required SE,Nonce in parameters\n", __func__);
- return -1;
- }
-
- if (_plist_dict_copy_data(request, parameters, "SE,RootKeyIdentifier", NULL) < 0) {
- error("ERROR: %s: Unable to find required SE,RootKeyIdentifier in parameters\n", __func__);
- return -1;
- }
-
- /* 'IsDev' determines whether we have Production or Development */
- uint8_t is_dev = _plist_dict_get_bool(parameters, "SE,IsDev");
-
- /* 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);
- }
-
- /* fallback in case no @SE2,Ticket or @SE,Ticket was provided */
- if (!plist_dict_get_item(request, "@SE2,Ticket") && !plist_dict_get_item(request, "@SE,Ticket")) {
- plist_dict_set_item(request, "@SE,Ticket", plist_new_bool(1));
- }
-
- 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));
-
- if (_plist_dict_copy_data(request, parameters, "Savage,UID", NULL) < 0) {
- error("ERROR: %s: Unable to find required Savage,UID in parameters\n", __func__);
- return -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);
-
- if (_plist_dict_copy_uint(request, parameters, "Savage,PatchEpoch", NULL) < 0) {
- error("ERROR: %s: Unable to find required Savage,PatchEpoch in parameters\n", __func__);
- return -1;
- }
-
- if (_plist_dict_copy_uint(request, parameters, "Savage,ChipID", NULL) < 0) {
- error("ERROR: %s: Unable to find required Savage,ChipID in parameters\n", __func__);
- return -1;
- }
-
- if (_plist_dict_copy_bool(request, parameters, "Savage,AllowOfflineBoot", NULL) < 0) {
- error("ERROR: %s: Unable to find required Savage,AllowOfflineBoot in parameters\n", __func__);
- return -1;
- }
-
- if (_plist_dict_copy_bool(request, parameters, "Savage,ReadFWKey", NULL) < 0) {
- error("ERROR: %s: Unable to find required Savage,ReadFWKey in parameters\n", __func__);
- return -1;
- }
-
- if (_plist_dict_copy_bool(request, parameters, "Savage,ProductionMode", NULL) < 0) {
- error("ERROR: %s: Unable to find required Savage,ProductionMode in parameters\n", __func__);
- return -1;
- }
-
- const char *comp_name = NULL;
- uint8_t isprod = _plist_dict_get_bool(request, "Savage,ProductionMode");
-
- /* 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);
- }
-
- if (_plist_dict_copy_data(request, parameters, "Savage,Nonce", NULL) < 0) {
- error("ERROR: %s: Unable to find required Savage,Nonce in parameters\n", __func__);
- return -1;
- }
-
- if (_plist_dict_copy_bool(request, parameters, "Savage,ReadECKey", NULL) < 0) {
- error("ERROR: %s: Unable to find required Savage,ReadECKey in parameters\n", __func__);
- return -1;
- }
-
- /* 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 = _plist_dict_get_bool(parameters, "Yonkers,ProductionMode");
- uint64_t fabrevision = _plist_dict_get_uint(parameters, "Yonkers,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));
-
- _plist_dict_copy_bool(request, parameters, "eUICC,ApProductionMode", "ApProductionMode");
- _plist_dict_copy_uint(request, parameters, "eUICC,ChipID", NULL);
- _plist_dict_copy_data(request, parameters, "eUICC,EID", NULL);
- _plist_dict_copy_data(request, parameters, "eUICC,RootKeyIdentifier", NULL);
-
- if (!plist_dict_get_item(request, "eUICC,Gold")) {
- plist_t n = plist_access_path(parameters, 2, "Manifest", "eUICC,Gold");
- if (n) {
- plist_t p = plist_new_dict();
- _plist_dict_copy_data(p, n, "Digest", NULL);
- plist_dict_set_item(request, "eUICC,Gold", p);
- }
- }
-
- if (!plist_dict_get_item(request, "eUICC,Main")) {
- plist_t n = plist_access_path(parameters, 2, "Manifest", "eUICC,Main");
- if (n) {
- plist_t p = plist_new_dict();
- _plist_dict_copy_data(p, n, "Digest", NULL);
- plist_dict_set_item(request, "eUICC,Main", p);
- }
- }
-
- /* 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));
-
- _plist_dict_copy_uint(request, parameters, "Rap,BoardID", NULL);
- _plist_dict_copy_uint(request, parameters, "Rap,ChipID", NULL);
- _plist_dict_copy_uint(request, parameters, "Rap,ECID", NULL);
- _plist_dict_copy_data(request, parameters, "Rap,Nonce", NULL);
- _plist_dict_copy_bool(request, parameters, "Rap,ProductionMode", NULL);
- _plist_dict_copy_uint(request, parameters, "Rap,SecurityDomain", NULL);
- _plist_dict_copy_bool(request, parameters, "Rap,SecurityMode", NULL);
- _plist_dict_copy_data(request, parameters, "Rap,FdrRootCaDigest", NULL);
-
- 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 */
- if (_plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "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));
-
- _plist_dict_copy_uint(request, parameters, "BMU,BoardID", NULL);
- _plist_dict_copy_uint(request, parameters, "BMU,ChipID", "ChipID");
- _plist_dict_copy_data(request, parameters, "BMU,Nonce", "Nonce");
- _plist_dict_copy_bool(request, parameters, "BMU,ProductionMode", "ProductionMode");
- _plist_dict_copy_uint(request, parameters, "BMU,UniqueID", "UniqueID");
-
- 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 */
- if (_plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "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));
-
- _plist_dict_copy_uint(request, parameters, "Baobab,BoardID", NULL);
- _plist_dict_copy_uint(request, parameters, "Baobab,ChipID", NULL);
- _plist_dict_copy_data(request, parameters, "Baobab,ECID", NULL);
- _plist_dict_copy_uint(request, parameters, "Baobab,Life", NULL);
- _plist_dict_copy_uint(request, parameters, "Baobab,ManifestEpoch", NULL);
- _plist_dict_copy_bool(request, parameters, "Baobab,ProductionMode", NULL);
- _plist_dict_copy_uint(request, parameters, "Baobab,SecurityDomain", NULL);
- _plist_dict_copy_data(request, parameters, "Baobab,UpdateNonce", NULL);
-
- uint8_t isprod = _plist_dict_get_bool(parameters, "Baobab,ProductionMode");
-
- 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;
-}
-
-int tss_request_add_timer_tags(plist_t request, plist_t parameters, plist_t overrides)
-{
- plist_t node = NULL;
- uint32_t tag = 0;
-
- 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 Timer ticket */
- plist_dict_set_item(request, "@BBTicket", plist_new_bool(1));
-
- node = plist_dict_get_item(parameters, "TicketName");
- if (!node) {
- error("ERROR: %s: Missing TicketName\n", __func__);
- return -1;
- }
- char key[64];
- sprintf(key, "@%s", plist_get_string_ptr(node, NULL));
-
- plist_dict_set_item(request, key, plist_new_bool(1));
-
- tag = (uint32_t)_plist_dict_get_uint(parameters, "TagNumber");
-
- sprintf(key, "Timer,BoardID,%u", tag);
- _plist_dict_copy_uint(request, parameters, key, NULL);
-
- sprintf(key, "Timer,ChipID,%u", tag);
- _plist_dict_copy_uint(request, parameters, key, NULL);
-
- sprintf(key, "Timer,SecurityDomain,%u", tag);
- _plist_dict_copy_uint(request, parameters, key, NULL);
-
- sprintf(key, "Timer,SecurityMode,%u", tag);
- _plist_dict_copy_bool(request, parameters, key, NULL);
-
- sprintf(key, "Timer,ProductionMode,%u", tag);
- _plist_dict_copy_bool(request, parameters, key, NULL);
-
- sprintf(key, "Timer,ECID,%u", tag);
- _plist_dict_copy_uint(request, parameters, key, NULL);
-
- sprintf(key, "Timer,Nonce,%u", tag);
- _plist_dict_copy_data(request, parameters, key, NULL);
-
- 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, "Timer,", 6)) {
- 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 */
- if (_plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "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_cryptex_tags(plist_t request, plist_t parameters, plist_t overrides)
-{
- tss_request_add_common_tags(request, parameters, NULL);
-
- if (plist_dict_get_item(parameters, "Ap,LocalPolicy")) {
- /* Cryptex1LocalPolicy */
- tss_request_add_local_policy_tags(request, parameters);
- _plist_dict_copy_data(request, parameters, "Ap,NextStageCryptex1IM4MHash", NULL);
- } else {
- /* Cryptex1 */
- plist_dict_set_item(request, "@Cryptex1,Ticket", plist_new_bool(1));
-
- _plist_dict_copy_bool(request, parameters, "ApSecurityMode", NULL);
- _plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL);
-
- plist_dict_iter iter = NULL;
- plist_dict_new_iter(parameters, &iter);
- plist_t value = NULL;
- while (1) {
- char *key = NULL;
- plist_dict_next_item(parameters, iter, &key, &value);
- if (key == NULL)
- break;
- if (strncmp(key, "Cryptex1", 8) == 0) {
- plist_dict_set_item(request, key, plist_copy(value));
- }
- free(key);
- }
- }
-
- /* 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);
- info("Request URL set to %s\n", 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 8af2fcc..0000000
--- a/src/tss.h
+++ /dev/null
@@ -1,76 +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>
-#include <stdbool.h>
-
-/* parameters */
-int tss_parameters_add_from_manifest(plist_t parameters, plist_t build_identity, bool include_manifest);
-
-/* 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_timer_tags(plist_t request, plist_t parameters, plist_t overrides);
-int tss_request_add_cryptex_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