diff options
Diffstat (limited to 'src/restore.c')
| -rw-r--r-- | src/restore.c | 2717 |
1 files changed, 1949 insertions, 768 deletions
diff --git a/src/restore.c b/src/restore.c index 1261147..12f837c 100644 --- a/src/restore.c +++ b/src/restore.c @@ -30,7 +30,10 @@ #include <string.h> #include <unistd.h> #include <libgen.h> +#include <math.h> #include <libimobiledevice/restore.h> +#include <libimobiledevice/property_list_service.h> +#include <libimobiledevice-glue/thread.h> #ifdef HAVE_REVERSE_PROXY #include <libimobiledevice/reverse_proxy.h> #else @@ -38,6 +41,8 @@ #endif #include <zip.h> #include <libirecovery.h> +#include <libtatsu/tss.h> +#include <curl/curl.h> #include "idevicerestore.h" #include "asr.h" @@ -45,7 +50,6 @@ #include "fls.h" #include "mbn.h" #include "ftab.h" -#include "tss.h" #include "ipsw.h" #include "restore.h" #include "common.h" @@ -123,7 +127,7 @@ int restore_client_new(struct idevicerestore_client_t* client) { struct restore_client_t* restore = (struct restore_client_t*) malloc(sizeof(struct restore_client_t)); if (restore == NULL) { - error("ERROR: Out of memory\n"); + logger(LL_ERROR, "Out of memory\n"); return -1; } @@ -180,12 +184,12 @@ static int restore_idevice_new(struct idevicerestore_client_t* client, idevice_t } device_error = idevice_new(&dev, devices[j]); if (device_error != IDEVICE_E_SUCCESS) { - debug("%s: can't open device with UDID %s\n", __func__, devices[j]); + logger(LL_DEBUG, "%s: can't open device with UDID %s\n", __func__, devices[j]); continue; } if (restored_client_new(dev, &restore, "idevicerestore") != RESTORE_E_SUCCESS) { - debug("%s: can't connect to restored on device with UDID %s\n", __func__, devices[j]); + logger(LL_DEBUG, "%s: can't connect to restored on device with UDID %s\n", __func__, devices[j]); continue; } @@ -281,7 +285,7 @@ irecv_device_t restore_get_irecv_device(struct idevicerestore_client_t* client) if (client->srnm == NULL) { if (restored_get_value(restore, "SerialNumber", &node) == RESTORE_E_SUCCESS) { plist_get_string_val(node, &client->srnm); - info("INFO: device serial number is %s\n", client->srnm); + logger(LL_INFO, "INFO: device serial number is %s\n", client->srnm); plist_free(node); node = NULL; } @@ -291,7 +295,7 @@ irecv_device_t restore_get_irecv_device(struct idevicerestore_client_t* client) restored_client_free(restore); idevice_free(device); if (restore_error != RESTORE_E_SUCCESS || !node || plist_get_node_type(node) != PLIST_STRING) { - error("ERROR: Unable to get HardwareModel from restored\n"); + logger(LL_ERROR, "Unable to get HardwareModel from restored\n"); plist_free(node); return NULL; } @@ -312,7 +316,7 @@ int restore_is_image4_supported(struct idevicerestore_client_t* client) restored_error_t restore_error = RESTORE_E_SUCCESS; if (idevice_new(&device, client->udid) != IDEVICE_E_SUCCESS) { - error("ERROR: Could not connect to device %s\n", client->udid); + logger(LL_ERROR, "Could not connect to device %s\n", client->udid); return -1; } @@ -347,14 +351,14 @@ int restore_reboot(struct idevicerestore_client_t* client) { if(client->restore == NULL) { if (restore_open_with_timeout(client) < 0) { - error("ERROR: Unable to open device in restore mode\n"); + logger(LL_ERROR, "Unable to open device in restore mode\n"); return -1; } } mutex_lock(&client->device_event_mutex); - info("Rebooting restore mode device...\n"); + logger(LL_INFO, "Rebooting restore mode device...\n"); restored_reboot(client->restore->client); restored_client_free(client->restore->client); @@ -375,7 +379,7 @@ static int restore_is_current_device(struct idevicerestore_client_t* client, con return 0; } if (!client->ecid) { - error("ERROR: %s: no ECID given in client data\n", __func__); + logger(LL_ERROR, "%s: no ECID given in client data\n", __func__); return 0; } @@ -388,21 +392,21 @@ static int restore_is_current_device(struct idevicerestore_client_t* client, con device_error = idevice_new(&device, udid); if (device_error != IDEVICE_E_SUCCESS) { - debug("%s: can't open device with UDID %s\n", __func__, udid); + logger(LL_DEBUG, "%s: can't open device with UDID %s\n", __func__, udid); return 0; } restore_error = restored_client_new(device, &restored, "idevicerestore"); if (restore_error != RESTORE_E_SUCCESS) { - debug("%s: can't connect to restored\n", __func__); + logger(LL_DEBUG, "%s: can't connect to restored\n", __func__); idevice_free(device); return 0; } restore_error = restored_query_type(restored, &type, &version); if ((restore_error == RESTORE_E_SUCCESS) && type && (strcmp(type, "com.apple.mobile.restored") == 0)) { - debug("%s: Connected to %s, version %d\n", __func__, type, (int)version); + logger(LL_DEBUG, "%s: Connected to %s, version %d\n", __func__, type, (int)version); } else { - debug("%s: device %s is not in restore mode\n", __func__, udid); + logger(LL_DEBUG, "%s: device %s is not in restore mode\n", __func__, udid); restored_client_free(restored); idevice_free(device); return 0; @@ -411,7 +415,7 @@ static int restore_is_current_device(struct idevicerestore_client_t* client, con plist_t hwinfo = NULL; restore_error = restored_query_value(restored, "HardwareInfo", &hwinfo); if ((restore_error != RESTORE_E_SUCCESS) || !hwinfo) { - error("ERROR: %s: Unable to get HardwareInfo from restored\n", __func__); + logger(LL_ERROR, "%s: Unable to get HardwareInfo from restored\n", __func__); restored_client_free(restored); idevice_free(device); plist_free(hwinfo); @@ -428,7 +432,7 @@ static int restore_is_current_device(struct idevicerestore_client_t* client, con plist_free(hwinfo); if (this_ecid == 0) { - error("ERROR: %s: Unable to get ECID from restored\n", __func__); + logger(LL_ERROR, "%s: Unable to get ECID from restored\n", __func__); return 0; } @@ -450,7 +454,7 @@ int restore_open_with_timeout(struct idevicerestore_client_t* client) } if (client->ecid == 0) { - error("ERROR: no ECID in client data!\n"); + logger(LL_ERROR, "no ECID in client data!\n"); return -1; } @@ -458,7 +462,7 @@ int restore_open_with_timeout(struct idevicerestore_client_t* client) if (client->restore == NULL) { client->restore = (struct restore_client_t*) malloc(sizeof(struct restore_client_t)); if(client->restore == NULL) { - error("ERROR: Out of memory\n"); + logger(LL_ERROR, "Out of memory\n"); return -1; } memset(client->restore, '\0', sizeof(struct restore_client_t)); @@ -467,11 +471,11 @@ int restore_open_with_timeout(struct idevicerestore_client_t* client) restore_device_connected = 0; if (!restore_is_current_device(client, client->udid)) { - error("ERROR: Unable to connect to device in restore mode\n"); + logger(LL_ERROR, "Unable to connect to device in restore mode\n"); return -1; } - info("Connecting now...\n"); + logger(LL_INFO, "Connecting now...\n"); device_error = idevice_new(&device, client->udid); if (device_error != IDEVICE_E_SUCCESS) { return -1; @@ -486,9 +490,9 @@ int restore_open_with_timeout(struct idevicerestore_client_t* client) restore_error = restored_query_type(restored, &type, &version); if ((restore_error == RESTORE_E_SUCCESS) && type && (strcmp(type, "com.apple.mobile.restored") == 0)) { client->restore->protocol_version = version; - info("Connected to %s, version %d\n", type, (int)version); + logger(LL_INFO, "Connected to %s, version %d\n", type, (int)version); } else { - error("ERROR: Unable to connect to restored, error=%d\n", restore_error); + logger(LL_ERROR, "Unable to connect to restored, error=%d\n", restore_error); restored_client_free(restored); idevice_free(device); return -1; @@ -633,6 +637,107 @@ const char* restore_progress_string(unsigned int operation) } } +struct restored_service_client { + +}; + +#define SERVICE_TYPE_RESTORED 1 +#define SERVICE_TYPE_PLIST 2 + +typedef struct restore_service_client { + void* client; + int type; +} *restore_service_client_t; + +static void* _restore_get_service_client_for_data_request(struct idevicerestore_client_t *client, plist_t message) +{ + if (!client || !client->restore || !client->restore->client) return NULL; + restore_service_client_t service = (restore_service_client_t)malloc(sizeof(struct restore_service_client)); + if (!PLIST_IS_DICT(message) || !plist_dict_get_item(message, "DataPort")) { + service->client = client->restore->client; + service->type = SERVICE_TYPE_RESTORED; + return service; + } + plist_t data_type = plist_dict_get_item(message, "DataType"); + uint16_t data_port = plist_dict_get_uint(message, "DataPort"); + const char* data_type_str = plist_get_string_ptr(data_type, NULL); + + struct lockdownd_service_descriptor svcdesc = { + data_port, + 0, + (char*)data_type_str + }; + property_list_service_client_t plclient = NULL; + logger(LL_INFO, "Connecting to %s data port %u\n", data_type_str, data_port); + if (property_list_service_client_new(client->restore->device, &svcdesc, &plclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) { + logger(LL_ERROR, "Failed to start service connection for %s on port %u\n", data_type_str, data_port); + free(service); + return NULL; + } + service->client = plclient; + service->type = SERVICE_TYPE_PLIST; + + return service; +} + +static int _restore_service_send(restore_service_client_t service, plist_t plist, plist_format_t fmt) +{ + if (!service) { + return -1; + } + switch (service->type) { + case SERVICE_TYPE_RESTORED: + return restored_send((restored_client_t)service->client, plist); + case SERVICE_TYPE_PLIST: + if (fmt == PLIST_FORMAT_BINARY) { + return property_list_service_send_binary_plist((property_list_service_client_t)service->client, plist); + } + return property_list_service_send_xml_plist((property_list_service_client_t)service->client, plist); + default: + break; + } + return -1; +} + +static int _restore_service_recv_timeout(restore_service_client_t service, plist_t *plist, unsigned int timeout) +{ + struct restored_client_private { + property_list_service_client_t parent; + char *udid; + char *label; + plist_t info; + }; + if (!service) { + return -1; + } + switch (service->type) { + case SERVICE_TYPE_RESTORED: + return property_list_service_receive_plist_with_timeout(((struct restored_client_private*)service->client)->parent, plist, timeout); + case SERVICE_TYPE_PLIST: + return property_list_service_receive_plist_with_timeout((property_list_service_client_t)service->client, plist, timeout); + default: + break; + } + return -1; +} + +static void _restore_service_free(restore_service_client_t service) +{ + if (!service) { + return; + } + switch (service->type) { + case SERVICE_TYPE_RESTORED: + break; + case SERVICE_TYPE_PLIST: + property_list_service_client_free((property_list_service_client_t)service->client); + break; + default: + break; + } + free(service); +} + static int lastop = 0; static int restore_handle_previous_restore_log_msg(restored_client_t client, plist_t msg) @@ -642,12 +747,12 @@ static int restore_handle_previous_restore_log_msg(restored_client_t client, pli node = plist_dict_get_item(msg, "PreviousRestoreLog"); if (!node || plist_get_node_type(node) != PLIST_STRING) { - debug("Failed to parse restore log from PreviousRestoreLog plist\n"); + logger(LL_DEBUG, "Failed to parse restore log from PreviousRestoreLog plist\n"); return -1; } plist_get_string_val(node, &restorelog); - info("Previous Restore Log Received:\n%s\n", restorelog); + logger(LL_VERBOSE, "Previous Restore Log Received:\n%s\n", restorelog); free(restorelog); return 0; @@ -661,14 +766,14 @@ int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t node = plist_dict_get_item(msg, "Operation"); if (!node || plist_get_node_type(node) != PLIST_UINT) { - debug("Failed to parse operation from ProgressMsg plist\n"); + logger(LL_DEBUG, "Failed to parse operation from ProgressMsg plist\n"); return -1; } plist_get_uint_val(node, &operation); node = plist_dict_get_item(msg, "Progress"); if (!node || plist_get_node_type(node) != PLIST_UINT) { - debug("Failed to parse progress from ProgressMsg plist \n"); + logger(LL_DEBUG, "Failed to parse progress from ProgressMsg plist \n"); return -1; } plist_get_uint_val(node, &progress); @@ -683,9 +788,12 @@ int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t if ((progress > 0) && (progress <= 100)) { if ((int)operation != lastop) { - info("%s (%d)\n", restore_progress_string(adapted_operation), (int)operation); + logger(LL_INFO, "%s (%d)\n", restore_progress_string(adapted_operation), (int)operation); } switch (adapted_operation) { + case RESTORE_IMAGE: + idevicerestore_progress(client, RESTORE_STEP_UPLOAD_FS, progress / 100.0); + break; case VERIFY_RESTORE: idevicerestore_progress(client, RESTORE_STEP_VERIFY_FS, progress / 100.0); break; @@ -704,23 +812,23 @@ int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t case REQUESTING_EAN_DATA: break; default: - debug("Unhandled progress operation %d (%d)\n", adapted_operation, (int)operation); + logger(LL_DEBUG, "Unhandled progress operation %d (%d)\n", adapted_operation, (int)operation); break; } } else { - info("%s (%d)\n", restore_progress_string(adapted_operation), (int)operation); + logger(LL_INFO, "%s (%d)\n", restore_progress_string(adapted_operation), (int)operation); } lastop = (int)operation; return 0; } -int restore_handle_status_msg(restored_client_t client, plist_t msg) +int restore_handle_status_msg(struct idevicerestore_client_t* client, plist_t msg) { int result = 0; uint64_t value = 0; char* log = NULL; - info("Got status message\n"); + logger(LL_INFO, "Got status message\n"); // read status code plist_t node = plist_dict_get_item(msg, "Status"); @@ -728,34 +836,34 @@ int restore_handle_status_msg(restored_client_t client, plist_t msg) switch(value) { case 0: - info("Status: Restore Finished\n"); + logger(LL_INFO, "Status: Restore Finished\n"); restore_finished = 1; break; case 0xFFFFFFFFFFFFFFFFLL: - info("Status: Verification Error\n"); + logger(LL_INFO, "Status: Verification Error\n"); break; case 6: - info("Status: Disk Failure\n"); + logger(LL_INFO, "Status: Disk Failure\n"); break; case 14: - info("Status: Fail\n"); + logger(LL_INFO, "Status: Fail\n"); break; case 27: - info("Status: Failed to mount filesystems.\n"); + logger(LL_INFO, "Status: Failed to mount filesystems.\n"); break; case 50: case 51: - info("Status: Failed to load SEP Firmware.\n"); + logger(LL_INFO, "Status: Failed to load SEP Firmware.\n"); break; case 53: - info("Status: Failed to recover FDR data.\n"); + logger(LL_INFO, "Status: Failed to recover FDR data.\n"); break; case 1015: - info("Status: X-Gold Baseband Update Failed. Defective Unit?\n"); + logger(LL_INFO, "Status: X-Gold Baseband Update Failed. Defective Unit?\n"); break; default: - info("Unhandled status message (%" PRIu64 ")\n", value); - debug_plist(msg); + logger(LL_INFO, "Unhandled status message (%" PRIu64 ")\n", value); + logger_dump_plist(LL_VERBOSE, msg, 1); break; } @@ -773,7 +881,7 @@ int restore_handle_status_msg(restored_client_t client, plist_t msg) node = plist_dict_get_item(msg, "Log"); if (node && plist_get_node_type(node) == PLIST_STRING) { plist_get_string_val(node, &log); - info("Log is available:\n%s\n", log); + logger(LL_INFO, "Log is available:\n%s\n", log); free(log); log = NULL; } @@ -781,10 +889,10 @@ int restore_handle_status_msg(restored_client_t client, plist_t msg) return result; } -static int restore_handle_baseband_updater_output_data(restored_client_t restore, struct idevicerestore_client_t* client, idevice_t device, plist_t msg) +static int restore_handle_baseband_updater_output_data(struct idevicerestore_client_t* client, plist_t message) { int result = -1; - plist_t node = plist_dict_get_item(msg, "DataPort"); + plist_t node = plist_dict_get_item(message, "DataPort"); uint64_t u64val = 0; plist_get_uint_val(node, &u64val); uint16_t data_port = (uint16_t)u64val; @@ -793,43 +901,48 @@ static int restore_handle_baseband_updater_output_data(restored_client_t restore idevice_connection_t connection = NULL; idevice_error_t device_error = IDEVICE_E_SUCCESS; - debug("Connecting to baseband updater data port\n"); + if (!client || !client->restore || !client->restore->build_identity || !client->restore->device) { + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + + logger(LL_DEBUG, "Connecting to baseband updater data port\n"); while (--attempts > 0) { - device_error = idevice_connect(device, data_port, &connection); + device_error = idevice_connect(client->restore->device, data_port, &connection); if (device_error == IDEVICE_E_SUCCESS) { break; } sleep(1); - debug("Retrying connection...\n"); + logger(LL_DEBUG, "Retrying connection...\n"); } if (device_error != IDEVICE_E_SUCCESS) { - error("ERROR: Unable to connect to baseband updater data port\n"); + logger(LL_ERROR, "Unable to connect to baseband updater data port\n"); return result; } int fl = snprintf(NULL, 0, "updater_output-%s.cpio", client->udid); if (fl < 0) { idevice_disconnect(connection); - error("ERROR: snprintf failed?!\n"); + logger(LL_ERROR, "snprintf failed?!\n"); return result; } char* updater_out_fn = malloc(fl+1); if (!updater_out_fn) { idevice_disconnect(connection); - error("ERROR: Could not allocate buffer for filename\n"); + logger(LL_ERROR, "Could not allocate buffer for filename\n"); return result; } snprintf(updater_out_fn, fl+1, "updater_output-%s.cpio", client->udid); FILE* f = fopen(updater_out_fn, "wb"); if (!f) { - error("Could not open %s for writing, will not write baseband updater output data.\n", updater_out_fn); + logger(LL_ERROR, "Could not open %s for writing, will not write baseband updater output data.\n", updater_out_fn); } const int bufsize = 65536; char* buf = malloc(bufsize); if (!buf) { free(updater_out_fn); idevice_disconnect(connection); - error("ERROR: Could not allocate buffer\n"); + logger(LL_ERROR, "Could not allocate buffer\n"); return result; } uint32_t size = 0; @@ -840,7 +953,7 @@ static int restore_handle_baseband_updater_output_data(restored_client_t restore } if (f) { fclose(f); - info("Wrote baseband updater output data to %s\n", updater_out_fn); + logger(LL_INFO, "Wrote baseband updater output data to %s\n", updater_out_fn); } free(updater_out_fn); free(buf); @@ -850,46 +963,51 @@ static int restore_handle_baseband_updater_output_data(restored_client_t restore return result; } -static int restore_handle_bb_update_status_msg(restored_client_t client, plist_t msg) +static int restore_handle_bb_update_status_msg(struct idevicerestore_client_t* client, plist_t message) { int result = -1; - plist_t node = plist_dict_get_item(msg, "Accepted"); + plist_t node = plist_dict_get_item(message, "Accepted"); uint8_t accepted = 0; plist_get_bool_val(node, &accepted); if (!accepted) { - error("ERROR: device didn't accept BasebandData\n"); + logger(LL_ERROR, "device didn't accept BasebandData\n"); return result; } uint8_t done = 0; - node = plist_access_path(msg, 2, "Output", "done"); + node = plist_access_path(message, 2, "Output", "done"); if (node && plist_get_node_type(node) == PLIST_BOOLEAN) { plist_get_bool_val(node, &done); } if (done) { - info("Updating Baseband completed.\n"); - plist_t provisioning = plist_access_path(msg, 2, "Output", "provisioning"); + logger(LL_INFO, "Updating Baseband completed.\n"); + plist_t provisioning = plist_access_path(message, 2, "Output", "provisioning"); if (provisioning && plist_get_node_type(provisioning) == PLIST_DICT) { char* sval = NULL; node = plist_dict_get_item(provisioning, "IMEI"); if (node && plist_get_node_type(node) == PLIST_STRING) { plist_get_string_val(node, &sval); - info("Provisioning:\n"); - info("IMEI:%s\n", sval); + logger(LL_INFO, "Provisioning:\n"); + logger(LL_INFO, "IMEI:%s\n", sval); free(sval); sval = NULL; } } } else { - info("Updating Baseband in progress...\n"); + logger(LL_INFO, "Updating Baseband in progress...\n"); } result = 0; return result; } +struct _restore_asr_progress_data { + struct idevicerestore_client_t* client; + uint32_t tag; +}; + static void restore_asr_progress_cb(double progress, void* userdata) { struct idevicerestore_client_t* client = (struct idevicerestore_client_t*)userdata; @@ -898,17 +1016,22 @@ static void restore_asr_progress_cb(double progress, void* userdata) } } -int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device, plist_t build_identity) +int restore_send_filesystem(struct idevicerestore_client_t* client, plist_t message) { asr_client_t asr = NULL; - - info("About to send filesystem...\n"); - ipsw_archive_t ipsw_dummy = NULL; ipsw_file_handle_t file = NULL; char* fsname = NULL; - if (build_identity_get_component_path(build_identity, "OS", &fsname) < 0) { - error("ERROR: Unable to get path for filesystem component\n"); + + if (!client || !client->restore || !client->restore->build_identity || !client->restore->device) { + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + + logger(LL_INFO, "About to send filesystem...\n"); + + if (build_identity_get_component_path(client->restore->build_identity, "OS", &fsname) < 0) { + logger(LL_ERROR, "Unable to get path for filesystem component\n"); return -1; } if (client->filesystem) { @@ -922,57 +1045,63 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t de file = ipsw_file_open(client->ipsw, fsname); } if (!file) { - error("ERROR: Unable to open '%s' in ipsw\n", fsname); + logger(LL_ERROR, "Unable to open '%s' in ipsw\n", fsname); free(fsname); } - if (asr_open_with_timeout(device, &asr) < 0) { + uint16_t asr_port = (uint16_t)plist_dict_get_uint(message, "DataPort"); + if (asr_port == 0) { + asr_port = ASR_DEFAULT_PORT; + } + if (asr_open_with_timeout(client->restore->device, &asr, asr_port) < 0) { ipsw_file_close(file); ipsw_close(ipsw_dummy); - error("ERROR: Unable to connect to ASR\n"); + logger(LL_ERROR, "Unable to connect to ASR\n"); return -1; } - info("Connected to ASR\n"); - - asr_set_progress_callback(asr, restore_asr_progress_cb, (void*)client); + logger(LL_INFO, "Connected to ASR\n"); // this step sends requested chunks of data from various offsets to asr so // it can validate the filesystem before installing it - info("Validating the filesystem\n"); + logger(LL_INFO, "Validating the filesystem\n"); if (asr_perform_validation(asr, file) < 0) { ipsw_file_close(file); ipsw_close(ipsw_dummy); - error("ERROR: ASR was unable to validate the filesystem\n"); + logger(LL_ERROR, "ASR was unable to validate the filesystem\n"); asr_free(asr); return -1; } - info("Filesystem validated\n"); + logger(LL_INFO, "Filesystem validated\n"); + + if (asr_port == ASR_DEFAULT_PORT) { + asr_set_progress_callback(asr, restore_asr_progress_cb, client); + } // once the target filesystem has been validated, ASR then requests the // entire filesystem to be sent. - info("Sending filesystem now...\n"); + logger(LL_INFO, "Sending filesystem now...\n"); if (asr_send_payload(asr, file) < 0) { ipsw_file_close(file); ipsw_close(ipsw_dummy); - error("ERROR: Unable to send payload to ASR\n"); + logger(LL_ERROR, "Unable to send payload to ASR\n"); asr_free(asr); return -1; } ipsw_file_close(file); ipsw_close(ipsw_dummy); - info("Done sending filesystem\n"); + logger(LL_INFO, "Done sending filesystem\n"); asr_free(asr); return 0; } -int restore_send_recovery_os_root_ticket(restored_client_t restore, struct idevicerestore_client_t* client) +int restore_send_recovery_os_root_ticket(struct idevicerestore_client_t* client, plist_t message) { restored_error_t restore_error; plist_t dict; - info("About to send RecoveryOSRootTicket...\n"); + logger(LL_INFO, "About to send RecoveryOSRootTicket...\n"); if (client->root_ticket) { dict = plist_new_dict(); @@ -982,18 +1111,18 @@ int restore_send_recovery_os_root_ticket(restored_client_t restore, struct idevi unsigned int len = 0; if (!client->tss_recoveryos_root_ticket && !(client->flags & FLAG_CUSTOM)) { - error("ERROR: Cannot send RootTicket without TSS\n"); + logger(LL_ERROR, "Cannot send RootTicket without TSS\n"); return -1; } if (client->image4supported) { if (tss_response_get_ap_img4_ticket(client->tss_recoveryos_root_ticket, &data, &len) < 0) { - error("ERROR: Unable to get ApImg4Ticket from TSS\n"); + logger(LL_ERROR, "Unable to get ApImg4Ticket from TSS\n"); return -1; } } else { if (!(client->flags & FLAG_CUSTOM) && (tss_response_get_ap_ticket(client->tss, &data, &len) < 0)) { - error("ERROR: Unable to get ticket from TSS\n"); + logger(LL_ERROR, "Unable to get ticket from TSS\n"); return -1; } } @@ -1002,30 +1131,37 @@ int restore_send_recovery_os_root_ticket(restored_client_t restore, struct idevi if (data && (len > 0)) { plist_dict_set_item(dict, "RootTicketData", plist_new_data((char*)data, len)); } else { - info("NOTE: not sending RootTicketData (no data present)\n"); + logger(LL_NOTICE, "Not sending RootTicketData (no data present)\n"); } free(data); } - info("Sending RecoveryOSRootTicket now...\n"); - restore_error = restored_send(restore, dict); + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); + return -1; + } + + logger(LL_INFO, "Sending RecoveryOSRootTicket now...\n"); + restore_error = _restore_service_send(service, dict, 0); plist_free(dict); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send RootTicket (%d)\n", restore_error); + logger(LL_ERROR, "Unable to send RootTicket (%d)\n", restore_error); return -1; } - info("Done sending RecoveryOS RootTicket\n"); + logger(LL_INFO, "Done sending RecoveryOS RootTicket\n"); return 0; } -int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_client_t* client) +int restore_send_root_ticket(struct idevicerestore_client_t* client, plist_t message) { restored_error_t restore_error; plist_t dict; - info("About to send RootTicket...\n"); + logger(LL_INFO, "About to send RootTicket...\n"); if (client->root_ticket) { dict = plist_new_dict(); @@ -1035,18 +1171,18 @@ int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_cl unsigned int len = 0; if (!client->tss && !(client->flags & FLAG_CUSTOM)) { - error("ERROR: Cannot send RootTicket without TSS\n"); + logger(LL_ERROR, "Cannot send RootTicket without TSS\n"); return -1; } if (client->image4supported) { if (tss_response_get_ap_img4_ticket(client->tss, &data, &len) < 0) { - error("ERROR: Unable to get ApImg4Ticket from TSS\n"); + logger(LL_ERROR, "Unable to get ApImg4Ticket from TSS\n"); return -1; } } else { if (!(client->flags & FLAG_CUSTOM) && (tss_response_get_ap_ticket(client->tss, &data, &len) < 0)) { - error("ERROR: Unable to get ticket from TSS\n"); + logger(LL_ERROR, "Unable to get ticket from TSS\n"); return -1; } } @@ -1055,88 +1191,345 @@ int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_cl if (data && (len > 0)) { plist_dict_set_item(dict, "RootTicketData", plist_new_data((char*)data, len)); } else { - info("NOTE: not sending RootTicketData (no data present)\n"); + logger(LL_INFO, "Not sending RootTicketData (no data present)\n"); } free(data); } - info("Sending RootTicket now...\n"); - restore_error = restored_send(restore, dict); + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); + return -1; + } + + logger(LL_INFO, "Sending RootTicket now...\n"); + restore_error = _restore_service_send(service, dict, 0); plist_free(dict); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send RootTicket (%d)\n", restore_error); + logger(LL_ERROR, "Unable to send RootTicket (%d)\n", restore_error); return -1; } - info("Done sending RootTicket\n"); + logger(LL_INFO, "Done sending RootTicket\n"); + return 0; +} + +typedef struct { + int length; + char* content; +} query_response; + +static size_t _curl_write_callback(char* data, size_t size, size_t nmemb, query_response* response) +{ + size_t total = size * nmemb; + if (total != 0) { + response->content = realloc(response->content, response->length + total + 1); + memcpy(response->content + response->length, data, total); + response->content[response->length + total] = '\0'; + response->length += total; + } + + return total; +} + +static size_t _curl_header_callback(char* buffer, size_t size, size_t nitems, void* userdata) +{ + plist_t header_dict = (plist_t)userdata; + size_t len = nitems*size; + char* key = NULL; + char* val = NULL; + size_t i = 0; + while (i < len) { + if (buffer[i] == ':') { + key = malloc(i+1); + strncpy(key, buffer, i); + key[i] = '\0'; + i++; + while (i < len && (buffer[i] == ' ' || buffer[i] == '\t')) i++; + val = malloc(len-i+1); + strncpy(val, buffer+i, len-i); + val[len-i] = '\0'; + break; + } + i++; + } + if (key && val) { + plist_dict_set_item(header_dict, key, plist_new_string(val)); + } + free(key); + free(val); + return len; +} + +int restore_send_url_asset(struct idevicerestore_client_t* client, plist_t message) +{ + plist_t arguments = plist_dict_get_item(message, "Arguments"); + if (!PLIST_IS_DICT(arguments)) { + logger(LL_ERROR, "%s: Unexpected arguments\n", __func__); + logger_dump_plist(LL_VERBOSE, message, 1); + return -1; + } + + const char* request_method = plist_get_string_ptr(plist_dict_get_item(arguments, "RequestMethod"), NULL); + if (!request_method) { + logger(LL_ERROR, "%s: Unable to extract RequestMethod from Arguments\n", __func__); + return -1; + } + if (strcmp(request_method, "GET")) { + logger(LL_ERROR, "%s: Unexpected RequestMethod '%s' in message\n", __func__, request_method); + return -1; + } + const char* request_url = plist_get_string_ptr(plist_dict_get_item(arguments, "RequestURL"), NULL); + if (!request_url) { + logger(LL_ERROR, "%s: Unable to extract RequestURL from Arguments\n", __func__); + return -1; + } + logger(LL_INFO, "Requesting URLAsset from %s\n", request_url); + + char curl_error_message[CURL_ERROR_SIZE]; + CURL* handle = curl_easy_init(); + /* disable SSL verification to allow download from untrusted https locations */ + curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); + + query_response* response = malloc(sizeof(query_response)); + if (response == NULL) { + logger(LL_ERROR, "%s: Unable to allocate sufficient memory\n", __func__); + return -1; + } + + response->length = 0; + response->content = malloc(1); + response->content[0] = '\0'; + + curl_easy_setopt(handle, CURLOPT_HTTPGET, 1L); + curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, curl_error_message); + curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, (curl_write_callback)&_curl_write_callback); + curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, &_curl_header_callback); + plist_t response_headers = plist_new_dict(); + curl_easy_setopt(handle, CURLOPT_HEADERDATA, response_headers); + curl_easy_setopt(handle, CURLOPT_WRITEDATA, response); + if (client->debug_level > 0) { + curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L); + } + curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1); + curl_easy_setopt(handle, CURLOPT_URL, request_url); + curl_easy_perform(handle); + + long http_response = 0; + curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &http_response); + + curl_easy_cleanup(handle); + + plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "ResponseBody", plist_new_data(response->content, response->length)); + plist_dict_set_item(dict, "ResponseBodyDone", plist_new_bool(1)); + plist_dict_set_item(dict, "ResponseHeaders", response_headers); + plist_dict_set_item(dict, "ResponseStatus", plist_new_uint(http_response)); + + free(response); + + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); + return -1; + } + + _restore_service_send(service, dict, PLIST_FORMAT_BINARY); + _restore_service_free(service); + + return 0; +} + +int restore_send_streamed_image_decryption_key(struct idevicerestore_client_t* client, plist_t message) +{ + logger(LL_DEBUG, "%s\n", __func__); + plist_t arguments = plist_dict_get_item(message, "Arguments"); + if (!PLIST_IS_DICT(arguments)) { + logger(LL_ERROR, "%s: Unexpected arguments\n", __func__); + logger_dump_plist(LL_VERBOSE, arguments, 1); + return -1; + } + + const char* request_method = plist_get_string_ptr(plist_dict_get_item(arguments, "RequestMethod"), NULL); + if (!request_method) { + logger(LL_ERROR, "%s: Unable to extract RequestMethod from Arguments\n", __func__); + return -1; + } + if (strcmp(request_method, "POST")) { + logger(LL_ERROR, "%s: Unexpected RequestMethod '%s' in message\n", __func__, request_method); + return -1; + } + const char* request_url = plist_get_string_ptr(plist_dict_get_item(arguments, "RequestURL"), NULL); + if (!request_url) { + logger(LL_ERROR, "%s: Unable to extract RequestURL from Arguments\n", __func__); + return -1; + } + + struct curl_slist* header = NULL; + + plist_t headers = plist_dict_get_item(arguments, "RequestAdditionalHeaders"); + if (!headers) { + logger(LL_ERROR, "%s: Missing 'RequestAdditionalHeaders'\n", __func__); + return -1; + } + + uint64_t request_body_size = 0; + const char* request_body = plist_get_data_ptr(plist_dict_get_item(arguments, "RequestBody"), &request_body_size); + if (!request_body) { + logger(LL_ERROR, "%s: Missing 'RequestBody'\n", __func__); + return -1; + } + + logger(LL_INFO, "Requesting image decryption key from %s\n", request_url); + + char curl_error_message[CURL_ERROR_SIZE]; + char header_tmp[1024]; + plist_dict_iter iter = NULL; + plist_dict_new_iter(headers, &iter); + plist_t node = NULL; + do { + char *key = NULL; + plist_dict_next_item(headers, iter, &key, &node); + if (!node) break; + snprintf(header_tmp, sizeof(header_tmp), "%s: %s", key, plist_get_string_ptr(node, NULL)); + curl_slist_append(header, header_tmp); + } while (node); + plist_mem_free(iter); + + CURL* handle = curl_easy_init(); + /* disable SSL verification to allow download from untrusted https locations */ + curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); + + query_response* response = malloc(sizeof(query_response)); + if (response == NULL) { + logger(LL_ERROR, "%s: Unable to allocate sufficient memory\n", __func__); + return -1; + } + + response->length = 0; + response->content = malloc(1); + response->content[0] = '\0'; + + curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, curl_error_message); + curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, (curl_write_callback)&_curl_write_callback); + curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, &_curl_header_callback); + plist_t response_headers = plist_new_dict(); + curl_easy_setopt(handle, CURLOPT_HEADERDATA, response_headers); + curl_easy_setopt(handle, CURLOPT_WRITEDATA, response); + curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header); + curl_easy_setopt(handle, CURLOPT_POSTFIELDS, request_body); + curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, (long)request_body_size); + if (client->debug_level > 0) { + curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L); + } + curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1); + curl_easy_setopt(handle, CURLOPT_URL, request_url); + curl_easy_perform(handle); + curl_slist_free_all(header); + + long http_response = 0; + curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &http_response); + + curl_easy_cleanup(handle); + + plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "ResponseBody", plist_new_data(response->content, response->length)); + plist_dict_set_item(dict, "ResponseBodyDone", plist_new_bool(1)); + plist_dict_set_item(dict, "ResponseHeaders", response_headers); + plist_dict_set_item(dict, "ResponseStatus", plist_new_uint(http_response)); + + free(response); + + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); + return -1; + } + + _restore_service_send(service, dict, PLIST_FORMAT_BINARY); + _restore_service_free(service); + return 0; } -int restore_send_component(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, const char* component, const char* component_name) +int restore_send_component(struct idevicerestore_client_t* client, plist_t message, const char* component, const char* component_name) { - unsigned int size = 0; - unsigned char* data = NULL; + size_t size = 0; + void* data = NULL; char* path = NULL; plist_t blob = NULL; plist_t dict = NULL; restored_error_t restore_error = RESTORE_E_SUCCESS; + if (!client || !client->restore || !client->restore->build_identity) { + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + if (component_name == NULL) { component_name = component; } - info("About to send %s...\n", component_name); + logger(LL_INFO, "About to send %s...\n", component_name); if (client->tss) { if (tss_response_get_path_by_entry(client->tss, component, &path) < 0) { - debug("NOTE: No path for component %s in TSS, will fetch from build identity\n", component); + logger(LL_DEBUG, "No path for component %s in TSS, will fetch from build identity\n", component); } } if (!path) { - if (build_identity_get_component_path(build_identity, component, &path) < 0) { - error("ERROR: Unable to find %s path from build identity\n", component); + if (build_identity_get_component_path(client->restore->build_identity, component, &path) < 0) { + logger(LL_ERROR, "Unable to find %s path from build identity\n", component); return -1; } } - unsigned char* component_data = NULL; - unsigned int component_size = 0; + void* component_data = NULL; + size_t component_size = 0; int ret = extract_component(client->ipsw, path, &component_data, &component_size); free(path); path = NULL; if (ret < 0) { - error("ERROR: Unable to extract component %s\n", component); + logger(LL_ERROR, "Unable to extract component %s\n", component); return -1; } - ret = personalize_component(component, component_data, component_size, client->tss, &data, &size); + ret = personalize_component(client, component, component_data, component_size, client->tss, &data, &size); free(component_data); component_data = NULL; if (ret < 0) { - error("ERROR: Unable to get personalized component %s\n", component); + logger(LL_ERROR, "Unable to get personalized component %s\n", component); return -1; } dict = plist_new_dict(); blob = plist_new_data((char*)data, size); char compkeyname[256]; - sprintf(compkeyname, "%sFile", component_name); + snprintf(compkeyname, sizeof(compkeyname), "%sFile", component_name); plist_dict_set_item(dict, compkeyname, blob); free(data); - info("Sending %s now...\n", component_name); - restore_error = restored_send(restore, dict); + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); + return -1; + } + + logger(LL_INFO, "Sending %s now...\n", component_name); + restore_error = _restore_service_send(service, dict, 0); plist_free(dict); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send component %s data\n", component_name); + logger(LL_ERROR, "Unable to send component %s data\n", component_name); return -1; } - info("Done sending %s\n", component_name); + logger(LL_INFO, "Done sending %s\n", component_name); return 0; } -int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message) +int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) { char* llb_path = NULL; char* llb_filename = NULL; @@ -1144,19 +1537,24 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* char* restore_sep_path = NULL; char firmware_path[PATH_MAX - 9]; char manifest_file[PATH_MAX]; - unsigned int manifest_size = 0; - unsigned char* manifest_data = NULL; + size_t manifest_size = 0; + void* manifest_data = NULL; char firmware_filename[PATH_MAX]; - unsigned int llb_size = 0; - unsigned char* llb_data = NULL; + size_t llb_size = 0; + void* llb_data = NULL; plist_t dict = NULL; - unsigned int nor_size = 0; - unsigned char* nor_data = NULL; + size_t nor_size = 0; + void* nor_data = NULL; plist_t norimage = NULL; plist_t firmware_files = NULL; int flash_version_1 = 0; - info("About to send NORData...\n"); + if (!client || !client->restore || !client->restore->build_identity) { + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + + logger(LL_INFO, "About to send NORData...\n"); plist_t arguments = plist_dict_get_item(message, "Arguments"); if (arguments && plist_get_node_type(arguments) == PLIST_DICT) { @@ -1165,26 +1563,26 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* if (client->tss) { if (tss_response_get_path_by_entry(client->tss, "LLB", &llb_path) < 0) { - debug("NOTE: Could not get LLB path from TSS data, will fetch from build identity\n"); + logger(LL_DEBUG, "Could not get LLB path from TSS data, will fetch from build identity\n"); } } if (llb_path == NULL) { - if (build_identity_get_component_path(build_identity, "LLB", &llb_path) < 0) { - error("ERROR: Unable to get component path for LLB\n"); + if (build_identity_get_component_path(client->restore->build_identity, "LLB", &llb_path) < 0) { + logger(LL_ERROR, "Unable to get component path for LLB\n"); return -1; } } llb_filename = strstr(llb_path, "LLB"); if (llb_filename == NULL) { - error("ERROR: Unable to extract firmware path from LLB filename\n"); + logger(LL_ERROR, "Unable to extract firmware path from LLB filename\n"); free(llb_path); return -1; } memset(firmware_path, '\0', sizeof(firmware_path)); memcpy(firmware_path, llb_path, (llb_filename - 1) - llb_path); - info("Found firmware path %s\n", firmware_path); + logger(LL_INFO, "Found firmware path %s\n", firmware_path); memset(manifest_file, '\0', sizeof(manifest_file)); snprintf(manifest_file, sizeof(manifest_file), "%s/manifest", firmware_path); @@ -1194,7 +1592,7 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* ipsw_extract_to_memory(client->ipsw, manifest_file, &manifest_data, &manifest_size); } if (manifest_data && manifest_size > 0) { - info("Getting firmware manifest from %s\n", manifest_file); + logger(LL_INFO, "Getting firmware manifest from %s\n", manifest_file); char *manifest_p = (char*)manifest_data; char *filename = NULL; while ((filename = strsep(&manifest_p, "\r\n")) != NULL) { @@ -1207,9 +1605,9 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* } free(manifest_data); } else { - info("Getting firmware manifest from build identity\n"); + logger(LL_INFO, "Getting firmware manifest from build identity\n"); plist_dict_iter iter = NULL; - plist_t build_id_manifest = plist_dict_get_item(build_identity, "Manifest"); + plist_t build_id_manifest = plist_dict_get_item(client->restore->build_identity, "Manifest"); if (build_id_manifest) { plist_dict_new_iter(build_id_manifest, &iter); } @@ -1255,31 +1653,31 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* } if (plist_dict_get_size(firmware_files) == 0) { - error("ERROR: Unable to get list of firmware files.\n"); + logger(LL_ERROR, "Unable to get list of firmware files.\n"); return -1; } const char* component = "LLB"; - unsigned char* component_data = NULL; - unsigned int component_size = 0; + void* component_data = NULL; + size_t component_size = 0; int ret = extract_component(client->ipsw, llb_path, &component_data, &component_size); free(llb_path); if (ret < 0) { - error("ERROR: Unable to extract component: %s\n", component); + logger(LL_ERROR, "Unable to extract component: %s\n", component); return -1; } - ret = personalize_component(component, component_data, component_size, client->tss, &llb_data, &llb_size); + ret = personalize_component(client, component, component_data, component_size, client->tss, &llb_data, &llb_size); free(component_data); component_data = NULL; component_size = 0; if (ret < 0) { - error("ERROR: Unable to get personalized component: %s\n", component); + logger(LL_ERROR, "Unable to get personalized component: %s\n", component); return -1; } dict = plist_new_dict(); - plist_dict_set_item(dict, "LlbImageData", plist_new_data((char*)llb_data, (uint64_t) llb_size)); + plist_dict_set_item(dict, "LlbImageData", plist_new_data((char*)llb_data, llb_size)); free(llb_data); if (flash_version_1) { @@ -1314,24 +1712,24 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* } component_data = NULL; - unsigned int component_size = 0; + component_size = 0; if (extract_component(client->ipsw, comppath, &component_data, &component_size) < 0) { free(iter); free(comp); free(comppath); plist_free(firmware_files); - error("ERROR: Unable to extract component: %s\n", component); + logger(LL_ERROR, "Unable to extract component: %s\n", component); return -1; } - if (personalize_component(component, component_data, component_size, client->tss, &nor_data, &nor_size) < 0) { + if (personalize_component(client, component, component_data, component_size, client->tss, &nor_data, &nor_size) < 0) { free(iter); free(comp); free(comppath); free(component_data); plist_free(firmware_files); - error("ERROR: Unable to get personalized component: %s\n", component); + logger(LL_ERROR, "Unable to get personalized component: %s\n", component); return -1; } free(component_data); @@ -1339,13 +1737,13 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* component_size = 0; if (flash_version_1) { - plist_dict_set_item(norimage, component, plist_new_data((char*)nor_data, (uint64_t)nor_size)); + plist_dict_set_item(norimage, component, plist_new_data((char*)nor_data, nor_size)); } else { /* make sure iBoot is the first entry in the array */ if (!strncmp("iBoot", component, 5)) { - plist_array_insert_item(norimage, plist_new_data((char*)nor_data, (uint64_t)nor_size), 0); + plist_array_insert_item(norimage, plist_new_data((char*)nor_data, nor_size), 0); } else { - plist_array_append_item(norimage, plist_new_data((char*)nor_data, (uint64_t)nor_size)); + plist_array_append_item(norimage, plist_new_data((char*)nor_data, nor_size)); } } @@ -1359,100 +1757,107 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* plist_free(firmware_files); plist_dict_set_item(dict, "NorImageData", norimage); - unsigned char* personalized_data = NULL; - unsigned int personalized_size = 0; + void* personalized_data = NULL; + size_t personalized_size = 0; - if (build_identity_has_component(build_identity, "RestoreSEP") && - build_identity_get_component_path(build_identity, "RestoreSEP", &restore_sep_path) == 0) { + if (build_identity_has_component(client->restore->build_identity, "RestoreSEP") && + build_identity_get_component_path(client->restore->build_identity, "RestoreSEP", &restore_sep_path) == 0) { component = "RestoreSEP"; ret = extract_component(client->ipsw, restore_sep_path, &component_data, &component_size); free(restore_sep_path); if (ret < 0) { - error("ERROR: Unable to extract component: %s\n", component); + logger(LL_ERROR, "Unable to extract component: %s\n", component); return -1; } - ret = personalize_component(component, component_data, component_size, client->tss, &personalized_data, &personalized_size); + ret = personalize_component(client, component, component_data, component_size, client->tss, &personalized_data, &personalized_size); free(component_data); component_data = NULL; component_size = 0; if (ret < 0) { - error("ERROR: Unable to get personalized component: %s\n", component); + logger(LL_ERROR, "Unable to get personalized component: %s\n", component); return -1; } - plist_dict_set_item(dict, "RestoreSEPImageData", plist_new_data((char*)personalized_data, (uint64_t) personalized_size)); + plist_dict_set_item(dict, "RestoreSEPImageData", plist_new_data((char*)personalized_data, personalized_size)); free(personalized_data); personalized_data = NULL; personalized_size = 0; } - if (build_identity_has_component(build_identity, "SEP") && - build_identity_get_component_path(build_identity, "SEP", &sep_path) == 0) { + if (build_identity_has_component(client->restore->build_identity, "SEP") && + build_identity_get_component_path(client->restore->build_identity, "SEP", &sep_path) == 0) { component = "SEP"; ret = extract_component(client->ipsw, sep_path, &component_data, &component_size); free(sep_path); if (ret < 0) { - error("ERROR: Unable to extract component: %s\n", component); + logger(LL_ERROR, "Unable to extract component: %s\n", component); return -1; } - ret = personalize_component(component, component_data, component_size, client->tss, &personalized_data, &personalized_size); + ret = personalize_component(client, component, component_data, component_size, client->tss, &personalized_data, &personalized_size); free(component_data); component_data = NULL; component_size = 0; if (ret < 0) { - error("ERROR: Unable to get personalized component: %s\n", component); + logger(LL_ERROR, "Unable to get personalized component: %s\n", component); return -1; } - plist_dict_set_item(dict, "SEPImageData", plist_new_data((char*)personalized_data, (uint64_t) personalized_size)); + plist_dict_set_item(dict, "SEPImageData", plist_new_data((char*)personalized_data, personalized_size)); free(personalized_data); personalized_data = NULL; personalized_size = 0; } - if (build_identity_has_component(build_identity, "SepStage1") && - build_identity_get_component_path(build_identity, "SepStage1", &sep_path) == 0) { + if (build_identity_has_component(client->restore->build_identity, "SepStage1") && + build_identity_get_component_path(client->restore->build_identity, "SepStage1", &sep_path) == 0) { component = "SepStage1"; ret = extract_component(client->ipsw, sep_path, &component_data, &component_size); free(sep_path); if (ret < 0) { - error("ERROR: Unable to extract component: %s\n", component); + logger(LL_ERROR, "Unable to extract component: %s\n", component); return -1; } - ret = personalize_component(component, component_data, component_size, client->tss, &personalized_data, &personalized_size); + ret = personalize_component(client, component, component_data, component_size, client->tss, &personalized_data, &personalized_size); free(component_data); component_data = NULL; component_size = 0; if (ret < 0) { - error("ERROR: Unable to get personalized component: %s\n", component); + logger(LL_ERROR, "Unable to get personalized component: %s\n", component); return -1; } - plist_dict_set_item(dict, "SEPPatchImageData", plist_new_data((char*)personalized_data, (uint64_t) personalized_size)); + plist_dict_set_item(dict, "SEPPatchImageData", plist_new_data((char*)personalized_data, personalized_size)); free(personalized_data); personalized_data = NULL; personalized_size = 0; } - if (idevicerestore_debug) - debug_plist(dict); + if (client->debug_level > 1) + logger_dump_plist(LL_DEBUG, dict, 0); - info("Sending NORData now...\n"); - if (restored_send(restore, dict) != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send NORData\n"); - plist_free(dict); + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); return -1; } - info("Done sending NORData\n"); + logger(LL_INFO, "Sending NORData now...\n"); + restored_error_t restore_error = _restore_service_send(service, dict, 0); plist_free(dict); + _restore_service_free(service); + if (restore_error != RESTORE_E_SUCCESS) { + logger(LL_ERROR, "Unable to send NORData\n"); + return -1; + } + + logger(LL_INFO, "Done sending NORData\n"); return 0; } -static const char* restore_get_bbfw_fn_for_element(const char* elem) +static const char* restore_get_bbfw_fn_for_element(const char* elem, uint32_t bb_chip_id) { struct bbfw_fn_elem_t { const char* element; @@ -1483,34 +1888,48 @@ static const char* restore_get_bbfw_fn_for_element(const char* elem) { NULL, NULL } }; + struct bbfw_fn_elem_t bbfw_fn_elem_mav25[] = { + // Mav25 Firmware files + { "Misc", "multi_image.mbn" }, + { "RestoreSBL1", "restorexbl_sc.elf" }, + { "SBL1", "xbl_sc.elf" }, + { "TME", "signed_firmware_soc_view.elf" }, + { NULL, NULL } + }; + + struct bbfw_fn_elem_t* bbfw_fn_elems = (struct bbfw_fn_elem_t*)bbfw_fn_elem; + if (bb_chip_id == 0x1F30E1) { + bbfw_fn_elems = (struct bbfw_fn_elem_t*)bbfw_fn_elem_mav25; + } + int i; - for (i = 0; bbfw_fn_elem[i].element != NULL; i++) { - if (strcmp(bbfw_fn_elem[i].element, elem) == 0) { - return bbfw_fn_elem[i].fn; + for (i = 0; bbfw_fn_elems[i].element != NULL; i++) { + if (strcmp(bbfw_fn_elems[i].element, elem) == 0) { + return bbfw_fn_elems[i].fn; } } return NULL; } -static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned char* bb_nonce) +static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned char* bb_nonce, uint32_t bb_chip_id) { int res = -1; // check for BBTicket in result plist_t bbticket = plist_dict_get_item(bbtss, "BBTicket"); if (!bbticket || plist_get_node_type(bbticket) != PLIST_DATA) { - error("ERROR: Could not find BBTicket in Baseband TSS response\n"); + logger(LL_ERROR, "Could not find BBTicket in Baseband TSS response\n"); return -1; } plist_t bbfw_dict = plist_dict_get_item(bbtss, "BasebandFirmware"); if (!bbfw_dict || plist_get_node_type(bbfw_dict) != PLIST_DICT) { - error("ERROR: Could not find BasebandFirmware Dictionary node in Baseband TSS response\n"); + logger(LL_ERROR, "Could not find BasebandFirmware Dictionary node in Baseband TSS response\n"); return -1; } unsigned char* buffer = NULL; - unsigned char* blob = NULL; + const unsigned char* blob = NULL; unsigned char* fdata = NULL; uint64_t fsize = 0; uint64_t blob_size = 0; @@ -1520,19 +1939,18 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned struct zip_file* zfile = NULL; struct zip* za = NULL; struct zip_source* zs = NULL; - mbn_file* mbn = NULL; fls_file* fls = NULL; za = zip_open(bbfwtmp, 0, &zerr); if (!za) { - error("ERROR: Could not open ZIP archive '%s': %d\n", bbfwtmp, zerr); + logger(LL_ERROR, "Could not open ZIP archive '%s': %d\n", bbfwtmp, zerr); goto leave; } plist_dict_iter iter = NULL; plist_dict_new_iter(bbfw_dict, &iter); if (!iter) { - error("ERROR: Could not create dict iter for BasebandFirmware Dictionary\n"); + logger(LL_ERROR, "Could not create dict iter for BasebandFirmware Dictionary\n"); return -1; } @@ -1548,9 +1966,9 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned if (node && (strcmp(key + (strlen(key) - 5), "-Blob") == 0) && (plist_get_node_type(node) == PLIST_DATA)) { char *ptr = strchr(key, '-'); *ptr = '\0'; - const char* signfn = restore_get_bbfw_fn_for_element(key); + const char* signfn = restore_get_bbfw_fn_for_element(key, bb_chip_id); if (!signfn) { - error("ERROR: can't match element name '%s' to baseband firmware file name.\n", key); + logger(LL_ERROR, "can't match element name '%s' to baseband firmware file name.\n", key); goto leave; } char* ext = strrchr(signfn, '.'); @@ -1560,30 +1978,30 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned zindex = zip_name_locate(za, signfn, 0); if (zindex < 0) { - error("ERROR: can't locate '%s' in '%s'\n", signfn, bbfwtmp); + logger(LL_ERROR, "can't locate '%s' in '%s'\n", signfn, bbfwtmp); goto leave; } zip_stat_init(&zstat); if (zip_stat_index(za, zindex, 0, &zstat) != 0) { - error("ERROR: zip_stat_index failed for index %" PRIi64 "\n", zindex); + logger(LL_ERROR, "zip_stat_index failed for index %" PRIi64 "\n", zindex); goto leave; } zfile = zip_fopen_index(za, zindex, 0); if (zfile == NULL) { - error("ERROR: zip_fopen_index failed for index %" PRIi64 "\n", zindex); + logger(LL_ERROR, "zip_fopen_index failed for index %" PRIi64 "\n", zindex); goto leave; } buffer = (unsigned char*) malloc(zstat.size + 1); if (buffer == NULL) { - error("ERROR: Out of memory\n"); + logger(LL_ERROR, "Out of memory\n"); goto leave; } if (zip_fread(zfile, buffer, zstat.size) != zstat.size) { - error("ERROR: zip_fread: failed\n"); + logger(LL_ERROR, "zip_fread: failed\n"); goto leave; } buffer[zstat.size] = '\0'; @@ -1594,66 +2012,60 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned if (is_fls) { fls = fls_parse(buffer, zstat.size); if (!fls) { - error("ERROR: could not parse fls file\n"); - goto leave; - } - } else { - mbn = mbn_parse(buffer, zstat.size); - if (!mbn) { - error("ERROR: could not parse mbn file\n"); + logger(LL_ERROR, "could not parse fls file\n"); goto leave; } } - free(buffer); - buffer = NULL; - blob = NULL; blob_size = 0; - plist_get_data_val(node, (char**)&blob, &blob_size); + blob = (const unsigned char*)plist_get_data_ptr(node, &blob_size); if (!blob) { - error("ERROR: could not get %s-Blob data\n", key); + logger(LL_ERROR, "could not get %s-Blob data\n", key); goto leave; } + logger(LL_VERBOSE, "Stitching %s\n", signfn); if (is_fls) { - if (fls_update_sig_blob(fls, blob, (unsigned int)blob_size) != 0) { - error("ERROR: could not sign %s\n", signfn); + if (fls_update_sig_blob(fls, blob, (size_t)blob_size) != 0) { + logger(LL_ERROR, "Could not stitch %s\n", signfn); goto leave; } - } else { - if (mbn_update_sig_blob(mbn, blob, (unsigned int)blob_size) != 0) { - error("ERROR: could not sign %s\n", signfn); + fsize = fls->size; + fdata = (unsigned char*)malloc(fsize); + if (fdata == NULL) { + logger(LL_ERROR, "out of memory\n"); goto leave; } - } - free(blob); - blob = NULL; - - fsize = (is_fls ? fls->size : mbn->size); - fdata = (unsigned char*)malloc(fsize); - if (fdata == NULL) { - error("ERROR: out of memory\n"); - goto leave; - } - if (is_fls) { memcpy(fdata, fls->data, fsize); fls_free(fls); fls = NULL; + } else if (bb_chip_id == 0x1F30E1) { // Mav25 - Qualcomm Snapdragon X80 5G Modem + fdata = mbn_mav25_stitch(buffer, zstat.size, blob, (size_t)blob_size); + fsize = zstat.size; + if (!fdata) { + logger(LL_ERROR, "Could not stitch %s\n", signfn); + goto leave; + } } else { - memcpy(fdata, mbn->data, fsize); - mbn_free(mbn); - mbn = NULL; + fdata = mbn_stitch(buffer, zstat.size, blob, (size_t)blob_size); + fsize = zstat.size; + if (!fdata) { + logger(LL_ERROR, "Could not stitch %s\n", signfn); + goto leave; + } } + free(buffer); + buffer = NULL; zs = zip_source_buffer(za, fdata, fsize, 1); if (!zs) { - error("ERROR: out of memory\n"); + logger(LL_ERROR, "out of memory\n"); free(fdata); goto leave; } if (zip_file_replace(za, zindex, zs, 0) == -1) { - error("ERROR: could not update signed '%s' in archive\n", signfn); + logger(LL_ERROR, "Could not update signed '%s' in archive\n", signfn); goto leave; } @@ -1682,8 +2094,8 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned } } // check for anything but .mbn and .fls if bb_nonce is set - if (bb_nonce && !keep) { - const char* fn = zip_get_name(za, i, 0); + const char* fn = zip_get_name(za, i, 0); + if (!keep) { if (fn) { char* ext = strrchr(fn, '.'); if (ext && (!strcmp(ext, ".fls") || !strcmp(ext, ".mbn") || !strcmp(ext, ".elf") || !strcmp(ext, ".bin"))) { @@ -1692,39 +2104,42 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned } } if (!keep) { + logger(LL_DEBUG, "%s: removing %s from bbfw\n", __func__, fn); zip_delete(za, i); + } else { + logger(LL_DEBUG, "%s: keeping %s in bbfw\n", __func__, fn); } } - if (bb_nonce) { + if (bbticket) { if (is_fls) { // add BBTicket to file ebl.fls zindex = zip_name_locate(za, "ebl.fls", 0); if (zindex < 0) { - error("ERROR: can't locate 'ebl.fls' in '%s'\n", bbfwtmp); + logger(LL_ERROR, "can't locate 'ebl.fls' in '%s'\n", bbfwtmp); goto leave; } zip_stat_init(&zstat); if (zip_stat_index(za, zindex, 0, &zstat) != 0) { - error("ERROR: zip_stat_index failed for index %" PRIi64 "\n", zindex); + logger(LL_ERROR, "zip_stat_index failed for index %" PRIi64 "\n", zindex); goto leave; } zfile = zip_fopen_index(za, zindex, 0); if (zfile == NULL) { - error("ERROR: zip_fopen_index failed for index %" PRIi64 "\n", zindex); + logger(LL_ERROR, "zip_fopen_index failed for index %" PRIi64 "\n", zindex); goto leave; } buffer = (unsigned char*) malloc(zstat.size + 1); if (buffer == NULL) { - error("ERROR: Out of memory\n"); + logger(LL_ERROR, "Out of memory\n"); goto leave; } if (zip_fread(zfile, buffer, zstat.size) != zstat.size) { - error("ERROR: zip_fread: failed\n"); + logger(LL_ERROR, "zip_fread: failed\n"); goto leave; } buffer[zstat.size] = '\0'; @@ -1736,29 +2151,26 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned free(buffer); buffer = NULL; if (!fls) { - error("ERROR: could not parse fls file\n"); + logger(LL_ERROR, "could not parse fls file\n"); goto leave; } - blob = NULL; blob_size = 0; - plist_get_data_val(bbticket, (char**)&blob, &blob_size); + blob = (const unsigned char*)plist_get_data_ptr(bbticket, &blob_size); if (!blob) { - error("ERROR: could not get BBTicket data\n"); + logger(LL_ERROR, "could not get BBTicket data\n"); goto leave; } if (fls_insert_ticket(fls, blob, (unsigned int)blob_size) != 0) { - error("ERROR: could not insert BBTicket to ebl.fls\n"); + logger(LL_ERROR, "could not insert BBTicket to ebl.fls\n"); goto leave; } - free(blob); - blob = NULL; fsize = fls->size; fdata = (unsigned char*)malloc(fsize); if (!fdata) { - error("ERROR: out of memory\n"); + logger(LL_ERROR, "out of memory\n"); goto leave; } memcpy(fdata, fls->data, fsize); @@ -1767,34 +2179,32 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned zs = zip_source_buffer(za, fdata, fsize, 1); if (!zs) { - error("ERROR: out of memory\n"); + logger(LL_ERROR, "out of memory\n"); free(fdata); goto leave; } if (zip_file_replace(za, zindex, zs, 0) == -1) { - error("ERROR: could not update archive with ticketed ebl.fls\n"); + logger(LL_ERROR, "could not update archive with ticketed ebl.fls\n"); goto leave; } } else { // add BBTicket as bbticket.der - blob = NULL; blob_size = 0; - plist_get_data_val(bbticket, (char**)&blob, &blob_size); + blob = (const unsigned char*)plist_get_data_ptr(bbticket, &blob_size); if (!blob) { - error("ERROR: could not get BBTicket data\n"); + logger(LL_ERROR, "could not get BBTicket data\n"); goto leave; } - zs = zip_source_buffer(za, blob, blob_size, 1); + zs = zip_source_buffer(za, blob, blob_size, 0); if (!zs) { - error("ERROR: out of memory\n"); + logger(LL_ERROR, "out of memory\n"); goto leave; } - blob = NULL; if (zip_file_add(za, "bbticket.der", zs, ZIP_FL_OVERWRITE) == -1) { - error("ERROR: could not add bbticket.der to archive\n"); + logger(LL_ERROR, "could not add bbticket.der to archive\n"); goto leave; } } @@ -1802,7 +2212,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned // this will write out the modified zip if (zip_close(za) == -1) { - error("ERROR: could not close and write modified archive: %s\n", zip_strerror(za)); + logger(LL_ERROR, "could not close and write modified archive: %s\n", zip_strerror(za)); res = -1; } else { res = 0; @@ -1821,15 +2231,13 @@ leave: zip_unchange_all(za); zip_close(za); } - mbn_free(mbn); fls_free(fls); free(buffer); - free(blob); return res; } -static int restore_send_baseband_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message) +static int restore_send_baseband_data(struct idevicerestore_client_t* client, plist_t message) { int res = -1; uint64_t bb_cert_id = 0; @@ -1843,7 +2251,12 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer char* bbfwtmp = NULL; plist_t dict = NULL; - info("About to send BasebandData...\n"); + if (!client || !client->restore || !client->restore->build_identity) { + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + + logger(LL_INFO, "About to send BasebandData...\n"); // NOTE: this function is called 2 or 3 times! @@ -1879,12 +2292,12 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer plist_dict_set_item(parameters, "BbGoldCertId", plist_new_uint(bb_cert_id)); plist_dict_set_item(parameters, "BbSNUM", plist_new_data((const char*)bb_snum, bb_snum_size)); - tss_parameters_add_from_manifest(parameters, build_identity, true); + tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true); /* create baseband request */ plist_t request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create Baseband TSS request\n"); + logger(LL_ERROR, "Unable to create Baseband TSS request\n"); plist_free(parameters); return -1; } @@ -1893,7 +2306,7 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer tss_request_add_common_tags(request, parameters, NULL); tss_request_add_baseband_tags(request, parameters, NULL); - plist_t node = plist_access_path(build_identity, 2, "Info", "FDRSupport"); + plist_t node = plist_access_path(client->restore->build_identity, 2, "Info", "FDRSupport"); if (node && plist_get_node_type(node) == PLIST_BOOLEAN) { uint8_t b = 0; plist_get_bool_val(node, &b); @@ -1902,34 +2315,30 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer plist_dict_set_item(request, "ApSecurityMode", plist_new_bool(1)); } } - if (idevicerestore_debug) - debug_plist(request); - - info("Sending Baseband TSS request...\n"); + logger(LL_INFO, "Sending Baseband TSS request...\n"); + logger_dump_plist(LL_DEBUG, request, 0); response = tss_request_send(request, client->tss_url); plist_free(request); plist_free(parameters); if (response == NULL) { - error("ERROR: Unable to fetch Baseband TSS\n"); + logger(LL_ERROR, "Unable to fetch Baseband TSS\n"); return -1; } - info("Received Baseband SHSH blobs\n"); - - if (idevicerestore_debug) - debug_plist(response); + logger(LL_INFO, "Received Baseband SHSH blobs\n"); + logger_dump_plist(LL_DEBUG, response, 0); } // get baseband firmware file path from build identity - plist_t bbfw_path = plist_access_path(build_identity, 4, "Manifest", "BasebandFirmware", "Info", "Path"); + plist_t bbfw_path = plist_access_path(client->restore->build_identity, 4, "Manifest", "BasebandFirmware", "Info", "Path"); if (!bbfw_path || plist_get_node_type(bbfw_path) != PLIST_STRING) { - error("ERROR: Unable to get BasebandFirmware/Info/Path node\n"); + logger(LL_ERROR, "Unable to get BasebandFirmware/Info/Path node\n"); plist_free(response); return -1; } char* bbfwpath = NULL; plist_get_string_val(bbfw_path, &bbfwpath); if (!bbfwpath) { - error("ERROR: Unable to get baseband path\n"); + logger(LL_ERROR, "Unable to get baseband path\n"); plist_free(response); return -1; } @@ -1942,10 +2351,10 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer strcpy(bbfwtmp, "bbfw_"); strncpy(bbfwtmp + 5, client->udid, l); strcpy(bbfwtmp + 5 + l, ".tmp"); - error("WARNING: Could not generate temporary filename, using %s in current directory\n", bbfwtmp); + logger(LL_WARNING, "Could not generate temporary filename, using %s in current directory\n", bbfwtmp); } if (ipsw_extract_to_file(client->ipsw, bbfwpath, bbfwtmp) != 0) { - error("ERROR: Unable to extract baseband firmware from ipsw\n"); + logger(LL_ERROR, "Unable to extract baseband firmware from ipsw\n"); goto leave; } @@ -1955,7 +2364,7 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer response = NULL; } - res = restore_sign_bbfw(bbfwtmp, (client->restore->bbtss) ? client->restore->bbtss : response, bb_nonce); + res = restore_sign_bbfw(bbfwtmp, (client->restore->bbtss) ? client->restore->bbtss : response, bb_nonce, bb_chip_id); if (res != 0) { goto leave; } @@ -1964,30 +2373,44 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer size_t sz = 0; if (read_file(bbfwtmp, (void**)&buffer, &sz) < 0) { - error("ERROR: could not read updated bbfw archive\n"); + logger(LL_ERROR, "could not read updated bbfw archive\n"); goto leave; } // send file dict = plist_new_dict(); - plist_dict_set_item(dict, "BasebandData", plist_new_data(buffer, (uint64_t)sz)); + plist_dict_set_item(dict, "BasebandData", plist_new_data(buffer, sz)); free(buffer); buffer = NULL; - info("Sending BasebandData now...\n"); - if (restored_send(restore, dict) != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send BasebandData data\n"); + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); + return -1; + } + + logger(LL_INFO, "Sending BasebandData now...\n"); + if (_restore_service_send(service, dict, 0) != RESTORE_E_SUCCESS) { + logger(LL_ERROR, "Unable to send BasebandData data\n"); goto leave; } - info("Done sending BasebandData\n"); + _restore_service_free(service); + + logger(LL_INFO, "Done sending BasebandData\n"); res = 0; leave: plist_free(dict); free(buffer); if (bbfwtmp) { - remove(bbfwtmp); + if (client->flags & FLAG_KEEP_PERS) { + const char* bbfwname = path_get_basename(bbfwtmp); + logger(LL_VERBOSE, "%s: Keeping personalized BBFW as %s\n", __func__, bbfwname); + rename(bbfwtmp, bbfwname); + } else { + remove(bbfwtmp); + } free(bbfwtmp); } plist_free(response); @@ -1995,32 +2418,39 @@ leave: return res; } -int restore_send_fdr_trust_data(restored_client_t restore, idevice_t device) +int restore_send_fdr_trust_data(struct idevicerestore_client_t* client, plist_t message) { restored_error_t restore_error; plist_t dict; - info("About to send FDR Trust data...\n"); + logger(LL_INFO, "About to send FDR Trust data...\n"); // FIXME: What should we send here? /* Sending an empty dict makes it continue with FDR * and this is what iTunes seems to be doing too */ dict = plist_new_dict(); - info("Sending FDR Trust data now...\n"); - restore_error = restored_send(restore, dict); + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); + return -1; + } + + logger(LL_INFO, "Sending FDR Trust data now...\n"); + restore_error = _restore_service_send(service, dict, 0); plist_free(dict); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: During sending FDR Trust data (%d)\n", restore_error); + logger(LL_ERROR, "During sending FDR Trust data (%d)\n", restore_error); return -1; } - info("Done sending FDR Trust Data\n"); + logger(LL_INFO, "Done sending FDR Trust Data\n"); return 0; } -static int restore_send_image_data(restored_client_t restore, struct idevicerestore_client_t *client, plist_t build_identity, plist_t message, const char *image_list_k, const char *image_type_k, const char *image_data_k) +static int restore_send_image_data(struct idevicerestore_client_t *client, plist_t message, const char *image_list_k, const char *image_type_k, const char *image_data_k) { restored_error_t restore_error; plist_t arguments; @@ -2033,8 +2463,13 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest char *image_name = NULL; int want_image_list = 0; + if (!client || !client->restore || !client->restore->build_identity) { + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + arguments = plist_dict_get_item(message, "Arguments"); - want_image_list = _plist_dict_get_bool(arguments, image_list_k); + want_image_list = plist_dict_get_bool(arguments, image_list_k); node = plist_dict_get_item(arguments, "ImageName"); if (node) { plist_get_string_val(node, &image_name); @@ -2046,12 +2481,12 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest } } if (!image_type_k) { - error("ERROR: missing ImageType"); + logger(LL_ERROR, "Missing ImageType\n"); return -1; } if (!want_image_list && !image_name) { - info("About to send %s...\n", image_data_k); + logger(LL_INFO, "About to send %s...\n", image_data_k); } if (want_image_list) { @@ -2060,7 +2495,7 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest data_dict = plist_new_dict(); } - build_id_manifest = plist_dict_get_item(build_identity, "Manifest"); + build_id_manifest = plist_dict_get_item(client->restore->build_identity, "Manifest"); if (build_id_manifest) { plist_dict_new_iter(build_id_manifest, &iter); } @@ -2079,34 +2514,34 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest } if (is_image_type) { if (want_image_list) { - info("Found %s component %s\n", image_type_k, component); + logger(LL_INFO, "Found %s component %s\n", image_type_k, component); plist_array_append_item(matched_images, plist_new_string(component)); } else if (!image_name || !strcmp(image_name, component)) { char *path = NULL; - unsigned char* data = NULL; - unsigned int size = 0; - unsigned char* component_data = NULL; - unsigned int component_size = 0; + void* data = NULL; + size_t size = 0; + void* component_data = NULL; + size_t component_size = 0; int ret = -1; if (!image_name) { - info("Found %s component '%s'\n", image_type_k, component); + logger(LL_INFO, "Found %s component '%s'\n", image_type_k, component); } - build_identity_get_component_path(build_identity, component, &path); + build_identity_get_component_path(client->restore->build_identity, component, &path); if (path) { ret = extract_component(client->ipsw, path, &component_data, &component_size); } free(path); path = NULL; if (ret < 0) { - error("ERROR: Unable to extract component: %s\n", component); + logger(LL_ERROR, "Unable to extract component: %s\n", component); } - ret = personalize_component(component, component_data, component_size, client->tss, &data, &size); + ret = personalize_component(client, component, component_data, component_size, client->tss, &data, &size); free(component_data); component_data = NULL; if (ret < 0) { - error("ERROR: Unable to get personalized component: %s\n", component); + logger(LL_ERROR, "Unable to get personalized component: %s\n", component); } plist_dict_set_item(data_dict, component, plist_new_data((const char*)data, size)); @@ -2119,10 +2554,16 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest free(iter); } + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); + return -1; + } + dict = plist_new_dict(); if (want_image_list) { plist_dict_set_item(dict, image_list_k, matched_images); - info("Sending %s image list\n", image_type_k); + logger(LL_INFO, "Sending %s image list\n", image_type_k); } else { if (image_name) { node = plist_dict_get_item(data_dict, image_name); @@ -2130,24 +2571,25 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest plist_dict_set_item(dict, image_data_k, plist_copy(node)); } plist_dict_set_item(dict, "ImageName", plist_new_string(image_name)); - info("Sending %s for %s...\n", image_type_k, image_name); + logger(LL_INFO, "Sending %s for %s...\n", image_type_k, image_name); } else { plist_dict_set_item(dict, image_data_k, data_dict); - info("Sending %s now...\n", image_type_k); + logger(LL_INFO, "Sending %s now...\n", image_type_k); } } - restore_error = restored_send(restore, dict); + restore_error = _restore_service_send(service, dict, 0); plist_free(dict); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { if (want_image_list) { - error("ERROR: Failed to send %s image list (%d)\n", image_type_k, restore_error); + logger(LL_ERROR, "Failed to send %s image list (%d)\n", image_type_k, restore_error); } else { if (image_name) { - error("ERROR: Failed to send %s for %s (%d)\n", image_type_k, image_name, restore_error); + logger(LL_ERROR, "Failed to send %s for %s (%d)\n", image_type_k, image_name, restore_error); free(image_name); } else { - error("ERROR: Failed to send %s (%d)\n", image_type_k, restore_error); + logger(LL_ERROR, "Failed to send %s (%d)\n", image_type_k, restore_error); } } return -1; @@ -2157,71 +2599,86 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest if (image_name) { free(image_name); } else { - info("Done sending %s\n", image_type_k); + logger(LL_INFO, "Done sending %s\n", image_type_k); } } return 0; } -static plist_t restore_get_se_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info, plist_t arguments) +static int _wants_firmware_data(plist_t arguments) +{ + int result = 0; + plist_t tags = plist_access_path(arguments, 2, "DeviceGeneratedTags", "ResponseTags"); + if (tags) { + plist_array_iter iter = NULL; + plist_array_new_iter(tags, &iter); + plist_t node = NULL; + do { + plist_array_next_item(tags, iter, &node); + if (node) { + const char* tag = plist_get_string_ptr(node, NULL); + if (tag && (strcmp(tag, "FirmwareData") == 0)) { + result = 1; + } + } + } while (node); + plist_mem_free(iter); + } + return result; +} + +static plist_t restore_get_se_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { const char *comp_name = NULL; char *comp_path = NULL; - unsigned char* component_data = NULL; - unsigned int component_size = 0; + void* component_data = NULL; + size_t component_size = 0; plist_t parameters = NULL; plist_t request = NULL; plist_t response = NULL; plist_t p_dgr = NULL; int ret; uint64_t chip_id = 0; + + if (!client || !client->restore || !client->restore->build_identity) { + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); + return NULL; + } + plist_t node = plist_dict_get_item(p_info, "SE,ChipID"); if (node && plist_get_node_type(node) == PLIST_UINT) { plist_get_uint_val(node, &chip_id); } if (chip_id == 0x20211) { comp_name = "SE,Firmware"; - } else if (chip_id == 0x73 || chip_id == 0x64 || chip_id == 0xC8 || chip_id == 0xD2 || chip_id == 0x2C || chip_id == 0x36) { + } else if (chip_id == 0x73 || chip_id == 0x64 || chip_id == 0xC8 || chip_id == 0xD2 || chip_id == 0x2C || chip_id == 0x36 || chip_id == 0x37) { comp_name = "SE,UpdatePayload"; } else { - info("WARNING: Unknown SE,ChipID 0x%" PRIx64 " detected. Restore might fail.\n", (uint64_t)chip_id); - if (build_identity_has_component(build_identity, "SE,UpdatePayload")) + logger(LL_WARNING, "Unknown SE,ChipID 0x%" PRIx64 " detected. Restore might fail.\n", (uint64_t)chip_id); + if (build_identity_has_component(client->restore->build_identity, "SE,UpdatePayload")) comp_name = "SE,UpdatePayload"; - else if (build_identity_has_component(build_identity, "SE,Firmware")) + else if (build_identity_has_component(client->restore->build_identity, "SE,Firmware")) comp_name = "SE,Firmware"; else { - error("ERROR: Neither 'SE,Firmware' nor 'SE,UpdatePayload' found in build identity.\n"); + logger(LL_ERROR, "Neither 'SE,Firmware' nor 'SE,UpdatePayload' found in build identity.\n"); return NULL; } - debug("DEBUG: %s: using %s\n", __func__, comp_name); + logger(LL_DEBUG, "%s: using %s\n", __func__, comp_name); } p_dgr = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); if (!p_dgr) { - info("NOTE: %s: No DeviceGeneratedRequest in firmware updater data request. Continuing anyway.\n", __func__); + logger(LL_NOTICE, "%s: No DeviceGeneratedRequest in firmware updater data request. Continuing anyway.\n", __func__); } else if (!PLIST_IS_DICT(p_dgr)) { - error("ERROR: %s: DeviceGeneratedRequest has invalid type!\n", __func__); - return NULL; - } - - if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { - error("ERROR: Unable to get path for '%s' component\n", comp_name); - return NULL; - } - - ret = extract_component(client->ipsw, comp_path, &component_data, &component_size); - free(comp_path); - comp_path = NULL; - if (ret < 0) { - error("ERROR: Unable to extract '%s' component\n", comp_name); + logger(LL_ERROR, "%s: DeviceGeneratedRequest has invalid type!\n", __func__); return NULL; } /* create SE request */ request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create SE TSS request\n"); + logger(LL_ERROR, "Unable to create SE TSS request\n"); free(component_data); return NULL; } @@ -2229,7 +2686,7 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity, true); + tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true); /* add SE,* tags from info dictionary to parameters */ plist_dict_merge(¶meters, p_info); @@ -2239,24 +2696,45 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id plist_free(parameters); - info("Sending SE TSS request...\n"); + logger(LL_INFO, "Sending SE TSS request...\n"); response = tss_request_send(request, client->tss_url); plist_free(request); if (response == NULL) { - error("ERROR: Unable to fetch SE ticket\n"); + logger(LL_ERROR, "Unable to fetch SE ticket\n"); free(component_data); return NULL; } if (plist_dict_get_item(response, "SE2,Ticket")) { - info("Received SE2,Ticket\n"); + logger(LL_INFO, "Received SE2,Ticket\n"); } else if (plist_dict_get_item(response, "SE,Ticket")) { - info("Received SE,Ticket\n"); + logger(LL_INFO, "Received SE,Ticket\n"); } else { - error("ERROR: No 'SE ticket' in TSS response, this might not work\n"); + logger(LL_ERROR, "No 'SE ticket' in TSS response, this might not work\n"); + } + + /* don't add FirmwareData if not requested via ResponseTags */ + if (!_wants_firmware_data(arguments)) { + logger(LL_DEBUG, "Not adding FirmwareData as it was not requested\n"); + return response; + } + + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { + plist_free(response); + logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name); + return NULL; + } + + ret = extract_component(client->ipsw, comp_path, &component_data, &component_size); + free(comp_path); + comp_path = NULL; + if (ret < 0) { + plist_free(response); + logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name); + return NULL; } - plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, (uint64_t) component_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size)); free(component_data); component_data = NULL; component_size = 0; @@ -2264,63 +2742,81 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id return response; } -static plist_t restore_get_savage_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info) +static plist_t restore_get_savage_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { char *comp_name = NULL; char *comp_path = NULL; - unsigned char* component_data = NULL; - unsigned int component_size = 0; - unsigned char* component_data_tmp = NULL; + void* component_data = NULL; + size_t component_size = 0; + void* component_data_tmp = NULL; plist_t parameters = NULL; plist_t request = NULL; plist_t response = NULL; int ret; + if (!client || !client->restore || !client->restore->build_identity) { + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); + return NULL; + } + + plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); + if (device_generated_request && !PLIST_IS_DICT(device_generated_request)) { + logger(LL_ERROR, "%s: DeviceGeneratedRequest has invalid type!\n", __func__); + return NULL; + } + /* create Savage request */ request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create Savage TSS request\n"); + logger(LL_ERROR, "Unable to create Savage TSS request\n"); return NULL; } parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity, true); + tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true); /* add Savage,* tags from info dictionary to parameters */ plist_dict_merge(¶meters, p_info); /* add required tags for Savage TSS request */ - tss_request_add_savage_tags(request, parameters, NULL, &comp_name); + tss_request_add_savage_tags(request, parameters, device_generated_request, &comp_name); plist_free(parameters); if (!comp_name) { - error("ERROR: Could not determine Savage firmware component\n"); + logger(LL_ERROR, "Could not determine Savage firmware component\n"); plist_free(request); return NULL; } - debug("DEBUG: %s: using %s\n", __func__, comp_name); + logger(LL_DEBUG, "%s: using %s\n", __func__, comp_name); - info("Sending Savage TSS request...\n"); + logger(LL_INFO, "Sending Savage TSS request...\n"); response = tss_request_send(request, client->tss_url); plist_free(request); if (response == NULL) { - error("ERROR: Unable to fetch Savage ticket\n"); + logger(LL_ERROR, "Unable to fetch Savage ticket\n"); free(comp_name); return NULL; } if (plist_dict_get_item(response, "Savage,Ticket")) { - info("Received Savage ticket\n"); + logger(LL_INFO, "Received Savage ticket\n"); } else { - error("ERROR: No 'Savage,Ticket' in TSS response, this might not work\n"); + logger(LL_ERROR, "No 'Savage,Ticket' in TSS response, this might not work\n"); + } + + /* don't add FirmwareData if not requested via ResponseTags */ + if (!_wants_firmware_data(arguments)) { + logger(LL_DEBUG, "Not adding FirmwareData as it was not requested\n"); + return response; } /* now get actual component data */ - if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { - error("ERROR: Unable to get path for '%s' component\n", comp_name); + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { + plist_free(response); + logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name); free(comp_name); return NULL; } @@ -2329,7 +2825,8 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc free(comp_path); comp_path = NULL; if (ret < 0) { - error("ERROR: Unable to extract '%s' component\n", comp_name); + plist_free(response); + logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name); free(comp_name); return NULL; } @@ -2339,6 +2836,7 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc component_data_tmp = realloc(component_data, (size_t)component_size+16); if (!component_data_tmp) { free(component_data); + plist_free(response); return NULL; } component_data = component_data_tmp; @@ -2347,7 +2845,7 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc *(uint32_t*)(component_data + 4) = htole32((uint32_t)component_size); component_size += 16; - plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, (uint64_t) component_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size)); free(component_data); component_data = NULL; component_size = 0; @@ -2355,63 +2853,80 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc return response; } -static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info) +static plist_t restore_get_yonkers_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { char *comp_name = NULL; char *comp_path = NULL; - unsigned char* component_data = NULL; - unsigned int component_size = 0; + void* component_data = NULL; + size_t component_size = 0; plist_t parameters = NULL; plist_t request = NULL; plist_t response = NULL; int ret; + if (!client || !client->restore || !client->restore->build_identity) { + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); + return NULL; + } + + plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); + if (device_generated_request && !PLIST_IS_DICT(device_generated_request)) { + logger(LL_ERROR, "%s: DeviceGeneratedRequest has invalid type!\n", __func__); + return NULL; + } + /* create Yonkers request */ request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create Yonkers TSS request\n"); - free(component_data); - free(comp_name); + logger(LL_ERROR, "Unable to create Yonkers TSS request\n"); return NULL; } parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity, true); + tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true); /* add Yonkers,* tags from info dictionary to parameters */ plist_dict_merge(¶meters, p_info); /* add required tags for Yonkers TSS request */ - tss_request_add_yonkers_tags(request, parameters, NULL, &comp_name); + tss_request_add_yonkers_tags(request, parameters, device_generated_request, &comp_name); plist_free(parameters); if (!comp_name) { - error("ERROR: Could not determine Yonkers firmware component\n"); + logger(LL_ERROR, "Could not determine Yonkers firmware component\n"); plist_free(request); return NULL; } - debug("DEBUG: %s: using %s\n", __func__, comp_name); + logger(LL_DEBUG, "%s: using %s\n", __func__, comp_name); - info("Sending Yonkers TSS request...\n"); + logger(LL_INFO, "Sending Yonkers TSS request...\n"); response = tss_request_send(request, client->tss_url); plist_free(request); if (response == NULL) { - error("ERROR: Unable to fetch Yonkers ticket\n"); - free(component_data); + logger(LL_ERROR, "Unable to fetch Yonkers ticket\n"); + free(comp_name); return NULL; } if (plist_dict_get_item(response, "Yonkers,Ticket")) { - info("Received Yonkers ticket\n"); + logger(LL_INFO, "Received Yonkers ticket\n"); } else { - error("ERROR: No 'Yonkers,Ticket' in TSS response, this might not work\n"); + logger(LL_ERROR, "No 'Yonkers,Ticket' in TSS response, this might not work\n"); } - if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { - error("ERROR: Unable to get path for '%s' component\n", comp_name); + /* don't add FirmwareData if not requested via ResponseTags */ + if (!_wants_firmware_data(arguments)) { + logger(LL_DEBUG, "Not adding FirmwareData as it was not requested\n"); + free(comp_name); + return response; + } + + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { + plist_free(response); + logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name); free(comp_name); return NULL; } @@ -2421,7 +2936,8 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru free(comp_path); comp_path = NULL; if (ret < 0) { - error("ERROR: Unable to extract '%s' component\n", comp_name); + plist_free(response); + logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name); free(comp_name); return NULL; } @@ -2429,7 +2945,7 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru comp_name = NULL; plist_t firmware_data = plist_new_dict(); - plist_dict_set_item(firmware_data, "YonkersFirmware", plist_new_data((char *)component_data, (uint64_t)component_size)); + plist_dict_set_item(firmware_data, "YonkersFirmware", plist_new_data((char*)component_data, component_size)); plist_dict_set_item(response, "FirmwareData", firmware_data); free(component_data); @@ -2439,12 +2955,12 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru return response; } -static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info, plist_t arguments) +static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { char *comp_name = NULL; char *comp_path = NULL; - unsigned char* component_data = NULL; - unsigned int component_size = 0; + void* component_data = NULL; + size_t component_size = 0; ftab_t ftab = NULL; ftab_t rftab = NULL; uint32_t ftag = 0; @@ -2453,18 +2969,22 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct plist_t response = NULL; int ret; + if (!client || !client->restore || !client->restore->build_identity) { + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); + return NULL; + } + /* create Rose request */ request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create Rose TSS request\n"); - free(component_data); + logger(LL_ERROR, "Unable to create Rose TSS request\n"); return NULL; } parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity, true); + tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true); plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1)); if (client->image4supported) { @@ -2488,56 +3008,59 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct plist_free(parameters); - info("Sending Rose TSS request...\n"); + logger(LL_INFO, "Sending Rose TSS request...\n"); response = tss_request_send(request, client->tss_url); plist_free(request); if (response == NULL) { - error("ERROR: Unable to fetch Rose ticket\n"); - free(component_data); + logger(LL_ERROR, "Unable to fetch Rose ticket\n"); return NULL; } if (plist_dict_get_item(response, "Rap,Ticket")) { - info("Received Rose ticket\n"); + logger(LL_INFO, "Received Rose ticket\n"); } else { - error("ERROR: No 'Rap,Ticket' in TSS response, this might not work\n"); + logger(LL_ERROR, "No 'Rap,Ticket' in TSS response, this might not work\n"); } - /* skip FirmwareData for newer versions */ - if (client->build_major >= 20) { - debug("DEBUG: Not adding FirmwareData.\n"); + /* don't add FirmwareData if not requested via ResponseTags */ + if (!_wants_firmware_data(arguments)) { + logger(LL_DEBUG, "Not adding FirmwareData as it was not requested\n"); return response; } comp_name = "Rap,RTKitOS"; - if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { - error("ERROR: Unable to get path for '%s' component\n", comp_name); + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { + plist_free(response); + logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name); return NULL; } ret = extract_component(client->ipsw, comp_path, &component_data, &component_size); free(comp_path); comp_path = NULL; if (ret < 0) { - error("ERROR: Unable to extract '%s' component\n", comp_name); + plist_free(response); + logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name); return NULL; } if (ftab_parse(component_data, component_size, &ftab, &ftag) != 0) { + plist_free(response); free(component_data); - error("ERROR: Failed to parse '%s' component data.\n", comp_name); + logger(LL_ERROR, "Failed to parse '%s' component data.\n", comp_name); return NULL; } free(component_data); component_data = NULL; component_size = 0; if (ftag != 'rkos') { - error("WARNING: Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos'); + logger(LL_WARNING, "Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos'); } comp_name = "Rap,RestoreRTKitOS"; - if (build_identity_has_component(build_identity, comp_name)) { - if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { + if (build_identity_has_component(client->restore->build_identity, comp_name)) { + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { ftab_free(ftab); - error("ERROR: Unable to get path for '%s' component\n", comp_name); + plist_free(response); + logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name); return NULL; } ret = extract_component(client->ipsw, comp_path, &component_data, &component_size); @@ -2545,7 +3068,8 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct comp_path = NULL; if (ret < 0) { ftab_free(ftab); - error("ERROR: Unable to extract '%s' component\n", comp_name); + plist_free(response); + logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name); return NULL; } @@ -2553,32 +3077,33 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct if (ftab_parse(component_data, component_size, &rftab, &ftag) != 0) { free(component_data); ftab_free(ftab); - error("ERROR: Failed to parse '%s' component data.\n", comp_name); + plist_free(response); + logger(LL_ERROR, "Failed to parse '%s' component data.\n", comp_name); return NULL; } free(component_data); component_data = NULL; component_size = 0; if (ftag != 'rkos') { - error("WARNING: Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos'); + logger(LL_WARNING, "Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos'); } if (ftab_get_entry_ptr(rftab, 'rrko', &component_data, &component_size) == 0) { ftab_add_entry(ftab, 'rrko', component_data, component_size); } else { - error("ERROR: Could not find 'rrko' entry in ftab. This will probably break things.\n"); + logger(LL_ERROR, "Could not find 'rrko' entry in ftab. This will probably break things.\n"); } ftab_free(rftab); component_data = NULL; component_size = 0; } else { - info("NOTE: Build identity does not have a '%s' component.\n", comp_name); + logger(LL_NOTICE, "Build identity does not have a '%s' component.\n", comp_name); } ftab_write(ftab, &component_data, &component_size); ftab_free(ftab); - plist_dict_set_item(response, "FirmwareData", plist_new_data((char *)component_data, (uint64_t)component_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size)); free(component_data); component_data = NULL; component_size = 0; @@ -2586,21 +3111,32 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct return response; } -static plist_t restore_get_veridian_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info) +static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { char *comp_name = "BMU,FirmwareMap"; char *comp_path = NULL; - unsigned char* component_data = NULL; - unsigned int component_size = 0; + void* component_data = NULL; + size_t component_size = 0; plist_t parameters = NULL; plist_t request = NULL; plist_t response = NULL; int ret; + if (!client || !client->restore || !client->restore->build_identity) { + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); + return NULL; + } + + plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); + if (device_generated_request && !PLIST_IS_DICT(device_generated_request)) { + logger(LL_ERROR, "%s: DeviceGeneratedRequest has invalid type!\n", __func__); + return NULL; + } + /* create Veridian request */ request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create Veridian TSS request\n"); + logger(LL_ERROR, "Unable to create Veridian TSS request\n"); free(component_data); return NULL; } @@ -2608,33 +3144,40 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity, true); + tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true); /* add BMU,* tags from info dictionary to parameters */ plist_dict_merge(¶meters, p_info); /* add required tags for Veridian TSS request */ - tss_request_add_veridian_tags(request, parameters, NULL); + tss_request_add_veridian_tags(request, parameters, device_generated_request); plist_free(parameters); - info("Sending Veridian TSS request...\n"); + logger(LL_INFO, "Sending Veridian TSS request...\n"); response = tss_request_send(request, client->tss_url); plist_free(request); if (response == NULL) { - error("ERROR: Unable to fetch Veridian ticket\n"); + logger(LL_ERROR, "Unable to fetch Veridian ticket\n"); free(component_data); return NULL; } if (plist_dict_get_item(response, "BMU,Ticket")) { - info("Received Veridian ticket\n"); + logger(LL_INFO, "Received Veridian ticket\n"); } else { - error("ERROR: No 'BMU,Ticket' in TSS response, this might not work\n"); + logger(LL_ERROR, "No 'BMU,Ticket' in TSS response, this might not work\n"); } - if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { - error("ERROR: Unable to get path for '%s' component\n", comp_name); + /* don't add FirmwareData if not requested via ResponseTags */ + if (!_wants_firmware_data(arguments)) { + logger(LL_DEBUG, "Not adding FirmwareData as it was not requested\n"); + return response; + } + + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { + plist_free(response); + logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name); return NULL; } @@ -2643,7 +3186,8 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str free(comp_path); comp_path = NULL; if (ret < 0) { - error("ERROR: Unable to extract '%s' component\n", comp_name); + plist_free(response); + logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name); return NULL; } @@ -2658,14 +3202,16 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str component_size = 0; if (!fw_map) { - error("ERROR: Unable to parse '%s' component data as plist\n", comp_name); + plist_free(response); + logger(LL_ERROR, "Unable to parse '%s' component data as plist\n", comp_name); return NULL; } - plist_t fw_map_digest = plist_access_path(build_identity, 3, "Manifest", comp_name, "Digest"); + plist_t fw_map_digest = plist_access_path(client->restore->build_identity, 3, "Manifest", comp_name, "Digest"); if (!fw_map_digest) { plist_free(fw_map); - error("ERROR: Unable to get Digest for '%s' component\n", comp_name); + plist_free(response); + logger(LL_ERROR, "Unable to get Digest for '%s' component\n", comp_name); return NULL; } @@ -2676,13 +3222,13 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str plist_to_bin(fw_map, &bin_plist, &bin_size); plist_free(fw_map); - plist_dict_set_item(response, "FirmwareData", plist_new_data(bin_plist, (uint64_t)bin_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data(bin_plist, bin_size)); free(bin_plist); return response; } -static plist_t restore_get_generic_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info, plist_t arguments) +static plist_t restore_get_generic_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { plist_t request = NULL; plist_t response = NULL; @@ -2699,59 +3245,72 @@ static plist_t restore_get_generic_firmware_data(restored_client_t restore, stru } } if (response_ticket == NULL) { - error("ERROR: Unable to determine response ticket from device generated tags"); + logger(LL_ERROR, "Unable to determine response ticket from device generated tags\n"); return NULL; } /* create TSS request */ request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create %s TSS request\n", s_updater_name); + logger(LL_ERROR, "Unable to create %s TSS request\n", s_updater_name); return NULL; } /* add device generated request data to request */ plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); if (!device_generated_request) { - error("ERROR: Could not find DeviceGeneratedRequest in arguments dictionary\n"); + logger(LL_ERROR, "Could not find DeviceGeneratedRequest in arguments dictionary\n"); plist_free(request); return NULL; } plist_dict_merge(&request, device_generated_request); - info("Sending %s TSS request...\n", s_updater_name); + logger(LL_INFO, "Sending %s TSS request...\n", s_updater_name); + logger_dump_plist(LL_DEBUG, request, 0); response = tss_request_send(request, client->tss_url); plist_free(request); if (response == NULL) { - error("ERROR: Unable to fetch %s ticket\n", s_updater_name); + logger(LL_ERROR, "Unable to fetch %s ticket\n", s_updater_name); return NULL; } + logger_dump_plist(LL_DEBUG, response, 0); if (plist_dict_get_item(response, response_ticket)) { - info("Received %s\n", response_ticket); + logger(LL_INFO, "Received %s\n", response_ticket); } else { - error("ERROR: No '%s' in TSS response, this might not work\n", response_ticket); - debug_plist(response); + logger(LL_ERROR, "No '%s' in TSS response, this might not work\n", response_ticket); + logger_dump_plist(LL_VERBOSE, response, 0); } return response; } -static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info) +static plist_t restore_get_tcon_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { char *comp_name = "Baobab,TCON"; char *comp_path = NULL; - unsigned char* component_data = NULL; - unsigned int component_size = 0; + void* component_data = NULL; + size_t component_size = 0; plist_t parameters = NULL; plist_t request = NULL; plist_t response = NULL; int ret; + if (!client || !client->restore || !client->restore->build_identity) { + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); + return NULL; + } + + plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); + if (device_generated_request && !PLIST_IS_DICT(device_generated_request)) { + logger(LL_ERROR, "%s: DeviceGeneratedRequest has invalid type!\n", __func__); + return NULL; + } + /* create Baobab request */ request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create Baobab TSS request\n"); + logger(LL_ERROR, "Unable to create Baobab TSS request\n"); free(component_data); return NULL; } @@ -2759,33 +3318,40 @@ static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity, true); + tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true); /* add Baobab,* tags from info dictionary to parameters */ plist_dict_merge(¶meters, p_info); /* add required tags for Baobab TSS request */ - tss_request_add_tcon_tags(request, parameters, NULL); + tss_request_add_tcon_tags(request, parameters, device_generated_request); plist_free(parameters); - info("Sending Baobab TSS request...\n"); + logger(LL_INFO, "Sending Baobab TSS request...\n"); response = tss_request_send(request, client->tss_url); plist_free(request); if (response == NULL) { - error("ERROR: Unable to fetch Baobab ticket\n"); + logger(LL_ERROR, "Unable to fetch Baobab ticket\n"); free(component_data); return NULL; } if (plist_dict_get_item(response, "Baobab,Ticket")) { - info("Received Baobab ticket\n"); + logger(LL_INFO, "Received Baobab ticket\n"); } else { - error("ERROR: No 'Baobab,Ticket' in TSS response, this might not work\n"); + logger(LL_ERROR, "No 'Baobab,Ticket' in TSS response, this might not work\n"); } - if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { - error("ERROR: Unable to get path for '%s' component\n", comp_name); + /* don't add FirmwareData if not requested via ResponseTags */ + if (!_wants_firmware_data(arguments)) { + logger(LL_DEBUG, "Not adding FirmwareData as it was not requested\n"); + return response; + } + + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { + logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name); + plist_free(response); return NULL; } @@ -2794,11 +3360,12 @@ static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct free(comp_path); comp_path = NULL; if (ret < 0) { - error("ERROR: Unable to extract '%s' component\n", comp_name); + logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name); + plist_free(response); return NULL; } - plist_dict_set_item(response, "FirmwareData", plist_new_data((char *)component_data, (uint64_t)component_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size)); free(component_data); component_data = NULL; component_size = 0; @@ -2806,12 +3373,12 @@ static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct return response; } -static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info) +static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { char comp_name[64]; char *comp_path = NULL; - unsigned char* component_data = NULL; - unsigned int component_size = 0; + void* component_data = NULL; + size_t component_size = 0; ftab_t ftab = NULL; ftab_t rftab = NULL; uint32_t ftag = 0; @@ -2822,17 +3389,28 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct uint32_t tag = 0; int ret; + if (!client || !client->restore || !client->restore->build_identity) { + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); + return NULL; + } + + plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); + if (device_generated_request && !PLIST_IS_DICT(device_generated_request)) { + logger(LL_ERROR, "%s: DeviceGeneratedRequest has invalid type!\n", __func__); + return NULL; + } + /* create Timer request */ request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create Timer TSS request\n"); + logger(LL_ERROR, "Unable to create Timer TSS request\n"); return NULL; } parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity, true); + tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true); plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1)); if (client->image4supported) { @@ -2845,13 +3423,13 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct /* add Timer,* tags from info dictionary to parameters */ plist_t info_array = plist_dict_get_item(p_info, "InfoArray"); if (!info_array) { - error("ERROR: Could not find InfoArray in info dictionary\n"); + logger(LL_ERROR, "Could not find InfoArray in info dictionary\n"); plist_free(parameters); return NULL; } else { plist_t info_dict = plist_array_get_item(info_array, 0); plist_t hwid = plist_dict_get_item(info_dict, "HardwareID"); - tag = (uint32_t)_plist_dict_get_uint(info_dict, "TagNumber"); + tag = (uint32_t)plist_dict_get_uint(info_dict, "TagNumber"); char key[64]; plist_dict_set_item(parameters, "TagNumber", plist_new_uint(tag)); @@ -2861,30 +3439,30 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct plist_dict_set_item(parameters, "TicketName", plist_copy(node)); } - sprintf(key, "Timer,ChipID,%u", tag); - _plist_dict_copy_uint(parameters, hwid, key, "ChipID"); + snprintf(key, sizeof(key), "Timer,ChipID,%u", tag); + plist_dict_copy_uint(parameters, hwid, key, "ChipID"); - sprintf(key, "Timer,BoardID,%u", tag); - _plist_dict_copy_uint(parameters, hwid, key, "BoardID"); + snprintf(key, sizeof(key), "Timer,BoardID,%u", tag); + plist_dict_copy_uint(parameters, hwid, key, "BoardID"); - sprintf(key, "Timer,ECID,%u", tag); - _plist_dict_copy_uint(parameters, hwid, key, "ECID"); + snprintf(key, sizeof(key), "Timer,ECID,%u", tag); + plist_dict_copy_uint(parameters, hwid, key, "ECID"); - sprintf(key, "Timer,Nonce,%u", tag); - _plist_dict_copy_data(parameters, hwid, key, "Nonce"); + snprintf(key, sizeof(key), "Timer,Nonce,%u", tag); + plist_dict_copy_data(parameters, hwid, key, "Nonce"); - sprintf(key, "Timer,SecurityMode,%u", tag); - _plist_dict_copy_bool(parameters, hwid, key, "SecurityMode"); + snprintf(key, sizeof(key), "Timer,SecurityMode,%u", tag); + plist_dict_copy_bool(parameters, hwid, key, "SecurityMode"); - sprintf(key, "Timer,SecurityDomain,%u", tag); - _plist_dict_copy_uint(parameters, hwid, key, "SecurityDomain"); + snprintf(key, sizeof(key), "Timer,SecurityDomain,%u", tag); + plist_dict_copy_uint(parameters, hwid, key, "SecurityDomain"); - sprintf(key, "Timer,ProductionMode,%u", tag); - _plist_dict_copy_uint(parameters, hwid, key, "ProductionStatus"); + snprintf(key, sizeof(key), "Timer,ProductionMode,%u", tag); + plist_dict_copy_uint(parameters, hwid, key, "ProductionStatus"); } plist_t ap_info = plist_dict_get_item(p_info, "APInfo"); if (!ap_info) { - error("ERROR: Could not find APInfo in info dictionary\n"); + logger(LL_ERROR, "Could not find APInfo in info dictionary\n"); plist_free(parameters); return NULL; } else { @@ -2892,57 +3470,67 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct } /* add required tags for Timer TSS request */ - tss_request_add_timer_tags(request, parameters, NULL); + tss_request_add_timer_tags(request, parameters, device_generated_request); plist_free(parameters); - info("Sending %s TSS request...\n", ticket_name); + logger(LL_INFO, "Sending %s TSS request...\n", ticket_name); response = tss_request_send(request, client->tss_url); plist_free(request); if (response == NULL) { - error("ERROR: Unable to fetch %s\n", ticket_name); + logger(LL_ERROR, "Unable to fetch %s\n", ticket_name); return NULL; } if (plist_dict_get_item(response, ticket_name)) { - info("Received %s\n", ticket_name); + logger(LL_INFO, "Received %s\n", ticket_name); } else { - error("ERROR: No '%s' in TSS response, this might not work\n", ticket_name); + logger(LL_ERROR, "No '%s' in TSS response, this might not work\n", ticket_name); } - sprintf(comp_name, "Timer,RTKitOS,%u", tag); - if (build_identity_has_component(build_identity, comp_name)) { - if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { - error("ERROR: Unable to get path for '%s' component\n", comp_name); + /* don't add FirmwareData if not requested via ResponseTags */ + if (!_wants_firmware_data(arguments)) { + logger(LL_DEBUG, "Not adding FirmwareData as it was not requested\n"); + return response; + } + + snprintf(comp_name, sizeof(comp_name), "Timer,RTKitOS,%u", tag); + if (build_identity_has_component(client->restore->build_identity, comp_name)) { + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { + plist_free(response); + logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name); return NULL; } ret = extract_component(client->ipsw, comp_path, &component_data, &component_size); free(comp_path); comp_path = NULL; if (ret < 0) { - error("ERROR: Unable to extract '%s' component\n", comp_name); + logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name); + plist_free(response); return NULL; } if (ftab_parse(component_data, component_size, &ftab, &ftag) != 0) { free(component_data); - error("ERROR: Failed to parse '%s' component data.\n", comp_name); + plist_free(response); + logger(LL_ERROR, "Failed to parse '%s' component data.\n", comp_name); return NULL; } free(component_data); component_data = NULL; component_size = 0; if (ftag != 'rkos') { - error("WARNING: Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos'); + logger(LL_WARNING, "Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos'); } } else { - info("NOTE: Build identity does not have a '%s' component.\n", comp_name); + logger(LL_NOTICE, "Build identity does not have a '%s' component.\n", comp_name); } - sprintf(comp_name, "Timer,RestoreRTKitOS,%u", tag); - if (build_identity_has_component(build_identity, comp_name)) { - if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { + snprintf(comp_name, sizeof(comp_name), "Timer,RestoreRTKitOS,%u", tag); + if (build_identity_has_component(client->restore->build_identity, comp_name)) { + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { ftab_free(ftab); - error("ERROR: Unable to get path for '%s' component\n", comp_name); + plist_free(response); + logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name); return NULL; } ret = extract_component(client->ipsw, comp_path, &component_data, &component_size); @@ -2950,7 +3538,8 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct comp_path = NULL; if (ret < 0) { ftab_free(ftab); - error("ERROR: Unable to extract '%s' component\n", comp_name); + plist_free(response); + logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name); return NULL; } @@ -2958,32 +3547,33 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct if (ftab_parse(component_data, component_size, &rftab, &ftag) != 0) { free(component_data); ftab_free(ftab); - error("ERROR: Failed to parse '%s' component data.\n", comp_name); + plist_free(response); + logger(LL_ERROR, "Failed to parse '%s' component data.\n", comp_name); return NULL; } free(component_data); component_data = NULL; component_size = 0; if (ftag != 'rkos') { - error("WARNING: Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos'); + logger(LL_WARNING, "Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos'); } if (ftab_get_entry_ptr(rftab, 'rrko', &component_data, &component_size) == 0) { ftab_add_entry(ftab, 'rrko', component_data, component_size); } else { - error("ERROR: Could not find 'rrko' entry in ftab. This will probably break things.\n"); + logger(LL_ERROR, "Could not find 'rrko' entry in ftab. This will probably break things.\n"); } ftab_free(rftab); component_data = NULL; component_size = 0; } else { - info("NOTE: Build identity does not have a '%s' component.\n", comp_name); + logger(LL_NOTICE, "Build identity does not have a '%s' component.\n", comp_name); } ftab_write(ftab, &component_data, &component_size); ftab_free(ftab); - plist_dict_set_item(response, "FirmwareData", plist_new_data((char *)component_data, (uint64_t)component_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size)); free(component_data); component_data = NULL; component_size = 0; @@ -2991,12 +3581,17 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct return response; } -static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info, plist_t arguments) +static plist_t restore_get_cryptex1_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { plist_t parameters = NULL; plist_t request = NULL; plist_t response = NULL; + if (!client || !client->restore || !client->restore->build_identity) { + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); + return NULL; + } + plist_t p_updater_name = plist_dict_get_item(arguments, "MessageArgUpdaterName"); const char* s_updater_name = plist_get_string_ptr(p_updater_name, NULL); @@ -3012,7 +3607,7 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str /* create Cryptex1 request */ request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create %s TSS request\n", s_updater_name); + logger(LL_ERROR, "Unable to create %s TSS request\n", s_updater_name); return NULL; } @@ -3028,7 +3623,7 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str for (i = 0; i < plist_array_get_size(build_identity_tags); i++) { plist_t node = plist_array_get_item(build_identity_tags, i); const char* key = plist_get_string_ptr(node, NULL); - plist_t item = plist_dict_get_item(build_identity, key); + plist_t item = plist_dict_get_item(client->restore->build_identity, key); if (item) { plist_dict_set_item(parameters, key, plist_copy(item)); } @@ -3043,16 +3638,16 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(1)); } if (!plist_dict_get_item(parameters, "ApChipID")) { - _plist_dict_copy_uint(parameters, build_identity, "ApChipID", NULL); + plist_dict_copy_uint(parameters, client->restore->build_identity, "ApChipID", NULL); } if (!plist_dict_get_item(parameters, "ApBoardID")) { - _plist_dict_copy_uint(parameters, build_identity, "ApBoardID", NULL); + plist_dict_copy_uint(parameters, client->restore->build_identity, "ApBoardID", NULL); } /* add device generated request data to parameters */ plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); if (!device_generated_request) { - error("ERROR: Could not find DeviceGeneratedRequest in arguments dictionary\n"); + logger(LL_ERROR, "Could not find DeviceGeneratedRequest in arguments dictionary\n"); plist_free(parameters); return NULL; } @@ -3063,49 +3658,56 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str plist_free(parameters); - info("Sending %s TSS request...\n", s_updater_name); + logger(LL_INFO, "Sending %s TSS request...\n", s_updater_name); response = tss_request_send(request, client->tss_url); plist_free(request); if (response == NULL) { - error("ERROR: Unable to fetch %s ticket\n", s_updater_name); + logger(LL_ERROR, "Unable to fetch %s ticket\n", s_updater_name); return NULL; } if (plist_dict_get_item(response, response_ticket)) { - info("Received %s\n", response_ticket); + logger(LL_INFO, "Received %s\n", response_ticket); } else { - error("ERROR: No '%s' in TSS response, this might not work\n", response_ticket); - debug_plist(response); + logger(LL_ERROR, "No '%s' in TSS response, this might not work\n", response_ticket); + logger_dump_plist(LL_VERBOSE, response, 0); } return response; } -static int restore_send_firmware_updater_preflight(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message) +static int restore_send_firmware_updater_preflight(struct idevicerestore_client_t* client, plist_t message) { plist_t dict = NULL; int restore_error; - if (idevicerestore_debug) { - debug("DEBUG: %s: Got FirmwareUpdaterPreflight request:\n", __func__); - debug_plist(message); + if (client->debug_level > 1) { + logger(LL_DEBUG, "%s: Got FirmwareUpdaterPreflight request:\n", __func__); + logger_dump_plist(LL_DEBUG, message, 1); + } + + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); + return -1; } dict = plist_new_dict(); - info("Sending FirmwareResponsePreflight now...\n"); - restore_error = restored_send(restore, dict); + logger(LL_INFO, "Sending FirmwareResponsePreflight now...\n"); + restore_error = _restore_service_send(service, dict, 0); plist_free(dict); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Couldn't send FirmwareResponsePreflight data (%d)\n", restore_error); + logger(LL_ERROR, "Couldn't send FirmwareResponsePreflight data (%d)\n", restore_error); return -1; } - info("Done sending FirmwareUpdaterPreflight response\n"); + logger(LL_INFO, "Done sending FirmwareUpdaterPreflight response\n"); return 0; } -static int restore_send_firmware_updater_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message) +static int restore_send_firmware_updater_data(struct idevicerestore_client_t* client, plist_t message) { plist_t arguments; plist_t p_type, p_updater_name, p_loop_count, p_info; @@ -3116,26 +3718,31 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct char *s_updater_name = NULL; int restore_error; - if (idevicerestore_debug) { - debug("DEBUG: %s: Got FirmwareUpdaterData request:\n", __func__); - debug_plist(message); + if (!client || !client->restore || !client->restore->build_identity) { + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + + if (client->debug_level > 1) { + logger(LL_DEBUG, "%s: Got FirmwareUpdaterData request:\n", __func__); + logger_dump_plist(LL_DEBUG, message, 1); } arguments = plist_dict_get_item(message, "Arguments"); if (!arguments || plist_get_node_type(arguments) != PLIST_DICT) { - error("ERROR: %s: Arguments missing or has invalid type!\n", __func__); + logger(LL_ERROR, "%s: Arguments missing or has invalid type!\n", __func__); goto error_out; } p_type = plist_dict_get_item(arguments, "MessageArgType"); if (!p_type || (plist_get_node_type(p_type) != PLIST_STRING)) { - error("ERROR: %s: MessageArgType missing or has invalid type!\n", __func__); + logger(LL_ERROR, "%s: MessageArgType missing or has invalid type!\n", __func__); goto error_out; } p_updater_name = plist_dict_get_item(arguments, "MessageArgUpdaterName"); if (!p_updater_name || (plist_get_node_type(p_updater_name) != PLIST_STRING)) { - error("ERROR: %s: MessageArgUpdaterName missing or has invalid type!\n", __func__); + logger(LL_ERROR, "%s: MessageArgUpdaterName missing or has invalid type!\n", __func__); goto error_out; } @@ -3147,7 +3754,7 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct plist_get_string_val(p_type, &s_type); if (!s_type || strcmp(s_type, "FirmwareResponseData")) { - error("ERROR: %s: MessageArgType has unexpected value '%s'\n", __func__, s_type); + logger(LL_ERROR, "%s: MessageArgType has unexpected value '%s'\n", __func__, s_type); goto error_out; } free(s_type); @@ -3155,96 +3762,120 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct p_info = plist_dict_get_item(arguments, "MessageArgInfo"); if (!p_info || (plist_get_node_type(p_info) != PLIST_DICT)) { - error("ERROR: %s: MessageArgInfo missing or has invalid type!\n", __func__); + logger(LL_ERROR, "%s: MessageArgInfo missing or has invalid type!\n", __func__); goto error_out; } plist_get_string_val(p_updater_name, &s_updater_name); + logger_dump_plist(LL_DEBUG, p_info, 1); if (strcmp(s_updater_name, "SE") == 0) { - fwdict = restore_get_se_firmware_data(restore, client, build_identity, p_info, arguments); + fwdict = restore_get_se_firmware_data(client, p_info, arguments); if (fwdict == NULL) { - error("ERROR: %s: Couldn't get SE firmware data\n", __func__); + logger(LL_ERROR, "%s: Couldn't get SE firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "Savage") == 0) { const char *fwtype = "Savage"; - plist_t p_info2 = plist_dict_get_item(p_info, "YonkersDeviceInfo"); - if (p_info2 && plist_get_node_type(p_info2) == PLIST_DICT) { + plist_t p_info_yonkers = plist_dict_get_item(p_info, "YonkersDeviceInfo"); + plist_t p_info_jasmine = plist_dict_get_item(p_info, "JasmineIR1DeviceInfo"); + if (PLIST_IS_DICT(p_info_yonkers)) { fwtype = "Yonkers"; - fwdict = restore_get_yonkers_firmware_data(restore, client, build_identity, p_info2); + fwdict = restore_get_yonkers_firmware_data(client, p_info_yonkers, arguments); + } else if (PLIST_IS_DICT(p_info_jasmine)) { + fwtype = "Jasmine"; + fwdict = restore_get_generic_firmware_data(client, p_info_jasmine, arguments); } else { - fwdict = restore_get_savage_firmware_data(restore, client, build_identity, p_info); + fwdict = restore_get_savage_firmware_data(client, p_info, arguments); } if (fwdict == NULL) { - error("ERROR: %s: Couldn't get %s firmware data\n", __func__, fwtype); + logger(LL_ERROR, "%s: Couldn't get %s firmware data\n", __func__, fwtype); goto error_out; } } else if (strcmp(s_updater_name, "Rose") == 0) { - fwdict = restore_get_rose_firmware_data(restore, client, build_identity, p_info, arguments); + fwdict = restore_get_rose_firmware_data(client, p_info, arguments); if (fwdict == NULL) { - error("ERROR: %s: Couldn't get Rose firmware data\n", __func__); + logger(LL_ERROR, "%s: Couldn't get Rose firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "T200") == 0) { - fwdict = restore_get_veridian_firmware_data(restore, client, build_identity, p_info); + fwdict = restore_get_veridian_firmware_data(client, p_info, arguments); if (fwdict == NULL) { - error("ERROR: %s: Couldn't get Veridian firmware data\n", __func__); + logger(LL_ERROR, "%s: Couldn't get Veridian firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "AppleTCON") == 0) { - fwdict = restore_get_tcon_firmware_data(restore, client, build_identity, p_info); + fwdict = restore_get_tcon_firmware_data(client, p_info, arguments); if (fwdict == NULL) { - error("ERROR: %s: Couldn't get AppleTCON firmware data\n", __func__); + logger(LL_ERROR, "%s: Couldn't get AppleTCON firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "PS190") == 0) { - fwdict = restore_get_generic_firmware_data(restore, client, build_identity, p_info, arguments); + fwdict = restore_get_generic_firmware_data(client, p_info, arguments); if (fwdict == NULL) { - error("ERROR: %s: Couldn't get PCON1 firmware data\n", __func__); + logger(LL_ERROR, "%s: Couldn't get PCON1 firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "AppleTypeCRetimer") == 0) { - fwdict = restore_get_timer_firmware_data(restore, client, build_identity, p_info); + fwdict = restore_get_timer_firmware_data(client, p_info, arguments); if (fwdict == NULL) { - error("ERROR: %s: Couldn't get AppleTypeCRetimer firmware data\n", __func__); + logger(LL_ERROR, "%s: Couldn't get AppleTypeCRetimer firmware data\n", __func__); goto error_out; } } else if ((strcmp(s_updater_name, "Cryptex1") == 0) || (strcmp(s_updater_name, "Cryptex1LocalPolicy") == 0)) { - fwdict = restore_get_cryptex1_firmware_data(restore, client, build_identity, p_info, arguments); + fwdict = restore_get_cryptex1_firmware_data(client, p_info, arguments); if (fwdict == NULL) { - error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); + logger(LL_ERROR, "%s: Couldn't get %s firmware data\n", __func__, s_updater_name); goto error_out; } } else if (strcmp(s_updater_name, "Ace3") == 0) { - fwdict = restore_get_generic_firmware_data(restore, client, build_identity, p_info, arguments); + fwdict = restore_get_generic_firmware_data(client, p_info, arguments); if (fwdict == NULL) { - error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); + logger(LL_ERROR, "%s: Couldn't get %s firmware data\n", __func__, s_updater_name); + goto error_out; + } + } else if (strcmp(s_updater_name, "Centauri") == 0) { + fwdict = restore_get_generic_firmware_data(client, p_info, arguments); + if (fwdict == NULL) { + logger(LL_ERROR, "%s: Couldn't get %s firmware data\n", __func__, s_updater_name); + goto error_out; + } + } else if (strcmp(s_updater_name, "Vinyl") == 0) { + fwdict = restore_get_generic_firmware_data(client, p_info, arguments); + if (fwdict == NULL) { + logger(LL_ERROR, "%s: Couldn't get %s firmware data\n", __func__, s_updater_name); goto error_out; } } else { - error("ERROR: %s: Got unknown updater name '%s', trying to discover from device generated request.\n", __func__, s_updater_name); - fwdict = restore_get_generic_firmware_data(restore, client, build_identity, p_info, arguments); + logger(LL_ERROR, "%s: Got unknown updater name '%s', trying to discover from device generated request.\n", __func__, s_updater_name); + fwdict = restore_get_generic_firmware_data(client, p_info, arguments); if (fwdict == NULL) { - error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); + logger(LL_ERROR, "%s: Couldn't get %s firmware data\n", __func__, s_updater_name); goto error_out; } } free(s_updater_name); s_updater_name = NULL; + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); + return -1; + } + dict = plist_new_dict(); plist_dict_set_item(dict, "FirmwareResponseData", fwdict); - info("Sending FirmwareResponse data now...\n"); - restore_error = restored_send(restore, dict); + logger(LL_INFO, "Sending FirmwareResponse data now...\n"); + restore_error = _restore_service_send(service, dict, 0); plist_free(dict); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Couldn't send FirmwareResponse data (%d)\n", restore_error); + logger(LL_ERROR, "Couldn't send FirmwareResponse data (%d)\n", restore_error); goto error_out; } - info("Done sending FirmwareUpdater data\n"); + logger(LL_INFO, "Done sending FirmwareUpdater data\n"); return 0; @@ -3255,29 +3886,41 @@ error_out: return -1; } -static int restore_send_receipt_manifest(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity) +static int restore_send_receipt_manifest(struct idevicerestore_client_t* client, plist_t message) { plist_t dict; int restore_error; - plist_t manifest = plist_dict_get_item(build_identity, "Manifest"); + if (!client || !client->restore || !client->restore->build_identity) { + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + + plist_t manifest = plist_dict_get_item(client->restore->build_identity, "Manifest"); if (!manifest) { - error("failed to get Manifest node from build_identity"); + logger(LL_ERROR, "%s: Failed to get Manifest node from build_identity\n", __func__); goto error_out; } + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); + return -1; + } + dict = plist_new_dict(); plist_dict_set_item(dict, "ReceiptManifest", plist_copy(manifest)); - info("Sending ReceiptManifest data now...\n"); - restore_error = restored_send(restore, dict); + logger(LL_INFO, "Sending ReceiptManifest data now...\n"); + restore_error = _restore_service_send(service, dict, 0); plist_free(dict); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Couldn't send ReceiptManifest data (%d)\n", restore_error); + logger(LL_ERROR, "Couldn't send ReceiptManifest data (%d)\n", restore_error); goto error_out; } - info("Done sending ReceiptManifest data\n"); + logger(LL_INFO, "Done sending ReceiptManifest data\n"); return 0; @@ -3331,20 +3974,20 @@ static int cpio_send_file(idevice_connection_t connection, const char *name, str device_error = idevice_connection_send(connection, (void *)&hdr, sizeof(hdr), &bytes); if (device_error != IDEVICE_E_SUCCESS || bytes != sizeof(hdr)) { - error("ERROR: BootabilityBundle unable to send header. (%d) Sent %u of %lu bytes.\n", device_error, bytes, (long)sizeof(hdr)); + logger(LL_ERROR, "BootabilityBundle unable to send header. (%d) Sent %u of %lu bytes.\n", device_error, bytes, (long)sizeof(hdr)); return -1; } device_error = idevice_connection_send(connection, (void *)name, name_len, &bytes); if (device_error != IDEVICE_E_SUCCESS || bytes != name_len) { - error("ERROR: BootabilityBundle unable to send filename. (%d) Sent %u of %u bytes.\n", device_error, bytes, name_len); + logger(LL_ERROR, "BootabilityBundle unable to send filename. (%d) Sent %u of %u bytes.\n", device_error, bytes, name_len); return -1; } if (st->st_size && data) { device_error = idevice_connection_send(connection, data, st->st_size, &bytes); if (device_error != IDEVICE_E_SUCCESS || bytes != st->st_size) { - error("ERROR: BootabilityBundle unable to send data. (%d) Sent %u of %lu bytes.\n", device_error, bytes, (long)st->st_size); + logger(LL_ERROR, "BootabilityBundle unable to send data. (%d) Sent %u of %lu bytes.\n", device_error, bytes, (long)st->st_size); return -1; } } @@ -3366,15 +4009,15 @@ static int restore_bootability_send_one(void *ctx, ipsw_archive_t ipsw, const ch subpath = name + strlen(prefix); } - debug("DEBUG: BootabilityBundle send m=%07o s=%10ld %s\n", stat->st_mode, (long)stat->st_size, subpath); + logger(LL_DEBUG, "BootabilityBundle send m=%07o s=%10ld %s\n", stat->st_mode, (long)stat->st_size, subpath); - unsigned char *buf = NULL; - unsigned int size = 0; + void *buf = NULL; + size_t size = 0; if ((S_ISLNK(stat->st_mode) || S_ISREG(stat->st_mode)) && stat->st_size != 0) { ipsw_extract_to_memory(ipsw, name, &buf, &size); if (size != stat->st_size) { - error("ERROR: expected %ld bytes but got %d for file %s\n", (long)stat->st_size, size, name); + logger(LL_ERROR, "expected %zu bytes but got %zu for file %s\n", (size_t)stat->st_size, size, name); free(buf); return -1; } @@ -3388,11 +4031,11 @@ static int restore_bootability_send_one(void *ctx, ipsw_archive_t ipsw, const ch return ret; } -static int restore_send_bootability_bundle_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message, idevice_t device) +static int restore_send_bootability_bundle_data(struct idevicerestore_client_t* client, plist_t message) { - if (idevicerestore_debug) { - debug("DEBUG: %s: Got BootabilityBundle request:\n", __func__); - debug_plist(message); + if (client->debug_level > 1) { + logger(LL_DEBUG, "%s: Got BootabilityBundle request:\n", __func__); + logger_dump_plist(LL_DEBUG, message, 1); } plist_t node = plist_dict_get_item(message, "DataPort"); @@ -3404,24 +4047,29 @@ static int restore_send_bootability_bundle_data(restored_client_t restore, struc idevice_connection_t connection = NULL; idevice_error_t device_error = IDEVICE_E_SUCCESS; - debug("Connecting to BootabilityBundle data port\n"); + if (!client || !client->restore || !client->restore->build_identity || !client->restore->device) { + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + + logger(LL_DEBUG, "Connecting to BootabilityBundle data port\n"); while (--attempts > 0) { - device_error = idevice_connect(device, data_port, &connection); + device_error = idevice_connect(client->restore->device, data_port, &connection); if (device_error == IDEVICE_E_SUCCESS) { break; } sleep(1); - debug("Retrying connection...\n"); + logger(LL_DEBUG, "Retrying connection...\n"); } if (device_error != IDEVICE_E_SUCCESS) { - error("ERROR: Unable to connect to BootabilityBundle data port\n"); + logger(LL_ERROR, "Unable to connect to BootabilityBundle data port\n"); return -1; } int ret = ipsw_list_contents(client->ipsw, restore_bootability_send_one, connection); if (ret < 0) { - error("ERROR: Failed to send BootabilityBundle\n"); + logger(LL_ERROR, "Failed to send BootabilityBundle\n"); return ret; } @@ -3451,30 +4099,30 @@ plist_t restore_get_build_identity(struct idevicerestore_client_t* client, uint8 plist_t unique_id_node = plist_dict_get_item(client->build_manifest, "UniqueBuildID"); if (unique_id_node) { - printf("UniqueBuildID: "); + logger(LL_INFO, "UniqueBuildID: "); plist_write_to_stream(unique_id_node, stdout, PLIST_FORMAT_PRINT, PLIST_OPT_NONE); } return build_identity; } -plist_t restore_get_build_identity_from_request(struct idevicerestore_client_t* client, plist_t msg) +plist_t restore_get_build_identity_from_request(struct idevicerestore_client_t* client, plist_t message) { - plist_t args = plist_dict_get_item(msg, "Arguments"); - return restore_get_build_identity(client, _plist_dict_get_bool(args, "IsRecoveryOS")); + plist_t args = plist_dict_get_item(message, "Arguments"); + return restore_get_build_identity(client, plist_dict_get_bool(args, "IsRecoveryOS")); } int extract_macos_variant(plist_t build_identity, char** output) { plist_t build_info = plist_dict_get_item(build_identity, "Info"); if (!build_info) { - error("ERROR: build identity does not contain an 'Info' element\n"); + logger(LL_ERROR, "build identity does not contain an 'Info' element\n"); return -1; } plist_t macos_variant_node = plist_dict_get_item(build_info, "MacOSVariant"); if (!macos_variant_node) { - error("ERROR: build identity info does not contain a MacOSVariant\n"); + logger(LL_ERROR, "build identity info does not contain a MacOSVariant\n"); return -1; } plist_get_string_val(macos_variant_node, output); @@ -3486,13 +4134,13 @@ static char* extract_global_manifest_path(plist_t build_identity, char *variant) { plist_t build_info = plist_dict_get_item(build_identity, "Info"); if (!build_info) { - error("ERROR: build identity does not contain an 'Info' element\n"); + logger(LL_ERROR, "build identity does not contain an 'Info' element\n"); return NULL; } plist_t device_class_node = plist_dict_get_item(build_info, "DeviceClass"); if (!device_class_node) { - error("ERROR: build identity info does not contain a DeviceClass\n"); + logger(LL_ERROR, "build identity info does not contain a DeviceClass\n"); return NULL; } char *device_class = NULL; @@ -3511,8 +4159,9 @@ static char* extract_global_manifest_path(plist_t build_identity, char *variant) } // The path of the global manifest is hardcoded. There's no pointer to in the build manifest. - char *ticket_path = malloc((42+strlen(macos_variant)+strlen(device_class)+1)*sizeof(char)); - sprintf(ticket_path, "Firmware/Manifests/restore/%s/apticket.%s.im4m", macos_variant, device_class); + size_t psize = 42+strlen(macos_variant)+strlen(device_class)+1; + char *ticket_path = malloc(psize); + snprintf(ticket_path, psize, "Firmware/Manifests/restore/%s/apticket.%s.im4m", macos_variant, device_class); free(device_class); free(macos_variant); @@ -3520,17 +4169,17 @@ static char* extract_global_manifest_path(plist_t build_identity, char *variant) return ticket_path; } -int extract_global_manifest(struct idevicerestore_client_t* client, plist_t build_identity, char *variant, unsigned char** pbuffer, unsigned int* psize) +int extract_global_manifest(struct idevicerestore_client_t* client, plist_t build_identity, char *variant, void** pbuffer, size_t* psize) { char* ticket_path = extract_global_manifest_path(build_identity, variant); if (!ticket_path) { - error("ERROR: failed to get global manifest path\n"); + logger(LL_ERROR, "failed to get global manifest path\n"); return -1; } int ret = ipsw_extract_to_memory(client->ipsw, ticket_path, pbuffer, psize); if (ret != 0) { free(ticket_path); - error("ERROR: failed to read global manifest\n"); + logger(LL_ERROR, "failed to read global manifest\n"); return -1; } free(ticket_path); @@ -3540,11 +4189,12 @@ int extract_global_manifest(struct idevicerestore_client_t* client, plist_t buil struct _restore_send_file_data_ctx { struct idevicerestore_client_t* client; - restored_client_t restore; + restore_service_client_t service; int last_progress; + uint32_t tag; }; -static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, void* data, size_t size, size_t done, size_t total_size) +static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, const void* data, size_t size, size_t done, size_t total_size) { plist_t dict = plist_new_dict(); if (data != NULL) { @@ -3554,15 +4204,34 @@ static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, voi // Send FileDataDone to mark end of transfer plist_dict_set_item(dict, "FileDataDone", plist_new_bool(1)); } - restored_error_t restore_error = restored_send(rctx->restore, dict); + restored_error_t restore_error = _restore_service_send(rctx->service, dict, 0); if (restore_error != RESTORE_E_SUCCESS) { plist_free(dict); - error("ERROR: %s: Failed to send data (%d)\n", __func__, restore_error); + logger(LL_ERROR, "%s: Failed to send data (%d)\n", __func__, restore_error); return -1; } plist_free(dict); + + /* special handling for AEA image format */ + if (done == 0 && (memcmp(data, "AEA1", 4) == 0)) { + logger(LL_VERBOSE, "Encountered First Chunk in AEA image\n"); + plist_t message = NULL; + property_list_service_error_t err = _restore_service_recv_timeout(rctx->service, &message, 3000); + if (err == PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT) { + logger(LL_VERBOSE, "No URLAsset requested, assuming it is not necessary.\n"); + } else if (err == PROPERTY_LIST_SERVICE_E_SUCCESS) { + if (PLIST_IS_DICT(message) && plist_dict_get_item(message, "Arguments")) { + restore_send_url_asset(rctx->client, message); + } else { + logger(LL_DEBUG, "%s: Unexpected message received\n", __func__); + logger_dump_plist(LL_DEBUG, message, 1); + } + } + } + if (total_size > 0x1000000) { double progress = (double)done / (double)total_size; + set_progress(rctx->tag, progress); int progress_int = (int)(progress*100.0); if (progress_int > rctx->last_progress) { idevicerestore_progress(rctx->client, RESTORE_STEP_UPLOAD_IMG, progress); @@ -3572,105 +4241,115 @@ static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, voi return 0; } -int restore_send_personalized_boot_object_v3(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg, plist_t build_identity) +int restore_send_personalized_boot_object_v3(struct idevicerestore_client_t* client, plist_t message) { - if (idevicerestore_debug) { - debug("DEBUG: %s: Got PersonalizedBootObjectV3 request:\n", __func__); - debug_plist(msg); + if (client->debug_level > 1) { + logger(LL_DEBUG, "%s: Got PersonalizedBootObjectV3 request:\n", __func__); + logger_dump_plist(LL_DEBUG, message, 1); } char *image_name = NULL; - plist_t node = plist_access_path(msg, 2, "Arguments", "ImageName"); + plist_t node = plist_access_path(message, 2, "Arguments", "ImageName"); if (!node || plist_get_node_type(node) != PLIST_STRING) { - debug("Failed to parse arguments from PersonalizedBootObjectV3 plist\n"); + logger(LL_DEBUG, "Failed to parse arguments from PersonalizedBootObjectV3 plist\n"); return -1; } plist_get_string_val(node, &image_name); if (!image_name) { - debug("Failed to parse arguments from PersonalizedBootObjectV3 as string\n"); + logger(LL_DEBUG, "Failed to parse arguments from PersonalizedBootObjectV3 as string\n"); return -1; } char *component = image_name; - unsigned int size = 0; - unsigned char *data = NULL; + size_t size = 0; + void *data = NULL; char *path = NULL; - plist_t blob = NULL; - plist_t dict = NULL; - restored_error_t restore_error = RESTORE_E_SUCCESS; - info("About to send %s...\n", component); + logger(LL_INFO, "About to send %s...\n", component); if (strcmp(image_name, "__GlobalManifest__") == 0) { - int ret = extract_global_manifest(client, build_identity, NULL, &data, &size); + int ret = extract_global_manifest(client, client->restore->build_identity, NULL, &data, &size); if (ret != 0) { return -1; } } else if (strcmp(image_name, "__RestoreVersion__") == 0) { int ret = ipsw_extract_to_memory(client->ipsw, "RestoreVersion.plist", &data, &size); if (ret != 0) { - error("ERROR: failed to read global manifest\n"); + logger(LL_ERROR, "failed to read global manifest\n"); return -1; } } else if (strcmp(image_name, "__SystemVersion__") == 0) { int ret = ipsw_extract_to_memory(client->ipsw, "SystemVersion.plist", &data, &size); if (ret != 0) { - error("ERROR: failed to read global manifest\n"); + logger(LL_ERROR, "failed to read global manifest\n"); return -1; } } else { // Get component path if (client->tss) { if (tss_response_get_path_by_entry(client->tss, component, &path) < 0) { - debug("NOTE: No path for component %s in TSS, will fetch from build identity\n", component); + logger(LL_DEBUG, "No path for component %s in TSS, will fetch from build identity\n", component); } } if (!path) { - plist_t build_identity = restore_get_build_identity_from_request(client, msg); + plist_t build_identity = restore_get_build_identity_from_request(client, message); if (!build_identity) { - error("ERROR: Unable to find a matching build identity\n"); + logger(LL_ERROR, "Unable to find a matching build identity\n"); return -1; } if (build_identity_get_component_path(build_identity, component, &path) < 0) { - error("ERROR: Unable to find %s path from build identity\n", component); + logger(LL_ERROR, "Unable to find %s path from build identity\n", component); return -1; } } // Extract component - unsigned char *component_data = NULL; - unsigned int component_size = 0; + void *component_data = NULL; + size_t component_size = 0; int ret = extract_component(client->ipsw, path, &component_data, &component_size); free(path); path = NULL; if (ret < 0) { - error("ERROR: Unable to extract component %s\n", component); + logger(LL_ERROR, "Unable to extract component %s\n", component); return -1; } // Personalize IMG4 - ret = personalize_component(component, component_data, component_size, client->tss, &data, &size); + ret = personalize_component(client, component, component_data, component_size, client->tss, &data, &size); free(component_data); component_data = NULL; if (ret < 0) { - error("ERROR: Unable to get personalized component %s\n", component); + logger(LL_ERROR, "Unable to get personalized component %s\n", component); return -1; } } - info("Sending %s now (%" PRIu64 " bytes)...\n", component, (uint64_t)size); + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); + return -1; + } + + logger(LL_INFO, "Sending %s now (%" PRIu64 " bytes)...\n", component, (uint64_t)size); struct _restore_send_file_data_ctx rctx; rctx.client = client; - rctx.restore = restore; + rctx.service = service; rctx.last_progress = 0; + rctx.tag = progress_get_next_tag(); + + if (size > 0x2000000) { + register_progress(rctx.tag, component); + } int64_t i = size; while (i > 0) { int blob_size = i > 8192 ? 8192 : i; - if (_restore_send_file_data(&rctx, (data + size - i), blob_size, size-i, size) < 0) { + if (_restore_send_file_data(&rctx, ((char*)data + size - i), blob_size, size-i, size) < 0) { free(data); - error("ERROR: Unable to send component %s data\n", component); + _restore_service_free(service); + finalize_progress(rctx.tag); + logger(LL_ERROR, "Unable to send component %s data\n", component); return -1; } i -= blob_size; @@ -3678,56 +4357,54 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i free(data); _restore_send_file_data(&rctx, NULL, 0, size-i, size); + finalize_progress(rctx.tag); + + _restore_service_free(service); - info("Done sending %s\n", component); + logger(LL_INFO, "Done sending %s\n", component); return 0; } -int restore_send_source_boot_object_v4(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg, plist_t build_identity) +int restore_send_source_boot_object_v4(struct idevicerestore_client_t* client, plist_t message) { - if (idevicerestore_debug) { - debug("DEBUG: %s: Got SourceBootObjectV4 request:\n", __func__); - debug_plist(msg); + if (client->debug_level > 1) { + logger(LL_DEBUG, "%s: Got SourceBootObjectV4 request:\n", __func__); + logger_dump_plist(LL_DEBUG, message, 1); } char *image_name = NULL; - plist_t node = plist_access_path(msg, 2, "Arguments", "ImageName"); + plist_t node = plist_access_path(message, 2, "Arguments", "ImageName"); if (!node || plist_get_node_type(node) != PLIST_STRING) { - debug("Failed to parse arguments from SourceBootObjectV4 plist\n"); + logger(LL_DEBUG, "Failed to parse arguments from SourceBootObjectV4 plist\n"); return -1; } plist_get_string_val(node, &image_name); if (!image_name) { - debug("Failed to parse arguments from SourceBootObjectV4 as string\n"); + logger(LL_DEBUG, "Failed to parse arguments from SourceBootObjectV4 as string\n"); return -1; } char *component = image_name; // Fork from restore_send_component // - unsigned int size = 0; - unsigned char *data = NULL; char *path = NULL; - plist_t blob = NULL; - plist_t dict = NULL; - restored_error_t restore_error = RESTORE_E_SUCCESS; - info("About to send %s...\n", component); + logger(LL_INFO, "About to send %s...\n", component); if (strcmp(image_name, "__GlobalManifest__") == 0) { char *variant = NULL; - plist_t node = plist_access_path(msg, 2, "Arguments", "Variant"); + plist_t node = plist_access_path(message, 2, "Arguments", "Variant"); if (!node || plist_get_node_type(node) != PLIST_STRING) { - debug("Failed to parse arguments from SourceBootObjectV4 plist\n"); + logger(LL_DEBUG, "Failed to parse arguments from SourceBootObjectV4 plist\n"); return -1; } plist_get_string_val(node, &variant); if (!variant) { - debug("Failed to parse arguments from SourceBootObjectV4 as string\n"); + logger(LL_DEBUG, "Failed to parse arguments from SourceBootObjectV4 as string\n"); return -1; } - path = extract_global_manifest_path(build_identity, variant); + path = extract_global_manifest_path(client->restore->build_identity, variant); } else if (strcmp(image_name, "__RestoreVersion__") == 0) { path = strdup("RestoreVersion.plist"); } else if (strcmp(image_name, "__SystemVersion__") == 0) { @@ -3736,51 +4413,65 @@ int restore_send_source_boot_object_v4(restored_client_t restore, struct idevice // Get component path if (client->tss) { if (tss_response_get_path_by_entry(client->tss, component, &path) < 0) { - debug("NOTE: No path for component %s in TSS, will fetch from build identity\n", component); + logger(LL_DEBUG, "No path for component %s in TSS, will fetch from build identity\n", component); } } if (!path) { - plist_t build_identity = restore_get_build_identity_from_request(client, msg); + plist_t build_identity = restore_get_build_identity_from_request(client, message); if (build_identity_get_component_path(build_identity, component, &path) < 0) { - error("ERROR: Unable to find %s path from build identity\n", component); + logger(LL_ERROR, "Unable to find %s path from build identity\n", component); return -1; } } } if (!path) { - error("ERROR: Failed to get path for component %s\n", component); + logger(LL_ERROR, "Failed to get path for component %s\n", component); return -1; } uint64_t fsize = 0; ipsw_get_file_size(client->ipsw, path, &fsize); - info("Sending %s now (%" PRIu64 " bytes)\n", component, fsize); + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); + return -1; + } + + logger(LL_INFO, "Sending %s now (%" PRIu64 " bytes)\n", component, fsize); struct _restore_send_file_data_ctx rctx; rctx.client = client; - rctx.restore = restore; + rctx.service = service; rctx.last_progress = 0; + rctx.tag = progress_get_next_tag(); + + register_progress(rctx.tag, component); if (ipsw_extract_send(client->ipsw, path, 8192, (ipsw_send_cb)_restore_send_file_data, &rctx) < 0) { free(path); - error("ERROR: Failed to send component %s\n", component); + _restore_service_free(service); + finalize_progress(rctx.tag); + logger(LL_ERROR, "Failed to send component %s\n", component); return -1; } free(path); - info("Done sending %s\n", component); + _restore_service_free(service); + finalize_progress(rctx.tag); + + logger(LL_INFO, "Done sending %s\n", component); return 0; } -int restore_send_restore_local_policy(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg) +int restore_send_restore_local_policy(struct idevicerestore_client_t* client, plist_t message) { - unsigned int size = 0; - unsigned char* data = NULL; + size_t size = 0; + void* data = NULL; - unsigned char* component_data = NULL; - unsigned int component_size = 0; + void* component_data = NULL; + size_t component_size = 0; char* component = "Ap,LocalPolicy"; @@ -3791,26 +4482,34 @@ int restore_send_restore_local_policy(restored_client_t restore, struct idevicer // The Update mode does not have a specific build identity for the recovery os. plist_t build_identity = restore_get_build_identity(client, client->flags & FLAG_ERASE ? 1 : 0); - int ret = get_recovery_os_local_policy_tss_response(client, build_identity, &client->tss_localpolicy, plist_dict_get_item(msg, "Arguments")); + int ret = get_recovery_os_local_policy_tss_response(client, build_identity, &client->tss_localpolicy, plist_dict_get_item(message, "Arguments")); if (ret < 0) { - error("ERROR: Unable to get recovery os local policy tss response\n"); + logger(LL_ERROR, "Unable to get recovery os local policy tss response\n"); return -1; } - ret = personalize_component(component, component_data, component_size, client->tss_localpolicy, &data, &size); + ret = personalize_component(client, component, component_data, component_size, client->tss_localpolicy, &data, &size); free(component_data); component_data = NULL; if (ret < 0) { - error("ERROR: Unable to get personalized component %s\n", component); + logger(LL_ERROR, "Unable to get personalized component %s\n", component); return -1; } plist_t dict = plist_new_dict(); plist_dict_set_item(dict, "Ap,LocalPolicy", plist_new_data((char*)data, size)); - int restore_error = restored_send(restore, dict); + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); + return -1; + } + + int restore_error = 0; + restore_error = _restore_service_send(service, dict, 0); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send component %s data\n", component); + logger(LL_ERROR, "Unable to send component %s data\n", component); return -1; } @@ -3820,38 +4519,276 @@ int restore_send_restore_local_policy(restored_client_t restore, struct idevicer return 0; } -int restore_send_buildidentity(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg) +int restore_send_buildidentity(struct idevicerestore_client_t* client, plist_t message) { restored_error_t restore_error; plist_t dict; - info("About to send BuildIdentity Dict...\n"); + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); + return -1; + } + + logger(LL_INFO, "About to send BuildIdentity Dict...\n"); - plist_t build_identity = restore_get_build_identity_from_request(client, msg); + plist_t build_identity = restore_get_build_identity_from_request(client, message); dict = plist_new_dict(); plist_dict_set_item(dict, "BuildIdentityDict", plist_copy(build_identity)); - plist_t node = plist_access_path(msg, 2, "Arguments", "Variant"); + plist_t node = plist_access_path(message, 2, "Arguments", "Variant"); if(node) { plist_dict_set_item(dict, "Variant", plist_copy(node)); } else { plist_dict_set_item(dict, "Variant", plist_new_string("Erase")); } - info("Sending BuildIdentityDict now...\n"); - restore_error = restored_send(restore, dict); + logger(LL_INFO, "Sending BuildIdentityDict now...\n"); + restore_error = _restore_service_send(service, dict, 0); + _restore_service_free(service); plist_free(dict); if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send BuildIdentityDict (%d)\n", restore_error); + logger(LL_ERROR, "Unable to send BuildIdentityDict (%d)\n", restore_error); + return -1; + } + + logger(LL_INFO, "Done sending BuildIdentityDict\n"); + return 0; +} + +int restore_send_recovery_os_file_asset_image(struct idevicerestore_client_t* client, plist_t message) +{ + char *fw_override_key = NULL; + plist_t node = plist_access_path(message, 2, "Arguments", "FWOverrideKey"); + if (PLIST_IS_STRING(node)) { + plist_get_string_val(node, &fw_override_key); + } + if (!fw_override_key) { + logger(LL_ERROR, "Failed to get FWOverrideKey from arguments. Trying to continue anyway.\n"); + return -1; + } + + plist_t dict = plist_new_dict(); + if (!client->recovery_variant) { + logger(LL_ERROR, "no RecoveryOS variant in BuildManifest. Trying to continue anyway.\n"); + plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1)); + restored_send(client->restore->client, dict); + plist_free(dict); + return 0; + } + + if (strncmp(fw_override_key, "RecoveryOS", 10) != 0) { + logger(LL_ERROR, "FWOVerrideKey has unexpected prefix\n"); + plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1)); + restored_send(client->restore->client, dict); + plist_free(dict); + return 0; + } + + const char* component = fw_override_key+10; + char* path = NULL; + if (build_identity_get_component_path(client->recovery_variant, component, &path) < 0) { + logger(LL_ERROR, "Unable to find %s path from recovery build identity. Trying to continue anyway.\n", component); + plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1)); + restored_send(client->restore->client, dict); + plist_free(dict); + return 0; + } + + void* component_data = NULL; + size_t component_size = 0; + int ret = extract_component(client->ipsw, path, &component_data, &component_size); + free(path); + path = NULL; + if (ret < 0) { + logger(LL_ERROR, "Unable to extract component %s. Trying to continue anyway.\n", component); + plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1)); + restored_send(client->restore->client, dict); + plist_free(dict); + return 0; + } + + void* data = NULL; + size_t size = 0; + ret = personalize_component(client, component, component_data, component_size, client->tss_recoveryos_root_ticket, &data, &size); + free(component_data); + component_data = NULL; + if (ret < 0) { + logger(LL_ERROR, "Unable to get personalized component %s. Trying to continue anyway.\n", component); + plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1)); + restored_send(client->restore->client, dict); + plist_free(dict); + return 0; + } + + logger(LL_INFO, "Sending %s\n", fw_override_key); + + plist_dict_set_item(dict, "AdditionalBootImages", plist_new_data((char*)data, size)); + free(data); + restored_send(client->restore->client, dict); + plist_free(dict); + + return 0; +} + +int restore_send_recovery_os_iboot_fw_files_images(struct idevicerestore_client_t* client, plist_t message) +{ + plist_t build_id_manifest = plist_dict_get_item(client->recovery_variant, "Manifest"); + if (!build_id_manifest) { + logger(LL_ERROR, "Missing Manifest dictionary in build identity?!\n"); + return -1; + } + + plist_t firmware_files = plist_new_dict(); + + plist_dict_iter iter = NULL; + plist_dict_new_iter(build_id_manifest, &iter); + if (iter) { + char *component = NULL; + plist_t manifest_entry; + do { + component = NULL; + manifest_entry = NULL; + plist_dict_next_item(build_id_manifest, iter, &component, &manifest_entry); + if (component && PLIST_IS_DICT(manifest_entry)) { + uint8_t loaded_by_iboot = 0; + uint8_t loaded_by_iboot_stage1 = 0; + plist_t fw_node; + + fw_node = plist_access_path(manifest_entry, 2, "Info", "IsLoadedByiBoot"); + if (fw_node && plist_get_node_type(fw_node) == PLIST_BOOLEAN) { + plist_get_bool_val(fw_node, &loaded_by_iboot); + } + fw_node = plist_access_path(manifest_entry, 2, "Info", "IsLoadedByiBootStage1"); + if (fw_node && plist_get_node_type(fw_node) == PLIST_BOOLEAN) { + plist_get_bool_val(fw_node, &loaded_by_iboot_stage1); + } + if (loaded_by_iboot || loaded_by_iboot_stage1) { + plist_t comp_path = plist_access_path(manifest_entry, 2, "Info", "Path"); + if (comp_path) { + const char* path = plist_get_string_ptr(comp_path, NULL); + void* component_data = NULL; + size_t component_size = 0; + int ret = extract_component(client->ipsw, path, &component_data, &component_size); + if (ret == 0) { + void* data = NULL; + size_t size = 0; + ret = personalize_component(client, component, component_data, component_size, client->tss_recoveryos_root_ticket, &data, &size); + free(component_data); + component_data = NULL; + if (ret == 0) { + plist_dict_set_item(firmware_files, component, plist_new_data((char*)data, size)); + free(data); + } + } + } + } + } + free(component); + } while (manifest_entry); + plist_mem_free(iter); + } + + plist_t dict = plist_new_dict(); + + if (plist_dict_get_size(firmware_files) == 0) { + plist_free(firmware_files); + logger(LL_NOTICE, "No iBoot firmware files. Continuing.\n"); + plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1)); + restored_send(client->restore->client, dict); + plist_free(dict); + return 0; + + } + + logger(LL_INFO, "Sending iBoot additional firmware files\n"); + + plist_dict_set_item(dict, "AdditionalBootImages", firmware_files); + restored_send(client->restore->client, dict); + plist_free(dict); + + return 0; +} + +int restore_send_recovery_os_image(struct idevicerestore_client_t* client, plist_t message) +{ + const char* component = "OS"; + char* path = NULL; + if (build_identity_get_component_path(client->recovery_variant, component, &path) < 0) { + logger(LL_ERROR, "Unable to find %s path from build identity\n", component); + return -1; + } + if (!path) { + logger(LL_ERROR, "Failed to get path for component %s\n", component); + return -1; + } + + uint64_t fsize = 0; + ipsw_get_file_size(client->ipsw, path, &fsize); + + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); return -1; } - info("Done sending BuildIdentityDict\n"); + logger(LL_INFO, "Sending %s now (%" PRIu64 " bytes)\n", component, fsize); + + struct _restore_send_file_data_ctx rctx; + rctx.client = client; + rctx.service = service; + rctx.last_progress = 0; + rctx.tag = progress_get_next_tag(); + + register_progress(rctx.tag, component); + + if (ipsw_extract_send(client->ipsw, path, 8192, (ipsw_send_cb)_restore_send_file_data, &rctx) < 0) { + free(path); + _restore_service_free(service); + finalize_progress(rctx.tag); + logger(LL_ERROR, "Failed to send component %s\n", component); + return -1; + } + free(path); + + _restore_service_free(service); + finalize_progress(rctx.tag); + + logger(LL_INFO, "Done sending %s\n", component); + return 0; } -int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t build_identity) +int restore_send_recovery_os_version_data(struct idevicerestore_client_t* client, plist_t message) +{ + plist_t build_id_info = plist_dict_get_item(client->recovery_variant, "Info"); + if (!build_id_info) { + logger(LL_ERROR, "Missing Info dictionary in build identity?!\n"); + return -1; + } + plist_t version_data = plist_new_dict(); + plist_dict_copy_item(version_data, build_id_info, "BuildNumber", NULL); + plist_dict_copy_item(version_data, build_id_info, "Variant", NULL); + plist_dict_copy_item(version_data, build_id_info, "BuildTrain", NULL); + plist_dict_copy_item(version_data, build_id_info, "ProductVersion", "ProductMarketingVersion"); + char *xml = NULL; + uint32_t xml_len = 0; + plist_to_xml(version_data, &xml, &xml_len); + plist_free(version_data); + + logger(LL_INFO, "Sending RecoveryOS version data\n"); + + plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "RecoveryOSVersionData", plist_new_data(xml, xml_len)); + plist_mem_free(xml); + restored_send(client->restore->client, dict); + plist_free(dict); + + return 0; +} + +int restore_handle_data_request_msg(struct idevicerestore_client_t* client, plist_t message) { plist_t node = NULL; @@ -3860,191 +4797,354 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev node = plist_dict_get_item(message, "DataType"); if (node && PLIST_STRING == plist_get_node_type(node)) { const char *type = plist_get_string_ptr(node, NULL); - +logger(LL_DEBUG, "%s: type = %s\n", __func__, type); // this request is sent when restored is ready to receive the filesystem if (!strcmp(type, "SystemImageData")) { - if(restore_send_filesystem(client, device, build_identity) < 0) { - error("ERROR: Unable to send filesystem\n"); + if (restore_send_filesystem(client, message) < 0) { + logger(LL_ERROR, "Unable to send filesystem\n"); return -2; } } else if (!strcmp(type, "BuildIdentityDict")) { - if (restore_send_buildidentity(restore, client, message) < 0) { - error("ERROR: Unable to send RootTicket\n"); + if (restore_send_buildidentity(client, message) < 0) { + logger(LL_ERROR, "Unable to send RootTicket\n"); return -1; } } else if (!strcmp(type, "PersonalizedBootObjectV3")) { - if (restore_send_personalized_boot_object_v3(restore, client, message, build_identity) < 0) { - error("ERROR: Unable to send PersonalizedBootObjectV3\n"); + if (restore_send_personalized_boot_object_v3(client, message) < 0) { + logger(LL_ERROR, "Unable to send PersonalizedBootObjectV3\n"); return -1; } } else if (!strcmp(type, "SourceBootObjectV4")) { - if (restore_send_source_boot_object_v4(restore, client, message, build_identity) < 0) { - error("ERROR: Unable to send SourceBootObjectV4\n"); + if (restore_send_source_boot_object_v4(client, message) < 0) { + logger(LL_ERROR, "Unable to send SourceBootObjectV4\n"); return -1; } } else if (!strcmp(type, "RecoveryOSLocalPolicy")) { - if (restore_send_restore_local_policy(restore, client, message) < 0) { - error("ERROR: Unable to send RecoveryOSLocalPolicy\n"); + if (restore_send_restore_local_policy(client, message) < 0) { + logger(LL_ERROR, "Unable to send RecoveryOSLocalPolicy\n"); return -1; } } // this request is sent when restored is ready to receive the filesystem else if (!strcmp(type, "RecoveryOSASRImage")) { - if(restore_send_filesystem(client, device, build_identity) < 0) { - error("ERROR: Unable to send filesystem\n"); + if (restore_send_filesystem(client, message) < 0) { + logger(LL_ERROR, "Unable to send filesystem\n"); return -2; } } // Send RecoveryOS RTD else if(!strcmp(type, "RecoveryOSRootTicketData")) { - if (restore_send_recovery_os_root_ticket(restore, client) < 0) { - error("ERROR: Unable to send RootTicket\n"); + if (restore_send_recovery_os_root_ticket(client, message) < 0) { + logger(LL_ERROR, "Unable to send RootTicket\n"); return -1; } } // send RootTicket (== APTicket from the TSS request) else if (!strcmp(type, "RootTicket")) { - if (restore_send_root_ticket(restore, client) < 0) { - error("ERROR: Unable to send RootTicket\n"); + if (restore_send_root_ticket(client, message) < 0) { + logger(LL_ERROR, "Unable to send RootTicket\n"); return -1; } } // send KernelCache else if (!strcmp(type, "KernelCache")) { - if (restore_send_component(restore, client, build_identity, "KernelCache", NULL) < 0) { - error("ERROR: Unable to send kernelcache\n"); + if (restore_send_component(client, message, "KernelCache", NULL) < 0) { + logger(LL_ERROR, "Unable to send kernelcache\n"); return -1; } } else if (!strcmp(type, "DeviceTree")) { - if (restore_send_component(restore, client, build_identity, "DeviceTree", NULL) < 0) { - error("ERROR: Unable to send DeviceTree\n"); + if (restore_send_component(client, message, "DeviceTree", NULL) < 0) { + logger(LL_ERROR, "Unable to send DeviceTree\n"); return -1; } } else if (!strcmp(type, "SystemImageRootHash")) { - if (restore_send_component(restore, client, build_identity, "SystemVolume", type) < 0) { - error("ERROR: Unable to send SystemImageRootHash data\n"); + if (restore_send_component(client, message, "SystemVolume", type) < 0) { + logger(LL_ERROR, "Unable to send SystemImageRootHash data\n"); return -1; } } else if (!strcmp(type, "SystemImageCanonicalMetadata")) { - if (restore_send_component(restore, client, build_identity, "Ap,SystemVolumeCanonicalMetadata", type) < 0) { - error("ERROR: Unable to send SystemImageCanonicalMetadata data\n"); + if (restore_send_component(client, message, "Ap,SystemVolumeCanonicalMetadata", type) < 0) { + logger(LL_ERROR, "Unable to send SystemImageCanonicalMetadata data\n"); return -1; } } else if (!strcmp(type, "NORData")) { if((client->flags & FLAG_EXCLUDE) == 0) { - if(restore_send_nor(restore, client, build_identity, message) < 0) { - error("ERROR: Unable to send NOR data\n"); + if(restore_send_nor(client, message) < 0) { + logger(LL_ERROR, "Unable to send NOR data\n"); return -1; } } else { - info("Not sending NORData... Quitting...\n"); + logger(LL_INFO, "Not sending NORData... Quitting...\n"); client->flags |= FLAG_QUIT; } } else if (!strcmp(type, "BasebandData")) { - if(restore_send_baseband_data(restore, client, build_identity, message) < 0) { - error("ERROR: Unable to send baseband data\n"); + if(restore_send_baseband_data(client, message) < 0) { + logger(LL_ERROR, "Unable to send baseband data\n"); return -1; } } else if (!strcmp(type, "FDRTrustData")) { - if(restore_send_fdr_trust_data(restore, device) < 0) { - error("ERROR: Unable to send FDR Trust data\n"); + if(restore_send_fdr_trust_data(client, message) < 0) { + logger(LL_ERROR, "Unable to send FDR Trust data\n"); return -1; } } else if (!strcmp(type, "FUDData")) { - if(restore_send_image_data(restore, client, build_identity, message, "FUDImageList", "IsFUDFirmware", "FUDImageData") < 0) { - error("ERROR: Unable to send FUD data\n"); + if(restore_send_image_data(client, message, "FUDImageList", "IsFUDFirmware", "FUDImageData") < 0) { + logger(LL_ERROR, "Unable to send FUD data\n"); return -1; } } else if (!strcmp(type, "FirmwareUpdaterPreflight")) { - if(restore_send_firmware_updater_preflight(restore, client, build_identity, message) < 0) { - error("ERROR: Unable to send FirmwareUpdaterPreflight\n"); + if(restore_send_firmware_updater_preflight(client, message) < 0) { + logger(LL_ERROR, "Unable to send FirmwareUpdaterPreflight\n"); return -1; } } else if (!strcmp(type, "FirmwareUpdaterData")) { - if(restore_send_firmware_updater_data(restore, client, build_identity, message) < 0) { - error("ERROR: Unable to send FirmwareUpdater data\n"); + if(restore_send_firmware_updater_data(client, message) < 0) { + logger(LL_ERROR, "Unable to send FirmwareUpdater data\n"); return -1; } } else if (!strcmp(type, "PersonalizedData")) { - if(restore_send_image_data(restore, client, build_identity, message, "ImageList", NULL, "ImageData") < 0) { - error("ERROR: Unable to send Personalized data\n"); + if(restore_send_image_data(client, message, "ImageList", NULL, "ImageData") < 0) { + logger(LL_ERROR, "Unable to send Personalized data\n"); return -1; } } else if (!strcmp(type, "EANData")) { - if(restore_send_image_data(restore, client, build_identity, message, "EANImageList", "IsEarlyAccessFirmware", "EANData") < 0) { - error("ERROR: Unable to send Personalized data\n"); + if(restore_send_image_data(client, message, "EANImageList", "IsEarlyAccessFirmware", "EANData") < 0) { + logger(LL_ERROR, "Unable to send Personalized data\n"); return -1; } } else if (!strcmp(type, "BootabilityBundle")) { - if (restore_send_bootability_bundle_data(restore, client, build_identity, message, device) < 0) { - error("ERROR: Unable to send BootabilityBundle data\n"); + if (restore_send_bootability_bundle_data(client, message) < 0) { + logger(LL_ERROR, "Unable to send BootabilityBundle data\n"); return -1; } } else if (!strcmp(type, "ReceiptManifest")) { - if (restore_send_receipt_manifest(restore, client, build_identity) < 0) { - error("ERROR: Unable to send ReceiptManifest data\n"); + if (restore_send_receipt_manifest(client, message) < 0) { + logger(LL_ERROR, "Unable to send ReceiptManifest data\n"); return -1; } } else if (!strcmp(type, "BasebandUpdaterOutputData")) { - if (restore_handle_baseband_updater_output_data(restore, client, device, message) < 0) { - error("ERROR: Unable to send BasebandUpdaterOutputData data\n"); + if (restore_handle_baseband_updater_output_data(client, message) < 0) { + logger(LL_ERROR, "Unable to send BasebandUpdaterOutputData data\n"); + return -1; + } + } + + else if (!strcmp(type, "URLAsset")) { + if (restore_send_url_asset(client, message) < 0) { + logger(LL_ERROR, "Unable to send URLAsset data\n"); + return -1; + } + } + + else if (!strcmp(type, "StreamedImageDecryptionKey")) { + if (restore_send_streamed_image_decryption_key(client, message) < 0) { + logger(LL_ERROR, "Unable to send StreamedImageDecryptionKey data\n"); + return -1; + } + } + + else if (!strcmp(type, "RecoveryOSFileAssetImage")) { + if (restore_send_recovery_os_file_asset_image(client, message) < 0) { + logger(LL_ERROR, "Unable to send RecoveryOSFileImageAssetImage data\n"); + return -1; + } + } + + else if (!strcmp(type, "RecoveryOSIBootFWFilesImages")) { + if (restore_send_recovery_os_iboot_fw_files_images(client, message) < 0) { + logger(LL_ERROR, "Unable to send RecoveryOSIBootFWFilesImages data\n"); + return -1; + } + } + + else if (!strcmp(type, "RecoveryOSImage")) { + if (restore_send_recovery_os_image(client, message) < 0) { + logger(LL_ERROR, "Unable to send RecoveryOSImage data\n"); + return -1; + } + } + + else if (!strcmp(type, "RecoveryOSVersionData")) { + if (restore_send_recovery_os_version_data(client, message) < 0) { + logger(LL_ERROR, "Unable to send RecoveryOSVersionData data\n"); return -1; } } else { // Unknown DataType!! - error("Unknown data request '%s' received\n", type); - if (idevicerestore_debug) - debug_plist(message); + logger(LL_ERROR, "Unknown data request '%s' received\n", type); + logger_dump_plist(LL_VERBOSE, message, 1); } } return 0; } +struct _restore_async_args { + struct idevicerestore_client_t* client; + plist_t message; +}; + +static void* _restore_handle_async_data_request(void* args) +{ + struct _restore_async_args* async_args = (struct _restore_async_args*)args; + struct idevicerestore_client_t* client = async_args->client; + plist_t message = async_args->message; + free(async_args); + + int err = restore_handle_data_request_msg(client, message); + if (err < 0) { + client->async_err = err; + client->flags |= FLAG_QUIT; + } + + plist_free(message); + return NULL; +} + +static int restore_handle_restored_crash(struct idevicerestore_client_t* client, plist_t message) +{ + plist_t backtrace = plist_dict_get_item(message, "RestoredBacktrace"); + logger(LL_INFO, "*** restored crashed, backtrace following ***\n"); + if (PLIST_IS_STRING(backtrace)) { + logger(LL_INFO, "%s\n", plist_get_string_ptr(backtrace, NULL)); + } else if (PLIST_IS_ARRAY(backtrace)) { + uint32_t i = 0; + for (i = 0; i < plist_array_get_size(backtrace); i++) { + plist_t line = plist_array_get_item(backtrace, i); + logger(LL_INFO, "\t%s\n", plist_get_string_ptr(line, NULL)); + } + } else { + logger_dump_plist(LL_VERBOSE, message, 1); + } + return 0; +} + +static int restore_handle_async_wait(struct idevicerestore_client_t* client, plist_t message) +{ + logger(LL_DEBUG, "AsyncWait\n"); + logger_dump_plist(LL_DEBUG, message, 1); + return 0; +} + +static int restore_handle_restore_attestation(struct idevicerestore_client_t* client, plist_t message) +{ + logger_dump_plist(LL_DEBUG, message, 1); + logger(LL_DEBUG, "Sending RestoreShouldAttest: false\n"); + plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "RestoreShouldAttest", plist_new_bool(0)); + restored_error_t restore_error = restored_send(client->restore->client, dict); + plist_free(dict); + if (restore_error != RESTORE_E_SUCCESS) { + logger(LL_ERROR, "Unable to send RestoreShouldAttest (%d)\n", restore_error); + return -1; + } + return 0; +} + +static void _restore_calculate_recovery_os_partition_size(struct idevicerestore_client_t* client, uint64_t* min_size, uint64_t* max_size) +{ + const char* asset_list[] = { "OS", "KernelCache", "DeviceTree", "iBEC", "AppleLogo", "StaticTrustCache", "iBootData", "Diags", "Ap,SystemVolumeCanonicalMetadata", "SystemVolume", "BaseSystemVolume", "Ap,BaseSystemTrustCache", "AVISP1,RTKitOS", NULL }; + + if (min_size) *min_size = 356; + if (max_size) *max_size = 420; + + double total_size = 0; + plist_t firmware_items = plist_new_dict(); + plist_t build_id_manifest = plist_dict_get_item(client->recovery_variant, "Manifest"); + plist_dict_iter iter = NULL; + plist_dict_new_iter(build_id_manifest, &iter); + if (iter) { + char *component = NULL; + plist_t manifest_entry; + do { + component = NULL; + manifest_entry = NULL; + plist_dict_next_item(build_id_manifest, iter, &component, &manifest_entry); + if (component && PLIST_IS_DICT(manifest_entry) && plist_dict_get_item(firmware_items, component) == NULL) { + int add_image = 0; + int i = 0; + while (asset_list[i]) { + if (!strcmp(asset_list[i], component)) { + add_image = 1; + break; + } + i++; + } + plist_t fw_node; + fw_node = plist_access_path(manifest_entry, 2, "Info", "IsLoadedByiBoot"); + if (fw_node && plist_get_node_type(fw_node) == PLIST_BOOLEAN) { + uint8_t loaded_by_iboot = 0; + plist_get_bool_val(fw_node, &loaded_by_iboot); + if (loaded_by_iboot) { + add_image = 1; + } + } + if (add_image) { + plist_t p_path = plist_access_path(manifest_entry, 2, "Info", "Path"); + if (p_path) { + const char* path = plist_get_string_ptr(p_path, NULL); + uint64_t fsize = 0; + if (ipsw_get_file_size(client->ipsw, path, &fsize) == 0) { + logger(LL_DEBUG, "%s: Adding %s (%s, %" PRIu64 " bytes)\n", __func__, component, path, fsize); + total_size += (double)fsize / 0x100000; + } + } + } + } + free(component); + } while (manifest_entry); + plist_mem_free(iter); + } + total_size = ceil(total_size); + if (min_size) *min_size = total_size * 1.05 + 25; + if (max_size) *max_size = total_size * 1.25 + 25; +} + // Extracted from ac2 plist_t restore_supported_data_types() { plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "AuthInstallCACert", plist_new_bool(1)); plist_dict_set_item(dict, "BasebandBootData", plist_new_bool(0)); plist_dict_set_item(dict, "BasebandData", plist_new_bool(0)); plist_dict_set_item(dict, "BasebandStackData", plist_new_bool(0)); @@ -4062,20 +5162,26 @@ plist_t restore_supported_data_types() plist_dict_set_item(dict, "FileData", plist_new_bool(0)); plist_dict_set_item(dict, "FileDataDone", plist_new_bool(0)); plist_dict_set_item(dict, "FirmwareUpdaterData", plist_new_bool(0)); + plist_dict_set_item(dict, "FirmwareUpdaterDataV2", plist_new_bool(0)); + plist_dict_set_item(dict, "FirmwareUpdaterDataV3", plist_new_bool(1)); + plist_dict_set_item(dict, "FirmwareUpdaterPreflight", plist_new_bool(1)); plist_dict_set_item(dict, "GrapeFWData", plist_new_bool(0)); plist_dict_set_item(dict, "HPMFWData", plist_new_bool(0)); plist_dict_set_item(dict, "HostSystemTime", plist_new_bool(1)); plist_dict_set_item(dict, "KernelCache", plist_new_bool(0)); + plist_dict_set_item(dict, "MessageUseStreamedImageFile", plist_new_bool(1)); plist_dict_set_item(dict, "NORData", plist_new_bool(0)); plist_dict_set_item(dict, "NitrogenFWData", plist_new_bool(1)); plist_dict_set_item(dict, "OpalFWData", plist_new_bool(0)); plist_dict_set_item(dict, "OverlayRootDataCount", plist_new_bool(0)); plist_dict_set_item(dict, "OverlayRootDataForKey", plist_new_bool(1)); + plist_dict_set_item(dict, "OverlayRootDataForKeyIndex", plist_new_bool(1)); plist_dict_set_item(dict, "PeppyFWData", plist_new_bool(1)); plist_dict_set_item(dict, "PersonalizedBootObjectV3", plist_new_bool(0)); plist_dict_set_item(dict, "PersonalizedData", plist_new_bool(1)); plist_dict_set_item(dict, "ProvisioningData", plist_new_bool(0)); plist_dict_set_item(dict, "RamdiskFWData", plist_new_bool(1)); + plist_dict_set_item(dict, "ReceiptManifest", plist_new_bool(1)); plist_dict_set_item(dict, "RecoveryOSASRImage", plist_new_bool(1)); plist_dict_set_item(dict, "RecoveryOSAppleLogo", plist_new_bool(1)); plist_dict_set_item(dict, "RecoveryOSDeviceTree", plist_new_bool(1)); @@ -4089,6 +5195,7 @@ plist_t restore_supported_data_types() plist_dict_set_item(dict, "RecoveryOSRootTicketData", plist_new_bool(1)); plist_dict_set_item(dict, "RecoveryOSStaticTrustCache", plist_new_bool(1)); plist_dict_set_item(dict, "RecoveryOSVersionData", plist_new_bool(1)); + plist_dict_set_item(dict, "RestoreLocalPolicy", plist_new_bool(1)); plist_dict_set_item(dict, "RootData", plist_new_bool(0)); plist_dict_set_item(dict, "RootTicket", plist_new_bool(0)); plist_dict_set_item(dict, "S3EOverride", plist_new_bool(0)); @@ -4099,14 +5206,10 @@ plist_t restore_supported_data_types() plist_dict_set_item(dict, "SystemImageCanonicalMetadata", plist_new_bool(0)); plist_dict_set_item(dict, "SystemImageData", plist_new_bool(0)); plist_dict_set_item(dict, "SystemImageRootHash", plist_new_bool(0)); + plist_dict_set_item(dict, "URLAsset", plist_new_bool(1)); plist_dict_set_item(dict, "USBCFWData", plist_new_bool(0)); plist_dict_set_item(dict, "USBCOverride", plist_new_bool(0)); - plist_dict_set_item(dict, "FirmwareUpdaterPreflight", plist_new_bool(1)); - plist_dict_set_item(dict, "ReceiptManifest", plist_new_bool(1)); - plist_dict_set_item(dict, "FirmwareUpdaterDataV2", plist_new_bool(0)); - plist_dict_set_item(dict, "RestoreLocalPolicy", plist_new_bool(1)); - plist_dict_set_item(dict, "AuthInstallCACert", plist_new_bool(1)); - plist_dict_set_item(dict, "OverlayRootDataForKeyIndex", plist_new_bool(1)); + plist_dict_set_item(dict, "UpdateVolumeOverlayRootDataCount", plist_new_bool(1)); return dict; } @@ -4114,8 +5217,11 @@ plist_t restore_supported_data_types() plist_t restore_supported_message_types() { plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "AsyncDataRequestMsg", plist_new_bool(1)); + plist_dict_set_item(dict, "AsyncWait", plist_new_bool(1)); plist_dict_set_item(dict, "BBUpdateStatusMsg", plist_new_bool(0)); plist_dict_set_item(dict, "CheckpointMsg", plist_new_bool(1)); + plist_dict_set_item(dict, "CrashLog", plist_new_bool(1)); plist_dict_set_item(dict, "DataRequestMsg", plist_new_bool(0)); plist_dict_set_item(dict, "FDRSubmit", plist_new_bool(1)); plist_dict_set_item(dict, "MsgType", plist_new_bool(0)); @@ -4125,6 +5231,7 @@ plist_t restore_supported_message_types() plist_dict_set_item(dict, "ProvisioningInfo", plist_new_bool(0)); plist_dict_set_item(dict, "ProvisioningStatusMsg", plist_new_bool(0)); plist_dict_set_item(dict, "ReceivedFinalStatusMsg", plist_new_bool(0)); + plist_dict_set_item(dict, "RestoreAttestation", plist_new_bool(1)); plist_dict_set_item(dict, "RestoredCrash", plist_new_bool(1)); plist_dict_set_item(dict, "StatusMsg", plist_new_bool(0)); return dict; @@ -4133,12 +5240,12 @@ plist_t restore_supported_message_types() #ifdef HAVE_REVERSE_PROXY static void rp_log_cb(reverse_proxy_client_t client, const char* log_msg, void* user_data) { - info("ReverseProxy[%s]: %s\n", (reverse_proxy_get_type(client) == RP_TYPE_CTRL) ? "Ctrl" : "Conn", log_msg); + logger(LL_VERBOSE, "ReverseProxy[%s]: %s\n", (reverse_proxy_get_type(client) == RP_TYPE_CTRL) ? "Ctrl" : "Conn", log_msg); } static void rp_status_cb(reverse_proxy_client_t client, reverse_proxy_status_t status, const char* status_msg, void* user_data) { - info("ReverseProxy[%s]: (status=%d) %s\n", (reverse_proxy_get_type(client) == RP_TYPE_CTRL) ? "Ctrl" : "Conn", status, status_msg); + logger(LL_VERBOSE, "ReverseProxy[%s]: (status=%d) %s\n", (reverse_proxy_get_type(client) == RP_TYPE_CTRL) ? "Ctrl" : "Conn", status, status_msg); } #endif @@ -4161,11 +5268,12 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // open our connection to the device and verify we're in restore mode err = restore_open_with_timeout(client); if (err < 0) { - error("ERROR: Unable to open device in restore mode\n"); + logger(LL_ERROR, "Unable to open device in restore mode\n"); return (err == -2) ? -1: -2; } - info("Device %s has successfully entered restore mode\n", client->udid); + logger(LL_INFO, "Device %s has successfully entered restore mode\n", client->udid); + client->restore->build_identity = build_identity; restore = client->restore->client; device = client->restore->device; @@ -4173,30 +5281,30 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit if (restore_error == RESTORE_E_SUCCESS) { uint64_t i = 0; uint8_t b = 0; - info("Hardware Information:\n"); + logger(LL_INFO, "Hardware Information:\n"); node = plist_dict_get_item(hwinfo, "BoardID"); if (node && plist_get_node_type(node) == PLIST_UINT) { plist_get_uint_val(node, &i); - info("BoardID: %d\n", (int)i); + logger(LL_INFO, "BoardID: %d\n", (int)i); } node = plist_dict_get_item(hwinfo, "ChipID"); if (node && plist_get_node_type(node) == PLIST_UINT) { plist_get_uint_val(node, &i); - info("ChipID: %d\n", (int)i); + logger(LL_INFO, "ChipID: %d\n", (int)i); } node = plist_dict_get_item(hwinfo, "UniqueChipID"); if (node && plist_get_node_type(node) == PLIST_UINT) { plist_get_uint_val(node, &i); - info("UniqueChipID: %" PRIu64 "\n", i); + logger(LL_INFO, "UniqueChipID: %" PRIu64 "\n", i); } node = plist_dict_get_item(hwinfo, "ProductionMode"); if (node && plist_get_node_type(node) == PLIST_BOOLEAN) { plist_get_bool_val(node, &b); - info("ProductionMode: %s\n", (b==1) ? "true":"false"); + logger(LL_INFO, "ProductionMode: %s\n", (b==1) ? "true":"false"); } plist_free(hwinfo); } @@ -4208,7 +5316,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit node = plist_dict_get_item(hwinfo, "PreviousExitStatus"); if (node && plist_get_node_type(node) == PLIST_STRING) { plist_get_string_val(node, &sval); - info("Previous restore exit status: %s\n", sval); + logger(LL_INFO, "Previous restore exit status: %s\n", sval); free(sval); sval = NULL; } @@ -4216,7 +5324,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit node = plist_dict_get_item(hwinfo, "USBLog"); if (node && plist_get_node_type(node) == PLIST_STRING) { plist_get_string_val(node, &sval); - info("USB log is available:\n%s\n", sval); + logger(LL_INFO, "USB log is available:\n%s\n", sval); free(sval); sval = NULL; } @@ -4224,7 +5332,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit node = plist_dict_get_item(hwinfo, "PanicLog"); if (node && plist_get_node_type(node) == PLIST_STRING) { plist_get_string_val(node, &sval); - info("Panic log is available:\n%s\n", sval); + logger(LL_INFO, "Panic log is available:\n%s\n", sval); free(sval); sval = NULL; } @@ -4236,42 +5344,42 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit } #ifdef HAVE_REVERSE_PROXY - info("Starting Reverse Proxy\n"); + logger(LL_INFO, "Starting Reverse Proxy\n"); reverse_proxy_client_t rproxy = NULL; if (reverse_proxy_client_create_with_port(device, &rproxy, REVERSE_PROXY_DEFAULT_PORT) != REVERSE_PROXY_E_SUCCESS) { - error("Could not create Reverse Proxy\n"); + logger(LL_ERROR, "Could not create Reverse Proxy\n"); } else { if (client->flags & FLAG_DEBUG) { reverse_proxy_client_set_log_callback(rproxy, rp_log_cb, NULL); } reverse_proxy_client_set_status_callback(rproxy, rp_status_cb, NULL); if (reverse_proxy_client_start_proxy(rproxy, 2) != REVERSE_PROXY_E_SUCCESS) { - error("Device didn't accept new reverse proxy protocol, trying to use old one\n"); + logger(LL_ERROR, "Device didn't accept new reverse proxy protocol, trying to use old one\n"); reverse_proxy_client_free(rproxy); rproxy = NULL; if (reverse_proxy_client_create_with_port(device, &rproxy, REVERSE_PROXY_DEFAULT_PORT) != REVERSE_PROXY_E_SUCCESS) { - error("Could not create Reverse Proxy\n"); + logger(LL_ERROR, "Could not create Reverse Proxy\n"); } else { if (client->flags & FLAG_DEBUG) { reverse_proxy_client_set_log_callback(rproxy, rp_log_cb, NULL); } reverse_proxy_client_set_status_callback(rproxy, rp_status_cb, NULL); if (reverse_proxy_client_start_proxy(rproxy, 1) != REVERSE_PROXY_E_SUCCESS) { - error("ReverseProxy: Device didn't accept old protocol, giving up\n"); + logger(LL_ERROR, "ReverseProxy: Device didn't accept old protocol, giving up\n"); } } } } #else fdr_client_t fdr_control_channel = NULL; - info("Starting FDR listener thread\n"); + logger(LL_INFO, "Starting FDR listener thread\n"); if (!fdr_connect(device, FDR_CTRL, &fdr_control_channel)) { if(thread_new(&fdr_thread, fdr_listener_thread, fdr_control_channel)) { - error("ERROR: Failed to start FDR listener thread\n"); + logger(LL_ERROR, "Failed to start FDR listener thread\n"); fdr_thread = THREAD_T_NULL; /* undefined after failure */ } } else { - error("ERROR: Failed to start FDR Ctrl channel\n"); + logger(LL_ERROR, "Failed to start FDR Ctrl channel\n"); // FIXME: We might want to return failure here as it will likely fail } #endif @@ -4281,15 +5389,15 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit //plist_dict_set_item(opts, "AuthInstallRestoreBehavior", plist_new_string("Erase")); plist_dict_set_item(opts, "AutoBootDelay", plist_new_uint(0)); - if (client->preflight_info) { - plist_t bbus = plist_copy(client->preflight_info); + if (client->firmware_preflight_info) { + plist_t bbus = plist_copy(client->firmware_preflight_info); plist_dict_remove_item(bbus, "FusingStatus"); plist_dict_remove_item(bbus, "PkHash"); plist_dict_set_item(opts, "BBUpdaterState", bbus); - _plist_dict_copy_data(opts, client->preflight_info, "BasebandNonce", "Nonce"); + plist_dict_copy_data(opts, client->firmware_preflight_info, "BasebandNonce", "Nonce"); } plist_dict_set_item(opts, "SupportedDataTypes", restore_supported_data_types()); @@ -4335,7 +5443,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit } } else { // FIXME: new on iOS 5 ? - plist_dict_set_item(opts, "BootImageType", plist_new_string("UserOrInternal")); + plist_dict_set_item(opts, "BootImageType", plist_new_string("User")); // FIXME: required? //plist_dict_set_item(opts, "BootImageFile", plist_new_string("018-7923-347.dmg")); plist_dict_set_item(opts, "DFUFileType", plist_new_string("RELEASE")); @@ -4361,7 +5469,32 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // FIXME: new on iOS 5 ? plist_dict_set_item(opts, "SystemImageType", plist_new_string("User")); // FIXME: does this have any effect actually? - plist_dict_set_item(opts, "UpdateBaseband", plist_new_bool(0)); + plist_dict_set_item(opts, "UpdateBaseband", plist_new_bool(1)); + plist_dict_set_item(opts, "InstallDiags", plist_new_bool(0)); + if (client->recovery_variant) { + plist_dict_set_item(opts, "InstallRecoveryOS", plist_new_bool(1)); + plist_dict_set_item(opts, "RecoveryOSBundlePath", plist_new_string("/tmp/Per2.tmp")); + plist_t recovery_variant = plist_access_path(client->recovery_variant, 2, "Info", "Variant"); + plist_dict_set_item(opts, "AuthInstallRecoveryOSVariant", plist_copy(recovery_variant)); + uint64_t max_size = 0; + uint64_t min_size = 0; + _restore_calculate_recovery_os_partition_size(client, &min_size, &max_size); + logger(LL_INFO, "Calculated recoveryOSPartitionSize as %" PRIu64 " MB\n", min_size); + logger(LL_INFO, "Calculated recoveryOSMaxPartitionSize as %" PRIu64 " MB\n", max_size); + plist_dict_set_item(opts, "recoveryOSMaxPartitionSize", plist_new_uint(max_size)); + plist_dict_set_item(opts, "recoveryOSPartitionSize", plist_new_uint(min_size)); + } + + if (plist_dict_get_bool(client->parameters, "RequiresNonceSlot")) { + logger(LL_INFO, "Device will use nonce slots.\n"); + } else { + logger(LL_INFO, "Device will not use nonce slots.\n"); + } + + // Added for iOS 18.0 beta 1 + plist_dict_set_item(opts, "HostHasFixFor99053849", plist_new_bool(1)); + plist_dict_set_item(opts, "SystemImageFormat", plist_new_string("AEAWrappedDiskImage")); + plist_dict_set_item(opts, "WaitForDeviceConnectionToFinishStateMachine", plist_new_bool(0)); plist_t sep = plist_access_path(build_identity, 3, "Manifest", "SEP", "Info"); if (sep) { @@ -4369,7 +5502,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit if (node && plist_get_node_type(node) == PLIST_STRING) { char* sval = NULL; plist_get_string_val(node, &sval); - debug("TZ0RequiredCapacity: %s\n", sval); + logger(LL_DEBUG, "TZ0RequiredCapacity: %s\n", sval); plist_dict_set_item(opts, "TZ0RequiredCapacity", plist_copy(node)); free(sval); sval = NULL; @@ -4381,6 +5514,15 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit plist_dict_set_item(opts, "PersonalizedDuringPreflight", plist_new_bool(1)); } + // Added for iOS 18.0 and macOS 15.0 + plist_t async_data_types = plist_new_dict(); + plist_dict_set_item(async_data_types, "BasebandData", plist_new_bool(0)); + plist_dict_set_item(async_data_types, "RecoveryOSASRImage", plist_new_bool(0)); + plist_dict_set_item(async_data_types, "StreamedImageDecryptionKey", plist_new_bool(0)); + plist_dict_set_item(async_data_types, "SystemImageData", plist_new_bool(0)); + plist_dict_set_item(async_data_types, "URLAsset", plist_new_bool(1)); + plist_dict_set_item(opts, "SupportedAsyncDataTypes", async_data_types); + plist_dict_set_item(opts, "RootToInstall", plist_new_bool(0)); char* guid = generate_guid(); if (guid) { @@ -4397,10 +5539,14 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit spp = plist_copy(spp); } else { spp = plist_new_dict(); + plist_dict_set_item(spp, "1024", plist_new_uint(1280)); plist_dict_set_item(spp, "128", plist_new_uint(1280)); plist_dict_set_item(spp, "16", plist_new_uint(160)); + plist_dict_set_item(spp, "256", plist_new_uint(1280)); plist_dict_set_item(spp, "32", plist_new_uint(320)); + plist_dict_set_item(spp, "512", plist_new_uint(1280)); plist_dict_set_item(spp, "64", plist_new_uint(640)); + plist_dict_set_item(spp, "768", plist_new_uint(1280)); plist_dict_set_item(spp, "8", plist_new_uint(80)); } plist_dict_set_item(opts, "SystemPartitionPadding", spp); @@ -4408,7 +5554,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // start the restore process restore_error = restored_start_restore(restore, opts, client->restore->protocol_version); if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to start the restore process\n"); + logger(LL_ERROR, "Unable to start the restore process\n"); plist_free(opts); restore_client_free(client); return -1; @@ -4420,30 +5566,30 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // restored and passes that data on to it's specific handler while (!(client->flags & FLAG_QUIT)) { if (err != 0 && client->flags & FLAG_IGNORE_ERRORS) { - error("WARNING: Attempting to continue after critical error, restore might fail...\n"); + logger(LL_WARNING, "Attempting to continue after critical error, restore might fail...\n"); err = 0; } // finally, if any of these message handlers returned -1 then we encountered // an unrecoverable error, so we need to bail. if (err < 0) { - error("ERROR: Unable to successfully restore device\n"); + logger(LL_ERROR, "Unable to successfully restore device\n"); client->flags |= FLAG_QUIT; } restore_error = restored_receive(restore, &message); #ifdef HAVE_RESTORE_E_RECEIVE_TIMEOUT if (restore_error == RESTORE_E_RECEIVE_TIMEOUT) { - debug("No data to read (timeout)\n"); + logger(LL_DEBUG, "No data to read (timeout)\n"); message = NULL; continue; } else if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Could not read data (%d). Aborting.\n", restore_error); + logger(LL_ERROR, "Could not read data (%d). Aborting.\n", restore_error); err = -11; break; } #else if (restore_error != RESTORE_E_SUCCESS) { - debug("No data to read\n"); + logger(LL_DEBUG, "No data to read\n"); message = NULL; continue; } @@ -4452,9 +5598,8 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // discover what kind of message has been received node = plist_dict_get_item(message, "MsgType"); if (!node || plist_get_node_type(node) != PLIST_STRING) { - debug("Unknown message received:\n"); - //if (idevicerestore_debug) - debug_plist(message); + logger(LL_DEBUG, "Unknown message received:\n"); + logger_dump_plist(LL_DEBUG, message, 1); plist_free(message); message = NULL; continue; @@ -4465,7 +5610,25 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // files sent to the server by the client. these data requests include // SystemImageData, RootTicket, KernelCache, NORData and BasebandData requests if (!strcmp(type, "DataRequestMsg")) { - err = restore_handle_data_request_msg(client, device, restore, message, build_identity); + err = restore_handle_data_request_msg(client, message); + } + + // async data request message + else if (!strcmp(type, "AsyncDataRequestMsg")) { + THREAD_T t = THREAD_T_NULL; + struct _restore_async_args* args = (struct _restore_async_args*)malloc(sizeof(struct _restore_async_args)); + args->client = client; + args->message = plist_copy(message); + if (thread_new(&t, _restore_handle_async_data_request, args) < 0) { + free(args); + logger(LL_ERROR, "Failed to start async data request handler thread!\n"); + err = -1; + if (client->flags & FLAG_IGNORE_ERRORS) { + client->flags &= ~FLAG_IGNORE_ERRORS; + } + } else { + thread_detach(t); + } } // restore logs are available if a previous restore failed @@ -4482,7 +5645,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // status messages usually indicate the current state of the restored // process or often to signal an error has been encountered else if (!strcmp(type, "StatusMsg")) { - err = restore_handle_status_msg(restore, message); + err = restore_handle_status_msg(client, message); if (restore_finished) { plist_t dict = plist_new_dict(); plist_dict_set_item(dict, "MsgType", plist_new_string("ReceivedFinalStatusMsg")); @@ -4500,8 +5663,9 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // Get checkpoint id node = plist_dict_get_item(message, "CHECKPOINT_ID"); if (!node || plist_get_node_type(node) != PLIST_INT) { - debug("Failed to parse checkpoint id from checkpoint plist\n"); - return -1; + logger(LL_DEBUG, "Failed to parse checkpoint id from checkpoint plist\n"); + err = -1; + break; } plist_get_uint_val(node, &ckpt_id); // Get checkpoint_name @@ -4510,8 +5674,9 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // Get checkpoint result node = plist_dict_get_item(message, "CHECKPOINT_RESULT"); if (!node || plist_get_node_type(node) != PLIST_INT) { - debug("Failed to parse checkpoint result from checkpoint plist\n"); - return -1; + logger(LL_DEBUG, "Failed to parse checkpoint result from checkpoint plist\n"); + err = -1; + break; } plist_get_int_val(node, &ckpt_res); // Get checkpoint complete @@ -4521,42 +5686,58 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit } if (ckpt_complete) { - info("Checkpoint completed id: 0x%" PRIX64 " (%s) result=%" PRIi64 "\n", ckpt_id, ckpt_name, ckpt_res); + logger(LL_VERBOSE, "Checkpoint completed id: 0x%" PRIX64 " (%s) result=%" PRIi64 "\n", ckpt_id, ckpt_name, ckpt_res); } else { - info("Checkpoint started id: 0x%" PRIX64 " (%s)\n", ckpt_id, ckpt_name); + logger(LL_VERBOSE, "Checkpoint started id: 0x%" PRIX64 " (%s)\n", ckpt_id, ckpt_name); } node = plist_dict_get_item(message, "CHECKPOINT_WARNING"); if (node) { - info("Checkpoint WARNING id: 0x%" PRIX64 " result=%" PRIi64 ": %s\n", ckpt_id, ckpt_res, plist_get_string_ptr(node, NULL)); + logger(LL_VERBOSE, "Checkpoint WARNING id: 0x%" PRIX64 " result=%" PRIi64 ": %s\n", ckpt_id, ckpt_res, plist_get_string_ptr(node, NULL)); } node = plist_dict_get_item(message, "CHECKPOINT_ERROR"); if (node) { - info("Checkpoint FAILURE id: 0x%" PRIX64 " result=%" PRIi64 ": %s\n", ckpt_id, ckpt_res, plist_get_string_ptr(node, NULL)); + logger(LL_VERBOSE, "Checkpoint FAILURE id: 0x%" PRIX64 " result=%" PRIi64 ": %s\n", ckpt_id, ckpt_res, plist_get_string_ptr(node, NULL)); } } // baseband update message else if (!strcmp(type, "BBUpdateStatusMsg")) { - err = restore_handle_bb_update_status_msg(restore, message); + err = restore_handle_bb_update_status_msg(client, message); } // baseband updater output data request else if (!strcmp(type, "BasebandUpdaterOutputData")) { - err = restore_handle_baseband_updater_output_data(restore, client, device, message); + err = restore_handle_baseband_updater_output_data(client, message); + } + + // handle restored crash, print backtrace + else if (!strcmp(type, "RestoredCrash")) { + err = restore_handle_restored_crash(client, message); + } + + // handle async wait + else if (!strcmp(type, "AsyncWait")) { + err = restore_handle_async_wait(client, message); + } + + else if (!strcmp(type, "RestoreAttestation")) { + err = restore_handle_restore_attestation(client, message); } // there might be some other message types i'm not aware of, but I think // at least the "previous error logs" messages usually end up here else { - debug("Unknown message type received\n"); - //if (idevicerestore_debug) - debug_plist(message); + logger(LL_DEBUG, "Unknown message type received\n"); + logger_dump_plist(LL_DEBUG, message, 1); } free(type); plist_free(message); message = NULL; } + if (client->async_err != 0) { + err = client->async_err; + } #ifdef HAVE_REVERSE_PROXY reverse_proxy_client_free(rproxy); |
