diff options
Diffstat (limited to 'src/restore.c')
-rw-r--r-- | src/restore.c | 947 |
1 files changed, 743 insertions, 204 deletions
diff --git a/src/restore.c b/src/restore.c index 7b61766..1261147 100644 --- a/src/restore.c +++ b/src/restore.c @@ -29,6 +29,7 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <libgen.h> #include <libimobiledevice/restore.h> #ifdef HAVE_REVERSE_PROXY #include <libimobiledevice/reverse_proxy.h> @@ -278,18 +279,12 @@ irecv_device_t restore_get_irecv_device(struct idevicerestore_client_t* client) } if (client->srnm == NULL) { - restore_error = restored_get_value(restore, "SerialNumber", &node); - if (restore_error != RESTORE_E_SUCCESS || !node || plist_get_node_type(node) != PLIST_STRING) { - error("ERROR: Unable to get SerialNumber from restored\n"); - restored_client_free(restore); - idevice_free(device); - return NULL; + if (restored_get_value(restore, "SerialNumber", &node) == RESTORE_E_SUCCESS) { + plist_get_string_val(node, &client->srnm); + info("INFO: device serial number is %s\n", client->srnm); + plist_free(node); + node = NULL; } - - plist_get_string_val(node, &client->srnm); - info("INFO: device serial number is %s\n", client->srnm); - plist_free(node); - node = NULL; } restore_error = restored_get_value(restore, "HardwareModel", &node); @@ -379,8 +374,8 @@ static int restore_is_current_device(struct idevicerestore_client_t* client, con if (!client) { return 0; } - if (!client->srnm) { - error("ERROR: %s: no SerialNumber given in client data\n", __func__); + if (!client->ecid) { + error("ERROR: %s: no ECID given in client data\n", __func__); return 0; } @@ -413,35 +408,35 @@ static int restore_is_current_device(struct idevicerestore_client_t* client, con return 0; } - plist_t node = NULL; - restore_error = restored_get_value(restored, "SerialNumber", &node); - if ((restore_error != RESTORE_E_SUCCESS) || !node || (plist_get_node_type(node) != PLIST_STRING)) { - error("ERROR: %s: Unable to get SerialNumber from restored\n", __func__); + plist_t hwinfo = NULL; + restore_error = restored_query_value(restored, "HardwareInfo", &hwinfo); + if ((restore_error != RESTORE_E_SUCCESS) || !hwinfo) { + error("ERROR: %s: Unable to get HardwareInfo from restored\n", __func__); restored_client_free(restored); idevice_free(device); - if (node) { - plist_free(node); - } + plist_free(hwinfo); return 0; } restored_client_free(restored); idevice_free(device); - char* this_srnm = NULL; - plist_get_string_val(node, &this_srnm); - plist_free(node); + uint64_t this_ecid = 0; + plist_t node = plist_dict_get_item(hwinfo, "UniqueChipID"); + if (node && plist_get_node_type(node) == PLIST_UINT) { + plist_get_uint_val(node, &this_ecid); + } + plist_free(hwinfo); - if (!this_srnm) { + if (this_ecid == 0) { + error("ERROR: %s: Unable to get ECID from restored\n", __func__); return 0; } - return (strcasecmp(this_srnm, client->srnm) == 0); + return (this_ecid == client->ecid); } int restore_open_with_timeout(struct idevicerestore_client_t* client) { - int i = 0; - int attempts = 180; char *type = NULL; uint64_t version = 0; idevice_t device = NULL; @@ -450,17 +445,17 @@ int restore_open_with_timeout(struct idevicerestore_client_t* client) restored_error_t restore_error = RESTORE_E_SUCCESS; // no context exists so bail - if(client == NULL) { + if (client == NULL) { return -1; } - if(client->srnm == NULL) { - error("ERROR: no SerialNumber in client data!\n"); + if (client->ecid == 0) { + error("ERROR: no ECID in client data!\n"); return -1; } // create our restore client if it doesn't yet exist - if(client->restore == NULL) { + if (client->restore == NULL) { client->restore = (struct restore_client_t*) malloc(sizeof(struct restore_client_t)); if(client->restore == NULL) { error("ERROR: Out of memory\n"); @@ -748,6 +743,7 @@ int restore_handle_status_msg(restored_client_t client, plist_t msg) case 27: info("Status: Failed to mount filesystems.\n"); break; + case 50: case 51: info("Status: Failed to load SEP Firmware.\n"); break; @@ -902,13 +898,37 @@ static void restore_asr_progress_cb(double progress, void* userdata) } } -int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device, const char* filesystem) +int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device, plist_t build_identity) { 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"); + return -1; + } + if (client->filesystem) { + char* path = strdup(client->filesystem); + const char* fsname_base = path_get_basename(path); + char* parent_dir = dirname(path); + ipsw_dummy = ipsw_open(parent_dir); + file = ipsw_file_open(ipsw_dummy, fsname_base); + free(path); + } else { + file = ipsw_file_open(client->ipsw, fsname); + } + if (!file) { + error("ERROR: Unable to open '%s' in ipsw\n", fsname); + free(fsname); + } + if (asr_open_with_timeout(device, &asr) < 0) { + ipsw_file_close(file); + ipsw_close(ipsw_dummy); error("ERROR: Unable to connect to ASR\n"); return -1; } @@ -919,7 +939,9 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t de // this step sends requested chunks of data from various offsets to asr so // it can validate the filesystem before installing it info("Validating the filesystem\n"); - if (asr_perform_validation(asr, filesystem) < 0) { + if (asr_perform_validation(asr, file) < 0) { + ipsw_file_close(file); + ipsw_close(ipsw_dummy); error("ERROR: ASR was unable to validate the filesystem\n"); asr_free(asr); return -1; @@ -929,11 +951,16 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t de // once the target filesystem has been validated, ASR then requests the // entire filesystem to be sent. info("Sending filesystem now...\n"); - if (asr_send_payload(asr, filesystem) < 0) { + if (asr_send_payload(asr, file) < 0) { + ipsw_file_close(file); + ipsw_close(ipsw_dummy); error("ERROR: Unable to send payload to ASR\n"); asr_free(asr); return -1; } + ipsw_file_close(file); + ipsw_close(ipsw_dummy); + info("Done sending filesystem\n"); asr_free(asr); @@ -1109,7 +1136,7 @@ int restore_send_component(restored_client_t restore, struct idevicerestore_clie return 0; } -int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity) +int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message) { char* llb_path = NULL; char* llb_filename = NULL; @@ -1127,10 +1154,15 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* unsigned char* nor_data = NULL; plist_t norimage = NULL; plist_t firmware_files = NULL; - uint32_t i; + int flash_version_1 = 0; info("About to send NORData...\n"); + plist_t arguments = plist_dict_get_item(message, "Arguments"); + if (arguments && plist_get_node_type(arguments) == PLIST_DICT) { + flash_version_1 = plist_dict_get_item(arguments, "FlashVersion1") ? 1 : 0; + } + if (client->tss) { if (tss_response_get_path_by_entry(client->tss, "LLB", &llb_path) < 0) { debug("NOTE: Could not get LLB path from TSS data, will fetch from build identity\n"); @@ -1250,9 +1282,7 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* plist_dict_set_item(dict, "LlbImageData", plist_new_data((char*)llb_data, (uint64_t) llb_size)); free(llb_data); - if (client->build_major >= 20) { - // Starting with M1 macs, it seems that NorImageData is now a dict. - // Sending an array like previous versions results in restore success but the machine will SOS after rebooting. + if (flash_version_1) { norimage = plist_new_dict(); } else { norimage = plist_new_array(); @@ -1308,7 +1338,7 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* component_data = NULL; component_size = 0; - if (client->build_major >= 20) { + if (flash_version_1) { plist_dict_set_item(norimage, component, plist_new_data((char*)nor_data, (uint64_t)nor_size)); } else { /* make sure iBoot is the first entry in the array */ @@ -1382,6 +1412,31 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* personalized_size = 0; } + if (build_identity_has_component(build_identity, "SepStage1") && + build_identity_get_component_path(build_identity, "SepStage1", &sep_path) == 0) { + component = "SepStage1"; + ret = extract_component(client->ipsw, sep_path, &component_data, &component_size); + free(sep_path); + if (ret < 0) { + error("ERROR: Unable to extract component: %s\n", component); + return -1; + } + + ret = personalize_component(component, component_data, component_size, client->tss, &personalized_data, &personalized_size); + free(component_data); + component_data = NULL; + component_size = 0; + if (ret < 0) { + error("ERROR: Unable to get personalized component: %s\n", component); + return -1; + } + + plist_dict_set_item(dict, "SEPPatchImageData", plist_new_data((char*)personalized_data, (uint64_t) personalized_size)); + free(personalized_data); + personalized_data = NULL; + personalized_size = 0; + } + if (idevicerestore_debug) debug_plist(dict); @@ -1460,7 +1515,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned uint64_t fsize = 0; uint64_t blob_size = 0; int zerr = 0; - int zindex = -1; + int64_t zindex = -1; struct zip_stat zstat; struct zip_file* zfile = NULL; struct zip* za = NULL; @@ -1482,7 +1537,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned } int is_fls = 0; - int signed_file_idxs[16]; + int64_t signed_file_idxs[16]; int signed_file_count = 0; char* key = NULL; plist_t node = NULL; @@ -1511,13 +1566,13 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned zip_stat_init(&zstat); if (zip_stat_index(za, zindex, 0, &zstat) != 0) { - error("ERROR: zip_stat_index failed for index %d\n", zindex); + error("ERROR: zip_stat_index failed for index %" PRIi64 "\n", zindex); goto leave; } zfile = zip_fopen_index(za, zindex, 0); if (zfile == NULL) { - error("ERROR: zip_fopen_index failed for index %d\n", zindex); + error("ERROR: zip_fopen_index failed for index %" PRIi64 "\n", zindex); goto leave; } @@ -1597,7 +1652,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned goto leave; } - if (zip_replace(za, zindex, zs) == -1) { + if (zip_file_replace(za, zindex, zs, 0) == -1) { error("ERROR: could not update signed '%s' in archive\n", signfn); goto leave; } @@ -1615,9 +1670,10 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned free(iter); // remove everything but required files - int i, j, keep, numf = zip_get_num_files(za); + int64_t i, numf = zip_get_num_entries(za, 0); for (i = 0; i < numf; i++) { - keep = 0; + int j; + int keep = 0; // check for signed file index for (j = 0; j < signed_file_count; j++) { if (i == signed_file_idxs[j]) { @@ -1651,13 +1707,13 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned zip_stat_init(&zstat); if (zip_stat_index(za, zindex, 0, &zstat) != 0) { - error("ERROR: zip_stat_index failed for index %d\n", zindex); + error("ERROR: zip_stat_index failed for index %" PRIi64 "\n", zindex); goto leave; } zfile = zip_fopen_index(za, zindex, 0); if (zfile == NULL) { - error("ERROR: zip_fopen_index failed for index %d\n", zindex); + error("ERROR: zip_fopen_index failed for index %" PRIi64 "\n", zindex); goto leave; } @@ -1716,7 +1772,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned goto leave; } - if (zip_replace(za, zindex, zs) == -1) { + if (zip_file_replace(za, zindex, zs, 0) == -1) { error("ERROR: could not update archive with ticketed ebl.fls\n"); goto leave; } @@ -1737,7 +1793,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned } blob = NULL; - if (zip_add(za, "bbticket.der", zs) == -1) { + if (zip_file_add(za, "bbticket.der", zs, ZIP_FL_OVERWRITE) == -1) { error("ERROR: could not add bbticket.der to archive\n"); goto leave; } @@ -1823,7 +1879,7 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer plist_dict_set_item(parameters, "BbGoldCertId", plist_new_uint(bb_cert_id)); plist_dict_set_item(parameters, "BbSNUM", plist_new_data((const char*)bb_snum, bb_snum_size)); - tss_parameters_add_from_manifest(parameters, build_identity); + tss_parameters_add_from_manifest(parameters, build_identity, true); /* create baseband request */ plist_t request = tss_request_new(NULL); @@ -2108,7 +2164,7 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest return 0; } -static plist_t restore_get_se_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info) +static plist_t restore_get_se_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info, plist_t arguments) { const char *comp_name = NULL; char *comp_path = NULL; @@ -2117,6 +2173,7 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id plist_t parameters = NULL; plist_t request = NULL; plist_t response = NULL; + plist_t p_dgr = NULL; int ret; uint64_t chip_id = 0; plist_t node = plist_dict_get_item(p_info, "SE,ChipID"); @@ -2125,7 +2182,7 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id } if (chip_id == 0x20211) { comp_name = "SE,Firmware"; - } else if (chip_id == 0x73 || chip_id == 0x64 || chip_id == 0xC8 || chip_id == 0xD2) { + } else if (chip_id == 0x73 || chip_id == 0x64 || chip_id == 0xC8 || chip_id == 0xD2 || chip_id == 0x2C || chip_id == 0x36) { comp_name = "SE,UpdatePayload"; } else { info("WARNING: Unknown SE,ChipID 0x%" PRIx64 " detected. Restore might fail.\n", (uint64_t)chip_id); @@ -2140,6 +2197,14 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id debug("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__); + } 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; @@ -2164,13 +2229,13 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity); + tss_parameters_add_from_manifest(parameters, build_identity, true); /* add SE,* tags from info dictionary to parameters */ plist_dict_merge(¶meters, p_info); /* add required tags for SE TSS request */ - tss_request_add_se_tags(request, parameters, NULL); + tss_request_add_se_tags(request, parameters, p_dgr); plist_free(parameters); @@ -2183,10 +2248,12 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id return NULL; } - if (plist_dict_get_item(response, "SE,Ticket")) { - info("Received SE ticket\n"); + if (plist_dict_get_item(response, "SE2,Ticket")) { + info("Received SE2,Ticket\n"); + } else if (plist_dict_get_item(response, "SE,Ticket")) { + info("Received SE,Ticket\n"); } else { - error("ERROR: No 'SE,Ticket' in TSS response, this might not work\n"); + error("ERROR: No 'SE ticket' in TSS response, this might not work\n"); } plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, (uint64_t) component_size)); @@ -2207,7 +2274,6 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc plist_t parameters = NULL; plist_t request = NULL; plist_t response = NULL; - plist_t node = NULL; int ret; /* create Savage request */ @@ -2220,7 +2286,7 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity); + tss_parameters_add_from_manifest(parameters, build_identity, true); /* add Savage,* tags from info dictionary to parameters */ plist_dict_merge(¶meters, p_info); @@ -2293,13 +2359,11 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru { char *comp_name = NULL; char *comp_path = NULL; - plist_t comp_node = NULL; unsigned char* component_data = NULL; unsigned int component_size = 0; plist_t parameters = NULL; plist_t request = NULL; plist_t response = NULL; - plist_t node = NULL; int ret; /* create Yonkers request */ @@ -2314,7 +2378,7 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity); + tss_parameters_add_from_manifest(parameters, build_identity, true); /* add Yonkers,* tags from info dictionary to parameters */ plist_dict_merge(¶meters, p_info); @@ -2375,11 +2439,10 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru return response; } -static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info) +static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info, plist_t arguments) { char *comp_name = NULL; char *comp_path = NULL; - plist_t comp_node = NULL; unsigned char* component_data = NULL; unsigned int component_size = 0; ftab_t ftab = NULL; @@ -2388,7 +2451,6 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct plist_t parameters = NULL; plist_t request = NULL; plist_t response = NULL; - plist_t node = NULL; int ret; /* create Rose request */ @@ -2402,7 +2464,7 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity); + tss_parameters_add_from_manifest(parameters, build_identity, true); plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1)); if (client->image4supported) { @@ -2412,8 +2474,14 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(0)); } - /* add Rap,* tags from info dictionary to parameters */ - plist_dict_merge(¶meters, p_info); + plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); + if (device_generated_request) { + /* use DeviceGeneratedRequest if present */ + plist_dict_merge(&request, device_generated_request); + } else { + /* add Rap,* tags from info dictionary to parameters */ + plist_dict_merge(¶meters, p_info); + } /* add required tags for Rose TSS request */ tss_request_add_rose_tags(request, parameters, NULL); @@ -2435,6 +2503,12 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct error("ERROR: No 'Rap,Ticket' in TSS response, this might not work\n"); } + /* skip FirmwareData for newer versions */ + if (client->build_major >= 20) { + debug("DEBUG: Not adding FirmwareData.\n"); + return response; + } + comp_name = "Rap,RTKitOS"; if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { error("ERROR: Unable to get path for '%s' component\n", comp_name); @@ -2516,13 +2590,11 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str { char *comp_name = "BMU,FirmwareMap"; char *comp_path = NULL; - plist_t comp_node = NULL; unsigned char* component_data = NULL; unsigned int component_size = 0; plist_t parameters = NULL; plist_t request = NULL; plist_t response = NULL; - plist_t node = NULL; int ret; /* create Veridian request */ @@ -2536,7 +2608,7 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity); + tss_parameters_add_from_manifest(parameters, build_identity, true); /* add BMU,* tags from info dictionary to parameters */ plist_dict_merge(¶meters, p_info); @@ -2610,17 +2682,70 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str 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) +{ + plist_t request = NULL; + plist_t response = NULL; + + plist_t p_updater_name = plist_dict_get_item(arguments, "MessageArgUpdaterName"); + const char* s_updater_name = plist_get_string_ptr(p_updater_name, NULL); + + plist_t response_tags = plist_access_path(arguments, 2, "DeviceGeneratedTags", "ResponseTags"); + const char* response_ticket = NULL; + if (PLIST_IS_ARRAY(response_tags)) { + plist_t tag0 = plist_array_get_item(response_tags, 0); + if (tag0) { + response_ticket = plist_get_string_ptr(tag0, NULL); + } + } + if (response_ticket == NULL) { + error("ERROR: Unable to determine response ticket from device generated tags"); + return NULL; + } + + /* create TSS request */ + request = tss_request_new(NULL); + if (request == NULL) { + error("ERROR: Unable to create %s TSS request\n", s_updater_name); + return NULL; + } + + /* add device generated request data to request */ + plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); + if (!device_generated_request) { + error("ERROR: Could not find DeviceGeneratedRequest in arguments dictionary\n"); + plist_free(request); + return NULL; + } + plist_dict_merge(&request, device_generated_request); + + info("Sending %s TSS request...\n", s_updater_name); + response = tss_request_send(request, client->tss_url); + plist_free(request); + if (response == NULL) { + error("ERROR: Unable to fetch %s ticket\n", s_updater_name); + return NULL; + } + + if (plist_dict_get_item(response, response_ticket)) { + info("Received %s\n", response_ticket); + } else { + error("ERROR: No '%s' in TSS response, this might not work\n", response_ticket); + debug_plist(response); + } + + return response; +} + static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info) { char *comp_name = "Baobab,TCON"; char *comp_path = NULL; - plist_t comp_node = NULL; unsigned char* component_data = NULL; unsigned int component_size = 0; plist_t parameters = NULL; plist_t request = NULL; plist_t response = NULL; - plist_t node = NULL; int ret; /* create Baobab request */ @@ -2634,7 +2759,7 @@ static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity); + tss_parameters_add_from_manifest(parameters, build_identity, true); /* add Baobab,* tags from info dictionary to parameters */ plist_dict_merge(¶meters, p_info); @@ -2681,6 +2806,305 @@ 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) +{ + char comp_name[64]; + char *comp_path = NULL; + unsigned char* component_data = NULL; + unsigned int component_size = 0; + ftab_t ftab = NULL; + ftab_t rftab = NULL; + uint32_t ftag = 0; + plist_t parameters = NULL; + plist_t request = NULL; + plist_t response = NULL; + const char* ticket_name = NULL; + uint32_t tag = 0; + int ret; + + /* create Timer request */ + request = tss_request_new(NULL); + if (request == NULL) { + error("ERROR: Unable to create Timer TSS request\n"); + return NULL; + } + + parameters = plist_new_dict(); + + /* add manifest for current build_identity to parameters */ + tss_parameters_add_from_manifest(parameters, build_identity, true); + + plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1)); + if (client->image4supported) { + plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(1)); + plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(1)); + } else { + plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(0)); + } + + /* add Timer,* tags from info dictionary to parameters */ + plist_t info_array = plist_dict_get_item(p_info, "InfoArray"); + if (!info_array) { + error("ERROR: Could not find InfoArray in info dictionary\n"); + plist_free(parameters); + return NULL; + } else { + plist_t info_dict = plist_array_get_item(info_array, 0); + plist_t hwid = plist_dict_get_item(info_dict, "HardwareID"); + tag = (uint32_t)_plist_dict_get_uint(info_dict, "TagNumber"); + char key[64]; + + plist_dict_set_item(parameters, "TagNumber", plist_new_uint(tag)); + plist_t node = plist_dict_get_item(info_dict, "TicketName"); + if (node) { + ticket_name = plist_get_string_ptr(node, NULL); + plist_dict_set_item(parameters, "TicketName", plist_copy(node)); + } + + sprintf(key, "Timer,ChipID,%u", tag); + _plist_dict_copy_uint(parameters, hwid, key, "ChipID"); + + sprintf(key, "Timer,BoardID,%u", tag); + _plist_dict_copy_uint(parameters, hwid, key, "BoardID"); + + sprintf(key, "Timer,ECID,%u", tag); + _plist_dict_copy_uint(parameters, hwid, key, "ECID"); + + sprintf(key, "Timer,Nonce,%u", tag); + _plist_dict_copy_data(parameters, hwid, key, "Nonce"); + + sprintf(key, "Timer,SecurityMode,%u", tag); + _plist_dict_copy_bool(parameters, hwid, key, "SecurityMode"); + + sprintf(key, "Timer,SecurityDomain,%u", tag); + _plist_dict_copy_uint(parameters, hwid, key, "SecurityDomain"); + + sprintf(key, "Timer,ProductionMode,%u", tag); + _plist_dict_copy_uint(parameters, hwid, key, "ProductionStatus"); + } + plist_t ap_info = plist_dict_get_item(p_info, "APInfo"); + if (!ap_info) { + error("ERROR: Could not find APInfo in info dictionary\n"); + plist_free(parameters); + return NULL; + } else { + plist_dict_merge(¶meters, ap_info); + } + + /* add required tags for Timer TSS request */ + tss_request_add_timer_tags(request, parameters, NULL); + + plist_free(parameters); + + info("Sending %s TSS request...\n", ticket_name); + response = tss_request_send(request, client->tss_url); + plist_free(request); + if (response == NULL) { + error("ERROR: Unable to fetch %s\n", ticket_name); + return NULL; + } + + if (plist_dict_get_item(response, ticket_name)) { + info("Received %s\n", ticket_name); + } else { + error("ERROR: No '%s' in TSS response, this might not work\n", ticket_name); + } + + sprintf(comp_name, "Timer,RTKitOS,%u", tag); + if (build_identity_has_component(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); + return NULL; + } + ret = extract_component(client->ipsw, comp_path, &component_data, &component_size); + free(comp_path); + comp_path = NULL; + if (ret < 0) { + error("ERROR: Unable to extract '%s' component\n", comp_name); + return NULL; + } + if (ftab_parse(component_data, component_size, &ftab, &ftag) != 0) { + free(component_data); + error("ERROR: Failed to parse '%s' component data.\n", comp_name); + return NULL; + } + free(component_data); + component_data = NULL; + component_size = 0; + if (ftag != 'rkos') { + error("WARNING: Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos'); + } + } else { + info("NOTE: Build identity does not have a '%s' component.\n", comp_name); + } + + sprintf(comp_name, "Timer,RestoreRTKitOS,%u", tag); + if (build_identity_has_component(build_identity, comp_name)) { + if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { + ftab_free(ftab); + error("ERROR: Unable to get path for '%s' component\n", comp_name); + return NULL; + } + ret = extract_component(client->ipsw, comp_path, &component_data, &component_size); + free(comp_path); + comp_path = NULL; + if (ret < 0) { + ftab_free(ftab); + error("ERROR: Unable to extract '%s' component\n", comp_name); + return NULL; + } + + ftag = 0; + if (ftab_parse(component_data, component_size, &rftab, &ftag) != 0) { + free(component_data); + ftab_free(ftab); + error("ERROR: Failed to parse '%s' component data.\n", comp_name); + return NULL; + } + free(component_data); + component_data = NULL; + component_size = 0; + if (ftag != 'rkos') { + error("WARNING: Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos'); + } + + if (ftab_get_entry_ptr(rftab, 'rrko', &component_data, &component_size) == 0) { + ftab_add_entry(ftab, 'rrko', component_data, component_size); + } else { + error("ERROR: Could not find 'rrko' entry in ftab. This will probably break things.\n"); + } + ftab_free(rftab); + component_data = NULL; + component_size = 0; + } else { + info("NOTE: Build identity does not have a '%s' component.\n", comp_name); + } + + ftab_write(ftab, &component_data, &component_size); + ftab_free(ftab); + + plist_dict_set_item(response, "FirmwareData", plist_new_data((char *)component_data, (uint64_t)component_size)); + free(component_data); + component_data = NULL; + component_size = 0; + + 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) +{ + plist_t parameters = NULL; + plist_t request = NULL; + plist_t response = NULL; + + plist_t p_updater_name = plist_dict_get_item(arguments, "MessageArgUpdaterName"); + const char* s_updater_name = plist_get_string_ptr(p_updater_name, NULL); + + plist_t response_tags = plist_access_path(arguments, 2, "DeviceGeneratedTags", "ResponseTags"); + const char* response_ticket = "Cryptex1,Ticket"; + if (PLIST_IS_ARRAY(response_tags)) { + plist_t tag0 = plist_array_get_item(response_tags, 0); + if (tag0) { + response_ticket = plist_get_string_ptr(tag0, NULL); + } + } + + /* create Cryptex1 request */ + request = tss_request_new(NULL); + if (request == NULL) { + error("ERROR: Unable to create %s TSS request\n", s_updater_name); + return NULL; + } + + parameters = plist_new_dict(); + + /* merge data from MessageArgInfo */ + plist_dict_merge(¶meters, p_info); + + /* add tags from manifest to parameters */ + plist_t build_identity_tags = plist_access_path(arguments, 2, "DeviceGeneratedTags", "BuildIdentityTags"); + if (PLIST_IS_ARRAY(build_identity_tags)) { + uint32_t i = 0; + for (i = 0; i < plist_array_get_size(build_identity_tags); i++) { + plist_t node = plist_array_get_item(build_identity_tags, i); + const char* key = plist_get_string_ptr(node, NULL); + plist_t item = plist_dict_get_item(build_identity, key); + if (item) { + plist_dict_set_item(parameters, key, plist_copy(item)); + } + } + } + + /* make sure we always have these required tags defined */ + if (!plist_dict_get_item(parameters, "ApProductionMode")) { + plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1)); + } + if (!plist_dict_get_item(parameters, "ApSecurityMode")) { + plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(1)); + } + if (!plist_dict_get_item(parameters, "ApChipID")) { + _plist_dict_copy_uint(parameters, build_identity, "ApChipID", NULL); + } + if (!plist_dict_get_item(parameters, "ApBoardID")) { + _plist_dict_copy_uint(parameters, build_identity, "ApBoardID", NULL); + } + + /* add device generated request data to parameters */ + plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); + if (!device_generated_request) { + error("ERROR: Could not find DeviceGeneratedRequest in arguments dictionary\n"); + plist_free(parameters); + return NULL; + } + plist_dict_merge(¶meters, device_generated_request); + + /* add Cryptex1 tags to request */ + tss_request_add_cryptex_tags(request, parameters, NULL); + + plist_free(parameters); + + info("Sending %s TSS request...\n", s_updater_name); + response = tss_request_send(request, client->tss_url); + plist_free(request); + if (response == NULL) { + error("ERROR: Unable to fetch %s ticket\n", s_updater_name); + return NULL; + } + + if (plist_dict_get_item(response, response_ticket)) { + info("Received %s\n", response_ticket); + } else { + error("ERROR: No '%s' in TSS response, this might not work\n", response_ticket); + debug_plist(response); + } + + return response; +} + +static int restore_send_firmware_updater_preflight(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message) +{ + plist_t dict = NULL; + int restore_error; + + if (idevicerestore_debug) { + debug("DEBUG: %s: Got FirmwareUpdaterPreflight request:\n", __func__); + debug_plist(message); + } + + dict = plist_new_dict(); + + info("Sending FirmwareResponsePreflight now...\n"); + restore_error = restored_send(restore, dict); + plist_free(dict); + if (restore_error != RESTORE_E_SUCCESS) { + error("ERROR: Couldn't send FirmwareResponsePreflight data (%d)\n", restore_error); + return -1; + } + + info("Done sending FirmwareUpdaterPreflight response\n"); + return 0; +} + static int restore_send_firmware_updater_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message) { plist_t arguments; @@ -2738,7 +3162,7 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct plist_get_string_val(p_updater_name, &s_updater_name); if (strcmp(s_updater_name, "SE") == 0) { - fwdict = restore_get_se_firmware_data(restore, client, build_identity, p_info); + fwdict = restore_get_se_firmware_data(restore, client, build_identity, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get SE firmware data\n", __func__); goto error_out; @@ -2757,7 +3181,7 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct goto error_out; } } else if (strcmp(s_updater_name, "Rose") == 0) { - fwdict = restore_get_rose_firmware_data(restore, client, build_identity, p_info); + fwdict = restore_get_rose_firmware_data(restore, client, build_identity, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get Rose firmware data\n", __func__); goto error_out; @@ -2774,9 +3198,37 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct error("ERROR: %s: Couldn't get AppleTCON firmware data\n", __func__); goto error_out; } + } else if (strcmp(s_updater_name, "PS190") == 0) { + fwdict = restore_get_generic_firmware_data(restore, client, build_identity, p_info, arguments); + if (fwdict == NULL) { + error("ERROR: %s: Couldn't get PCON1 firmware data\n", __func__); + goto error_out; + } + } else if (strcmp(s_updater_name, "AppleTypeCRetimer") == 0) { + fwdict = restore_get_timer_firmware_data(restore, client, build_identity, p_info); + if (fwdict == NULL) { + error("ERROR: %s: Couldn't get AppleTypeCRetimer firmware data\n", __func__); + goto error_out; + } + } else if ((strcmp(s_updater_name, "Cryptex1") == 0) || (strcmp(s_updater_name, "Cryptex1LocalPolicy") == 0)) { + fwdict = restore_get_cryptex1_firmware_data(restore, client, build_identity, p_info, arguments); + if (fwdict == NULL) { + error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); + goto error_out; + } + } else if (strcmp(s_updater_name, "Ace3") == 0) { + fwdict = restore_get_generic_firmware_data(restore, client, build_identity, p_info, arguments); + if (fwdict == NULL) { + error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); + goto error_out; + } } else { - error("ERROR: %s: Got unknown updater name '%s'.\n", __func__, s_updater_name); - goto error_out; + error("ERROR: %s: Got unknown updater name '%s', trying to discover from device generated request.\n", __func__, s_updater_name); + fwdict = restore_get_generic_firmware_data(restore, client, build_identity, p_info, arguments); + if (fwdict == NULL) { + error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); + goto error_out; + } } free(s_updater_name); s_updater_name = NULL; @@ -2803,6 +3255,37 @@ error_out: return -1; } +static int restore_send_receipt_manifest(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity) +{ + plist_t dict; + int restore_error; + + plist_t manifest = plist_dict_get_item(build_identity, "Manifest"); + if (!manifest) { + error("failed to get Manifest node from build_identity"); + goto error_out; + } + + 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); + plist_free(dict); + if (restore_error != RESTORE_E_SUCCESS) { + error("ERROR: Couldn't send ReceiptManifest data (%d)\n", restore_error); + goto error_out; + } + + info("Done sending ReceiptManifest data\n"); + + return 0; + +error_out: + return -1; +} + + struct cpio_odc_header { char c_magic[6]; char c_dev[6]; @@ -2869,7 +3352,7 @@ static int cpio_send_file(idevice_connection_t connection, const char *name, str return 0; } -static int restore_bootability_send_one(void *ctx, const char *ipsw, const char *name, struct stat *stat) +static int restore_bootability_send_one(void *ctx, ipsw_archive_t ipsw, const char *name, struct stat *stat) { idevice_connection_t connection = (idevice_connection_t)ctx; const char *prefix = "BootabilityBundle/Restore/Bootability/"; @@ -2950,24 +3433,27 @@ static int restore_send_bootability_bundle_data(restored_client_t restore, struc return 0; } -plist_t restore_get_build_identity(struct idevicerestore_client_t* client, uint8_t is_recover_os) +plist_t restore_get_build_identity(struct idevicerestore_client_t* client, uint8_t is_recovery_os) { const char *variant; - if (is_recover_os) - variant = "macOS Customer"; + if (is_recovery_os) + variant = RESTORE_VARIANT_MACOS_RECOVERY_OS; else if (client->flags & FLAG_ERASE) - variant = "Customer Erase Install (IPSW)"; + variant = RESTORE_VARIANT_ERASE_INSTALL; else - variant = "Customer Upgrade Install (IPSW)"; + variant = RESTORE_VARIANT_UPGRADE_INSTALL; plist_t build_identity = build_manifest_get_build_identity_for_model_with_variant( client->build_manifest, client->device->hardware_model, - variant); + variant, 0); plist_t unique_id_node = plist_dict_get_item(client->build_manifest, "UniqueBuildID"); - debug_plist(unique_id_node); + if (unique_id_node) { + printf("UniqueBuildID: "); + plist_write_to_stream(unique_id_node, stdout, PLIST_FORMAT_PRINT, PLIST_OPT_NONE); + } return build_identity; } @@ -2975,11 +3461,7 @@ plist_t restore_get_build_identity(struct idevicerestore_client_t* client, uint8 plist_t restore_get_build_identity_from_request(struct idevicerestore_client_t* client, plist_t msg) { plist_t args = plist_dict_get_item(msg, "Arguments"); - plist_t is_recovery_node = plist_dict_get_item(args, "IsRecoveryOS"); - uint8_t is_recovery = 0; - plist_get_bool_val(is_recovery_node, &is_recovery); - - return restore_get_build_identity(client, is_recovery); + return restore_get_build_identity(client, _plist_dict_get_bool(args, "IsRecoveryOS")); } int extract_macos_variant(plist_t build_identity, char** output) @@ -3000,27 +3482,32 @@ int extract_macos_variant(plist_t build_identity, char** output) return 0; } -int extract_global_manifest(struct idevicerestore_client_t* client, plist_t build_identity, unsigned char** pbuffer, unsigned int* psize) +static char* extract_global_manifest_path(plist_t build_identity, char *variant) { plist_t build_info = plist_dict_get_item(build_identity, "Info"); if (!build_info) { error("ERROR: build identity does not contain an 'Info' element\n"); - return -1; + return NULL; } plist_t device_class_node = plist_dict_get_item(build_info, "DeviceClass"); if (!device_class_node) { error("ERROR: build identity info does not contain a DeviceClass\n"); - return -1; + return NULL; } char *device_class = NULL; plist_get_string_val(device_class_node, &device_class); char *macos_variant = NULL; - int ret = extract_macos_variant(build_identity, &macos_variant); - if (ret != 0) { - free(device_class); - return -1; + int ret; + if (variant) { + macos_variant = variant; + } else { + ret = extract_macos_variant(build_identity, &macos_variant); + if (ret != 0) { + free(device_class); + return NULL; + } } // The path of the global manifest is hardcoded. There's no pointer to in the build manifest. @@ -3030,7 +3517,17 @@ int extract_global_manifest(struct idevicerestore_client_t* client, plist_t buil free(device_class); free(macos_variant); - ret = ipsw_extract_to_memory(client->ipsw, ticket_path, pbuffer, psize); + return ticket_path; +} + +int extract_global_manifest(struct idevicerestore_client_t* client, plist_t build_identity, char *variant, unsigned char** pbuffer, unsigned int* psize) +{ + char* ticket_path = extract_global_manifest_path(build_identity, variant); + if (!ticket_path) { + error("ERROR: failed to get global manifest path\n"); + return -1; + } + int ret = ipsw_extract_to_memory(client->ipsw, ticket_path, pbuffer, psize); if (ret != 0) { free(ticket_path); error("ERROR: failed to read global manifest\n"); @@ -3041,9 +3538,46 @@ int extract_global_manifest(struct idevicerestore_client_t* client, plist_t buil return 0; } +struct _restore_send_file_data_ctx { + struct idevicerestore_client_t* client; + restored_client_t restore; + int last_progress; +}; + +static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, void* data, size_t size, size_t done, size_t total_size) +{ + plist_t dict = plist_new_dict(); + if (data != NULL) { + // Send a chunk of file data + plist_dict_set_item(dict, "FileData", plist_new_data((char*)data, size)); + } else { + // Send FileDataDone to mark end of transfer + plist_dict_set_item(dict, "FileDataDone", plist_new_bool(1)); + } + restored_error_t restore_error = restored_send(rctx->restore, dict); + if (restore_error != RESTORE_E_SUCCESS) { + plist_free(dict); + error("ERROR: %s: Failed to send data (%d)\n", __func__, restore_error); + return -1; + } + plist_free(dict); + if (total_size > 0x1000000) { + double progress = (double)done / (double)total_size; + int progress_int = (int)(progress*100.0); + if (progress_int > rctx->last_progress) { + idevicerestore_progress(rctx->client, RESTORE_STEP_UPLOAD_IMG, progress); + rctx->last_progress = progress_int; + } + } + return 0; +} + int restore_send_personalized_boot_object_v3(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg, plist_t build_identity) { - debug_plist(msg); + if (idevicerestore_debug) { + debug("DEBUG: %s: Got PersonalizedBootObjectV3 request:\n", __func__); + debug_plist(msg); + } char *image_name = NULL; plist_t node = plist_access_path(msg, 2, "Arguments", "ImageName"); @@ -3064,12 +3598,11 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i plist_t blob = NULL; plist_t dict = NULL; restored_error_t restore_error = RESTORE_E_SUCCESS; - char *component_name = component; - info("About to send %s...\n", component_name); + info("About to send %s...\n", component); if (strcmp(image_name, "__GlobalManifest__") == 0) { - int ret = extract_global_manifest(client, build_identity, &data, &size); + int ret = extract_global_manifest(client, build_identity, NULL, &data, &size); if (ret != 0) { return -1; } @@ -3115,7 +3648,7 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i return -1; } - // Personalize IMG40 + // Personalize IMG4 ret = personalize_component(component, component_data, component_size, client->tss, &data, &size); free(component_data); component_data = NULL; @@ -3125,49 +3658,37 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i } } - // Make plist - info("Sending %s now...\n", component_name); + 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.last_progress = 0; int64_t i = size; while (i > 0) { int blob_size = i > 8192 ? 8192 : i; - - dict = plist_new_dict(); - blob = plist_new_data((char *) (data + size - i), blob_size); - plist_dict_set_item(dict, "FileData", blob); - - restore_error = restored_send(restore, dict); - if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send component %s data\n", component_name); + if (_restore_send_file_data(&rctx, (data + size - i), blob_size, size-i, size) < 0) { + free(data); + error("ERROR: Unable to send component %s data\n", component); return -1; } - - plist_free(dict); - i -= blob_size; } - debug("\n"); - - // Send FileDataDone - dict = plist_new_dict(); - plist_dict_set_item(dict, "FileDataDone", plist_new_bool(1)); - - restore_error = restored_send(restore, dict); - if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send component %s data\n", component_name); - return -1; - } - - plist_free(dict); free(data); - info("Done sending %s\n", component_name); + _restore_send_file_data(&rctx, NULL, 0, size-i, size); + + 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) { - debug_plist(msg); + if (idevicerestore_debug) { + debug("DEBUG: %s: Got SourceBootObjectV4 request:\n", __func__); + debug_plist(msg); + } char *image_name = NULL; plist_t node = plist_access_path(msg, 2, "Arguments", "ImageName"); @@ -3190,27 +3711,27 @@ int restore_send_source_boot_object_v4(restored_client_t restore, struct idevice plist_t blob = NULL; plist_t dict = NULL; restored_error_t restore_error = RESTORE_E_SUCCESS; - char *component_name = component; - info("About to send %s...\n", component_name); + info("About to send %s...\n", component); if (strcmp(image_name, "__GlobalManifest__") == 0) { - int ret = extract_global_manifest(client, build_identity, &data, &size); - if (ret != 0) { + char *variant = NULL; + plist_t node = plist_access_path(msg, 2, "Arguments", "Variant"); + if (!node || plist_get_node_type(node) != PLIST_STRING) { + debug("Failed to parse arguments from SourceBootObjectV4 plist\n"); return -1; } - } else if (strcmp(image_name, "__RestoreVersion__") == 0) { - int ret = ipsw_extract_to_memory(client->ipsw, "RestoreVersion.plist", &data, &size); - if (ret != 0) { - error("ERROR: failed to read global manifest\n"); + plist_get_string_val(node, &variant); + if (!variant) { + debug("Failed to parse arguments from SourceBootObjectV4 as string\n"); return -1; } + + path = extract_global_manifest_path(build_identity, variant); + } else if (strcmp(image_name, "__RestoreVersion__") == 0) { + path = strdup("RestoreVersion.plist"); } else if (strcmp(image_name, "__SystemVersion__") == 0) { - int ret = ipsw_extract_to_memory(client->ipsw, "SystemVersion.plist", &data, &size); - if (ret != 0) { - error("ERROR: failed to read global manifest\n"); - return -1; - } + path = strdup("SystemVersion.plist"); } else { // Get component path if (client->tss) { @@ -3225,53 +3746,31 @@ int restore_send_source_boot_object_v4(restored_client_t restore, struct idevice return -1; } } - - int ret = extract_component(client->ipsw, path, &data, &size); - free(path); - path = NULL; - if (ret < 0) { - error("ERROR: Unable to extract component %s\n", component); - return -1; - } } - // Make plist - info("Sending %s now...\n", component_name); - - int64_t i = size; - while (i > 0) { - int blob_size = i > 8192 ? 8192 : i; - - dict = plist_new_dict(); - blob = plist_new_data((char *) (data + size - i), blob_size); - plist_dict_set_item(dict, "FileData", blob); - - restore_error = restored_send(restore, dict); - if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send component %s data\n", component_name); - return -1; - } + if (!path) { + error("ERROR: Failed to get path for component %s\n", component); + return -1; + } - plist_free(dict); + uint64_t fsize = 0; + ipsw_get_file_size(client->ipsw, path, &fsize); - i -= blob_size; - } - debug("\n"); + info("Sending %s now (%" PRIu64 " bytes)\n", component, fsize); - // Send FileDataDone - dict = plist_new_dict(); - plist_dict_set_item(dict, "FileDataDone", plist_new_bool(1)); + struct _restore_send_file_data_ctx rctx; + rctx.client = client; + rctx.restore = restore; + rctx.last_progress = 0; - restore_error = restored_send(restore, dict); - if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send component %s data\n", component_name); + if (ipsw_extract_send(client->ipsw, path, 8192, (ipsw_send_cb)_restore_send_file_data, &rctx) < 0) { + free(path); + error("ERROR: Failed to send component %s\n", component); return -1; } + free(path); - plist_free(dict); - free(data); - - info("Done sending %s\n", component_name); + info("Done sending %s\n", component); return 0; } @@ -3352,7 +3851,7 @@ int restore_send_buildidentity(restored_client_t restore, struct idevicerestore_ return 0; } -int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t build_identity, const char* filesystem) +int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t build_identity) { plist_t node = NULL; @@ -3364,7 +3863,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev // this request is sent when restored is ready to receive the filesystem if (!strcmp(type, "SystemImageData")) { - if(restore_send_filesystem(client, device, filesystem) < 0) { + if(restore_send_filesystem(client, device, build_identity) < 0) { error("ERROR: Unable to send filesystem\n"); return -2; } @@ -3400,7 +3899,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev // this request is sent when restored is ready to receive the filesystem else if (!strcmp(type, "RecoveryOSASRImage")) { - if(restore_send_filesystem(client, device, filesystem) < 0) { + if(restore_send_filesystem(client, device, build_identity) < 0) { error("ERROR: Unable to send filesystem\n"); return -2; } @@ -3452,7 +3951,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev else if (!strcmp(type, "NORData")) { if((client->flags & FLAG_EXCLUDE) == 0) { - if(restore_send_nor(restore, client, build_identity) < 0) { + if(restore_send_nor(restore, client, build_identity, message) < 0) { error("ERROR: Unable to send NOR data\n"); return -1; } @@ -3483,6 +3982,13 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev } } + else if (!strcmp(type, "FirmwareUpdaterPreflight")) { + if(restore_send_firmware_updater_preflight(restore, client, build_identity, message) < 0) { + error("ERROR: Unable to send FirmwareUpdaterPreflight\n"); + return -1; + } + } + else if (!strcmp(type, "FirmwareUpdaterData")) { if(restore_send_firmware_updater_data(restore, client, build_identity, message) < 0) { error("ERROR: Unable to send FirmwareUpdater data\n"); @@ -3511,6 +4017,20 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev } } + else if (!strcmp(type, "ReceiptManifest")) { + if (restore_send_receipt_manifest(restore, client, build_identity) < 0) { + error("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"); + return -1; + } + } + else { // Unknown DataType!! error("Unknown data request '%s' received\n", type); @@ -3532,6 +4052,7 @@ plist_t restore_supported_data_types() plist_dict_set_item(dict, "BootabilityBundle", plist_new_bool(0)); plist_dict_set_item(dict, "BuildIdentityDict", plist_new_bool(0)); plist_dict_set_item(dict, "BuildIdentityDictV2", plist_new_bool(0)); + plist_dict_set_item(dict, "Cryptex1LocalPolicy", plist_new_bool(1)); plist_dict_set_item(dict, "DataType", plist_new_bool(0)); plist_dict_set_item(dict, "DiagData", plist_new_bool(0)); plist_dict_set_item(dict, "EANData", plist_new_bool(0)); @@ -3580,6 +4101,12 @@ plist_t restore_supported_data_types() plist_dict_set_item(dict, "SystemImageRootHash", plist_new_bool(0)); plist_dict_set_item(dict, "USBCFWData", plist_new_bool(0)); plist_dict_set_item(dict, "USBCOverride", plist_new_bool(0)); + plist_dict_set_item(dict, "FirmwareUpdaterPreflight", plist_new_bool(1)); + plist_dict_set_item(dict, "ReceiptManifest", plist_new_bool(1)); + plist_dict_set_item(dict, "FirmwareUpdaterDataV2", plist_new_bool(0)); + plist_dict_set_item(dict, "RestoreLocalPolicy", plist_new_bool(1)); + plist_dict_set_item(dict, "AuthInstallCACert", plist_new_bool(1)); + plist_dict_set_item(dict, "OverlayRootDataForKeyIndex", plist_new_bool(1)); return dict; } @@ -3615,7 +4142,7 @@ static void rp_status_cb(reverse_proxy_client_t client, reverse_proxy_status_t s } #endif -int restore_device(struct idevicerestore_client_t* client, plist_t build_identity, const char* filesystem) +int restore_device(struct idevicerestore_client_t* client, plist_t build_identity) { int err = 0; char* type = NULL; @@ -3755,7 +4282,6 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit plist_dict_set_item(opts, "AutoBootDelay", plist_new_uint(0)); if (client->preflight_info) { - plist_t node; plist_t bbus = plist_copy(client->preflight_info); plist_dict_remove_item(bbus, "FusingStatus"); @@ -3763,17 +4289,14 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit plist_dict_set_item(opts, "BBUpdaterState", bbus); - node = plist_dict_get_item(client->preflight_info, "Nonce"); - if (node) { - plist_dict_set_item(opts, "BasebandNonce", plist_copy(node)); - } + _plist_dict_copy_data(opts, client->preflight_info, "BasebandNonce", "Nonce"); } plist_dict_set_item(opts, "SupportedDataTypes", restore_supported_data_types()); plist_dict_set_item(opts, "SupportedMessageTypes", restore_supported_message_types()); // FIXME: Should be adjusted for update behaviors - if (client->build_major >= 20) { + if (client->macos_variant) { plist_dict_set_item(opts, "AddSystemPartitionPadding", plist_new_bool(1)); plist_dict_set_item(opts, "AllowUntetheredRestore", plist_new_bool(0)); plist_dict_set_item(opts, "AuthInstallEnableSso", plist_new_bool(0)); @@ -3896,7 +4419,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // this is the restore process loop, it reads each message in from // restored and passes that data on to it's specific handler while (!(client->flags & FLAG_QUIT)) { - if (client->flags & FLAG_IGNORE_ERRORS) { + if (err != 0 && client->flags & FLAG_IGNORE_ERRORS) { error("WARNING: Attempting to continue after critical error, restore might fail...\n"); err = 0; } @@ -3942,7 +4465,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // files sent to the server by the client. these data requests include // SystemImageData, RootTicket, KernelCache, NORData and BasebandData requests if (!strcmp(type, "DataRequestMsg")) { - err = restore_handle_data_request_msg(client, device, restore, message, build_identity, filesystem); + err = restore_handle_data_request_msg(client, device, restore, message, build_identity); } // restore logs are available if a previous restore failed @@ -3971,29 +4494,45 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit else if (!strcmp(type, "CheckpointMsg")) { uint64_t ckpt_id; - uint64_t ckpt_res; + int64_t ckpt_res; uint8_t ckpt_complete = 0; + const char* ckpt_name = NULL; // Get checkpoint id node = plist_dict_get_item(message, "CHECKPOINT_ID"); - if (!node || plist_get_node_type(node) != PLIST_UINT) { + if (!node || plist_get_node_type(node) != PLIST_INT) { debug("Failed to parse checkpoint id from checkpoint plist\n"); return -1; } plist_get_uint_val(node, &ckpt_id); + // Get checkpoint_name + node = plist_dict_get_item(message, "CHECKPOINT_NAME"); + ckpt_name = (node) ? plist_get_string_ptr(node, NULL) : "unknown"; // Get checkpoint result node = plist_dict_get_item(message, "CHECKPOINT_RESULT"); - if (!node || plist_get_node_type(node) != PLIST_UINT) { + if (!node || plist_get_node_type(node) != PLIST_INT) { debug("Failed to parse checkpoint result from checkpoint plist\n"); return -1; } - plist_get_uint_val(node, &ckpt_res); + plist_get_int_val(node, &ckpt_res); // Get checkpoint complete node = plist_dict_get_item(message, "CHECKPOINT_COMPLETE"); if (PLIST_IS_BOOLEAN(node)) { plist_get_bool_val(node, &ckpt_complete); } - if (ckpt_complete) - info("Checkpoint %" PRIu64 " complete with code %" PRIu64 "\n", ckpt_id, ckpt_res); + + if (ckpt_complete) { + info("Checkpoint completed id: 0x%" PRIX64 " (%s) result=%" PRIi64 "\n", ckpt_id, ckpt_name, ckpt_res); + } else { + info("Checkpoint started id: 0x%" PRIX64 " (%s)\n", ckpt_id, ckpt_name); + } + node = plist_dict_get_item(message, "CHECKPOINT_WARNING"); + if (node) { + info("Checkpoint WARNING id: 0x%" PRIX64 " result=%" PRIi64 ": %s\n", ckpt_id, ckpt_res, plist_get_string_ptr(node, NULL)); + } + node = plist_dict_get_item(message, "CHECKPOINT_ERROR"); + if (node) { + info("Checkpoint FAILURE id: 0x%" PRIX64 " result=%" PRIi64 ": %s\n", ckpt_id, ckpt_res, plist_get_string_ptr(node, NULL)); + } } // baseband update message |