diff options
Diffstat (limited to 'src/restore.c')
| -rw-r--r-- | src/restore.c | 133 |
1 files changed, 101 insertions, 32 deletions
diff --git a/src/restore.c b/src/restore.c index 877b4a8..1913835 100644 --- a/src/restore.c +++ b/src/restore.c @@ -4134,7 +4134,7 @@ int extract_macos_variant(plist_t build_identity, char** output) return 0; } -static char* extract_global_manifest_path(plist_t build_identity, char *variant) +static char* extract_global_manifest_path(plist_t build_identity, const char* variant, const char* prefix, const char* suffix) { plist_t build_info = plist_dict_get_item(build_identity, "Info"); if (!build_info) { @@ -4149,33 +4149,51 @@ static char* extract_global_manifest_path(plist_t build_identity, char *variant) } char *device_class = NULL; plist_get_string_val(device_class_node, &device_class); + if (!device_class) { + logger(LL_ERROR, "failed to get DeviceClass from build identity info\n"); + return NULL; + } - char *macos_variant = NULL; - int ret; - if (variant) { - macos_variant = variant; - } else { - ret = extract_macos_variant(build_identity, &macos_variant); - if (ret != 0) { + char *owned_macos_variant = NULL; + const char *macos_variant = variant; + if (!macos_variant) { + if (extract_macos_variant(build_identity, &owned_macos_variant) != 0 || !owned_macos_variant) { free(device_class); return NULL; } + macos_variant = owned_macos_variant; } - // The path of the global manifest is hardcoded. There's no pointer to in the build manifest. - 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); + // There is no path reference to the global manifest in the build manifest. + int length = snprintf(NULL, 0, "Firmware/Manifests/restore/%s/%s.%s%s.im4m", macos_variant, prefix, device_class, suffix); + if (length < 0) { + logger(LL_ERROR, "failed to format global manifest path\n"); + free(device_class); + free(owned_macos_variant); + return NULL; + } + char *ticket_path = malloc((size_t)length + 1); + if (!ticket_path) { + logger(LL_ERROR, "Out of memory\n"); + free(device_class); + free(owned_macos_variant); + return NULL; + } + if (snprintf(ticket_path, (size_t)length + 1, "Firmware/Manifests/restore/%s/%s.%s%s.im4m", macos_variant, prefix, device_class, suffix) != length) { + logger(LL_ERROR, "failed to format global manifest path\n"); + free(ticket_path); + ticket_path = NULL; + } free(device_class); - free(macos_variant); + free(owned_macos_variant); return ticket_path; } 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); + char* ticket_path = extract_global_manifest_path(build_identity, variant, "apticket", ""); if (!ticket_path) { logger(LL_ERROR, "failed to get global manifest path\n"); return -1; @@ -4217,7 +4235,7 @@ static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, con plist_free(dict); /* special handling for AEA image format */ - if (done == 0 && (memcmp(data, "AEA1", 4) == 0)) { + if (data != NULL && size >= 4 && 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); @@ -4376,39 +4394,77 @@ int restore_send_source_boot_object_v4(struct idevicerestore_client_t* client, p logger_dump_plist(LL_DEBUG, message, 1); } - char *image_name = NULL; - plist_t node = plist_access_path(message, 2, "Arguments", "ImageName"); + plist_t arguments = plist_dict_get_item(message, "Arguments"); + if (!arguments || plist_get_node_type(arguments) != PLIST_DICT) { + logger(LL_DEBUG, "Failed to parse arguments from SourceBootObjectV4 plist\n"); + return -1; + } + plist_t node = plist_dict_get_item(arguments, "ImageName"); if (!node || plist_get_node_type(node) != PLIST_STRING) { logger(LL_DEBUG, "Failed to parse arguments from SourceBootObjectV4 plist\n"); return -1; } - plist_get_string_val(node, &image_name); + const char *image_name = plist_get_string_ptr(node, NULL); if (!image_name) { logger(LL_DEBUG, "Failed to parse arguments from SourceBootObjectV4 as string\n"); return -1; } - char *component = image_name; + const char *component = image_name; // Fork from restore_send_component // char *path = NULL; + int path_optional = 0; logger(LL_INFO, "About to send %s...\n", component); if (strcmp(image_name, "__GlobalManifest__") == 0) { - char *variant = NULL; - plist_t node = plist_access_path(message, 2, "Arguments", "Variant"); + plist_t build_identity = restore_get_build_identity_from_request(client, message); + if (!build_identity) { + logger(LL_ERROR, "Unable to find a matching build identity\n"); + return -1; + } + + node = plist_dict_get_item(arguments, "Variant"); if (!node || plist_get_node_type(node) != PLIST_STRING) { logger(LL_DEBUG, "Failed to parse arguments from SourceBootObjectV4 plist\n"); return -1; } - plist_get_string_val(node, &variant); + const char *variant = plist_get_string_ptr(node, NULL); if (!variant) { logger(LL_DEBUG, "Failed to parse arguments from SourceBootObjectV4 as string\n"); return -1; } - path = extract_global_manifest_path(client->restore->build_identity, variant); + const char *prefix = "apticket"; + node = plist_dict_get_item(arguments, "GlobalManifestPrefix"); + if (node && plist_get_node_type(node) == PLIST_STRING) { + const char *value = plist_get_string_ptr(node, NULL); + if (value) { + prefix = value; + } + } + + const char *suffix = ""; + node = plist_dict_get_item(arguments, "GlobalManifestSuffix"); + if (node && plist_get_node_type(node) == PLIST_STRING) { + const char *value = plist_get_string_ptr(node, NULL); + if (value) { + suffix = value; + } + } + + path = extract_global_manifest_path(build_identity, variant, prefix, suffix); + if (!path) { + logger(LL_ERROR, "Failed to get global manifest path\n"); + return -1; + } + if (!ipsw_file_exists(client->ipsw, path)) { + free(path); + path = NULL; + } + path_optional = !plist_access_path(build_identity, 2, "Info", "VariantSupportsGlobalSigning") + || plist_dict_get_bool(arguments, "GlobalManifestOptional"); } else if (strcmp(image_name, "__RestoreVersion__") == 0) { path = strdup("RestoreVersion.plist"); } else if (strcmp(image_name, "__SystemVersion__") == 0) { @@ -4429,41 +4485,54 @@ int restore_send_source_boot_object_v4(struct idevicerestore_client_t* client, p } } - if (!path) { + if (!path && !path_optional) { 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); + if (path) { + ipsw_get_file_size(client->ipsw, path, &fsize); + } restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); if (!service) { + free(path); 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.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) { + int sent_file = path != NULL; + int ret; + if (sent_file) { + logger(LL_INFO, "Sending %s now (%" PRIu64 " bytes)\n", component, fsize); + register_progress(rctx.tag, component); + ret = ipsw_extract_send(client->ipsw, path, 8192, (ipsw_send_cb)_restore_send_file_data, &rctx); + } else { + logger(LL_INFO, "Skipping missing optional component %s\n", component); + ret = _restore_send_file_data(&rctx, NULL, 0, 0, 0); + } + if (ret < 0) { free(path); _restore_service_free(service); - finalize_progress(rctx.tag); + if (sent_file) { + 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); + if (sent_file) { + finalize_progress(rctx.tag); + } logger(LL_INFO, "Done sending %s\n", component); return 0; |
