summaryrefslogtreecommitdiffstats
path: root/src/restore.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/restore.c')
-rw-r--r--src/restore.c1899
1 files changed, 1568 insertions, 331 deletions
diff --git a/src/restore.c b/src/restore.c
index 7b61766..d3828f9 100644
--- a/src/restore.c
+++ b/src/restore.c
@@ -29,7 +29,10 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <libgen.h>
#include <libimobiledevice/restore.h>
+#include <libimobiledevice/property_list_service.h>
+#include <libimobiledevice-glue/thread.h>
#ifdef HAVE_REVERSE_PROXY
#include <libimobiledevice/reverse_proxy.h>
#else
@@ -37,6 +40,8 @@
#endif
#include <zip.h>
#include <libirecovery.h>
+#include <libtatsu/tss.h>
+#include <curl/curl.h>
#include "idevicerestore.h"
#include "asr.h"
@@ -44,7 +49,6 @@
#include "fls.h"
#include "mbn.h"
#include "ftab.h"
-#include "tss.h"
#include "ipsw.h"
#include "restore.h"
#include "common.h"
@@ -278,18 +282,12 @@ irecv_device_t restore_get_irecv_device(struct idevicerestore_client_t* client)
}
if (client->srnm == NULL) {
- restore_error = restored_get_value(restore, "SerialNumber", &node);
- if (restore_error != RESTORE_E_SUCCESS || !node || plist_get_node_type(node) != PLIST_STRING) {
- error("ERROR: Unable to get SerialNumber from restored\n");
- restored_client_free(restore);
- idevice_free(device);
- return NULL;
+ if (restored_get_value(restore, "SerialNumber", &node) == RESTORE_E_SUCCESS) {
+ plist_get_string_val(node, &client->srnm);
+ info("INFO: device serial number is %s\n", client->srnm);
+ plist_free(node);
+ node = NULL;
}
-
- plist_get_string_val(node, &client->srnm);
- info("INFO: device serial number is %s\n", client->srnm);
- plist_free(node);
- node = NULL;
}
restore_error = restored_get_value(restore, "HardwareModel", &node);
@@ -379,8 +377,8 @@ static int restore_is_current_device(struct idevicerestore_client_t* client, con
if (!client) {
return 0;
}
- if (!client->srnm) {
- error("ERROR: %s: no SerialNumber given in client data\n", __func__);
+ if (!client->ecid) {
+ error("ERROR: %s: no ECID given in client data\n", __func__);
return 0;
}
@@ -413,35 +411,35 @@ static int restore_is_current_device(struct idevicerestore_client_t* client, con
return 0;
}
- plist_t node = NULL;
- restore_error = restored_get_value(restored, "SerialNumber", &node);
- if ((restore_error != RESTORE_E_SUCCESS) || !node || (plist_get_node_type(node) != PLIST_STRING)) {
- error("ERROR: %s: Unable to get SerialNumber from restored\n", __func__);
+ plist_t hwinfo = NULL;
+ restore_error = restored_query_value(restored, "HardwareInfo", &hwinfo);
+ if ((restore_error != RESTORE_E_SUCCESS) || !hwinfo) {
+ error("ERROR: %s: Unable to get HardwareInfo from restored\n", __func__);
restored_client_free(restored);
idevice_free(device);
- if (node) {
- plist_free(node);
- }
+ plist_free(hwinfo);
return 0;
}
restored_client_free(restored);
idevice_free(device);
- char* this_srnm = NULL;
- plist_get_string_val(node, &this_srnm);
- plist_free(node);
+ uint64_t this_ecid = 0;
+ plist_t node = plist_dict_get_item(hwinfo, "UniqueChipID");
+ if (node && plist_get_node_type(node) == PLIST_UINT) {
+ plist_get_uint_val(node, &this_ecid);
+ }
+ plist_free(hwinfo);
- if (!this_srnm) {
+ if (this_ecid == 0) {
+ error("ERROR: %s: Unable to get ECID from restored\n", __func__);
return 0;
}
- return (strcasecmp(this_srnm, client->srnm) == 0);
+ return (this_ecid == client->ecid);
}
int restore_open_with_timeout(struct idevicerestore_client_t* client)
{
- int i = 0;
- int attempts = 180;
char *type = NULL;
uint64_t version = 0;
idevice_t device = NULL;
@@ -450,17 +448,17 @@ int restore_open_with_timeout(struct idevicerestore_client_t* client)
restored_error_t restore_error = RESTORE_E_SUCCESS;
// no context exists so bail
- if(client == NULL) {
+ if (client == NULL) {
return -1;
}
- if(client->srnm == NULL) {
- error("ERROR: no SerialNumber in client data!\n");
+ if (client->ecid == 0) {
+ error("ERROR: no ECID in client data!\n");
return -1;
}
// create our restore client if it doesn't yet exist
- if(client->restore == NULL) {
+ if (client->restore == NULL) {
client->restore = (struct restore_client_t*) malloc(sizeof(struct restore_client_t));
if(client->restore == NULL) {
error("ERROR: Out of memory\n");
@@ -638,6 +636,101 @@ 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 || !PLIST_IS_DICT(message)) return NULL;
+ restore_service_client_t service = (restore_service_client_t)malloc(sizeof(struct restore_service_client));
+ if (!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;
+ 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) {
+ error("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(restore_service_client_t service, plist_t *plist)
+{
+ if (!service) {
+ return -1;
+ }
+ switch (service->type) {
+ case SERVICE_TYPE_RESTORED:
+ return restored_receive((restored_client_t)service->client, plist);
+ case SERVICE_TYPE_PLIST:
+ return property_list_service_receive_plist((property_list_service_client_t)service->client, plist);
+ 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)
@@ -691,6 +784,9 @@ int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t
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;
@@ -720,7 +816,7 @@ int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t
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;
@@ -748,6 +844,7 @@ int restore_handle_status_msg(restored_client_t client, plist_t msg)
case 27:
info("Status: Failed to mount filesystems.\n");
break;
+ case 50:
case 51:
info("Status: Failed to load SEP Firmware.\n");
break;
@@ -785,10 +882,10 @@ int restore_handle_status_msg(restored_client_t client, plist_t msg)
return result;
}
-static int restore_handle_baseband_updater_output_data(restored_client_t restore, struct idevicerestore_client_t* client, idevice_t device, plist_t msg)
+static int restore_handle_baseband_updater_output_data(struct idevicerestore_client_t* client, plist_t message)
{
int result = -1;
- plist_t node = plist_dict_get_item(msg, "DataPort");
+ plist_t node = plist_dict_get_item(message, "DataPort");
uint64_t u64val = 0;
plist_get_uint_val(node, &u64val);
uint16_t data_port = (uint16_t)u64val;
@@ -797,9 +894,14 @@ 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;
+ if (!client || !client->restore || !client->restore->build_identity || !client->restore->device) {
+ error("ERROR: %s: idevicerestore client not initialized?!\n", __func__);
+ return -1;
+ }
+
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;
}
@@ -854,10 +956,10 @@ 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);
@@ -867,14 +969,14 @@ static int restore_handle_bb_update_status_msg(restored_client_t client, plist_t
}
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");
+ 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");
@@ -902,24 +1004,61 @@ static void restore_asr_progress_cb(double progress, void* userdata)
}
}
-int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device, const char* filesystem)
+int restore_send_filesystem(struct idevicerestore_client_t* client, plist_t message)
{
asr_client_t asr = NULL;
+ ipsw_archive_t ipsw_dummy = NULL;
+ ipsw_file_handle_t file = NULL;
+ char* fsname = NULL;
+
+ if (!client || !client->restore || !client->restore->build_identity || !client->restore->device) {
+ error("ERROR: %s: idevicerestore client not initialized?!\n", __func__);
+ return -1;
+ }
info("About to send filesystem...\n");
- if (asr_open_with_timeout(device, &asr) < 0) {
+ if (build_identity_get_component_path(client->restore->build_identity, "OS", &fsname) < 0) {
+ error("ERROR: Unable to get path for filesystem component\n");
+ return -1;
+ }
+ if (client->filesystem) {
+ char* path = strdup(client->filesystem);
+ const char* fsname_base = path_get_basename(path);
+ char* parent_dir = dirname(path);
+ ipsw_dummy = ipsw_open(parent_dir);
+ file = ipsw_file_open(ipsw_dummy, fsname_base);
+ free(path);
+ } else {
+ file = ipsw_file_open(client->ipsw, fsname);
+ }
+ if (!file) {
+ error("ERROR: Unable to open '%s' in ipsw\n", fsname);
+ free(fsname);
+ }
+
+ 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");
return -1;
}
info("Connected to ASR\n");
- asr_set_progress_callback(asr, restore_asr_progress_cb, (void*)client);
+ if (asr_port == ASR_DEFAULT_PORT) {
+ asr_set_progress_callback(asr, restore_asr_progress_cb, (void*)client);
+ }
// this step sends requested chunks of data from various offsets to asr so
// it can validate the filesystem before installing it
info("Validating the filesystem\n");
- if (asr_perform_validation(asr, filesystem) < 0) {
+ 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");
asr_free(asr);
return -1;
@@ -929,18 +1068,23 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t de
// once the target filesystem has been validated, ASR then requests the
// entire filesystem to be sent.
info("Sending filesystem now...\n");
- if (asr_send_payload(asr, filesystem) < 0) {
+ if (asr_send_payload(asr, file) < 0) {
+ ipsw_file_close(file);
+ ipsw_close(ipsw_dummy);
error("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");
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;
@@ -980,9 +1124,16 @@ int restore_send_recovery_os_root_ticket(restored_client_t restore, struct idevi
free(data);
}
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ error("ERROR: %s: Unable to connect to service client\n", __func__);
+ return -1;
+ }
+
info("Sending RecoveryOSRootTicket now...\n");
- 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) {
error("ERROR: Unable to send RootTicket (%d)\n", restore_error);
return -1;
@@ -993,7 +1144,7 @@ int restore_send_recovery_os_root_ticket(restored_client_t restore, struct idevi
}
-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;
@@ -1033,9 +1184,16 @@ int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_cl
free(data);
}
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ error("ERROR: %s: Unable to connect to service client\n", __func__);
+ return -1;
+ }
+
info("Sending RootTicket now...\n");
- 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) {
error("ERROR: Unable to send RootTicket (%d)\n", restore_error);
return -1;
@@ -1045,7 +1203,246 @@ int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_cl
return 0;
}
-int restore_send_component(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, const char* component, const char* component_name)
+typedef struct {
+ int length;
+ char* content;
+} query_response;
+
+static size_t _curl_write_callback(char* data, size_t size, size_t nmemb, query_response* response)
+{
+ size_t total = size * nmemb;
+ if (total != 0) {
+ response->content = realloc(response->content, response->length + total + 1);
+ memcpy(response->content + response->length, data, total);
+ response->content[response->length + total] = '\0';
+ response->length += total;
+ }
+
+ return total;
+}
+
+static size_t _curl_header_callback(char* buffer, size_t size, size_t nitems, void* userdata)
+{
+ plist_t header_dict = (plist_t)userdata;
+ size_t len = nitems*size;
+ char* key = NULL;
+ char* val = NULL;
+ size_t i = 0;
+ while (i < len) {
+ if (buffer[i] == ':') {
+ key = malloc(i+1);
+ strncpy(key, buffer, i);
+ key[i] = '\0';
+ i++;
+ while (i < len && buffer[i] == ' ' || buffer[i] == '\t') i++;
+ val = malloc(len-i+1);
+ strncpy(val, buffer+i, len-i);
+ val[len-i] = '\0';
+ break;
+ }
+ i++;
+ }
+ if (key && val) {
+ plist_dict_set_item(header_dict, key, plist_new_string(val));
+ }
+ free(key);
+ free(val);
+ return len;
+}
+
+int restore_send_url_asset(struct idevicerestore_client_t* client, plist_t message)
+{
+ debug("DEBUG: %s\n", __func__);
+ plist_t arguments = plist_dict_get_item(message, "Arguments");
+ if (!PLIST_IS_DICT(arguments)) {
+ error("ERROR: %s: Unexpected arguments\n", __func__);
+ debug_plist(arguments);
+ return -1;
+ }
+
+ const char* request_method = plist_get_string_ptr(plist_dict_get_item(arguments, "RequestMethod"), NULL);
+ if (!request_method) {
+ error("ERROR: %s: Unable to extract RequestMethod from Arguments\n", __func__);
+ return -1;
+ }
+ if (strcmp(request_method, "GET")) {
+ error("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) {
+ error("ERROR: %s: Unable to extract RequestURL from Arguments\n", __func__);
+ return -1;
+ }
+ 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) {
+ error("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 (idevicerestore_debug) {
+ 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) {
+ error("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)
+{
+ debug("DEBUG: %s\n", __func__);
+ plist_t arguments = plist_dict_get_item(message, "Arguments");
+ if (!PLIST_IS_DICT(arguments)) {
+ error("ERROR: %s: Unexpected arguments\n", __func__);
+ debug_plist(arguments);
+ return -1;
+ }
+
+ const char* request_method = plist_get_string_ptr(plist_dict_get_item(arguments, "RequestMethod"), NULL);
+ if (!request_method) {
+ error("ERROR: %s: Unable to extract RequestMethod from Arguments\n", __func__);
+ return -1;
+ }
+ if (strcmp(request_method, "POST")) {
+ error("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) {
+ error("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) {
+ error("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) {
+ error("ERROR: %s: Missing 'RequestBody'\n", __func__);
+ return -1;
+ }
+
+ 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) {
+ error("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, request_body_size);
+ if (idevicerestore_debug) {
+ 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) {
+ error("ERROR: %s: Unable to connect to service client\n", __func__);
+ return -1;
+ }
+
+ _restore_service_send(service, dict, PLIST_FORMAT_BINARY);
+ _restore_service_free(service);
+
+ return 0;
+}
+
+int restore_send_component(struct idevicerestore_client_t* client, plist_t message, const char* component, const char* component_name)
{
unsigned int size = 0;
unsigned char* data = NULL;
@@ -1054,6 +1451,11 @@ int restore_send_component(restored_client_t restore, struct idevicerestore_clie
plist_t dict = NULL;
restored_error_t restore_error = RESTORE_E_SUCCESS;
+ if (!client || !client->restore || !client->restore->build_identity) {
+ error("ERROR: %s: idevicerestore client not initialized?!\n", __func__);
+ return -1;
+ }
+
if (component_name == NULL) {
component_name = component;
}
@@ -1066,7 +1468,7 @@ int restore_send_component(restored_client_t restore, struct idevicerestore_clie
}
}
if (!path) {
- if (build_identity_get_component_path(build_identity, component, &path) < 0) {
+ if (build_identity_get_component_path(client->restore->build_identity, component, &path) < 0) {
error("ERROR: Unable to find %s path from build identity\n", component);
return -1;
}
@@ -1097,9 +1499,16 @@ int restore_send_component(restored_client_t restore, struct idevicerestore_clie
plist_dict_set_item(dict, compkeyname, blob);
free(data);
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ error("ERROR: %s: Unable to connect to service client\n", __func__);
+ return -1;
+ }
+
info("Sending %s now...\n", component_name);
- 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) {
error("ERROR: Unable to send component %s data\n", component_name);
return -1;
@@ -1109,7 +1518,7 @@ int restore_send_component(restored_client_t restore, struct idevicerestore_clie
return 0;
}
-int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity)
+int restore_send_nor(struct idevicerestore_client_t* client, plist_t message)
{
char* llb_path = NULL;
char* llb_filename = NULL;
@@ -1127,17 +1536,27 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t*
unsigned char* nor_data = NULL;
plist_t norimage = NULL;
plist_t firmware_files = NULL;
- uint32_t i;
+ int flash_version_1 = 0;
+
+ if (!client || !client->restore || !client->restore->build_identity) {
+ error("ERROR: %s: idevicerestore client not initialized?!\n", __func__);
+ return -1;
+ }
info("About to send NORData...\n");
+ plist_t arguments = plist_dict_get_item(message, "Arguments");
+ if (arguments && plist_get_node_type(arguments) == PLIST_DICT) {
+ flash_version_1 = plist_dict_get_item(arguments, "FlashVersion1") ? 1 : 0;
+ }
+
if (client->tss) {
if (tss_response_get_path_by_entry(client->tss, "LLB", &llb_path) < 0) {
debug("NOTE: Could not get LLB path from TSS data, will fetch from build identity\n");
}
}
if (llb_path == NULL) {
- if (build_identity_get_component_path(build_identity, "LLB", &llb_path) < 0) {
+ if (build_identity_get_component_path(client->restore->build_identity, "LLB", &llb_path) < 0) {
error("ERROR: Unable to get component path for LLB\n");
return -1;
}
@@ -1177,7 +1596,7 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t*
} else {
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);
}
@@ -1247,12 +1666,10 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t*
}
dict = plist_new_dict();
- plist_dict_set_item(dict, "LlbImageData", plist_new_data((char*)llb_data, (uint64_t) llb_size));
+ plist_dict_set_item(dict, "LlbImageData", plist_new_data((char*)llb_data, llb_size));
free(llb_data);
- if (client->build_major >= 20) {
- // Starting with M1 macs, it seems that NorImageData is now a dict.
- // Sending an array like previous versions results in restore success but the machine will SOS after rebooting.
+ if (flash_version_1) {
norimage = plist_new_dict();
} else {
norimage = plist_new_array();
@@ -1308,14 +1725,14 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t*
component_data = NULL;
component_size = 0;
- if (client->build_major >= 20) {
- plist_dict_set_item(norimage, component, plist_new_data((char*)nor_data, (uint64_t)nor_size));
+ if (flash_version_1) {
+ plist_dict_set_item(norimage, component, plist_new_data((char*)nor_data, nor_size));
} else {
/* make sure iBoot is the first entry in the array */
if (!strncmp("iBoot", component, 5)) {
- plist_array_insert_item(norimage, plist_new_data((char*)nor_data, (uint64_t)nor_size), 0);
+ plist_array_insert_item(norimage, plist_new_data((char*)nor_data, nor_size), 0);
} else {
- plist_array_append_item(norimage, plist_new_data((char*)nor_data, (uint64_t)nor_size));
+ plist_array_append_item(norimage, plist_new_data((char*)nor_data, nor_size));
}
}
@@ -1332,8 +1749,8 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t*
unsigned char* personalized_data = NULL;
unsigned int 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);
@@ -1351,14 +1768,14 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t*
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);
@@ -1376,7 +1793,32 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t*
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(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);
+ return -1;
+ }
+
+ ret = personalize_component(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);
+ return -1;
+ }
+
+ plist_dict_set_item(dict, "SEPPatchImageData", plist_new_data((char*)personalized_data, personalized_size));
free(personalized_data);
personalized_data = NULL;
personalized_size = 0;
@@ -1385,15 +1827,22 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t*
if (idevicerestore_debug)
debug_plist(dict);
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ error("ERROR: %s: Unable to connect to service client\n", __func__);
+ return -1;
+ }
+
info("Sending NORData now...\n");
- if (restored_send(restore, dict) != RESTORE_E_SUCCESS) {
+ restored_error_t 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 NORData\n");
- plist_free(dict);
return -1;
}
info("Done sending NORData\n");
- plist_free(dict);
return 0;
}
@@ -1455,12 +1904,12 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned
}
unsigned char* buffer = NULL;
- unsigned char* blob = NULL;
+ const unsigned char* blob = NULL;
unsigned char* fdata = NULL;
uint64_t fsize = 0;
uint64_t blob_size = 0;
int zerr = 0;
- int zindex = -1;
+ int64_t zindex = -1;
struct zip_stat zstat;
struct zip_file* zfile = NULL;
struct zip* za = NULL;
@@ -1482,7 +1931,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned
}
int is_fls = 0;
- int signed_file_idxs[16];
+ int64_t signed_file_idxs[16];
int signed_file_count = 0;
char* key = NULL;
plist_t node = NULL;
@@ -1511,13 +1960,13 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned
zip_stat_init(&zstat);
if (zip_stat_index(za, zindex, 0, &zstat) != 0) {
- error("ERROR: zip_stat_index failed for index %d\n", zindex);
+ error("ERROR: zip_stat_index failed for index %" PRIi64 "\n", zindex);
goto leave;
}
zfile = zip_fopen_index(za, zindex, 0);
if (zfile == NULL) {
- error("ERROR: zip_fopen_index failed for index %d\n", zindex);
+ error("ERROR: zip_fopen_index failed for index %" PRIi64 "\n", zindex);
goto leave;
}
@@ -1552,9 +2001,8 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned
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);
goto leave;
@@ -1571,8 +2019,6 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned
goto leave;
}
}
- free(blob);
- blob = NULL;
fsize = (is_fls ? fls->size : mbn->size);
fdata = (unsigned char*)malloc(fsize);
@@ -1597,7 +2043,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned
goto leave;
}
- if (zip_replace(za, zindex, zs) == -1) {
+ if (zip_file_replace(za, zindex, zs, 0) == -1) {
error("ERROR: could not update signed '%s' in archive\n", signfn);
goto leave;
}
@@ -1615,9 +2061,10 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned
free(iter);
// remove everything but required files
- int i, j, keep, numf = zip_get_num_files(za);
+ int64_t i, numf = zip_get_num_entries(za, 0);
for (i = 0; i < numf; i++) {
- keep = 0;
+ int j;
+ int keep = 0;
// check for signed file index
for (j = 0; j < signed_file_count; j++) {
if (i == signed_file_idxs[j]) {
@@ -1651,13 +2098,13 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned
zip_stat_init(&zstat);
if (zip_stat_index(za, zindex, 0, &zstat) != 0) {
- error("ERROR: zip_stat_index failed for index %d\n", zindex);
+ error("ERROR: zip_stat_index failed for index %" PRIi64 "\n", zindex);
goto leave;
}
zfile = zip_fopen_index(za, zindex, 0);
if (zfile == NULL) {
- error("ERROR: zip_fopen_index failed for index %d\n", zindex);
+ error("ERROR: zip_fopen_index failed for index %" PRIi64 "\n", zindex);
goto leave;
}
@@ -1684,9 +2131,8 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned
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");
goto leave;
@@ -1696,8 +2142,6 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned
error("ERROR: could not insert BBTicket to ebl.fls\n");
goto leave;
}
- free(blob);
- blob = NULL;
fsize = fls->size;
fdata = (unsigned char*)malloc(fsize);
@@ -1716,28 +2160,26 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned
goto leave;
}
- if (zip_replace(za, zindex, zs) == -1) {
+ if (zip_file_replace(za, zindex, zs, 0) == -1) {
error("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");
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");
goto leave;
}
- blob = NULL;
- if (zip_add(za, "bbticket.der", zs) == -1) {
+ if (zip_file_add(za, "bbticket.der", zs, ZIP_FL_OVERWRITE) == -1) {
error("ERROR: could not add bbticket.der to archive\n");
goto leave;
}
@@ -1768,12 +2210,11 @@ leave:
mbn_free(mbn);
fls_free(fls);
free(buffer);
- free(blob);
return res;
}
-static int restore_send_baseband_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message)
+static int restore_send_baseband_data(struct idevicerestore_client_t* client, plist_t message)
{
int res = -1;
uint64_t bb_cert_id = 0;
@@ -1787,6 +2228,11 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer
char* bbfwtmp = NULL;
plist_t dict = NULL;
+ if (!client || !client->restore || !client->restore->build_identity) {
+ error("ERROR: %s: idevicerestore client not initialized?!\n", __func__);
+ return -1;
+ }
+
info("About to send BasebandData...\n");
// NOTE: this function is called 2 or 3 times!
@@ -1823,7 +2269,7 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer
plist_dict_set_item(parameters, "BbGoldCertId", plist_new_uint(bb_cert_id));
plist_dict_set_item(parameters, "BbSNUM", plist_new_data((const char*)bb_snum, bb_snum_size));
- tss_parameters_add_from_manifest(parameters, build_identity);
+ tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true);
/* create baseband request */
plist_t request = tss_request_new(NULL);
@@ -1837,7 +2283,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);
@@ -1864,7 +2310,7 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer
}
// 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");
plist_free(response);
@@ -1914,16 +2360,24 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer
// 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;
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ error("ERROR: %s: Unable to connect to service client\n", __func__);
+ return -1;
+ }
+
info("Sending BasebandData now...\n");
- if (restored_send(restore, dict) != RESTORE_E_SUCCESS) {
+ if (_restore_service_send(service, dict, 0) != RESTORE_E_SUCCESS) {
error("ERROR: Unable to send BasebandData data\n");
goto leave;
}
+ _restore_service_free(service);
+
info("Done sending BasebandData\n");
res = 0;
@@ -1939,7 +2393,7 @@ 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;
@@ -1951,9 +2405,16 @@ int restore_send_fdr_trust_data(restored_client_t restore, idevice_t device)
* and this is what iTunes seems to be doing too */
dict = plist_new_dict();
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ error("ERROR: %s: Unable to connect to service client\n", __func__);
+ return -1;
+ }
+
info("Sending FDR Trust data now...\n");
- 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) {
error("ERROR: During sending FDR Trust data (%d)\n", restore_error);
return -1;
@@ -1964,7 +2425,7 @@ int restore_send_fdr_trust_data(restored_client_t restore, idevice_t device)
return 0;
}
-static int restore_send_image_data(restored_client_t restore, struct idevicerestore_client_t *client, plist_t build_identity, plist_t message, const char *image_list_k, const char *image_type_k, const char *image_data_k)
+static int restore_send_image_data(struct idevicerestore_client_t *client, plist_t message, const char *image_list_k, const char *image_type_k, const char *image_data_k)
{
restored_error_t restore_error;
plist_t arguments;
@@ -1977,8 +2438,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) {
+ error("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);
@@ -2004,7 +2470,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);
}
@@ -2036,7 +2502,7 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest
if (!image_name) {
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);
}
@@ -2063,6 +2529,12 @@ 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) {
+ error("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);
@@ -2081,8 +2553,9 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest
}
}
- 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);
@@ -2108,7 +2581,7 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest
return 0;
}
-static plist_t restore_get_se_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info)
+static 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;
@@ -2117,21 +2590,28 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id
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) {
+ error("ERROR: %s: idevicerestore client not initialized?!\n", __func__);
+ return NULL;
+ }
+
plist_t node = plist_dict_get_item(p_info, "SE,ChipID");
if (node && plist_get_node_type(node) == PLIST_UINT) {
plist_get_uint_val(node, &chip_id);
}
if (chip_id == 0x20211) {
comp_name = "SE,Firmware";
- } else if (chip_id == 0x73 || chip_id == 0x64 || chip_id == 0xC8 || chip_id == 0xD2) {
+ } else if (chip_id == 0x73 || chip_id == 0x64 || chip_id == 0xC8 || chip_id == 0xD2 || chip_id == 0x2C || chip_id == 0x36) {
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"))
+ 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");
@@ -2140,7 +2620,15 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id
debug("DEBUG: %s: using %s\n", __func__, comp_name);
}
- if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) {
+ 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__);
+ } else if (!PLIST_IS_DICT(p_dgr)) {
+ error("ERROR: %s: DeviceGeneratedRequest has invalid type!\n", __func__);
+ return NULL;
+ }
+
+ if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) {
error("ERROR: Unable to get path for '%s' component\n", comp_name);
return NULL;
}
@@ -2164,13 +2652,13 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id
parameters = plist_new_dict();
/* add manifest for current build_identity to parameters */
- tss_parameters_add_from_manifest(parameters, build_identity);
+ tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true);
/* add SE,* tags from info dictionary to parameters */
plist_dict_merge(&parameters, p_info);
/* add required tags for SE TSS request */
- tss_request_add_se_tags(request, parameters, NULL);
+ tss_request_add_se_tags(request, parameters, p_dgr);
plist_free(parameters);
@@ -2183,13 +2671,15 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id
return NULL;
}
- if (plist_dict_get_item(response, "SE,Ticket")) {
- info("Received SE ticket\n");
+ if (plist_dict_get_item(response, "SE2,Ticket")) {
+ info("Received SE2,Ticket\n");
+ } else if (plist_dict_get_item(response, "SE,Ticket")) {
+ info("Received SE,Ticket\n");
} else {
- error("ERROR: No 'SE,Ticket' in TSS response, this might not work\n");
+ error("ERROR: No 'SE ticket' in TSS response, this might not work\n");
}
- 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;
@@ -2197,7 +2687,7 @@ 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;
@@ -2207,9 +2697,19 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc
plist_t parameters = NULL;
plist_t request = NULL;
plist_t response = NULL;
- plist_t node = NULL;
int ret;
+ if (!client || !client->restore || !client->restore->build_identity) {
+ error("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)) {
+ error("ERROR: %s: DeviceGeneratedRequest has invalid type!\n", __func__);
+ return NULL;
+ }
+
/* create Savage request */
request = tss_request_new(NULL);
if (request == NULL) {
@@ -2220,13 +2720,13 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc
parameters = plist_new_dict();
/* add manifest for current build_identity to parameters */
- tss_parameters_add_from_manifest(parameters, build_identity);
+ tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true);
/* add Savage,* tags from info dictionary to parameters */
plist_dict_merge(&parameters, p_info);
/* add required tags for Savage TSS request */
- tss_request_add_savage_tags(request, parameters, NULL, &comp_name);
+ tss_request_add_savage_tags(request, parameters, device_generated_request, &comp_name);
plist_free(parameters);
@@ -2253,7 +2753,7 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc
}
/* now get actual component data */
- if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) {
+ if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) {
error("ERROR: Unable to get path for '%s' component\n", comp_name);
free(comp_name);
return NULL;
@@ -2281,7 +2781,7 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc
*(uint32_t*)(component_data + 4) = htole32((uint32_t)component_size);
component_size += 16;
- plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, (uint64_t) component_size));
+ plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size));
free(component_data);
component_data = NULL;
component_size = 0;
@@ -2289,19 +2789,28 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc
return response;
}
-static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info)
+static plist_t restore_get_yonkers_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments)
{
char *comp_name = NULL;
char *comp_path = NULL;
- plist_t comp_node = NULL;
unsigned char* component_data = NULL;
unsigned int component_size = 0;
plist_t parameters = NULL;
plist_t request = NULL;
plist_t response = NULL;
- plist_t node = NULL;
int ret;
+ if (!client || !client->restore || !client->restore->build_identity) {
+ error("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)) {
+ error("ERROR: %s: DeviceGeneratedRequest has invalid type!\n", __func__);
+ return NULL;
+ }
+
/* create Yonkers request */
request = tss_request_new(NULL);
if (request == NULL) {
@@ -2314,13 +2823,13 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru
parameters = plist_new_dict();
/* add manifest for current build_identity to parameters */
- tss_parameters_add_from_manifest(parameters, build_identity);
+ tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true);
/* add Yonkers,* tags from info dictionary to parameters */
plist_dict_merge(&parameters, p_info);
/* add required tags for Yonkers TSS request */
- tss_request_add_yonkers_tags(request, parameters, NULL, &comp_name);
+ tss_request_add_yonkers_tags(request, parameters, device_generated_request, &comp_name);
plist_free(parameters);
@@ -2346,7 +2855,7 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru
error("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) {
+ if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) {
error("ERROR: Unable to get path for '%s' component\n", comp_name);
free(comp_name);
return NULL;
@@ -2365,7 +2874,7 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru
comp_name = NULL;
plist_t firmware_data = plist_new_dict();
- plist_dict_set_item(firmware_data, "YonkersFirmware", plist_new_data((char *)component_data, (uint64_t)component_size));
+ plist_dict_set_item(firmware_data, "YonkersFirmware", plist_new_data((char*)component_data, component_size));
plist_dict_set_item(response, "FirmwareData", firmware_data);
free(component_data);
@@ -2375,11 +2884,10 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru
return response;
}
-static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info)
+static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments)
{
char *comp_name = NULL;
char *comp_path = NULL;
- plist_t comp_node = NULL;
unsigned char* component_data = NULL;
unsigned int component_size = 0;
ftab_t ftab = NULL;
@@ -2388,9 +2896,13 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct
plist_t parameters = NULL;
plist_t request = NULL;
plist_t response = NULL;
- plist_t node = NULL;
int ret;
+ if (!client || !client->restore || !client->restore->build_identity) {
+ error("ERROR: %s: idevicerestore client not initialized?!\n", __func__);
+ return NULL;
+ }
+
/* create Rose request */
request = tss_request_new(NULL);
if (request == NULL) {
@@ -2402,7 +2914,7 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct
parameters = plist_new_dict();
/* add manifest for current build_identity to parameters */
- tss_parameters_add_from_manifest(parameters, build_identity);
+ tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true);
plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1));
if (client->image4supported) {
@@ -2412,8 +2924,14 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct
plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(0));
}
- /* add Rap,* tags from info dictionary to parameters */
- plist_dict_merge(&parameters, p_info);
+ plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest");
+ if (device_generated_request) {
+ /* use DeviceGeneratedRequest if present */
+ plist_dict_merge(&request, device_generated_request);
+ } else {
+ /* add Rap,* tags from info dictionary to parameters */
+ plist_dict_merge(&parameters, p_info);
+ }
/* add required tags for Rose TSS request */
tss_request_add_rose_tags(request, parameters, NULL);
@@ -2435,8 +2953,14 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct
error("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");
+ return response;
+ }
+
comp_name = "Rap,RTKitOS";
- if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) {
+ if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) {
error("ERROR: Unable to get path for '%s' component\n", comp_name);
return NULL;
}
@@ -2460,8 +2984,8 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct
}
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);
return NULL;
@@ -2504,7 +3028,7 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct
ftab_write(ftab, &component_data, &component_size);
ftab_free(ftab);
- plist_dict_set_item(response, "FirmwareData", plist_new_data((char *)component_data, (uint64_t)component_size));
+ plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size));
free(component_data);
component_data = NULL;
component_size = 0;
@@ -2512,19 +3036,28 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct
return response;
}
-static plist_t restore_get_veridian_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info)
+static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments)
{
char *comp_name = "BMU,FirmwareMap";
char *comp_path = NULL;
- plist_t comp_node = NULL;
unsigned char* component_data = NULL;
unsigned int component_size = 0;
plist_t parameters = NULL;
plist_t request = NULL;
plist_t response = NULL;
- plist_t node = NULL;
int ret;
+ if (!client || !client->restore || !client->restore->build_identity) {
+ error("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)) {
+ error("ERROR: %s: DeviceGeneratedRequest has invalid type!\n", __func__);
+ return NULL;
+ }
+
/* create Veridian request */
request = tss_request_new(NULL);
if (request == NULL) {
@@ -2536,13 +3069,13 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str
parameters = plist_new_dict();
/* add manifest for current build_identity to parameters */
- tss_parameters_add_from_manifest(parameters, build_identity);
+ tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true);
/* add BMU,* tags from info dictionary to parameters */
plist_dict_merge(&parameters, p_info);
/* add required tags for Veridian TSS request */
- tss_request_add_veridian_tags(request, parameters, NULL);
+ tss_request_add_veridian_tags(request, parameters, device_generated_request);
plist_free(parameters);
@@ -2561,7 +3094,7 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str
error("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) {
+ if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) {
error("ERROR: Unable to get path for '%s' component\n", comp_name);
return NULL;
}
@@ -2590,7 +3123,7 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str
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);
@@ -2604,25 +3137,89 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str
plist_to_bin(fw_map, &bin_plist, &bin_size);
plist_free(fw_map);
- plist_dict_set_item(response, "FirmwareData", plist_new_data(bin_plist, (uint64_t)bin_size));
+ plist_dict_set_item(response, "FirmwareData", plist_new_data(bin_plist, bin_size));
free(bin_plist);
return response;
}
-static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info)
+static plist_t restore_get_generic_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments)
+{
+ plist_t request = NULL;
+ plist_t response = NULL;
+
+ plist_t p_updater_name = plist_dict_get_item(arguments, "MessageArgUpdaterName");
+ const char* s_updater_name = plist_get_string_ptr(p_updater_name, NULL);
+
+ plist_t response_tags = plist_access_path(arguments, 2, "DeviceGeneratedTags", "ResponseTags");
+ const char* response_ticket = NULL;
+ if (PLIST_IS_ARRAY(response_tags)) {
+ plist_t tag0 = plist_array_get_item(response_tags, 0);
+ if (tag0) {
+ response_ticket = plist_get_string_ptr(tag0, NULL);
+ }
+ }
+ if (response_ticket == NULL) {
+ error("ERROR: Unable to determine response ticket from device generated tags");
+ 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);
+ 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");
+ plist_free(request);
+ return NULL;
+ }
+ plist_dict_merge(&request, device_generated_request);
+
+ 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);
+ return NULL;
+ }
+
+ if (plist_dict_get_item(response, response_ticket)) {
+ info("Received %s\n", response_ticket);
+ } else {
+ error("ERROR: No '%s' in TSS response, this might not work\n", response_ticket);
+ debug_plist(response);
+ }
+
+ return response;
+}
+
+static plist_t restore_get_tcon_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments)
{
char *comp_name = "Baobab,TCON";
char *comp_path = NULL;
- plist_t comp_node = NULL;
unsigned char* component_data = NULL;
unsigned int component_size = 0;
plist_t parameters = NULL;
plist_t request = NULL;
plist_t response = NULL;
- plist_t node = NULL;
int ret;
+ if (!client || !client->restore || !client->restore->build_identity) {
+ error("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)) {
+ error("ERROR: %s: DeviceGeneratedRequest has invalid type!\n", __func__);
+ return NULL;
+ }
+
/* create Baobab request */
request = tss_request_new(NULL);
if (request == NULL) {
@@ -2634,13 +3231,13 @@ static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct
parameters = plist_new_dict();
/* add manifest for current build_identity to parameters */
- tss_parameters_add_from_manifest(parameters, build_identity);
+ tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true);
/* add Baobab,* tags from info dictionary to parameters */
plist_dict_merge(&parameters, p_info);
/* add required tags for Baobab TSS request */
- tss_request_add_tcon_tags(request, parameters, NULL);
+ tss_request_add_tcon_tags(request, parameters, device_generated_request);
plist_free(parameters);
@@ -2659,7 +3256,7 @@ static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct
error("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) {
+ if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) {
error("ERROR: Unable to get path for '%s' component\n", comp_name);
return NULL;
}
@@ -2673,7 +3270,203 @@ static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct
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;
+
+ return response;
+}
+
+static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments)
+{
+ char comp_name[64];
+ char *comp_path = NULL;
+ unsigned char* component_data = NULL;
+ unsigned int component_size = 0;
+ ftab_t ftab = NULL;
+ ftab_t rftab = NULL;
+ uint32_t ftag = 0;
+ plist_t parameters = NULL;
+ plist_t request = NULL;
+ plist_t response = NULL;
+ const char* ticket_name = NULL;
+ uint32_t tag = 0;
+ int ret;
+
+ if (!client || !client->restore || !client->restore->build_identity) {
+ error("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)) {
+ error("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");
+ return NULL;
+ }
+
+ parameters = plist_new_dict();
+
+ /* add manifest for current build_identity to parameters */
+ tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true);
+
+ plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1));
+ if (client->image4supported) {
+ plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(1));
+ plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(1));
+ } else {
+ plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(0));
+ }
+
+ /* add Timer,* tags from info dictionary to parameters */
+ plist_t info_array = plist_dict_get_item(p_info, "InfoArray");
+ if (!info_array) {
+ error("ERROR: Could not find InfoArray in info dictionary\n");
+ plist_free(parameters);
+ return NULL;
+ } else {
+ plist_t info_dict = plist_array_get_item(info_array, 0);
+ plist_t hwid = plist_dict_get_item(info_dict, "HardwareID");
+ tag = (uint32_t)plist_dict_get_uint(info_dict, "TagNumber");
+ char key[64];
+
+ plist_dict_set_item(parameters, "TagNumber", plist_new_uint(tag));
+ plist_t node = plist_dict_get_item(info_dict, "TicketName");
+ if (node) {
+ ticket_name = plist_get_string_ptr(node, NULL);
+ plist_dict_set_item(parameters, "TicketName", plist_copy(node));
+ }
+
+ sprintf(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");
+
+ sprintf(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");
+
+ sprintf(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");
+
+ sprintf(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");
+ plist_free(parameters);
+ return NULL;
+ } else {
+ plist_dict_merge(&parameters, ap_info);
+ }
+
+ /* add required tags for Timer TSS request */
+ tss_request_add_timer_tags(request, parameters, device_generated_request);
+
+ plist_free(parameters);
+
+ 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);
+ return NULL;
+ }
+
+ if (plist_dict_get_item(response, ticket_name)) {
+ info("Received %s\n", ticket_name);
+ } else {
+ error("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(client->restore->build_identity, comp_name)) {
+ if (build_identity_get_component_path(client->restore->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);
+ 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);
+ 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');
+ }
+ } else {
+ info("NOTE: Build identity does not have a '%s' component.\n", comp_name);
+ }
+
+ sprintf(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);
+ return NULL;
+ }
+ ret = extract_component(client->ipsw, comp_path, &component_data, &component_size);
+ free(comp_path);
+ comp_path = NULL;
+ if (ret < 0) {
+ ftab_free(ftab);
+ error("ERROR: Unable to extract '%s' component\n", comp_name);
+ return NULL;
+ }
+
+ ftag = 0;
+ if (ftab_parse(component_data, component_size, &rftab, &ftag) != 0) {
+ free(component_data);
+ ftab_free(ftab);
+ error("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');
+ }
+
+ 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");
+ }
+ ftab_free(rftab);
+ component_data = NULL;
+ component_size = 0;
+ } else {
+ info("NOTE: Build identity does not have a '%s' component.\n", comp_name);
+ }
+
+ ftab_write(ftab, &component_data, &component_size);
+ ftab_free(ftab);
+
+ plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size));
free(component_data);
component_data = NULL;
component_size = 0;
@@ -2681,7 +3474,133 @@ static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct
return response;
}
-static int restore_send_firmware_updater_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message)
+static plist_t restore_get_cryptex1_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments)
+{
+ plist_t parameters = NULL;
+ plist_t request = NULL;
+ plist_t response = NULL;
+
+ if (!client || !client->restore || !client->restore->build_identity) {
+ error("ERROR: %s: idevicerestore client not initialized?!\n", __func__);
+ return NULL;
+ }
+
+ plist_t p_updater_name = plist_dict_get_item(arguments, "MessageArgUpdaterName");
+ const char* s_updater_name = plist_get_string_ptr(p_updater_name, NULL);
+
+ plist_t response_tags = plist_access_path(arguments, 2, "DeviceGeneratedTags", "ResponseTags");
+ const char* response_ticket = "Cryptex1,Ticket";
+ if (PLIST_IS_ARRAY(response_tags)) {
+ plist_t tag0 = plist_array_get_item(response_tags, 0);
+ if (tag0) {
+ response_ticket = plist_get_string_ptr(tag0, NULL);
+ }
+ }
+
+ /* create Cryptex1 request */
+ request = tss_request_new(NULL);
+ if (request == NULL) {
+ error("ERROR: Unable to create %s TSS request\n", s_updater_name);
+ return NULL;
+ }
+
+ parameters = plist_new_dict();
+
+ /* merge data from MessageArgInfo */
+ plist_dict_merge(&parameters, p_info);
+
+ /* add tags from manifest to parameters */
+ plist_t build_identity_tags = plist_access_path(arguments, 2, "DeviceGeneratedTags", "BuildIdentityTags");
+ if (PLIST_IS_ARRAY(build_identity_tags)) {
+ uint32_t i = 0;
+ for (i = 0; i < plist_array_get_size(build_identity_tags); i++) {
+ plist_t node = plist_array_get_item(build_identity_tags, i);
+ const char* key = plist_get_string_ptr(node, NULL);
+ plist_t item = plist_dict_get_item(client->restore->build_identity, key);
+ if (item) {
+ plist_dict_set_item(parameters, key, plist_copy(item));
+ }
+ }
+ }
+
+ /* make sure we always have these required tags defined */
+ if (!plist_dict_get_item(parameters, "ApProductionMode")) {
+ plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1));
+ }
+ if (!plist_dict_get_item(parameters, "ApSecurityMode")) {
+ plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(1));
+ }
+ if (!plist_dict_get_item(parameters, "ApChipID")) {
+ plist_dict_copy_uint(parameters, client->restore->build_identity, "ApChipID", NULL);
+ }
+ if (!plist_dict_get_item(parameters, "ApBoardID")) {
+ plist_dict_copy_uint(parameters, client->restore->build_identity, "ApBoardID", NULL);
+ }
+
+ /* add device generated request data to parameters */
+ plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest");
+ if (!device_generated_request) {
+ error("ERROR: Could not find DeviceGeneratedRequest in arguments dictionary\n");
+ plist_free(parameters);
+ return NULL;
+ }
+ plist_dict_merge(&parameters, device_generated_request);
+
+ /* add Cryptex1 tags to request */
+ tss_request_add_cryptex_tags(request, parameters, NULL);
+
+ plist_free(parameters);
+
+ 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);
+ return NULL;
+ }
+
+ if (plist_dict_get_item(response, response_ticket)) {
+ info("Received %s\n", response_ticket);
+ } else {
+ error("ERROR: No '%s' in TSS response, this might not work\n", response_ticket);
+ debug_plist(response);
+ }
+
+ return response;
+}
+
+static int restore_send_firmware_updater_preflight(struct idevicerestore_client_t* client, plist_t message)
+{
+ plist_t dict = NULL;
+ int restore_error;
+
+ if (idevicerestore_debug) {
+ debug("DEBUG: %s: Got FirmwareUpdaterPreflight request:\n", __func__);
+ debug_plist(message);
+ }
+
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ error("ERROR: %s: Unable to connect to service client\n", __func__);
+ return -1;
+ }
+
+ dict = plist_new_dict();
+
+ 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);
+ return -1;
+ }
+
+ info("Done sending FirmwareUpdaterPreflight response\n");
+ return 0;
+}
+
+static int restore_send_firmware_updater_data(struct idevicerestore_client_t* client, plist_t message)
{
plist_t arguments;
plist_t p_type, p_updater_name, p_loop_count, p_info;
@@ -2692,6 +3611,11 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct
char *s_updater_name = NULL;
int restore_error;
+ if (!client || !client->restore || !client->restore->build_identity) {
+ error("ERROR: %s: idevicerestore client not initialized?!\n", __func__);
+ return -1;
+ }
+
if (idevicerestore_debug) {
debug("DEBUG: %s: Got FirmwareUpdaterData request:\n", __func__);
debug_plist(message);
@@ -2738,7 +3662,7 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct
plist_get_string_val(p_updater_name, &s_updater_name);
if (strcmp(s_updater_name, "SE") == 0) {
- fwdict = restore_get_se_firmware_data(restore, client, build_identity, p_info);
+ fwdict = restore_get_se_firmware_data(client, p_info, arguments);
if (fwdict == NULL) {
error("ERROR: %s: Couldn't get SE firmware data\n", __func__);
goto error_out;
@@ -2748,45 +3672,80 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct
plist_t p_info2 = plist_dict_get_item(p_info, "YonkersDeviceInfo");
if (p_info2 && plist_get_node_type(p_info2) == PLIST_DICT) {
fwtype = "Yonkers";
- fwdict = restore_get_yonkers_firmware_data(restore, client, build_identity, p_info2);
+ fwdict = restore_get_yonkers_firmware_data(client, p_info2, 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);
goto error_out;
}
} else if (strcmp(s_updater_name, "Rose") == 0) {
- fwdict = restore_get_rose_firmware_data(restore, client, build_identity, p_info);
+ fwdict = restore_get_rose_firmware_data(client, p_info, arguments);
if (fwdict == NULL) {
error("ERROR: %s: Couldn't get Rose firmware data\n", __func__);
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__);
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__);
goto error_out;
}
+ } else if (strcmp(s_updater_name, "PS190") == 0) {
+ fwdict = restore_get_generic_firmware_data(client, p_info, arguments);
+ if (fwdict == NULL) {
+ error("ERROR: %s: Couldn't get PCON1 firmware data\n", __func__);
+ goto error_out;
+ }
+ } else if (strcmp(s_updater_name, "AppleTypeCRetimer") == 0) {
+ fwdict = restore_get_timer_firmware_data(client, p_info, arguments);
+ if (fwdict == NULL) {
+ error("ERROR: %s: Couldn't get AppleTypeCRetimer firmware data\n", __func__);
+ goto error_out;
+ }
+ } else if ((strcmp(s_updater_name, "Cryptex1") == 0) || (strcmp(s_updater_name, "Cryptex1LocalPolicy") == 0)) {
+ fwdict = restore_get_cryptex1_firmware_data(client, p_info, arguments);
+ if (fwdict == NULL) {
+ error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name);
+ goto error_out;
+ }
+ } else if (strcmp(s_updater_name, "Ace3") == 0) {
+ fwdict = restore_get_generic_firmware_data(client, p_info, arguments);
+ if (fwdict == NULL) {
+ error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name);
+ goto error_out;
+ }
} else {
- error("ERROR: %s: Got unknown updater name '%s'.\n", __func__, s_updater_name);
- goto error_out;
+ 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(client, p_info, arguments);
+ if (fwdict == NULL) {
+ error("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) {
+ error("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);
+ 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);
goto error_out;
@@ -2803,6 +3762,49 @@ error_out:
return -1;
}
+static int restore_send_receipt_manifest(struct idevicerestore_client_t* client, plist_t message)
+{
+ plist_t dict;
+ int restore_error;
+
+ if (!client || !client->restore || !client->restore->build_identity) {
+ error("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");
+ goto error_out;
+ }
+
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ error("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 = _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);
+ goto error_out;
+ }
+
+ info("Done sending ReceiptManifest data\n");
+
+ return 0;
+
+error_out:
+ return -1;
+}
+
+
struct cpio_odc_header {
char c_magic[6];
char c_dev[6];
@@ -2869,7 +3871,7 @@ static int cpio_send_file(idevice_connection_t connection, const char *name, str
return 0;
}
-static int restore_bootability_send_one(void *ctx, const char *ipsw, const char *name, struct stat *stat)
+static int restore_bootability_send_one(void *ctx, ipsw_archive_t ipsw, const char *name, struct stat *stat)
{
idevice_connection_t connection = (idevice_connection_t)ctx;
const char *prefix = "BootabilityBundle/Restore/Bootability/";
@@ -2905,7 +3907,7 @@ static int restore_bootability_send_one(void *ctx, const char *ipsw, const char
return ret;
}
-static int restore_send_bootability_bundle_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message, idevice_t device)
+static int restore_send_bootability_bundle_data(struct idevicerestore_client_t* client, plist_t message)
{
if (idevicerestore_debug) {
debug("DEBUG: %s: Got BootabilityBundle request:\n", __func__);
@@ -2921,9 +3923,14 @@ 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;
+ if (!client || !client->restore || !client->restore->build_identity || !client->restore->device) {
+ error("ERROR: %s: idevicerestore client not initialized?!\n", __func__);
+ return -1;
+ }
+
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;
}
@@ -2950,36 +3957,35 @@ static int restore_send_bootability_bundle_data(restored_client_t restore, struc
return 0;
}
-plist_t restore_get_build_identity(struct idevicerestore_client_t* client, uint8_t is_recover_os)
+plist_t restore_get_build_identity(struct idevicerestore_client_t* client, uint8_t is_recovery_os)
{
const char *variant;
- if (is_recover_os)
- variant = "macOS Customer";
+ if (is_recovery_os)
+ variant = RESTORE_VARIANT_MACOS_RECOVERY_OS;
else if (client->flags & FLAG_ERASE)
- variant = "Customer Erase Install (IPSW)";
+ variant = RESTORE_VARIANT_ERASE_INSTALL;
else
- variant = "Customer Upgrade Install (IPSW)";
+ variant = RESTORE_VARIANT_UPGRADE_INSTALL;
plist_t build_identity = build_manifest_get_build_identity_for_model_with_variant(
client->build_manifest,
client->device->hardware_model,
- variant);
+ variant, 0);
plist_t unique_id_node = plist_dict_get_item(client->build_manifest, "UniqueBuildID");
- debug_plist(unique_id_node);
+ if (unique_id_node) {
+ info("UniqueBuildID: ");
+ plist_write_to_stream(unique_id_node, stdout, PLIST_FORMAT_PRINT, PLIST_OPT_NONE);
+ }
return build_identity;
}
-plist_t restore_get_build_identity_from_request(struct idevicerestore_client_t* client, plist_t msg)
+plist_t restore_get_build_identity_from_request(struct idevicerestore_client_t* client, plist_t message)
{
- plist_t args = plist_dict_get_item(msg, "Arguments");
- plist_t is_recovery_node = plist_dict_get_item(args, "IsRecoveryOS");
- uint8_t is_recovery = 0;
- plist_get_bool_val(is_recovery_node, &is_recovery);
-
- return restore_get_build_identity(client, is_recovery);
+ plist_t args = plist_dict_get_item(message, "Arguments");
+ return restore_get_build_identity(client, plist_dict_get_bool(args, "IsRecoveryOS"));
}
int extract_macos_variant(plist_t build_identity, char** output)
@@ -3000,27 +4006,32 @@ int extract_macos_variant(plist_t build_identity, char** output)
return 0;
}
-int extract_global_manifest(struct idevicerestore_client_t* client, plist_t build_identity, unsigned char** pbuffer, unsigned int* psize)
+static char* extract_global_manifest_path(plist_t build_identity, char *variant)
{
plist_t build_info = plist_dict_get_item(build_identity, "Info");
if (!build_info) {
error("ERROR: build identity does not contain an 'Info' element\n");
- return -1;
+ return NULL;
}
plist_t device_class_node = plist_dict_get_item(build_info, "DeviceClass");
if (!device_class_node) {
error("ERROR: build identity info does not contain a DeviceClass\n");
- return -1;
+ return NULL;
}
char *device_class = NULL;
plist_get_string_val(device_class_node, &device_class);
char *macos_variant = NULL;
- int ret = extract_macos_variant(build_identity, &macos_variant);
- if (ret != 0) {
- free(device_class);
- return -1;
+ int ret;
+ if (variant) {
+ macos_variant = variant;
+ } else {
+ ret = extract_macos_variant(build_identity, &macos_variant);
+ if (ret != 0) {
+ free(device_class);
+ return NULL;
+ }
}
// The path of the global manifest is hardcoded. There's no pointer to in the build manifest.
@@ -3030,7 +4041,17 @@ int extract_global_manifest(struct idevicerestore_client_t* client, plist_t buil
free(device_class);
free(macos_variant);
- ret = ipsw_extract_to_memory(client->ipsw, ticket_path, pbuffer, psize);
+ return ticket_path;
+}
+
+int extract_global_manifest(struct idevicerestore_client_t* client, plist_t build_identity, char *variant, unsigned char** pbuffer, unsigned int* psize)
+{
+ char* ticket_path = extract_global_manifest_path(build_identity, variant);
+ if (!ticket_path) {
+ error("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");
@@ -3041,12 +4062,58 @@ int extract_global_manifest(struct idevicerestore_client_t* client, plist_t buil
return 0;
}
-int restore_send_personalized_boot_object_v3(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg, plist_t build_identity)
+struct _restore_send_file_data_ctx {
+ struct idevicerestore_client_t* client;
+ restore_service_client_t service;
+ int last_progress;
+};
+
+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)
+{
+ plist_t dict = plist_new_dict();
+ if (data != NULL) {
+ // Send a chunk of file data
+ plist_dict_set_item(dict, "FileData", plist_new_data((char*)data, size));
+ } else {
+ // Send FileDataDone to mark end of transfer
+ plist_dict_set_item(dict, "FileDataDone", plist_new_bool(1));
+ }
+ restored_error_t restore_error = _restore_service_send(rctx->service, dict, 0);
+ if (restore_error != RESTORE_E_SUCCESS) {
+ plist_free(dict);
+ error("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)) {
+ info("Encountered First Chunk in AEA image\n");
+ plist_t message = NULL;
+ _restore_service_recv(rctx->service, &message);
+ restore_send_url_asset(rctx->client, message);
+ }
+
+ if (total_size > 0x1000000) {
+ double progress = (double)done / (double)total_size;
+ int progress_int = (int)(progress*100.0);
+ if (progress_int > rctx->last_progress) {
+ idevicerestore_progress(rctx->client, RESTORE_STEP_UPLOAD_IMG, progress);
+ rctx->last_progress = progress_int;
+ }
+ }
+ return 0;
+}
+
+int restore_send_personalized_boot_object_v3(struct idevicerestore_client_t* client, plist_t message)
{
- debug_plist(msg);
+ if (idevicerestore_debug) {
+ debug("DEBUG: %s: Got PersonalizedBootObjectV3 request:\n", __func__);
+ debug_plist(message);
+ }
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");
return -1;
@@ -3064,12 +4131,11 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i
plist_t blob = NULL;
plist_t dict = NULL;
restored_error_t restore_error = RESTORE_E_SUCCESS;
- char *component_name = component;
- info("About to send %s...\n", component_name);
+ info("About to send %s...\n", component);
if (strcmp(image_name, "__GlobalManifest__") == 0) {
- int ret = extract_global_manifest(client, build_identity, &data, &size);
+ int ret = extract_global_manifest(client, client->restore->build_identity, NULL, &data, &size);
if (ret != 0) {
return -1;
}
@@ -3093,7 +4159,7 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i
}
}
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");
return -1;
@@ -3115,7 +4181,7 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i
return -1;
}
- // Personalize IMG40
+ // Personalize IMG4
ret = personalize_component(component, component_data, component_size, client->tss, &data, &size);
free(component_data);
component_data = NULL;
@@ -3125,52 +4191,49 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i
}
}
- // Make plist
- info("Sending %s now...\n", component_name);
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ error("ERROR: %s: Unable to connect to service client\n", __func__);
+ return -1;
+ }
+
+ info("Sending %s now (%" PRIu64 " bytes)...\n", component, (uint64_t)size);
+
+ struct _restore_send_file_data_ctx rctx;
+ rctx.client = client;
+ rctx.service = service;
+ rctx.last_progress = 0;
int64_t i = size;
while (i > 0) {
int blob_size = i > 8192 ? 8192 : i;
-
- dict = plist_new_dict();
- blob = plist_new_data((char *) (data + size - i), blob_size);
- plist_dict_set_item(dict, "FileData", blob);
-
- restore_error = restored_send(restore, dict);
- if (restore_error != RESTORE_E_SUCCESS) {
- error("ERROR: Unable to send component %s data\n", component_name);
+ if (_restore_send_file_data(&rctx, (data + size - i), blob_size, size-i, size) < 0) {
+ free(data);
+ _restore_service_free(service);
+ error("ERROR: Unable to send component %s data\n", component);
return -1;
}
-
- plist_free(dict);
-
i -= blob_size;
}
- debug("\n");
-
- // Send FileDataDone
- dict = plist_new_dict();
- plist_dict_set_item(dict, "FileDataDone", plist_new_bool(1));
+ free(data);
- restore_error = restored_send(restore, dict);
- if (restore_error != RESTORE_E_SUCCESS) {
- error("ERROR: Unable to send component %s data\n", component_name);
- return -1;
- }
+ _restore_send_file_data(&rctx, NULL, 0, size-i, size);
- plist_free(dict);
- free(data);
+ _restore_service_free(service);
- info("Done sending %s\n", component_name);
+ info("Done sending %s\n", component);
return 0;
}
-int restore_send_source_boot_object_v4(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg, plist_t build_identity)
+int restore_send_source_boot_object_v4(struct idevicerestore_client_t* client, plist_t message)
{
- debug_plist(msg);
+ if (idevicerestore_debug) {
+ debug("DEBUG: %s: Got SourceBootObjectV4 request:\n", __func__);
+ debug_plist(message);
+ }
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");
return -1;
@@ -3190,27 +4253,27 @@ int restore_send_source_boot_object_v4(restored_client_t restore, struct idevice
plist_t blob = NULL;
plist_t dict = NULL;
restored_error_t restore_error = RESTORE_E_SUCCESS;
- char *component_name = component;
- info("About to send %s...\n", component_name);
+ info("About to send %s...\n", component);
if (strcmp(image_name, "__GlobalManifest__") == 0) {
- int ret = extract_global_manifest(client, build_identity, &data, &size);
- if (ret != 0) {
+ char *variant = NULL;
+ plist_t node = plist_access_path(message, 2, "Arguments", "Variant");
+ if (!node || plist_get_node_type(node) != PLIST_STRING) {
+ debug("Failed to parse arguments from SourceBootObjectV4 plist\n");
return -1;
}
- } else if (strcmp(image_name, "__RestoreVersion__") == 0) {
- int ret = ipsw_extract_to_memory(client->ipsw, "RestoreVersion.plist", &data, &size);
- if (ret != 0) {
- error("ERROR: failed to read global manifest\n");
+ plist_get_string_val(node, &variant);
+ if (!variant) {
+ debug("Failed to parse arguments from SourceBootObjectV4 as string\n");
return -1;
}
+
+ path = extract_global_manifest_path(client->restore->build_identity, variant);
+ } else if (strcmp(image_name, "__RestoreVersion__") == 0) {
+ path = strdup("RestoreVersion.plist");
} else if (strcmp(image_name, "__SystemVersion__") == 0) {
- int ret = ipsw_extract_to_memory(client->ipsw, "SystemVersion.plist", &data, &size);
- if (ret != 0) {
- error("ERROR: failed to read global manifest\n");
- return -1;
- }
+ path = strdup("SystemVersion.plist");
} else {
// Get component path
if (client->tss) {
@@ -3219,63 +4282,50 @@ int restore_send_source_boot_object_v4(restored_client_t restore, struct idevice
}
}
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);
return -1;
}
}
-
- int ret = extract_component(client->ipsw, path, &data, &size);
- free(path);
- path = NULL;
- if (ret < 0) {
- error("ERROR: Unable to extract component %s\n", component);
- return -1;
- }
}
- // Make plist
- info("Sending %s now...\n", component_name);
-
- int64_t i = size;
- while (i > 0) {
- int blob_size = i > 8192 ? 8192 : i;
-
- dict = plist_new_dict();
- blob = plist_new_data((char *) (data + size - i), blob_size);
- plist_dict_set_item(dict, "FileData", blob);
-
- restore_error = restored_send(restore, dict);
- if (restore_error != RESTORE_E_SUCCESS) {
- error("ERROR: Unable to send component %s data\n", component_name);
- return -1;
- }
+ if (!path) {
+ error("ERROR: Failed to get path for component %s\n", component);
+ return -1;
+ }
- plist_free(dict);
+ uint64_t fsize = 0;
+ ipsw_get_file_size(client->ipsw, path, &fsize);
- i -= blob_size;
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ error("ERROR: %s: Unable to connect to service client\n", __func__);
+ return -1;
}
- debug("\n");
- // Send FileDataDone
- dict = plist_new_dict();
- plist_dict_set_item(dict, "FileDataDone", plist_new_bool(1));
+ info("Sending %s now (%" PRIu64 " bytes)\n", component, fsize);
- restore_error = restored_send(restore, dict);
- if (restore_error != RESTORE_E_SUCCESS) {
- error("ERROR: Unable to send component %s data\n", component_name);
+ struct _restore_send_file_data_ctx rctx;
+ rctx.client = client;
+ rctx.service = service;
+ rctx.last_progress = 0;
+
+ if (ipsw_extract_send(client->ipsw, path, 8192, (ipsw_send_cb)_restore_send_file_data, &rctx) < 0) {
+ free(path);
+ _restore_service_free(service);
+ error("ERROR: Failed to send component %s\n", component);
return -1;
}
+ free(path);
- plist_free(dict);
- free(data);
+ _restore_service_free(service);
- info("Done sending %s\n", component_name);
+ 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;
@@ -3292,7 +4342,7 @@ 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");
return -1;
@@ -3309,7 +4359,15 @@ int restore_send_restore_local_policy(restored_client_t restore, struct idevicer
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) {
+ error("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);
return -1;
@@ -3321,19 +4379,25 @@ 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;
+ restore_service_client_t service = _restore_get_service_client_for_data_request(client, message);
+ if (!service) {
+ error("ERROR: %s: Unable to connect to service client\n", __func__);
+ return -1;
+ }
+
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 {
@@ -3341,7 +4405,8 @@ int restore_send_buildidentity(restored_client_t restore, struct idevicerestore_
}
info("Sending BuildIdentityDict now...\n");
- restore_error = restored_send(restore, dict);
+ 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);
@@ -3352,7 +4417,7 @@ int restore_send_buildidentity(restored_client_t restore, struct idevicerestore_
return 0;
}
-int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t build_identity, const char* filesystem)
+int restore_handle_data_request_msg(struct idevicerestore_client_t* client, plist_t message)
{
plist_t node = NULL;
@@ -3361,38 +4426,38 @@ 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);
-
+debug("%s: type = %s\n", __func__, type);
// this request is sent when restored is ready to receive the filesystem
if (!strcmp(type, "SystemImageData")) {
- if(restore_send_filesystem(client, device, filesystem) < 0) {
+ if (restore_send_filesystem(client, message) < 0) {
error("ERROR: Unable to send filesystem\n");
return -2;
}
}
else if (!strcmp(type, "BuildIdentityDict")) {
- if (restore_send_buildidentity(restore, client, message) < 0) {
+ if (restore_send_buildidentity(client, message) < 0) {
error("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) {
+ if (restore_send_personalized_boot_object_v3(client, message) < 0) {
error("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) {
+ if (restore_send_source_boot_object_v4(client, message) < 0) {
error("ERROR: Unable to send SourceBootObjectV4\n");
return -1;
}
}
else if (!strcmp(type, "RecoveryOSLocalPolicy")) {
- if (restore_send_restore_local_policy(restore, client, message) < 0) {
+ if (restore_send_restore_local_policy(client, message) < 0) {
error("ERROR: Unable to send RecoveryOSLocalPolicy\n");
return -1;
}
@@ -3400,7 +4465,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev
// this request is sent when restored is ready to receive the filesystem
else if (!strcmp(type, "RecoveryOSASRImage")) {
- if(restore_send_filesystem(client, device, filesystem) < 0) {
+ if (restore_send_filesystem(client, message) < 0) {
error("ERROR: Unable to send filesystem\n");
return -2;
}
@@ -3408,7 +4473,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev
// Send RecoveryOS RTD
else if(!strcmp(type, "RecoveryOSRootTicketData")) {
- if (restore_send_recovery_os_root_ticket(restore, client) < 0) {
+ if (restore_send_recovery_os_root_ticket(client, message) < 0) {
error("ERROR: Unable to send RootTicket\n");
return -1;
}
@@ -3416,35 +4481,35 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev
// send RootTicket (== APTicket from the TSS request)
else if (!strcmp(type, "RootTicket")) {
- if (restore_send_root_ticket(restore, client) < 0) {
+ if (restore_send_root_ticket(client, message) < 0) {
error("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) {
+ if (restore_send_component(client, message, "KernelCache", NULL) < 0) {
error("ERROR: Unable to send kernelcache\n");
return -1;
}
}
else if (!strcmp(type, "DeviceTree")) {
- if (restore_send_component(restore, client, build_identity, "DeviceTree", NULL) < 0) {
+ if (restore_send_component(client, message, "DeviceTree", NULL) < 0) {
error("ERROR: Unable to send DeviceTree\n");
return -1;
}
}
else if (!strcmp(type, "SystemImageRootHash")) {
- if (restore_send_component(restore, client, build_identity, "SystemVolume", type) < 0) {
+ if (restore_send_component(client, message, "SystemVolume", type) < 0) {
error("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) {
+ if (restore_send_component(client, message, "Ap,SystemVolumeCanonicalMetadata", type) < 0) {
error("ERROR: Unable to send SystemImageCanonicalMetadata data\n");
return -1;
}
@@ -3452,7 +4517,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev
else if (!strcmp(type, "NORData")) {
if((client->flags & FLAG_EXCLUDE) == 0) {
- if(restore_send_nor(restore, client, build_identity) < 0) {
+ if(restore_send_nor(client, message) < 0) {
error("ERROR: Unable to send NOR data\n");
return -1;
}
@@ -3463,54 +4528,89 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev
}
else if (!strcmp(type, "BasebandData")) {
- if(restore_send_baseband_data(restore, client, build_identity, message) < 0) {
+ if(restore_send_baseband_data(client, message) < 0) {
error("ERROR: Unable to send baseband data\n");
return -1;
}
}
else if (!strcmp(type, "FDRTrustData")) {
- if(restore_send_fdr_trust_data(restore, device) < 0) {
+ if(restore_send_fdr_trust_data(client, message) < 0) {
error("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) {
+ if(restore_send_image_data(client, message, "FUDImageList", "IsFUDFirmware", "FUDImageData") < 0) {
error("ERROR: Unable to send FUD data\n");
return -1;
}
}
+ else if (!strcmp(type, "FirmwareUpdaterPreflight")) {
+ if(restore_send_firmware_updater_preflight(client, message) < 0) {
+ error("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) {
+ if(restore_send_firmware_updater_data(client, message) < 0) {
error("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) {
+ if(restore_send_image_data(client, message, "ImageList", NULL, "ImageData") < 0) {
error("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) {
+ if(restore_send_image_data(client, message, "EANImageList", "IsEarlyAccessFirmware", "EANData") < 0) {
error("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) {
+ if (restore_send_bootability_bundle_data(client, message) < 0) {
error("ERROR: Unable to send BootabilityBundle data\n");
return -1;
}
}
+ else if (!strcmp(type, "ReceiptManifest")) {
+ if (restore_send_receipt_manifest(client, message) < 0) {
+ error("ERROR: Unable to send ReceiptManifest data\n");
+ return -1;
+ }
+ }
+
+ else if (!strcmp(type, "BasebandUpdaterOutputData")) {
+ if (restore_handle_baseband_updater_output_data(client, message) < 0) {
+ error("ERROR: Unable to send BasebandUpdaterOutputData data\n");
+ return -1;
+ }
+ }
+
+ else if (!strcmp(type, "URLAsset")) {
+ if (restore_send_url_asset(client, message) < 0) {
+ error("ERROR: Unable to send URLAsset data\n");
+ return -1;
+ }
+ }
+
+ else if (!strcmp(type, "StreamedImageDecryptionKey")) {
+ if (restore_send_streamed_image_decryption_key(client, message) < 0) {
+ error("ERROR: Unable to send StreamedImageDecryptionKey data\n");
+ return -1;
+ }
+ }
+
else {
// Unknown DataType!!
error("Unknown data request '%s' received\n", type);
@@ -3521,6 +4621,70 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev
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");
+ info("*** restored crashed, backtrace following ***");
+ if (PLIST_IS_STRING(backtrace)) {
+ 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);
+ info("\t%s\n", plist_get_string_ptr(line, NULL));
+ }
+ } else {
+ debug_plist(message);
+ }
+ return 0;
+}
+
+static int restore_handle_async_wait(struct idevicerestore_client_t* client, plist_t message)
+{
+ debug("AsyncWait\n");
+ if (idevicerestore_debug)
+ debug_plist(message);
+ return 0;
+}
+
+static int restore_handle_restore_attestation(struct idevicerestore_client_t* client, plist_t message)
+{
+ if (idevicerestore_debug)
+ debug_plist(message);
+ 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) {
+ error("ERROR: Unable to send RestoreShouldAttest (%d)\n", restore_error);
+ return -1;
+ }
+ return 0;
+}
+
// Extracted from ac2
plist_t restore_supported_data_types()
{
@@ -3532,6 +4696,7 @@ plist_t restore_supported_data_types()
plist_dict_set_item(dict, "BootabilityBundle", plist_new_bool(0));
plist_dict_set_item(dict, "BuildIdentityDict", plist_new_bool(0));
plist_dict_set_item(dict, "BuildIdentityDictV2", plist_new_bool(0));
+ plist_dict_set_item(dict, "Cryptex1LocalPolicy", plist_new_bool(1));
plist_dict_set_item(dict, "DataType", plist_new_bool(0));
plist_dict_set_item(dict, "DiagData", plist_new_bool(0));
plist_dict_set_item(dict, "EANData", plist_new_bool(0));
@@ -3580,6 +4745,16 @@ plist_t restore_supported_data_types()
plist_dict_set_item(dict, "SystemImageRootHash", plist_new_bool(0));
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, "FirmwareUpdaterDataV3", plist_new_bool(1));
+ plist_dict_set_item(dict, "MessageUseStreamedImageFile", plist_new_bool(1));
+ plist_dict_set_item(dict, "UpdateVolumeOverlayRootDataCount", plist_new_bool(1));
+ plist_dict_set_item(dict, "URLAsset", plist_new_bool(1));
return dict;
}
@@ -3600,6 +4775,9 @@ plist_t restore_supported_message_types()
plist_dict_set_item(dict, "ReceivedFinalStatusMsg", plist_new_bool(0));
plist_dict_set_item(dict, "RestoredCrash", plist_new_bool(1));
plist_dict_set_item(dict, "StatusMsg", plist_new_bool(0));
+ 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, "RestoreAttestation", plist_new_bool(1));
return dict;
}
@@ -3615,7 +4793,7 @@ static void rp_status_cb(reverse_proxy_client_t client, reverse_proxy_status_t s
}
#endif
-int restore_device(struct idevicerestore_client_t* client, plist_t build_identity, const char* filesystem)
+int restore_device(struct idevicerestore_client_t* client, plist_t build_identity)
{
int err = 0;
char* type = NULL;
@@ -3639,6 +4817,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
}
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;
@@ -3755,7 +4934,6 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
plist_dict_set_item(opts, "AutoBootDelay", plist_new_uint(0));
if (client->preflight_info) {
- plist_t node;
plist_t bbus = plist_copy(client->preflight_info);
plist_dict_remove_item(bbus, "FusingStatus");
@@ -3763,17 +4941,14 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
plist_dict_set_item(opts, "BBUpdaterState", bbus);
- node = plist_dict_get_item(client->preflight_info, "Nonce");
- if (node) {
- plist_dict_set_item(opts, "BasebandNonce", plist_copy(node));
- }
+ plist_dict_copy_data(opts, client->preflight_info, "BasebandNonce", "Nonce");
}
plist_dict_set_item(opts, "SupportedDataTypes", restore_supported_data_types());
plist_dict_set_item(opts, "SupportedMessageTypes", restore_supported_message_types());
// FIXME: Should be adjusted for update behaviors
- if (client->build_major >= 20) {
+ if (client->macos_variant) {
plist_dict_set_item(opts, "AddSystemPartitionPadding", plist_new_bool(1));
plist_dict_set_item(opts, "AllowUntetheredRestore", plist_new_bool(0));
plist_dict_set_item(opts, "AuthInstallEnableSso", plist_new_bool(0));
@@ -3840,6 +5015,18 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
// FIXME: does this have any effect actually?
plist_dict_set_item(opts, "UpdateBaseband", plist_new_bool(0));
+ // 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 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_t sep = plist_access_path(build_identity, 3, "Manifest", "SEP", "Info");
if (sep) {
node = plist_dict_get_item(sep, "RequiredCapacity");
@@ -3896,7 +5083,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
// this is the restore process loop, it reads each message in from
// restored and passes that data on to it's specific handler
while (!(client->flags & FLAG_QUIT)) {
- if (client->flags & FLAG_IGNORE_ERRORS) {
+ if (err != 0 && client->flags & FLAG_IGNORE_ERRORS) {
error("WARNING: Attempting to continue after critical error, restore might fail...\n");
err = 0;
}
@@ -3942,7 +5129,22 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
// files sent to the server by the client. these data requests include
// SystemImageData, RootTicket, KernelCache, NORData and BasebandData requests
if (!strcmp(type, "DataRequestMsg")) {
- err = restore_handle_data_request_msg(client, device, restore, message, build_identity, filesystem);
+ err = restore_handle_data_request_msg(client, message);
+ }
+
+ // async data request message
+ else if (!strcmp(type, "AsyncDataRequestMsg")) {
+ THREAD_T t = THREAD_T_NULL;
+ struct _restore_async_args* args = (struct _restore_async_args*)malloc(sizeof(struct _restore_async_args));
+ args->client = client;
+ args->message = plist_copy(message);
+ if (thread_new(&t, _restore_handle_async_data_request, args) < 0) {
+ free(args);
+ error("ERROR: Failed to start async data request handler thread!\n");
+ err = -1;
+ } else {
+ thread_detach(t);
+ }
}
// restore logs are available if a previous restore failed
@@ -3959,7 +5161,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
// status messages usually indicate the current state of the restored
// process or often to signal an error has been encountered
else if (!strcmp(type, "StatusMsg")) {
- err = restore_handle_status_msg(restore, message);
+ err = restore_handle_status_msg(client, message);
if (restore_finished) {
plist_t dict = plist_new_dict();
plist_dict_set_item(dict, "MsgType", plist_new_string("ReceivedFinalStatusMsg"));
@@ -3971,39 +5173,71 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
else if (!strcmp(type, "CheckpointMsg")) {
uint64_t ckpt_id;
- uint64_t ckpt_res;
+ int64_t ckpt_res;
uint8_t ckpt_complete = 0;
+ const char* ckpt_name = NULL;
// Get checkpoint id
node = plist_dict_get_item(message, "CHECKPOINT_ID");
- if (!node || plist_get_node_type(node) != PLIST_UINT) {
+ if (!node || plist_get_node_type(node) != PLIST_INT) {
debug("Failed to parse checkpoint id from checkpoint plist\n");
- return -1;
+ err = -1;
+ break;
}
plist_get_uint_val(node, &ckpt_id);
+ // Get checkpoint_name
+ node = plist_dict_get_item(message, "CHECKPOINT_NAME");
+ ckpt_name = (node) ? plist_get_string_ptr(node, NULL) : "unknown";
// Get checkpoint result
node = plist_dict_get_item(message, "CHECKPOINT_RESULT");
- if (!node || plist_get_node_type(node) != PLIST_UINT) {
+ if (!node || plist_get_node_type(node) != PLIST_INT) {
debug("Failed to parse checkpoint result from checkpoint plist\n");
- return -1;
+ err = -1;
+ break;
}
- plist_get_uint_val(node, &ckpt_res);
+ plist_get_int_val(node, &ckpt_res);
// Get checkpoint complete
node = plist_dict_get_item(message, "CHECKPOINT_COMPLETE");
if (PLIST_IS_BOOLEAN(node)) {
plist_get_bool_val(node, &ckpt_complete);
}
- if (ckpt_complete)
- info("Checkpoint %" PRIu64 " complete with code %" PRIu64 "\n", ckpt_id, ckpt_res);
+
+ if (ckpt_complete) {
+ info("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);
+ }
+ 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));
+ }
+ 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));
+ }
}
// 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
@@ -4018,6 +5252,9 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
plist_free(message);
message = NULL;
}
+ if (client->async_err != 0) {
+ err = client->async_err;
+ }
#ifdef HAVE_REVERSE_PROXY
reverse_proxy_client_free(rproxy);