diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 12 | ||||
-rw-r--r-- | src/ace3.c | 59 | ||||
-rw-r--r-- | src/ace3.h | 2 | ||||
-rw-r--r-- | src/asr.c | 138 | ||||
-rw-r--r-- | src/asr.h | 6 | ||||
-rw-r--r-- | src/common.c | 577 | ||||
-rw-r--r-- | src/common.h | 63 | ||||
-rw-r--r-- | src/dfu.c | 131 | ||||
-rw-r--r-- | src/dfu.h | 4 | ||||
-rw-r--r-- | src/download.c | 47 | ||||
-rw-r--r-- | src/download.h | 2 | ||||
-rw-r--r-- | src/fdr.c | 132 | ||||
-rw-r--r-- | src/fixedint.h | 72 | ||||
-rw-r--r-- | src/fls.c | 30 | ||||
-rw-r--r-- | src/fls.h | 8 | ||||
-rw-r--r-- | src/ftab.c | 18 | ||||
-rw-r--r-- | src/ftab.h | 8 | ||||
-rw-r--r-- | src/idevicerestore.c | 851 | ||||
-rw-r--r-- | src/idevicerestore.h | 9 | ||||
-rw-r--r-- | src/img3.c | 80 | ||||
-rw-r--r-- | src/img3.h | 16 | ||||
-rw-r--r-- | src/img4.c | 298 | ||||
-rw-r--r-- | src/img4.h | 2 | ||||
-rw-r--r-- | src/ipsw.c | 457 | ||||
-rw-r--r-- | src/ipsw.h | 7 | ||||
-rw-r--r-- | src/limera1n.c | 22 | ||||
-rw-r--r-- | src/locking.c | 12 | ||||
-rw-r--r-- | src/log.c | 227 | ||||
-rw-r--r-- | src/log.h | 45 | ||||
-rw-r--r-- | src/mbn.c | 489 | ||||
-rw-r--r-- | src/mbn.h | 85 | ||||
-rw-r--r-- | src/normal.c | 150 | ||||
-rw-r--r-- | src/normal.h | 1 | ||||
-rw-r--r-- | src/recovery.c | 128 | ||||
-rw-r--r-- | src/restore.c | 2717 | ||||
-rw-r--r-- | src/restore.h | 17 | ||||
-rw-r--r-- | src/sha1.c | 294 | ||||
-rw-r--r-- | src/sha1.h | 44 | ||||
-rw-r--r-- | src/sha512.c | 314 | ||||
-rw-r--r-- | src/sha512.h | 32 | ||||
-rw-r--r-- | src/tss.c | 1796 | ||||
-rw-r--r-- | src/tss.h | 76 |
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) @@ -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); @@ -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 } @@ -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; } @@ -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 @@ -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; @@ -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 @@ -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 @@ -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; @@ -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 @@ -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; } @@ -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(¶meters, 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); @@ -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; } @@ -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 } @@ -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); } } @@ -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 @@ -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; } } @@ -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(<); + 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 @@ -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; +} @@ -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(¶meters, 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(¶meters, 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(¶meters, 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(¶meters, 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(¶meters, 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 |