summaryrefslogtreecommitdiffstats
path: root/src/idevicerestore.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/idevicerestore.c')
-rw-r--r--src/idevicerestore.c801
1 files changed, 465 insertions, 336 deletions
diff --git a/src/idevicerestore.c b/src/idevicerestore.c
index 8de9186..04070a1 100644
--- a/src/idevicerestore.c
+++ b/src/idevicerestore.c
@@ -40,6 +40,7 @@
#include <libimobiledevice-glue/sha.h>
#include <libimobiledevice-glue/utils.h>
+#include <libimobiledevice-glue/termcolors.h>
#include <libtatsu/tss.h>
#include "ace3.h"
@@ -54,7 +55,9 @@
#include "recovery.h"
#include "idevicerestore.h"
+#ifdef HAVE_LIMERA1N
#include "limera1n.h"
+#endif
#include "locking.h"
@@ -73,7 +76,9 @@ static struct option longopts[] = {
{ "exclude", no_argument, NULL, 'x' },
{ "shsh", no_argument, NULL, 't' },
{ "keep-pers", no_argument, NULL, 'k' },
+#ifdef HAVE_LIMERA1N
{ "pwn", no_argument, NULL, 'p' },
+#endif
{ "no-action", no_argument, NULL, 'n' },
{ "cache-path", required_argument, NULL, 'C' },
{ "no-input", no_argument, NULL, 'y' },
@@ -85,11 +90,17 @@ static struct option longopts[] = {
{ "ipsw-info", no_argument, NULL, 'I' },
{ "ignore-errors", no_argument, NULL, 1 },
{ "variant", required_argument, NULL, 2 },
+ { "logfile", required_argument, NULL, 3 },
{ NULL, 0, NULL, 0 }
};
static void usage(int argc, char* argv[], int err)
{
+#ifdef HAVE_LIMERA1N
+#define PWN_FLAG_LINE " -p, --pwn Put device in pwned DFU mode and exit (limera1n devices)\n"
+#else
+#define PWN_FLAG_LINE ""
+#endif
char* name = strrchr(argv[0], '/');
fprintf((err) ? stderr : stdout,
"Usage: %s [OPTIONS] PATH\n" \
@@ -124,7 +135,9 @@ static void usage(int argc, char* argv[], int err)
" -h, --help Prints this usage information\n" \
" -C, --cache-path DIR Use specified directory for caching extracted or other\n" \
" reused files.\n" \
- " -d, --debug Enable communication debugging\n" \
+ " --logfile=PATH Write logging output to file at PATH. If PATH equals\n" \
+ " 'NULL' or 'NONE', no log file will be written.\n" \
+ " -d, --debug Print additional debug output\n" \
" -v, --version Print version information\n" \
"\n" \
"Advanced/experimental options:\n"
@@ -134,7 +147,7 @@ static void usage(int argc, char* argv[], int err)
" -t, --shsh Fetch TSS record and save to .shsh file, then exit\n" \
" -z, --no-restore Do not restore and end after booting to the ramdisk\n" \
" -k, --keep-pers Write personalized components to files for debugging\n" \
- " -p, --pwn Put device in pwned DFU mode and exit (limera1n devices)\n" \
+ PWN_FLAG_LINE \
" -P, --plain-progress Print progress as plain step and progress\n" \
" -R, --restore-mode Allow restoring from Restore mode\n" \
" -T, --ticket PATH Use file at PATH to send as AP ticket\n" \
@@ -158,8 +171,6 @@ const uint8_t lpol_file[22] = {
};
const uint32_t lpol_file_length = 22;
-static int idevicerestore_keep_pers = 0;
-
static int load_version_data(struct idevicerestore_client_t* client)
{
if (!client) {
@@ -190,9 +201,9 @@ static int load_version_data(struct idevicerestore_client_t* client)
if (download_to_file("http://itunes.apple.com/check/version", version_xml_tmp, 0) == 0) {
remove(version_xml);
if (rename(version_xml_tmp, version_xml) < 0) {
- error("ERROR: Could not update '%s'\n", version_xml);
+ logger(LL_ERROR, "Could not update '%s'\n", version_xml);
} else {
- info("NOTE: Updated version data.\n");
+ logger(LL_INFO, "Updated version data.\n");
}
}
} else {
@@ -204,7 +215,7 @@ static int load_version_data(struct idevicerestore_client_t* client)
read_file(version_xml, (void**)&verbuf, &verlen);
if (!verbuf) {
- error("ERROR: Could not load '%s'\n", version_xml);
+ logger(LL_ERROR, "Could not load '%s'\n", version_xml);
return -1;
}
@@ -214,12 +225,12 @@ static int load_version_data(struct idevicerestore_client_t* client)
if (!client->version_data) {
remove(version_xml);
- error("ERROR: Cannot parse plist data from '%s'.\n", version_xml);
+ logger(LL_ERROR, "Cannot parse plist data from '%s'.\n", version_xml);
return -1;
}
if (cached) {
- info("NOTE: using cached version data\n");
+ logger(LL_INFO, "Using cached version data\n");
}
return 0;
@@ -255,21 +266,24 @@ static void idevice_event_cb(const idevice_event_t *event, void *userdata)
if (normal_check_mode(client) == 0) {
mutex_lock(&client->device_event_mutex);
client->mode = MODE_NORMAL;
- debug("%s: device %016" PRIx64 " (udid: %s) connected in normal mode\n", __func__, client->ecid, client->udid);
+ logger(LL_DEBUG, "%s: device %016" PRIx64 " (udid: %s) connected in normal mode\n", __func__, client->ecid, client->udid);
cond_signal(&client->device_event_cond);
mutex_unlock(&client->device_event_mutex);
} else if (client->ecid && restore_check_mode(client) == 0) {
mutex_lock(&client->device_event_mutex);
client->mode = MODE_RESTORE;
- debug("%s: device %016" PRIx64 " (udid: %s) connected in restore mode\n", __func__, client->ecid, client->udid);
+ logger(LL_DEBUG, "%s: device %016" PRIx64 " (udid: %s) connected in restore mode\n", __func__, client->ecid, client->udid);
cond_signal(&client->device_event_cond);
mutex_unlock(&client->device_event_mutex);
}
+ if (!client->device) {
+ client->device = get_irecv_device(client);
+ }
} else if (event->event == IDEVICE_DEVICE_REMOVE) {
if (client->udid && !strcmp(event->udid, client->udid)) {
mutex_lock(&client->device_event_mutex);
client->mode = MODE_UNKNOWN;
- debug("%s: device %016" PRIx64 " (udid: %s) disconnected\n", __func__, client->ecid, client->udid);
+ logger(LL_DEBUG, "%s: device %016" PRIx64 " (udid: %s) disconnected\n", __func__, client->ecid, client->udid);
client->ignore_device_add_events = 0;
cond_signal(&client->device_event_cond);
mutex_unlock(&client->device_event_mutex);
@@ -305,7 +319,10 @@ static void irecv_event_cb(const irecv_device_event_t* event, void *userdata)
default:
client->mode = MODE_UNKNOWN;
}
- debug("%s: device %016" PRIx64 " (udid: %s) connected in %s mode\n", __func__, client->ecid, (client->udid) ? client->udid : "N/A", client->mode->string);
+ logger(LL_DEBUG, "%s: device %016" PRIx64 " (udid: %s) connected in %s mode\n", __func__, client->ecid, (client->udid) ? client->udid : "N/A", client->mode->string);
+ if (!client->device) {
+ client->device = get_irecv_device(client);
+ }
cond_signal(&client->device_event_cond);
mutex_unlock(&client->device_event_mutex);
}
@@ -313,7 +330,7 @@ static void irecv_event_cb(const irecv_device_event_t* event, void *userdata)
if (client->ecid && event->device_info->ecid == client->ecid) {
mutex_lock(&client->device_event_mutex);
client->mode = MODE_UNKNOWN;
- debug("%s: device %016" PRIx64 " (udid: %s) disconnected\n", __func__, client->ecid, (client->udid) ? client->udid : "N/A");
+ logger(LL_DEBUG, "%s: device %016" PRIx64 " (udid: %s) disconnected\n", __func__, client->ecid, (client->udid) ? client->udid : "N/A");
if (event->mode == IRECV_K_PORT_DFU_MODE) {
// We have to reset the ECID here if a port DFU device disconnects,
// because when the device reconnects in a different mode, it will
@@ -338,30 +355,38 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
}
if ((client->flags & FLAG_LATEST) && (client->flags & FLAG_CUSTOM)) {
- error("ERROR: FLAG_LATEST cannot be used with FLAG_CUSTOM.\n");
+ logger(LL_ERROR, "FLAG_LATEST cannot be used with FLAG_CUSTOM.\n");
return -1;
}
if (!client->ipsw && !(client->flags & FLAG_PWN) && !(client->flags & FLAG_LATEST)) {
- error("ERROR: no ipsw file given\n");
+ logger(LL_ERROR, "no ipsw file given\n");
return -1;
}
if (client->debug_level > 0) {
idevicerestore_debug = 1;
if (client->debug_level > 1) {
- idevice_set_debug_level(1);
irecv_set_debug_level(1);
}
+ if (client->debug_level > 2) {
+ idevice_set_debug_level(1);
+ }
tss_set_debug_level(client->debug_level);
}
+ progress_reset_tag();
+
idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.0);
- irecv_device_event_subscribe(&client->irecv_e_ctx, irecv_event_cb, client);
+ if (!client->irecv_e_ctx) {
+ irecv_device_event_subscribe(&client->irecv_e_ctx, irecv_event_cb, client);
+ }
- idevice_event_subscribe(idevice_event_cb, client);
- client->idevice_e_ctx = idevice_event_cb;
+ if (!client->idevice_e_ctx) {
+ idevice_event_subscribe(idevice_event_cb, client);
+ client->idevice_e_ctx = idevice_event_cb;
+ }
// check which mode the device is currently in so we know where to start
mutex_lock(&client->device_event_mutex);
@@ -369,31 +394,31 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000);
if (client->mode == MODE_UNKNOWN || (client->flags & FLAG_QUIT)) {
mutex_unlock(&client->device_event_mutex);
- error("ERROR: Unable to discover device mode. Please make sure a device is attached.\n");
+ logger(LL_ERROR, "Unable to discover device mode. Please make sure a device is attached.\n");
return -1;
}
}
idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.1);
- info("Found device in %s mode\n", client->mode->string);
+ logger(LL_INFO, "Found device in %s mode\n", client->mode->string);
mutex_unlock(&client->device_event_mutex);
if (client->mode == MODE_WTF) {
unsigned int cpid = 0;
if (dfu_client_new(client) != 0) {
- error("ERROR: Could not open device in WTF mode\n");
+ logger(LL_ERROR, "Could not open device in WTF mode\n");
return -1;
}
if ((dfu_get_cpid(client, &cpid) < 0) || (cpid == 0)) {
- error("ERROR: Could not get CPID for WTF mode device\n");
+ logger(LL_ERROR, "Could not get CPID for WTF mode device\n");
dfu_client_free(client);
return -1;
}
char wtfname[256];
- sprintf(wtfname, "Firmware/dfu/WTF.s5l%04xxall.RELEASE.dfu", cpid);
- unsigned char* wtftmp = NULL;
- unsigned int wtfsize = 0;
+ snprintf(wtfname, sizeof(wtfname), "Firmware/dfu/WTF.s5l%04xxall.RELEASE.dfu", cpid);
+ void* wtftmp = NULL;
+ size_t wtfsize = 0;
// Prefer to get WTF file from the restore IPSW
ipsw_extract_to_memory(client->ipsw, wtfname, &wtftmp, &wtfsize);
@@ -408,7 +433,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
plist_get_string_val(wtfurl, &s_wtfurl);
}
if (!s_wtfurl) {
- info("Using hardcoded x12220000_5_Recovery.ipsw URL\n");
+ logger(LL_INFO, "Using hardcoded x12220000_5_Recovery.ipsw URL\n");
s_wtfurl = strdup("http://appldnld.apple.com.edgesuite.net/content.info.apple.com/iPhone/061-6618.20090617.Xse7Y/x12220000_5_Recovery.ipsw");
}
@@ -439,14 +464,14 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
ipsw_extract_to_memory(wtf_ipsw, wtfname, &wtftmp, &wtfsize);
ipsw_close(wtf_ipsw);
if (!wtftmp) {
- error("ERROR: Could not extract WTF\n");
+ logger(LL_ERROR, "Could not extract WTF\n");
}
}
mutex_lock(&client->device_event_mutex);
if (wtftmp) {
if (dfu_send_buffer(client, wtftmp, wtfsize) != 0) {
- error("ERROR: Could not send WTF...\n");
+ logger(LL_ERROR, "Could not send WTF...\n");
}
}
dfu_client_free(client);
@@ -457,7 +482,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
if (client->mode != MODE_DFU || (client->flags & FLAG_QUIT)) {
mutex_unlock(&client->device_event_mutex);
/* TODO: verify if it actually goes from 0x1222 -> 0x1227 */
- error("ERROR: Failed to put device into DFU from WTF mode\n");
+ logger(LL_ERROR, "Failed to put device into DFU from WTF mode\n");
return -1;
}
mutex_unlock(&client->device_event_mutex);
@@ -466,20 +491,20 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
// discover the device type
client->device = get_irecv_device(client);
if (client->device == NULL) {
- error("ERROR: Unable to discover device type\n");
+ logger(LL_ERROR, "Unable to discover device type\n");
return -1;
}
if (client->ecid == 0) {
- error("ERROR: Unable to determine ECID\n");
+ logger(LL_ERROR, "Unable to determine ECID\n");
return -1;
}
- info("ECID: %" PRIu64 "\n", client->ecid);
+ logger(LL_INFO, "ECID: %" PRIu64 "\n", client->ecid);
idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.2);
- info("Identified device as %s, %s\n", client->device->hardware_model, client->device->product_type);
+ logger(LL_INFO, "Identified device as %s, %s\n", client->device->hardware_model, client->device->product_type);
if ((client->flags & FLAG_PWN) && (client->mode != MODE_DFU)) {
- error("ERROR: you need to put your device into DFU mode to pwn it.\n");
+ logger(LL_ERROR, "you need to put your device into DFU mode to pwn it.\n");
return -1;
}
@@ -495,39 +520,41 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
plist_free(pver);
}
}
- info("Device Product Version: %s\n", (client->device_version) ? client->device_version : "N/A");
- info("Device Product Build: %s\n", (client->device_build) ? client->device_build : "N/A");
+ logger(LL_INFO, "Device Product Version: %s\n", (client->device_version) ? client->device_version : "N/A");
+ logger(LL_INFO, "Device Product Build: %s\n", (client->device_build) ? client->device_build : "N/A");
if (client->flags & FLAG_PWN) {
+#ifdef HAVE_LIMERA1N
recovery_client_free(client);
if (client->mode != MODE_DFU) {
- error("ERROR: Device needs to be in DFU mode for this option.\n");
+ logger(LL_ERROR, "Device needs to be in DFU mode for this option.\n");
return -1;
}
- info("connecting to DFU\n");
+ logger(LL_INFO, "connecting to DFU\n");
if (dfu_client_new(client) < 0) {
return -1;
}
if (limera1n_is_supported(client->device)) {
- info("exploiting with limera1n...\n");
+ logger(LL_INFO, "exploiting with limera1n...\n");
if (limera1n_exploit(client->device, &client->dfu->client) != 0) {
- error("ERROR: limera1n exploit failed\n");
+ logger(LL_ERROR, "limera1n exploit failed\n");
dfu_client_free(client);
return -1;
}
dfu_client_free(client);
- info("Device should be in pwned DFU state now.\n");
+ logger(LL_INFO, "Device should be in pwned DFU state now.\n");
return 0;
}
else {
dfu_client_free(client);
- error("ERROR: This device is not supported by the limera1n exploit");
+ logger(LL_ERROR, "This device is not supported by the limera1n exploit");
return -1;
}
+#endif
}
if (client->flags & FLAG_LATEST) {
@@ -537,30 +564,24 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
plist_t signed_fws = NULL;
int res = ipsw_get_signed_firmwares(client->device->product_type, &signed_fws);
if (res < 0) {
- error("ERROR: Could not fetch list of signed firmwares.\n");
+ logger(LL_ERROR, "Could not fetch list of signed firmwares.\n");
return res;
}
uint32_t count = plist_array_get_size(signed_fws);
if (count == 0) {
plist_free(signed_fws);
- error("ERROR: No firmwares are currently being signed for %s (REALLY?!)\n", client->device->product_type);
+ logger(LL_ERROR, "No firmwares are currently being signed for %s (REALLY?!)\n", client->device->product_type);
return -1;
}
plist_t selected_fw = NULL;
if (client->flags & FLAG_INTERACTIVE) {
uint32_t i = 0;
- info("The following firmwares are currently being signed for %s:\n", client->device->product_type);
+ logger(LL_INFO, "The following firmwares are currently being signed for %s:\n", client->device->product_type);
for (i = 0; i < count; i++) {
plist_t fw = plist_array_get_item(signed_fws, i);
plist_t p_version = plist_dict_get_item(fw, "version");
plist_t p_build = plist_dict_get_item(fw, "buildid");
- char *s_version = NULL;
- char *s_build = NULL;
- plist_get_string_val(p_version, &s_version);
- plist_get_string_val(p_build, &s_build);
- info(" [%d] %s (build %s)\n", i+1, s_version, s_build);
- free(s_version);
- free(s_build);
+ logger(LL_INFO, " [%d] %s (build %s)\n", i+1, plist_get_string_ptr(p_version, NULL), plist_get_string_ptr(p_build, NULL));
}
while (1) {
char input[64];
@@ -584,23 +605,17 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
break;
}
} else {
- info("NOTE: Running non-interactively, automatically selecting latest available version\n");
+ logger(LL_NOTICE, "Running non-interactively, automatically selecting latest available version\n");
selected_fw = plist_array_get_item(signed_fws, 0);
}
if (!selected_fw) {
- error("ERROR: failed to select latest firmware?!\n");
+ logger(LL_ERROR, "failed to select latest firmware?!\n");
plist_free(signed_fws);
return -1;
} else {
plist_t p_version = plist_dict_get_item(selected_fw, "version");
plist_t p_build = plist_dict_get_item(selected_fw, "buildid");
- char *s_version = NULL;
- char *s_build = NULL;
- plist_get_string_val(p_version, &s_version);
- plist_get_string_val(p_build, &s_build);
- info("Selected firmware %s (build %s)\n", s_version, s_build);
- free(s_version);
- free(s_build);
+ logger(LL_NOTICE, "Selected firmware %s (build %s)\n", plist_get_string_ptr(p_version, NULL), plist_get_string_ptr(p_build, NULL));
plist_t p_url = plist_dict_get_item(selected_fw, "url");
plist_t p_sha1 = plist_dict_get_item(selected_fw, "sha1sum");
char *s_sha1 = NULL;
@@ -616,13 +631,13 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
}
p_fwsha1 = &fwsha1[0];
} else {
- error("ERROR: unexpected size of sha1sum\n");
+ logger(LL_ERROR, "unexpected size of sha1sum\n");
}
}
plist_free(signed_fws);
if (!fwurl || !p_fwsha1) {
- error("ERROR: Missing firmware URL or SHA1\n");
+ logger(LL_ERROR, "Missing firmware URL or SHA1\n");
return -1;
}
@@ -634,7 +649,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
} else {
client->ipsw = ipsw_open(ipsw);
if (!client->ipsw) {
- error("ERROR: Failed to open ipsw '%s'\n", ipsw);
+ logger(LL_ERROR, "Failed to open ipsw '%s'\n", ipsw);
free(ipsw);
return -1;
}
@@ -649,15 +664,15 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
// extract buildmanifest
if (client->flags & FLAG_CUSTOM) {
- info("Extracting Restore.plist from IPSW\n");
+ logger(LL_INFO, "Extracting Restore.plist from IPSW\n");
if (ipsw_extract_restore_plist(client->ipsw, &client->build_manifest) < 0) {
- error("ERROR: Unable to extract Restore.plist from %s. Firmware file might be corrupt.\n", client->ipsw->path);
+ logger(LL_ERROR, "Unable to extract Restore.plist from %s. Firmware file might be corrupt.\n", client->ipsw->path);
return -1;
}
} else {
- info("Extracting BuildManifest from IPSW\n");
+ logger(LL_INFO, "Extracting BuildManifest from IPSW\n");
if (ipsw_extract_build_manifest(client->ipsw, &client->build_manifest, &tss_enabled) < 0) {
- error("ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", client->ipsw->path);
+ logger(LL_ERROR, "Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", client->ipsw->path);
return -1;
}
}
@@ -665,13 +680,13 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
if (client->flags & FLAG_CUSTOM) {
// prevent attempt to sign custom firmware
tss_enabled = 0;
- info("Custom firmware requested; TSS has been disabled.\n");
+ logger(LL_INFO, "Custom firmware requested; TSS has been disabled.\n");
}
if (client->mode == MODE_RESTORE) {
if (!(client->flags & FLAG_ALLOW_RESTORE_MODE)) {
if (restore_reboot(client) < 0) {
- error("ERROR: Unable to exit restore mode\n");
+ logger(LL_ERROR, "Unable to exit restore mode\n");
return -2;
}
@@ -680,10 +695,10 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 60000);
if (client->mode == MODE_UNKNOWN || (client->flags & FLAG_QUIT)) {
mutex_unlock(&client->device_event_mutex);
- error("ERROR: Unable to discover device mode. Please make sure a device is attached.\n");
+ logger(LL_ERROR, "Unable to discover device mode. Please make sure a device is attached.\n");
return -1;
}
- info("Found device in %s mode\n", client->mode->string);
+ logger(LL_INFO, "Found device in %s mode\n", client->mode->string);
mutex_unlock(&client->device_event_mutex);
}
}
@@ -694,39 +709,39 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
unsigned int prev = 0;
if (dfu_get_bdid(client, &pdfu_bdid) < 0) {
- error("ERROR: Failed to get bdid for Port DFU device!\n");
+ logger(LL_ERROR, "Failed to get bdid for Port DFU device!\n");
return -1;
}
if (dfu_get_cpid(client, &pdfu_cpid) < 0) {
- error("ERROR: Failed to get cpid for Port DFU device!\n");
+ logger(LL_ERROR, "Failed to get cpid for Port DFU device!\n");
return -1;
}
if (dfu_get_prev(client, &prev) < 0) {
- error("ERROR: Failed to get PREV for Port DFU device!\n");
+ logger(LL_ERROR, "Failed to get PREV for Port DFU device!\n");
return -1;
}
unsigned char* pdfu_nonce = NULL;
unsigned int pdfu_nsize = 0;
if (dfu_get_portdfu_nonce(client, &pdfu_nonce, &pdfu_nsize) < 0) {
- error("ERROR: Failed to get nonce for Port DFU device!\n");
+ logger(LL_ERROR, "Failed to get nonce for Port DFU device!\n");
return -1;
}
plist_t build_identity = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, RESTORE_VARIANT_ERASE_INSTALL, 0);
if (!build_identity) {
- error("ERORR: Failed to get build identity\n");
+ logger(LL_ERROR, "ERORR: Failed to get build identity\n");
return -1;
}
unsigned int b_pdfu_cpid = (unsigned int)plist_dict_get_uint(build_identity, "USBPortController1,ChipID");
if (b_pdfu_cpid != pdfu_cpid) {
- error("ERROR: cpid 0x%02x doesn't match USBPortController1,ChipID in build identity (0x%02x)\n", pdfu_cpid, b_pdfu_cpid);
+ logger(LL_ERROR, "cpid 0x%02x doesn't match USBPortController1,ChipID in build identity (0x%02x)\n", pdfu_cpid, b_pdfu_cpid);
return -1;
}
unsigned int b_pdfu_bdid = (unsigned int)plist_dict_get_uint(build_identity, "USBPortController1,BoardID");
if (b_pdfu_bdid != pdfu_bdid) {
- error("ERROR: bdid 0x%x doesn't match USBPortController1,BoardID in build identity (0x%x)\n", pdfu_bdid, b_pdfu_bdid);
+ logger(LL_ERROR, "bdid 0x%x doesn't match USBPortController1,BoardID in build identity (0x%x)\n", pdfu_bdid, b_pdfu_bdid);
return -1;
}
@@ -738,29 +753,30 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
plist_dict_copy_item(parameters, build_identity, "USBPortController1,SecurityDomain", NULL);
plist_dict_set_item(parameters, "USBPortController1,SecurityMode", plist_new_bool(1));
plist_dict_set_item(parameters, "USBPortController1,ProductionMode", plist_new_bool(1));
+ int is_mac = plist_access_path(build_identity, 2, "Info", "MacOSVariant") != NULL;
plist_t usbf = plist_access_path(build_identity, 2, "Manifest", "USBPortController1,USBFirmware");
if (!usbf) {
plist_free(parameters);
- error("ERROR: Unable to find USBPortController1,USBFirmware in build identity\n");
+ logger(LL_ERROR, "Unable to find USBPortController1,USBFirmware in build identity\n");
return -1;
}
plist_t p_fwpath = plist_access_path(usbf, 2, "Info", "Path");
if (!p_fwpath) {
plist_free(parameters);
- error("ERROR: Unable to find path of USBPortController1,USBFirmware component\n");
+ logger(LL_ERROR, "Unable to find path of USBPortController1,USBFirmware component\n");
return -1;
}
const char* fwpath = plist_get_string_ptr(p_fwpath, NULL);
if (!fwpath) {
plist_free(parameters);
- error("ERROR: Unable to get path of USBPortController1,USBFirmware component\n");
+ logger(LL_ERROR, "Unable to get path of USBPortController1,USBFirmware component\n");
return -1;
}
- unsigned char* uarp_buf = NULL;
- unsigned int uarp_size = 0;
+ void* uarp_buf = NULL;
+ size_t uarp_size = 0;
if (ipsw_extract_to_memory(client->ipsw, fwpath, &uarp_buf, &uarp_size) < 0) {
plist_free(parameters);
- error("ERROR: Unable to extract '%s' from IPSW\n", fwpath);
+ logger(LL_ERROR, "Unable to extract '%s' from IPSW\n", fwpath);
return -1;
}
usbf = plist_copy(usbf);
@@ -771,7 +787,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
plist_t request = tss_request_new(NULL);
if (request == NULL) {
plist_free(parameters);
- error("ERROR: Unable to create TSS request\n");
+ logger(LL_ERROR, "Unable to create TSS request\n");
return -1;
}
plist_dict_merge(&request, parameters);
@@ -781,56 +797,60 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
plist_t response = tss_request_send(request, client->tss_url);
plist_free(request);
if (response == NULL) {
- error("ERROR: Unable to send TSS request\n");
+ logger(LL_ERROR, "Unable to send TSS request\n");
return -1;
}
- info("Received USBPortController1,Ticket\n");
+ logger(LL_INFO, "Received USBPortController1,Ticket\n");
- info("Creating Ace3Binary\n");
- unsigned char* ace3bin = NULL;
+ logger(LL_INFO, "Creating Ace3Binary\n");
+ void* ace3bin = NULL;
size_t ace3bin_size = 0;
if (ace3_create_binary(uarp_buf, uarp_size, pdfu_bdid, prev, response, &ace3bin, &ace3bin_size) < 0) {
- error("ERROR: Could not create Ace3Binary\n");
+ logger(LL_ERROR, "Could not create Ace3Binary\n");
return -1;
}
plist_free(response);
free(uarp_buf);
- if (idevicerestore_keep_pers) {
- write_file("Ace3Binary", (const char*)ace3bin, ace3bin_size);
+ if (client->flags & FLAG_KEEP_PERS) {
+ write_file("Ace3Binary", ace3bin, ace3bin_size);
}
if (dfu_send_buffer_with_options(client, ace3bin, ace3bin_size, IRECV_SEND_OPT_DFU_NOTIFY_FINISH | IRECV_SEND_OPT_DFU_SMALL_PKT) < 0) {
- error("ERROR: Could not send Ace3Buffer to device\n");
+ logger(LL_ERROR, "Could not send Ace3Buffer to device\n");
return -1;
}
- debug("Waiting for device to disconnect...\n");
+ logger(LL_DEBUG, "Waiting for device to disconnect...\n");
cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 5000);
if (client->mode != MODE_UNKNOWN || (client->flags & FLAG_QUIT)) {
mutex_unlock(&client->device_event_mutex);
if (!(client->flags & FLAG_QUIT)) {
- error("ERROR: Device did not disconnect. Port DFU failed.\n");
+ logger(LL_ERROR, "Device did not disconnect. Port DFU failed.\n");
}
return -2;
}
- debug("Waiting for device to reconnect in DFU mode...\n");
- cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 5000);
+ dfu_client_free(client);
+ logger(LL_DEBUG, "Waiting for device to reconnect in DFU mode...\n");
+ cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 20000);
if (client->mode != MODE_DFU || (client->flags & FLAG_QUIT)) {
mutex_unlock(&client->device_event_mutex);
if (!(client->flags & FLAG_QUIT)) {
- error("ERROR: Device did not reconnect in DFU mode. Port DFU failed.\n");
+ logger(LL_ERROR, "Device did not reconnect in DFU mode. Port DFU failed.\n");
+ if (is_mac) {
+ logger(LL_ERROR, "Make sure to use the correct USB port for this model, see https://support.apple.com/120694\n");
+ }
}
return -2;
}
mutex_unlock(&client->device_event_mutex);
if (client->flags & FLAG_NOACTION) {
- info("Port DFU restore successful.\n");
+ logger(LL_INFO, "Port DFU restore successful.\n");
return 0;
} else {
- info("Port DFU restore successful. Continuing.\n");
+ logger(LL_INFO, "Port DFU restore successful. Continuing.\n");
}
}
@@ -838,18 +858,18 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
/* check if device type is supported by the given build manifest */
if (build_manifest_check_compatibility(client->build_manifest, client->device->product_type) < 0) {
- error("ERROR: Could not make sure this firmware is suitable for the current device. Refusing to continue.\n");
+ logger(LL_ERROR, "Could not make sure this firmware is suitable for the current device. Refusing to continue.\n");
return -1;
}
/* print iOS information from the manifest */
build_manifest_get_version_information(client->build_manifest, client);
- info("IPSW Product Version: %s\n", client->version);
- info("IPSW Product Build: %s Major: %d\n", client->build, client->build_major);
+ logger(LL_INFO, "IPSW Product Version: %s\n", client->version);
+ logger(LL_INFO, "IPSW Product Build: %s Major: %d\n", client->build, client->build_major);
client->image4supported = is_image4_supported(client);
- info("Device supports Image4: %s\n", (client->image4supported) ? "true" : "false");
+ logger(LL_INFO, "Device supports Image4: %s\n", (client->image4supported) ? "true" : "false");
// choose whether this is an upgrade or a restore (default to upgrade)
client->tss = NULL;
@@ -874,16 +894,16 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
x++;
}
- sprintf(p_all_flash, "Firmware/all_flash/all_flash.%s.%s", lcmodel, "production");
+ snprintf(p_all_flash, sizeof(p_all_flash), "Firmware/all_flash/all_flash.%s.%s", lcmodel, "production");
strcpy(tmpstr, p_all_flash);
strcat(tmpstr, "/manifest");
// get all_flash file manifest
char *files[16];
- char *fmanifest = NULL;
- uint32_t msize = 0;
- if (ipsw_extract_to_memory(client->ipsw, tmpstr, (unsigned char**)&fmanifest, &msize) < 0) {
- error("ERROR: could not extract %s from IPSW\n", tmpstr);
+ void *fmanifest = NULL;
+ size_t msize = 0;
+ if (ipsw_extract_to_memory(client->ipsw, tmpstr, &fmanifest, &msize) < 0) {
+ logger(LL_ERROR, "could not extract %s from IPSW\n", tmpstr);
free(build_identity);
return -1;
}
@@ -916,7 +936,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
plist_dict_set_item(manifest, "RestoreDeviceTree", plist_copy(comp));
}
} else {
- error("WARNING: unhandled component %s\n", files[x]);
+ logger(LL_WARNING, "Unhandled component %s\n", files[x]);
plist_free(comp);
}
free(files[x]);
@@ -924,7 +944,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
}
// add iBSS
- sprintf(tmpstr, "Firmware/dfu/iBSS.%s.%s.dfu", lcmodel, "RELEASE");
+ snprintf(tmpstr, sizeof(tmpstr), "Firmware/dfu/iBSS.%s.%s.dfu", lcmodel, "RELEASE");
inf = plist_new_dict();
plist_dict_set_item(inf, "Path", plist_new_string(tmpstr));
comp = plist_new_dict();
@@ -932,7 +952,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
plist_dict_set_item(manifest, "iBSS", comp);
// add iBEC
- sprintf(tmpstr, "Firmware/dfu/iBEC.%s.%s.dfu", lcmodel, "RELEASE");
+ snprintf(tmpstr, sizeof(tmpstr), "Firmware/dfu/iBEC.%s.%s.dfu", lcmodel, "RELEASE");
inf = plist_new_dict();
plist_dict_set_item(inf, "Path", plist_new_string(tmpstr));
comp = plist_new_dict();
@@ -986,11 +1006,11 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
// add OS filesystem
node = plist_dict_get_item(client->build_manifest, "SystemRestoreImages");
if (!node) {
- error("ERROR: missing SystemRestoreImages in Restore.plist\n");
+ logger(LL_ERROR, "missing SystemRestoreImages in Restore.plist\n");
}
plist_t os = plist_dict_get_item(node, "User");
if (!os) {
- error("ERROR: missing filesystem in Restore.plist\n");
+ logger(LL_ERROR, "missing filesystem in Restore.plist\n");
} else {
inf = plist_new_dict();
plist_dict_set_item(inf, "Path", plist_copy(os));
@@ -1019,7 +1039,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
}
}
if (build_identity == NULL) {
- error("ERROR: Unable to find a matching build identity\n");
+ logger(LL_ERROR, "Unable to find a matching build identity\n");
return -1;
}
@@ -1029,47 +1049,37 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
build_identity_print_information(build_identity);
if (client->macos_variant) {
- info("Performing macOS restore\n");
+ logger(LL_INFO, "Performing macOS restore\n");
}
if (client->mode == MODE_NORMAL && !(client->flags & FLAG_ERASE) && !(client->flags & FLAG_SHSHONLY)) {
if (client->device_version && (compare_versions(client->device_version, client->version) > 0)) {
if (client->flags & FLAG_INTERACTIVE) {
- char input[64];
- char spaces[16];
- int num_spaces = 13 - strlen(client->version) - strlen(client->device_version);
- memset(spaces, ' ', num_spaces);
- spaces[num_spaces] = '\0';
- printf("################################ [ WARNING ] #################################\n"
- "# You are trying to DOWNGRADE a %s device with an IPSW for %s while%s #\n"
- "# trying to preserve the user data (Upgrade restore). This *might* work, but #\n"
- "# there is a VERY HIGH chance it might FAIL BADLY with COMPLETE DATA LOSS. #\n"
- "# Hit CTRL+C now if you want to abort the restore. #\n"
- "# If you want to take the risk (and have a backup of your important data!) #\n"
- "# type YES and press ENTER to continue. You have been warned. #\n"
- "##############################################################################\n",
- client->device_version, client->version, spaces);
- while (1) {
- printf("> ");
- fflush(stdout);
- fflush(stdin);
- input[0] = '\0';
- get_user_input(input, 63, 0);
- if (client->flags & FLAG_QUIT) {
- return -1;
- }
- if (*input != '\0' && !strcmp(input, "YES")) {
- break;
- } else {
- printf("Invalid input. Please type YES or hit CTRL+C to abort.\n");
- continue;
- }
+ char msgtext[512];
+ snprintf(msgtext, 512, "You are trying to DOWNGRADE a %s device with an IPSW for %s while\n"
+ "trying to preserve the user data (Upgrade restore). This *might* work, but\n"
+ "there is a VERY HIGH chance it might FAIL BADLY with COMPLETE DATA LOSS.\n"
+ "If you want to take the risk (and have a backup of your important data!) you may continue.\n"
+ "You have been warned.\n", client->device_version, client->version);
+ int pres = prompt_user("WARNING", msgtext);
+ if (pres < 0) {
+ client->flags |= FLAG_QUIT;
+ return -1;
}
}
}
}
if (client->flags & FLAG_ERASE && client->flags & FLAG_INTERACTIVE) {
+ int pres = prompt_user(
+ "WARNING",
+ "You are about to perform an *ERASE* restore. ALL DATA on the target device will be IRREVERSIBLY DESTROYED. If you want to update your device without erasing the user data, cancel now and restart without -e or --erase command line switch.\n"
+ );
+ if (pres < 0) {
+ client->flags |= FLAG_QUIT;
+ return -1;
+ }
+#if 0
char input[64];
printf("################################ [ WARNING ] #################################\n"
"# You are about to perform an *ERASE* restore. ALL DATA on the target device #\n"
@@ -1094,22 +1104,23 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
continue;
}
}
+#endif
}
idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.0);
/* check if all components we need are actually there */
- info("Checking IPSW for required components...\n");
+ logger(LL_INFO, "Checking IPSW for required components...\n");
if (build_identity_check_components_in_ipsw(build_identity, client->ipsw) < 0) {
- error("ERROR: Could not find all required components in IPSW %s\n", client->ipsw->path);
+ logger(LL_ERROR, "Could not find all required components in IPSW %s\n", client->ipsw->path);
return -1;
}
- info("All required components found in IPSW\n");
+ logger(LL_INFO, "All required components found in IPSW\n");
/* Get OS (filesystem) name from build identity */
char* os_path = NULL;
if (build_identity_get_component_path(build_identity, "OS", &os_path) < 0) {
- error("ERROR: Unable to get path for filesystem component\n");
+ logger(LL_ERROR, "Unable to get path for filesystem component\n");
return -1;
}
@@ -1154,16 +1165,16 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
memset(&st, '\0', sizeof(struct stat));
if (stat(tmpf, &st) == 0) {
if ((fssize > 0) && ((uint64_t)st.st_size == fssize)) {
- info("Using cached filesystem from '%s'\n", tmpf);
+ logger(LL_INFO, "Using cached filesystem from '%s'\n", tmpf);
client->filesystem = tmpf;
}
}
if (!client->filesystem) {
- info("Extracting filesystem from IPSW: %s\n", os_path);
+ logger(LL_INFO, "Extracting filesystem from IPSW: %s\n", os_path);
if (ipsw_extract_to_file_with_progress(client->ipsw, os_path, tmpf, 1) < 0) {
- error("ERROR: Unable to extract filesystem from IPSW\n");
- info("Removing %s\n", tmpf);
+ logger(LL_ERROR, "Unable to extract filesystem from IPSW\n");
+ logger(LL_INFO, "Removing %s\n", tmpf);
unlink(tmpf);
free(tmpf);
return -1;
@@ -1185,19 +1196,19 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
plist_get_bool_val(node, &needs_preboard);
}
if (needs_preboard) {
- info("Checking if device requires stashbag...\n");
+ logger(LL_INFO, "Checking if device requires stashbag...\n");
plist_t manifest;
if (get_preboard_manifest(client, build_identity, &manifest) < 0) {
- error("ERROR: Unable to create preboard manifest.\n");
+ logger(LL_ERROR, "Unable to create preboard manifest.\n");
return -1;
}
- debug("DEBUG: creating stashbag...\n");
+ logger(LL_DEBUG, "creating stashbag...\n");
int err = normal_handle_create_stashbag(client, manifest);
if (err < 0) {
if (err == -2) {
- error("ERROR: Could not create stashbag (timeout).\n");
+ logger(LL_ERROR, "Could not create stashbag (timeout).\n");
} else {
- error("ERROR: An error occurred while creating the stashbag.\n");
+ logger(LL_ERROR, "An error occurred while creating the stashbag.\n");
}
return -1;
} else if (err == 1) {
@@ -1212,7 +1223,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
unsigned int nonce_size = 0;
if (get_ap_nonce(client, &nonce, &nonce_size) < 0) {
/* the first nonce request with older firmware releases can fail and it's OK */
- info("NOTE: Unable to get nonce from device\n");
+ logger(LL_NOTICE, "Unable to get nonce from device\n");
}
if (!client->nonce || (nonce_size != client->nonce_size) || (memcmp(nonce, client->nonce, nonce_size) != 0)) {
@@ -1224,6 +1235,27 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
} else {
free(nonce);
}
+ if (client->mode == MODE_NORMAL) {
+ plist_t ap_params = normal_get_lockdown_value(client, NULL, "ApParameters");
+ if (ap_params) {
+ if (!client->parameters) {
+ client->parameters = plist_new_dict();
+ }
+ plist_dict_merge(&client->parameters, ap_params);
+ plist_t p_sep_nonce = plist_dict_get_item(ap_params, "SepNonce");
+ uint64_t sep_nonce_size = 0;
+ const char* sep_nonce = plist_get_data_ptr(p_sep_nonce, &sep_nonce_size);
+ if (sep_nonce) {
+ logger(LL_INFO, "Getting SepNonce in normal mode... ");
+ logger_dump_hex(LL_INFO, sep_nonce, sep_nonce_size);
+ }
+ plist_free(ap_params);
+ }
+ plist_t req_nonce_slot = plist_access_path(build_identity, 2, "Info", "RequiresNonceSlot");
+ if (req_nonce_slot) {
+ plist_dict_set_item(client->parameters, "RequiresNonceSlot", plist_copy(req_nonce_slot));
+ }
+ }
}
if (client->flags & FLAG_QUIT) {
@@ -1233,42 +1265,56 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
if (client->mode == MODE_RESTORE && client->root_ticket) {
plist_t ap_ticket = plist_new_data((char*)client->root_ticket, client->root_ticket_len);
if (!ap_ticket) {
- error("ERROR: Failed to create ApImg4Ticket node value.\n");
+ logger(LL_ERROR, "Failed to create ApImg4Ticket node value.\n");
return -1;
}
client->tss = plist_new_dict();
if (!client->tss) {
- error("ERROR: Failed to create ApImg4Ticket node.\n");
+ logger(LL_ERROR, "Failed to create ApImg4Ticket node.\n");
return -1;
}
plist_dict_set_item(client->tss, "ApImg4Ticket", ap_ticket);
} else {
if (get_tss_response(client, build_identity, &client->tss) < 0) {
- error("ERROR: Unable to get SHSH blobs for this device\n");
+ logger(LL_ERROR, "Unable to get SHSH blobs for this device\n");
return -1;
}
if (client->macos_variant) {
if (get_local_policy_tss_response(client, build_identity, &client->tss_localpolicy) < 0) {
- error("ERROR: Unable to get SHSH blobs for this device (local policy)\n");
+ logger(LL_ERROR, "Unable to get SHSH blobs for this device (local policy)\n");
return -1;
}
if (get_recoveryos_root_ticket_tss_response(client, build_identity, &client->tss_recoveryos_root_ticket) < 0) {
- error("ERROR: Unable to get SHSH blobs for this device (recovery OS Root Ticket)\n");
+ logger(LL_ERROR, "Unable to get SHSH blobs for this device (recovery OS Root Ticket)\n");
return -1;
}
+ } else {
+ plist_t recovery_variant = plist_access_path(build_identity, 2, "Info", "RecoveryVariant");
+ if (recovery_variant) {
+ const char* recovery_variant_str = plist_get_string_ptr(recovery_variant, NULL);
+ client->recovery_variant = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, recovery_variant_str, 1);
+ if (!client->recovery_variant) {
+ logger(LL_ERROR, "Variant '%s' not found in BuildManifest\n", recovery_variant_str);
+ return -1;
+ }
+ if (get_tss_response(client, client->recovery_variant, &client->tss_recoveryos_root_ticket) < 0) {
+ logger(LL_ERROR, "Unable to get SHSH blobs for this device (%s)\n", recovery_variant_str);
+ return -1;
+ }
+ }
}
}
if (stashbag_commit_required) {
plist_t ticket = plist_dict_get_item(client->tss, "ApImg4Ticket");
if (!ticket || plist_get_node_type(ticket) != PLIST_DATA) {
- error("ERROR: Missing ApImg4Ticket in TSS response for stashbag commit\n");
+ logger(LL_ERROR, "Missing ApImg4Ticket in TSS response for stashbag commit\n");
return -1;
}
- info("Committing stashbag...\n");
+ logger(LL_INFO, "Committing stashbag...\n");
int err = normal_handle_commit_stashbag(client, ticket);
if (err < 0) {
- error("ERROR: Could not commit stashbag (%d). Aborting.\n", err);
+ logger(LL_ERROR, "Could not commit stashbag (%d). Aborting.\n", err);
return -1;
}
}
@@ -1279,11 +1325,11 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
}
if (client->flags & FLAG_SHSHONLY) {
if (!tss_enabled) {
- info("This device does not require a TSS record\n");
+ logger(LL_INFO, "This device does not require a TSS record\n");
return 0;
}
if (!client->tss) {
- error("ERROR: could not fetch TSS record\n");
+ logger(LL_ERROR, "could not fetch TSS record\n");
return -1;
} else {
char *bin = NULL;
@@ -1298,19 +1344,19 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
strcpy(zfn, "shsh");
}
mkdir_with_parents(zfn, 0755);
- sprintf(zfn+strlen(zfn), "/%" PRIu64 "-%s-%s.shsh", client->ecid, client->device->product_type, client->version);
+ snprintf(&zfn[0]+strlen(zfn), sizeof(zfn)-strlen(zfn), "/%" PRIu64 "-%s-%s.shsh", client->ecid, client->device->product_type, client->version);
struct stat fst;
if (stat(zfn, &fst) != 0) {
gzFile zf = gzopen(zfn, "wb");
gzwrite(zf, bin, blen);
gzclose(zf);
- info("SHSH saved to '%s'\n", zfn);
+ logger(LL_INFO, "SHSH saved to '%s'\n", zfn);
} else {
- info("SHSH '%s' already present.\n", zfn);
+ logger(LL_INFO, "SHSH '%s' already present.\n", zfn);
}
free(bin);
} else {
- error("ERROR: could not get TSS record data\n");
+ logger(LL_ERROR, "could not get TSS record data\n");
}
plist_free(client->tss);
return 0;
@@ -1319,7 +1365,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
/* verify if we have tss records if required */
if ((tss_enabled) && (client->tss == NULL)) {
- error("ERROR: Unable to proceed without a TSS record.\n");
+ logger(LL_ERROR, "Unable to proceed without a TSS record.\n");
return -1;
}
@@ -1334,9 +1380,9 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
// if the device is in normal mode, place device into recovery mode
if (client->mode == MODE_NORMAL) {
- info("Entering recovery mode...\n");
+ logger(LL_INFO, "Entering recovery mode...\n");
if (normal_enter_recovery(client) < 0) {
- error("ERROR: Unable to place device into recovery mode from normal mode\n");
+ logger(LL_ERROR, "Unable to place device into recovery mode from normal mode\n");
if (client->tss)
plist_free(client->tss);
return -5;
@@ -1352,22 +1398,24 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
// if the device is in DFU mode, place it into recovery mode
dfu_client_free(client);
recovery_client_free(client);
+#ifdef HAVE_LIMERA1N
if ((client->flags & FLAG_CUSTOM) && limera1n_is_supported(client->device)) {
- info("connecting to DFU\n");
+ logger(LL_INFO, "connecting to DFU\n");
if (dfu_client_new(client) < 0) {
return -1;
}
- info("exploiting with limera1n\n");
+ logger(LL_INFO, "exploiting with limera1n\n");
if (limera1n_exploit(client->device, &client->dfu->client) != 0) {
- error("ERROR: limera1n exploit failed\n");
+ logger(LL_ERROR, "limera1n exploit failed\n");
dfu_client_free(client);
return -1;
}
dfu_client_free(client);
- info("exploited\n");
+ logger(LL_INFO, "exploited\n");
}
+#endif
if (dfu_enter_recovery(client, build_identity) < 0) {
- error("ERROR: Unable to place device into recovery mode from DFU mode\n");
+ logger(LL_ERROR, "Unable to place device into recovery mode from DFU mode\n");
if (client->tss)
plist_free(client->tss);
return -2;
@@ -1378,7 +1426,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
if (!client->image4supported) {
/* send ApTicket */
if (recovery_send_ticket(client) < 0) {
- error("ERROR: Unable to send APTicket\n");
+ logger(LL_ERROR, "Unable to send APTicket\n");
return -2;
}
}
@@ -1389,27 +1437,28 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
/* now we load the iBEC */
if (recovery_send_ibec(client, build_identity) < 0) {
mutex_unlock(&client->device_event_mutex);
- error("ERROR: Unable to send iBEC\n");
+ logger(LL_ERROR, "Unable to send iBEC\n");
return -2;
}
recovery_client_free(client);
- debug("Waiting for device to disconnect...\n");
+ logger(LL_DEBUG, "Waiting for device to disconnect...\n");
cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 60000);
if (client->mode != MODE_UNKNOWN || (client->flags & FLAG_QUIT)) {
mutex_unlock(&client->device_event_mutex);
if (!(client->flags & FLAG_QUIT)) {
- error("ERROR: Device did not disconnect. Possibly invalid iBEC. Reset device and try again.\n");
+ logger(LL_ERROR, "Device did not disconnect. Possibly invalid iBEC. Reset device and try again.\n");
}
return -2;
}
- debug("Waiting for device to reconnect in recovery mode...\n");
+ recovery_client_free(client);
+ logger(LL_DEBUG, "Waiting for device to reconnect in recovery mode...\n");
cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 60000);
if (client->mode != MODE_RECOVERY || (client->flags & FLAG_QUIT)) {
mutex_unlock(&client->device_event_mutex);
if (!(client->flags & FLAG_QUIT)) {
- error("ERROR: Device did not reconnect in recovery mode. Possibly invalid iBEC. Reset device and try again.\n");
+ logger(LL_ERROR, "Device did not reconnect in recovery mode. Possibly invalid iBEC. Reset device and try again.\n");
}
return -2;
}
@@ -1426,7 +1475,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
unsigned int nonce_size = 0;
int nonce_changed = 0;
if (get_ap_nonce(client, &nonce, &nonce_size) < 0) {
- error("ERROR: Unable to get nonce from device!\n");
+ logger(LL_ERROR, "Unable to get nonce from device!\n");
recovery_send_reset(client);
return -2;
}
@@ -1446,11 +1495,11 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
// Welcome iOS5. We have to re-request the TSS with our nonce.
plist_free(client->tss);
if (get_tss_response(client, build_identity, &client->tss) < 0) {
- error("ERROR: Unable to get SHSH blobs for this device\n");
+ logger(LL_ERROR, "Unable to get SHSH blobs for this device\n");
return -1;
}
if (!client->tss) {
- error("ERROR: can't continue without TSS\n");
+ logger(LL_ERROR, "can't continue without TSS\n");
return -1;
}
fixup_tss(client->tss);
@@ -1464,7 +1513,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
// now finally do the magic to put the device into restore mode
if (client->mode == MODE_RECOVERY) {
if (recovery_enter_restore(client, build_identity) < 0) {
- error("ERROR: Unable to place device into restore mode\n");
+ logger(LL_ERROR, "Unable to place device into restore mode\n");
if (client->tss)
plist_free(client->tss);
return -2;
@@ -1475,12 +1524,16 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
if (client->mode != MODE_RESTORE) {
mutex_lock(&client->device_event_mutex);
- info("Waiting for device to enter restore mode...\n");
- cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 180000);
+ logger(LL_INFO, "Waiting for device to enter restore mode...\n");
+ cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 300000);
if (client->mode != MODE_RESTORE || (client->flags & FLAG_QUIT)) {
mutex_unlock(&client->device_event_mutex);
- error("ERROR: Device failed to enter restore mode.\n");
- error("Please make sure that usbmuxd is running.\n");
+ logger(LL_ERROR, "Device failed to enter restore mode.\n");
+ if (client->mode == MODE_UNKNOWN) {
+ logger(LL_ERROR, "Make sure that usbmuxd is running.\n");
+ } else if (client->mode == MODE_RECOVERY || client->mode == MODE_DFU) {
+ logger(LL_ERROR, "Device reconnected in %s mode, most likely image personalization failed.\n", client->mode->string);
+ }
return -1;
}
mutex_unlock(&client->device_event_mutex);
@@ -1489,14 +1542,14 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
// device is finally in restore mode, let's do this
if (client->mode == MODE_RESTORE) {
if ((client->flags & FLAG_NO_RESTORE) != 0) {
- info("Device is now in restore mode. Exiting as requested.\n");
+ logger(LL_INFO, "Device is now in restore mode. Exiting as requested.\n");
return 0;
}
client->ignore_device_add_events = 1;
- info("About to restore device... \n");
+ logger(LL_INFO, "About to restore device... \n");
result = restore_device(client, build_identity);
if (result < 0) {
- error("ERROR: Unable to restore device\n");
+ logger(LL_ERROR, "Unable to restore device\n");
return result;
}
}
@@ -1507,18 +1560,18 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
if (recovery_set_autoboot(client, 1) == 0) {
recovery_send_reset(client);
} else {
- error("Setting auto-boot failed?!\n");
+ logger(LL_ERROR, "Setting auto-boot failed?!\n");
}
} else {
- error("Could not connect to device in recovery mode.\n");
+ logger(LL_ERROR, "Could not connect to device in recovery mode.\n");
}
}
if (result == 0) {
- info("DONE\n");
+ logger(LL_INFO, "DONE\n");
idevicerestore_progress(client, RESTORE_NUM_STEPS-1, 1.0);
} else {
- info("RESTORE FAILED\n");
+ logger(LL_INFO, "RESTORE FAILED\n");
}
if (build_identity_needs_free)
@@ -1531,7 +1584,7 @@ struct idevicerestore_client_t* idevicerestore_client_new(void)
{
struct idevicerestore_client_t* client = (struct idevicerestore_client_t*) malloc(sizeof(struct idevicerestore_client_t));
if (client == NULL) {
- error("ERROR: Out of memory\n");
+ logger(LL_ERROR, "Out of memory\n");
return NULL;
}
memset(client, '\0', sizeof(struct idevicerestore_client_t));
@@ -1596,6 +1649,9 @@ void idevicerestore_client_free(struct idevicerestore_client_t* client)
if (client->build_manifest) {
plist_free(client->build_manifest);
}
+ if (client->firmware_preflight_info) {
+ plist_free(client->firmware_preflight_info);
+ }
if (client->preflight_info) {
plist_free(client->preflight_info);
}
@@ -1671,6 +1727,7 @@ static void handle_signal(int sig)
{
if (idevicerestore_client) {
idevicerestore_client->flags |= FLAG_QUIT;
+ global_quit_flag++;
ipsw_cancel();
}
}
@@ -1681,16 +1738,51 @@ void plain_progress_cb(int step, double step_progress, void* userdata)
fflush(stdout);
}
-int main(int argc, char* argv[]) {
+static void plain_progress_func(struct progress_info_entry** progress_info, int count)
+{
+ int i = 0;
+ for (i = 0; i < count; i++) {
+ if (!progress_info[i]) continue;
+ printf("%s: %5.1f\n", progress_info[i]->label, progress_info[i]->progress);
+ fflush(stdout);
+ }
+}
+
+static void tty_print(enum loglevel level, const char* fmt, va_list ap)
+{
+ switch (level) {
+ case 0:
+ cprintf(FG_RED STYLE_BRIGHT);
+ break;
+ case 1:
+ cprintf(FG_YELLOW STYLE_BRIGHT);
+ break;
+ case 2:
+ cprintf(STYLE_BRIGHT);
+ break;
+ default:
+ break;
+ }
+
+ cvfprintf(stdout, fmt, ap);
+
+ cprintf(COLOR_RESET);
+}
+
+int main(int argc, char* argv[])
+{
int opt = 0;
int optindex = 0;
char* ipsw = NULL;
int ipsw_info = 0;
int result = 0;
+ const char* logfile = NULL;
+
+ logger_set_print_func(tty_print);
struct idevicerestore_client_t* client = idevicerestore_client_new();
if (client == NULL) {
- error("ERROR: could not create idevicerestore client\n");
+ logger(LL_ERROR, "Could not create idevicerestore client\n");
return EXIT_FAILURE;
}
@@ -1717,7 +1809,13 @@ int main(int argc, char* argv[]) {
client->flags |= FLAG_INTERACTIVE;
}
- while ((opt = getopt_long(argc, argv, "dhces:xtpli:u:nC:kyPRT:zv", longopts, &optindex)) > 0) {
+#ifdef HAVE_LIMERA1N
+#define P_FLAG "p"
+#else
+#define P_FLAG ""
+#endif
+
+ while ((opt = getopt_long(argc, argv, "dhces:xtli:u:nC:kyPRT:zv" P_FLAG, longopts, &optindex)) > 0) {
switch (opt) {
case 'h':
usage(argc, argv, 0);
@@ -1726,6 +1824,9 @@ int main(int argc, char* argv[]) {
case 'd':
client->flags |= FLAG_DEBUG;
client->debug_level++;
+ if (client->debug_level > 0) {
+ log_level = LL_DEBUG;
+ }
break;
case 'e':
@@ -1738,7 +1839,7 @@ int main(int argc, char* argv[]) {
case 's': {
if (!*optarg) {
- error("ERROR: URL argument for --server must not be empty!\n");
+ logger(LL_ERROR, "URL argument for --server must not be empty!\n");
usage(argc, argv, 1);
return EXIT_FAILURE;
}
@@ -1753,14 +1854,15 @@ int main(int argc, char* argv[]) {
if (!p || *(p+1) == '\0') {
// no path component, add default path
const char default_path[] = "/TSS/controller?action=2";
- char* newurl = malloc(strlen(optarg)+sizeof(default_path));
- sprintf(newurl, "%s%s", optarg, (p) ? default_path+1 : default_path);
+ size_t usize = strlen(optarg)+sizeof(default_path);
+ char* newurl = malloc(usize);
+ snprintf(newurl, usize, "%s%s", optarg, (p) ? default_path+1 : default_path);
client->tss_url = newurl;
} else {
client->tss_url = strdup(optarg);
}
} else {
- error("ERROR: URL argument for --server is invalid, must start with http:// or https://\n");
+ logger(LL_ERROR, "URL argument for --server is invalid, must start with http:// or https://\n");
usage(argc, argv, 1);
return EXIT_FAILURE;
}
@@ -1783,7 +1885,7 @@ int main(int argc, char* argv[]) {
client->ecid = 0;
}
if (client->ecid == 0) {
- error("ERROR: Could not parse ECID from '%s'\n", optarg);
+ logger(LL_ERROR, "Could not parse ECID from '%s'\n", optarg);
return EXIT_FAILURE;
}
}
@@ -1791,7 +1893,7 @@ int main(int argc, char* argv[]) {
case 'u':
if (!*optarg) {
- error("ERROR: UDID must not be empty!\n");
+ logger(LL_ERROR, "UDID must not be empty!\n");
usage(argc, argv, 1);
return EXIT_FAILURE;
}
@@ -1803,12 +1905,14 @@ int main(int argc, char* argv[]) {
break;
case 'k':
- idevicerestore_keep_pers = 1;
+ client->flags |= FLAG_KEEP_PERS;
break;
+#ifdef HAVE_LIMERA1N
case 'p':
client->flags |= FLAG_PWN;
break;
+#endif
case 'n':
client->flags |= FLAG_NOACTION;
@@ -1824,6 +1928,8 @@ int main(int argc, char* argv[]) {
case 'P':
idevicerestore_set_progress_callback(client, plain_progress_cb, NULL);
+ set_update_progress_func(plain_progress_func);
+ set_progress_granularity(0.01); // 1% granularity
break;
case 'R':
@@ -1835,7 +1941,7 @@ int main(int argc, char* argv[]) {
break;
case 'v':
- info("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
+ printf("%s %s (libirecovery %s, libtatsu %s)\n", PACKAGE_NAME, PACKAGE_VERSION, irecv_version(), libtatsu_version());
return EXIT_SUCCESS;
case 'T': {
@@ -1846,7 +1952,7 @@ int main(int argc, char* argv[]) {
}
client->root_ticket = root_ticket;
client->root_ticket_len = (int)root_ticket_len;
- info("Using ApTicket found at %s length %u\n", optarg, client->root_ticket_len);
+ logger(LL_INFO, "Using ApTicket found at %s length %u\n", optarg, client->root_ticket_len);
break;
}
@@ -1863,6 +1969,15 @@ int main(int argc, char* argv[]) {
client->restore_variant = strdup(optarg);
break;
+ case 3:
+ if (!*optarg) {
+ logger(LL_ERROR, "logfile must not be empty!\n");
+ usage(argc, argv, 1);
+ return EXIT_FAILURE;
+ }
+ logfile = optarg;
+ break;
+
default:
usage(argc, argv, 1);
return EXIT_FAILURE;
@@ -1871,7 +1986,7 @@ int main(int argc, char* argv[]) {
if (ipsw_info) {
if (argc-optind != 1) {
- error("ERROR: --ipsw-info requires an IPSW path.\n");
+ logger(LL_ERROR, "--ipsw-info requires an IPSW path.\n");
usage(argc, argv, 1);
return EXIT_FAILURE;
}
@@ -1889,24 +2004,41 @@ int main(int argc, char* argv[]) {
}
if ((client->flags & FLAG_LATEST) && (client->flags & FLAG_CUSTOM)) {
- error("ERROR: You can't use --custom and --latest options at the same time.\n");
+ logger(LL_ERROR, "You can't use --custom and --latest options at the same time.\n");
return EXIT_FAILURE;
}
- info("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
+ if (!logfile) {
+ char logfn[256];
+ int64_t timestamp = time(NULL);
+ if (client->ecid) {
+ snprintf(logfn, sizeof(logfn), "restore_%016" PRIx64 "_%" PRIi64 ".log", client->ecid, timestamp);
+ } else if (client->udid) {
+ snprintf(logfn, sizeof(logfn), "restore_%s_%" PRIi64 ".log", client->udid, timestamp);
+ } else {
+ snprintf(logfn, sizeof(logfn), "restore_%" PRIi64 ".log", timestamp);
+ }
+ logger_set_logfile(logfn);
+ } else {
+ logger_set_logfile(logfile);
+ }
+
+ logger(LL_INFO, "%s %s (libirecovery %s, libtatsu %s)\n", PACKAGE_NAME, PACKAGE_VERSION, irecv_version(), libtatsu_version());
if (ipsw) {
// verify if ipsw file exists
client->ipsw = ipsw_open(ipsw);
if (!client->ipsw) {
- error("ERROR: Firmware file %s cannot be opened.\n", ipsw);
+ logger(LL_ERROR, "Firmware file %s cannot be opened.\n", ipsw);
return -1;
}
}
curl_global_init(CURL_GLOBAL_ALL);
+ client->flags |= FLAG_IN_PROGRESS;
result = idevicerestore_start(client);
+ client->flags &= ~FLAG_IN_PROGRESS;
idevicerestore_client_free(client);
@@ -1964,7 +2096,7 @@ int is_image4_supported(struct idevicerestore_client_t* client)
res = recovery_is_image4_supported(client);
break;
default:
- error("ERROR: Device is in an invalid state\n");
+ logger(LL_ERROR, "Device is in an invalid state\n");
return 0;
}
return res;
@@ -1977,46 +2109,40 @@ int get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce,
*nonce = NULL;
*nonce_size = 0;
- info("Getting ApNonce ");
-
if (client->mode) {
mode = client->mode->index;
}
switch (mode) {
case _MODE_NORMAL:
- info("in normal mode... ");
+ logger(LL_INFO, "Getting ApNonce in Normal mode... ");
if (normal_get_ap_nonce(client, nonce, nonce_size) < 0) {
- info("failed\n");
+ logger(LL_INFO, "failed\n");
return -1;
}
break;
case _MODE_DFU:
- info("in dfu mode... ");
+ logger(LL_INFO, "Getting ApNonce in DFU mode... ");
if (dfu_get_ap_nonce(client, nonce, nonce_size) < 0) {
- info("failed\n");
+ logger(LL_INFO, "failed\n");
return -1;
}
break;
case _MODE_RECOVERY:
- info("in recovery mode... ");
+ logger(LL_INFO, "Getting ApNonce in Recovery mode... ");
if (recovery_get_ap_nonce(client, nonce, nonce_size) < 0) {
- info("failed\n");
+ logger(LL_INFO, "failed\n");
return -1;
}
break;
default:
- info("failed\n");
- error("ERROR: Device is in an invalid state\n");
+ logger(LL_INFO, "Getting ApNonce failed\n");
+ logger(LL_ERROR, "Device is in an invalid state\n");
return -1;
}
- int i = 0;
- for (i = 0; i < *nonce_size; i++) {
- info("%02x ", (*nonce)[i]);
- }
- info("\n");
+ logger_dump_hex(LL_INFO, *nonce, *nonce_size);
return 0;
}
@@ -2028,46 +2154,40 @@ int get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce,
*nonce = NULL;
*nonce_size = 0;
- info("Getting SepNonce ");
-
if (client->mode) {
mode = client->mode->index;
}
switch (mode) {
case _MODE_NORMAL:
- info("in normal mode... ");
+ logger(LL_INFO, "Getting SepNonce in normal mode... ");
if (normal_get_sep_nonce(client, nonce, nonce_size) < 0) {
- info("failed\n");
+ logger(LL_INFO, "failed\n");
return -1;
}
break;
case _MODE_DFU:
- info("in dfu mode... ");
+ logger(LL_INFO, "Getting SepNonce in dfu mode... ");
if (dfu_get_sep_nonce(client, nonce, nonce_size) < 0) {
- info("failed\n");
+ logger(LL_INFO, "failed\n");
return -1;
}
break;
case _MODE_RECOVERY:
- info("in recovery mode... ");
+ logger(LL_INFO, "Getting SepNonce in recovery mode... ");
if (recovery_get_sep_nonce(client, nonce, nonce_size) < 0) {
- info("failed\n");
+ logger(LL_INFO, "failed\n");
return -1;
}
break;
default:
- info("failed\n");
- error("ERROR: Device is in an invalid state\n");
+ logger(LL_INFO, "Getting SepNonce failed\n");
+ logger(LL_ERROR, "Device is in an invalid state\n");
return -1;
}
- int i = 0;
- for (i = 0; i < *nonce_size; i++) {
- info("%02x ", (*nonce)[i]);
- }
- info("\n");
+ logger_dump_hex(LL_INFO, *nonce, *nonce_size);
return 0;
}
@@ -2076,7 +2196,7 @@ plist_t build_manifest_get_build_identity_for_model_with_variant(plist_t build_m
{
plist_t build_identities_array = plist_dict_get_item(build_manifest, "BuildIdentities");
if (!build_identities_array || plist_get_node_type(build_identities_array) != PLIST_ARRAY) {
- error("ERROR: Unable to find build identities node\n");
+ logger(LL_ERROR, "Unable to find build identities node\n");
return NULL;
}
@@ -2152,14 +2272,14 @@ int get_preboard_manifest(struct idevicerestore_client_t* client, plist_t build_
/* create basic request */
request = tss_request_new(NULL);
if (request == NULL) {
- error("ERROR: Unable to create TSS request\n");
+ logger(LL_ERROR, "Unable to create TSS request\n");
plist_free(parameters);
return -1;
}
/* add common tags from manifest */
if (tss_request_add_common_tags(request, parameters, overrides) < 0) {
- error("ERROR: Unable to add common tags\n");
+ logger(LL_ERROR, "Unable to add common tags\n");
plist_free(request);
plist_free(parameters);
return -1;
@@ -2169,7 +2289,7 @@ int get_preboard_manifest(struct idevicerestore_client_t* client, plist_t build_
/* add tags from manifest */
if (tss_request_add_ap_tags(request, parameters, NULL) < 0) {
- error("ERROR: Unable to add ap tags\n");
+ logger(LL_ERROR, "Unable to add ap tags\n");
plist_free(request);
plist_free(parameters);
return -1;
@@ -2194,15 +2314,15 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident
*tss = NULL;
if ((client->build_major <= 8) || (client->flags & FLAG_CUSTOM)) {
- error("checking for local shsh\n");
+ logger(LL_ERROR, "checking for local shsh\n");
/* first check for local copy */
char zfn[1024];
if (client->version) {
if (client->cache_dir) {
- sprintf(zfn, "%s/shsh/%" PRIu64 "-%s-%s.shsh", client->cache_dir, client->ecid, client->device->product_type, client->version);
+ snprintf(zfn, sizeof(zfn), "%s/shsh/%" PRIu64 "-%s-%s.shsh", client->cache_dir, client->ecid, client->device->product_type, client->version);
} else {
- sprintf(zfn, "shsh/%" PRIu64 "-%s-%s.shsh", client->ecid, client->device->product_type, client->version);
+ snprintf(zfn, sizeof(zfn), "shsh/%" PRIu64 "-%s-%s.shsh", client->ecid, client->device->product_type, client->version);
}
struct stat fst;
if (stat(zfn, &fst) == 0) {
@@ -2216,7 +2336,7 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident
do {
int bytes_read = gzread(zf, p, readsize);
if (bytes_read < 0) {
- fprintf(stderr, "Error reading gz compressed data\n");
+ logger(LL_ERROR, "Error reading gz compressed data\n");
exit(EXIT_FAILURE);
}
blen += bytes_read;
@@ -2241,33 +2361,37 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident
free(bin);
}
} else {
- error("no local file %s\n", zfn);
+ logger(LL_ERROR, "no local file %s\n", zfn);
}
} else {
- error("No version found?!\n");
+ logger(LL_ERROR, "No version found?!\n");
}
}
if (*tss) {
- info("Using cached SHSH\n");
+ logger(LL_INFO, "Using cached SHSH\n");
return 0;
} else {
- info("Trying to fetch new SHSH blob\n");
+ logger(LL_INFO, "Trying to fetch new SHSH blob\n");
}
/* populate parameters */
plist_t parameters = plist_new_dict();
+ plist_dict_merge(&parameters, client->parameters);
+
plist_dict_set_item(parameters, "ApECID", plist_new_uint(client->ecid));
if (client->nonce) {
plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size));
}
- unsigned char* sep_nonce = NULL;
- unsigned int sep_nonce_size = 0;
- get_sep_nonce(client, &sep_nonce, &sep_nonce_size);
- if (sep_nonce) {
- plist_dict_set_item(parameters, "ApSepNonce", plist_new_data((const char*)sep_nonce, sep_nonce_size));
- free(sep_nonce);
+ if (!plist_dict_get_item(parameters, "SepNonce")) {
+ unsigned char* sep_nonce = NULL;
+ unsigned int sep_nonce_size = 0;
+ get_sep_nonce(client, &sep_nonce, &sep_nonce_size);
+ if (sep_nonce) {
+ plist_dict_set_item(parameters, "ApSepNonce", plist_new_data((const char*)sep_nonce, sep_nonce_size));
+ free(sep_nonce);
+ }
}
plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1));
@@ -2283,14 +2407,14 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident
/* create basic request */
request = tss_request_new(NULL);
if (request == NULL) {
- error("ERROR: Unable to create TSS request\n");
+ logger(LL_ERROR, "Unable to create TSS request\n");
plist_free(parameters);
return -1;
}
/* add common tags from manifest */
if (tss_request_add_common_tags(request, parameters, NULL) < 0) {
- error("ERROR: Unable to add common tags to TSS request\n");
+ logger(LL_ERROR, "Unable to add common tags to TSS request\n");
plist_free(request);
plist_free(parameters);
return -1;
@@ -2298,7 +2422,7 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident
/* add tags from manifest */
if (tss_request_add_ap_tags(request, parameters, NULL) < 0) {
- error("ERROR: Unable to add common tags to TSS request\n");
+ logger(LL_ERROR, "Unable to add common tags to TSS request\n");
plist_free(request);
plist_free(parameters);
return -1;
@@ -2307,7 +2431,7 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident
if (client->image4supported) {
/* add personalized parameters */
if (tss_request_add_ap_img4_tags(request, parameters) < 0) {
- error("ERROR: Unable to add img4 tags to TSS request\n");
+ logger(LL_ERROR, "Unable to add img4 tags to TSS request\n");
plist_free(request);
plist_free(parameters);
return -1;
@@ -2315,7 +2439,7 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident
} else {
/* add personalized parameters */
if (tss_request_add_ap_img3_tags(request, parameters) < 0) {
- error("ERROR: Unable to add img3 tags to TSS request\n");
+ logger(LL_ERROR, "Unable to add img3 tags to TSS request\n");
plist_free(request);
plist_free(parameters);
return -1;
@@ -2325,40 +2449,46 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident
if (client->mode == MODE_NORMAL) {
/* normal mode; request baseband ticket aswell */
plist_t pinfo = NULL;
- normal_get_preflight_info(client, &pinfo);
+ normal_get_firmware_preflight_info(client, &pinfo);
if (pinfo) {
plist_dict_copy_data(parameters, pinfo, "BbNonce", "Nonce");
plist_dict_copy_uint(parameters, pinfo, "BbChipID", "ChipID");
plist_dict_copy_uint(parameters, pinfo, "BbGoldCertId", "CertID");
plist_dict_copy_data(parameters, pinfo, "BbSNUM", "ChipSerialNo");
- /* add baseband parameters */
- tss_request_add_baseband_tags(request, parameters, NULL);
+ if (plist_dict_get_item(parameters, "BbSNUM")) {
+ /* add baseband parameters */
+ tss_request_add_baseband_tags(request, parameters, NULL);
- plist_dict_copy_uint(parameters, pinfo, "eUICC,ChipID", "EUICCChipID");
- if (plist_dict_get_uint(parameters, "eUICC,ChipID") >= 5) {
- plist_dict_copy_data(parameters, pinfo, "eUICC,EID", "EUICCCSN");
- plist_dict_copy_data(parameters, pinfo, "eUICC,RootKeyIdentifier", "EUICCCertIdentifier");
- plist_dict_copy_data(parameters, pinfo, "EUICCGoldNonce", NULL);
- plist_dict_copy_data(parameters, pinfo, "EUICCMainNonce", NULL);
+ plist_dict_copy_uint(parameters, pinfo, "eUICC,ChipID", "EUICCChipID");
+ if (plist_dict_get_uint(parameters, "eUICC,ChipID") >= 5) {
+ plist_dict_copy_data(parameters, pinfo, "eUICC,EID", "EUICCCSN");
+ plist_dict_copy_data(parameters, pinfo, "eUICC,RootKeyIdentifier", "EUICCCertIdentifier");
+ plist_dict_copy_data(parameters, pinfo, "EUICCGoldNonce", NULL);
+ plist_dict_copy_data(parameters, pinfo, "EUICCMainNonce", NULL);
- /* add vinyl parameters */
- tss_request_add_vinyl_tags(request, parameters, NULL);
+ /* add vinyl parameters */
+ tss_request_add_vinyl_tags(request, parameters, NULL);
+ }
}
}
+ client->firmware_preflight_info = pinfo;
+ pinfo = NULL;
+
+ normal_get_preflight_info(client, &pinfo);
client->preflight_info = pinfo;
}
/* send request and grab response */
response = tss_request_send(request, client->tss_url);
if (response == NULL) {
- info("ERROR: Unable to send TSS request\n");
+ logger(LL_INFO, "ERROR: Unable to send TSS request\n");
plist_free(request);
plist_free(parameters);
return -1;
}
- info("Received SHSH blobs\n");
+ logger(LL_INFO, "Received SHSH blobs\n");
plist_free(request);
plist_free(parameters);
@@ -2412,7 +2542,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie
/* Adds @HostPlatformInfo, @VersionInfo, @UUID */
request = tss_request_new(NULL);
if (request == NULL) {
- error("ERROR: Unable to create TSS request\n");
+ logger(LL_ERROR, "Unable to create TSS request\n");
plist_free(parameters);
return -1;
}
@@ -2420,7 +2550,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie
/* add common tags from manifest */
/* Adds Ap,OSLongVersion, ApNonce, @ApImg4Ticket */
if (tss_request_add_ap_img4_tags(request, parameters) < 0) {
- error("ERROR: Unable to add AP IMG4 tags to TSS request\n");
+ logger(LL_ERROR, "Unable to add AP IMG4 tags to TSS request\n");
plist_free(request);
plist_free(parameters);
return -1;
@@ -2428,7 +2558,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie
/* add AP tags from manifest */
if (tss_request_add_common_tags(request, parameters, NULL) < 0) {
- error("ERROR: Unable to add common tags to TSS request\n");
+ logger(LL_ERROR, "Unable to add common tags to TSS request\n");
plist_free(request);
plist_free(parameters);
return -1;
@@ -2437,7 +2567,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie
/* add AP tags from manifest */
/* Fills digests & co */
if (tss_request_add_ap_recovery_tags(request, parameters, NULL) < 0) {
- error("ERROR: Unable to add common tags to TSS request\n");
+ logger(LL_ERROR, "Unable to add common tags to TSS request\n");
plist_free(request);
plist_free(parameters);
return -1;
@@ -2446,14 +2576,14 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie
/* send request and grab response */
response = tss_request_send(request, client->tss_url);
if (response == NULL) {
- info("ERROR: Unable to send TSS request\n");
+ logger(LL_INFO, "ERROR: Unable to send TSS request\n");
plist_free(request);
plist_free(parameters);
return -1;
}
// request_add_ap_tags
- info("Received SHSH blobs\n");
+ logger(LL_INFO, "Received SHSH blobs\n");
plist_free(request);
plist_free(parameters);
@@ -2505,7 +2635,7 @@ int get_recovery_os_local_policy_tss_response(
unsigned int vuuid[16];
unsigned char vol_uuid[16];
if (sscanf(vol_uuid_str, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", &vuuid[0], &vuuid[1], &vuuid[2], &vuuid[3], &vuuid[4], &vuuid[5], &vuuid[6], &vuuid[7], &vuuid[8], &vuuid[9], &vuuid[10], &vuuid[11], &vuuid[12], &vuuid[13], &vuuid[14], &vuuid[15]) != 16) {
- error("ERROR: Failed to parse Ap,VolumeUUID (%s)\n", vol_uuid_str);
+ logger(LL_ERROR, "Failed to parse Ap,VolumeUUID (%s)\n", vol_uuid_str);
free(vol_uuid_str);
return -1;
}
@@ -2519,14 +2649,14 @@ int get_recovery_os_local_policy_tss_response(
/* create basic request */
request = tss_request_new(NULL);
if (request == NULL) {
- error("ERROR: Unable to create TSS request\n");
+ logger(LL_ERROR, "Unable to create TSS request\n");
plist_free(parameters);
return -1;
}
/* add common tags from manifest */
if (tss_request_add_local_policy_tags(request, parameters) < 0) {
- error("ERROR: Unable to add common tags to TSS request\n");
+ logger(LL_ERROR, "Unable to add common tags to TSS request\n");
plist_free(request);
plist_free(parameters);
return -1;
@@ -2535,13 +2665,13 @@ int get_recovery_os_local_policy_tss_response(
/* send request and grab response */
response = tss_request_send(request, client->tss_url);
if (response == NULL) {
- info("ERROR: Unable to send TSS request\n");
+ logger(LL_INFO, "ERROR: Unable to send TSS request\n");
plist_free(request);
plist_free(parameters);
return -1;
}
- info("Received SHSH blobs\n");
+ logger(LL_INFO, "Received SHSH blobs\n");
plist_free(request);
plist_free(parameters);
@@ -2604,14 +2734,14 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_
/* create basic request */
request = tss_request_new(NULL);
if (request == NULL) {
- error("ERROR: Unable to create TSS request\n");
+ logger(LL_ERROR, "Unable to create TSS request\n");
plist_free(parameters);
return -1;
}
/* add common tags from manifest */
if (tss_request_add_local_policy_tags(request, parameters) < 0) {
- error("ERROR: Unable to add common tags to TSS request\n");
+ logger(LL_ERROR, "Unable to add common tags to TSS request\n");
plist_free(request);
plist_free(parameters);
return -1;
@@ -2620,13 +2750,13 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_
/* send request and grab response */
response = tss_request_send(request, client->tss_url);
if (response == NULL) {
- info("ERROR: Unable to send TSS request\n");
+ logger(LL_INFO, "ERROR: Unable to send TSS request\n");
plist_free(request);
plist_free(parameters);
return -1;
}
- info("Received SHSH blobs\n");
+ logger(LL_INFO, "Received SHSH blobs\n");
plist_free(request);
plist_free(parameters);
@@ -2671,13 +2801,13 @@ int build_manifest_get_identity_count(plist_t build_manifest)
// fetch build identities array from BuildManifest
plist_t build_identities_array = plist_dict_get_item(build_manifest, "BuildIdentities");
if (!build_identities_array || plist_get_node_type(build_identities_array) != PLIST_ARRAY) {
- error("ERROR: Unable to find build identities node\n");
+ logger(LL_ERROR, "Unable to find build identities node\n");
return -1;
}
return plist_array_get_size(build_identities_array);
}
-int extract_component(ipsw_archive_t ipsw, const char* path, unsigned char** component_data, unsigned int* component_size)
+int extract_component(ipsw_archive_t ipsw, const char* path, void** component_data, size_t* component_size)
{
char* component_name = NULL;
if (!ipsw || !path || !component_data || !component_size) {
@@ -2690,39 +2820,38 @@ int extract_component(ipsw_archive_t ipsw, const char* path, unsigned char** com
else
component_name = (char*) path;
- info("Extracting %s (%s)...\n", component_name, path);
+ logger(LL_INFO, "Extracting %s (%s)...\n", component_name, path);
if (ipsw_extract_to_memory(ipsw, path, component_data, component_size) < 0) {
- error("ERROR: Unable to extract %s from %s\n", component_name, ipsw->path);
+ logger(LL_ERROR, "Unable to extract %s from %s\n", component_name, ipsw->path);
return -1;
}
return 0;
}
-int personalize_component(const char *component_name, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** personalized_component, unsigned int* personalized_component_size)
+int personalize_component(struct idevicerestore_client_t* client, const char *component_name, const void* component_data, size_t component_size, plist_t tss_response, void** personalized_component, size_t* personalized_component_size)
{
- unsigned char* component_blob = NULL;
- unsigned int component_blob_size = 0;
- unsigned char* stitched_component = NULL;
- unsigned int stitched_component_size = 0;
+ void* component_blob = NULL;
+ void* stitched_component = NULL;
+ size_t stitched_component_size = 0;
if (tss_response && plist_dict_get_item(tss_response, "ApImg4Ticket")) {
/* stitch ApImg4Ticket into IMG4 file */
- img4_stitch_component(component_name, component_data, component_size, tss_response, &stitched_component, &stitched_component_size);
+ img4_stitch_component(component_name, component_data, component_size, client->parameters, tss_response, &stitched_component, &stitched_component_size);
} else {
/* try to get blob for current component from tss response */
- if (tss_response && tss_response_get_blob_by_entry(tss_response, component_name, &component_blob) < 0) {
- debug("NOTE: No SHSH blob found for component %s\n", component_name);
+ if (tss_response && tss_response_get_blob_by_entry(tss_response, component_name, (unsigned char**)&component_blob) < 0) {
+ logger(LL_DEBUG, "NOTE: No SHSH blob found for component %s\n", component_name);
}
if (component_blob != NULL) {
if (img3_stitch_component(component_name, component_data, component_size, component_blob, 64, &stitched_component, &stitched_component_size) < 0) {
- error("ERROR: Unable to replace %s IMG3 signature\n", component_name);
+ logger(LL_ERROR, "Unable to replace %s IMG3 signature\n", component_name);
free(component_blob);
return -1;
}
} else {
- info("Not personalizing component %s...\n", component_name);
+ logger(LL_INFO, "Not personalizing component %s...\n", component_name);
stitched_component = (unsigned char*)malloc(component_size);
if (stitched_component) {
stitched_component_size = component_size;
@@ -2732,7 +2861,7 @@ int personalize_component(const char *component_name, const unsigned char* compo
}
free(component_blob);
- if (idevicerestore_keep_pers) {
+ if (client->flags & FLAG_KEEP_PERS) {
write_file(component_name, stitched_component, stitched_component_size);
}
@@ -2746,9 +2875,9 @@ int build_manifest_check_compatibility(plist_t build_manifest, const char* produ
int res = -1;
plist_t node = plist_dict_get_item(build_manifest, "SupportedProductTypes");
if (!node || (plist_get_node_type(node) != PLIST_ARRAY)) {
- debug("%s: ERROR: SupportedProductTypes key missing\n", __func__);
- debug("%s: WARNING: If attempting to install iPhoneOS 2.x, be advised that Restore.plist does not contain the", __func__);
- debug("%s: WARNING: key 'SupportedProductTypes'. Recommendation is to manually add it to the Restore.plist.", __func__);
+ logger(LL_DEBUG, "%s: ERROR: SupportedProductTypes key missing\n", __func__);
+ logger(LL_DEBUG, "%s: WARNING: If attempting to install iPhoneOS 2.x, be advised that Restore.plist does not contain the\n", __func__);
+ logger(LL_DEBUG, "%s: WARNING: key 'SupportedProductTypes'. Recommendation is to manually add it to the Restore.plist.\n", __func__);
return -1;
}
uint32_t pc = plist_array_get_size(node);
@@ -2776,14 +2905,14 @@ void build_manifest_get_version_information(plist_t build_manifest, struct idevi
node = plist_dict_get_item(build_manifest, "ProductVersion");
if (!node || plist_get_node_type(node) != PLIST_STRING) {
- error("ERROR: Unable to find ProductVersion node\n");
+ logger(LL_ERROR, "Unable to find ProductVersion node\n");
return;
}
plist_get_string_val(node, &client->version);
node = plist_dict_get_item(build_manifest, "ProductBuildVersion");
if (!node || plist_get_node_type(node) != PLIST_STRING) {
- error("ERROR: Unable to find ProductBuildVersion node\n");
+ logger(LL_ERROR, "Unable to find ProductBuildVersion node\n");
return;
}
plist_get_string_val(node, &client->build);
@@ -2799,25 +2928,25 @@ void build_identity_print_information(plist_t build_identity)
info_node = plist_dict_get_item(build_identity, "Info");
if (!info_node || plist_get_node_type(info_node) != PLIST_DICT) {
- error("ERROR: Unable to find Info node\n");
+ logger(LL_ERROR, "Unable to find Info node\n");
return;
}
node = plist_dict_get_item(info_node, "Variant");
if (!node || plist_get_node_type(node) != PLIST_STRING) {
- error("ERROR: Unable to find Variant node\n");
+ logger(LL_ERROR, "Unable to find Variant node\n");
return;
}
plist_get_string_val(node, &value);
- info("Variant: %s\n", value);
+ logger(LL_INFO, "Variant: %s\n", value);
if (strstr(value, RESTORE_VARIANT_UPGRADE_INSTALL))
- info("This restore will update the device without erasing user data.\n");
+ logger(LL_INFO, "This restore will update the device without erasing user data.\n");
else if (strstr(value, RESTORE_VARIANT_ERASE_INSTALL))
- info("This restore will erase all device data.\n");
+ logger(LL_INFO, "This restore will erase all device data.\n");
else
- info("Unknown Variant '%s'\n", value);
+ logger(LL_INFO, "Unknown Variant '%s'\n", value);
free(value);
@@ -2847,7 +2976,7 @@ int build_identity_check_components_in_ipsw(plist_t build_identity, ipsw_archive
plist_get_string_val(path, &comp_path);
if (comp_path) {
if (!ipsw_file_exists(ipsw, comp_path)) {
- error("ERROR: %s file %s not found in IPSW\n", key, comp_path);
+ logger(LL_ERROR, "%s file %s not found in IPSW\n", key, comp_path);
res = -1;
}
free(comp_path);
@@ -2880,7 +3009,7 @@ int build_identity_get_component_path(plist_t build_identity, const char* compon
plist_t manifest_node = plist_dict_get_item(build_identity, "Manifest");
if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) {
- error("ERROR: Unable to find manifest node\n");
+ logger(LL_ERROR, "Unable to find manifest node\n");
if (filename)
free(filename);
return -1;
@@ -2888,7 +3017,7 @@ int build_identity_get_component_path(plist_t build_identity, const char* compon
plist_t component_node = plist_dict_get_item(manifest_node, component);
if (!component_node || plist_get_node_type(component_node) != PLIST_DICT) {
- error("ERROR: Unable to find component node for %s\n", component);
+ logger(LL_ERROR, "Unable to find component node for %s\n", component);
if (filename)
free(filename);
return -1;
@@ -2896,7 +3025,7 @@ int build_identity_get_component_path(plist_t build_identity, const char* compon
plist_t component_info_node = plist_dict_get_item(component_node, "Info");
if (!component_info_node || plist_get_node_type(component_info_node) != PLIST_DICT) {
- error("ERROR: Unable to find component info node for %s\n", component);
+ logger(LL_ERROR, "Unable to find component info node for %s\n", component);
if (filename)
free(filename);
return -1;
@@ -2904,7 +3033,7 @@ int build_identity_get_component_path(plist_t build_identity, const char* compon
plist_t component_info_path_node = plist_dict_get_item(component_info_node, "Path");
if (!component_info_path_node || plist_get_node_type(component_info_path_node) != PLIST_STRING) {
- error("ERROR: Unable to find component info path node for %s\n", component);
+ logger(LL_ERROR, "Unable to find component info path node for %s\n", component);
if (filename)
free(filename);
return -1;
@@ -2949,6 +3078,6 @@ const char* get_component_name(const char* filename)
}
i++;
}
- error("WARNING: Unhandled component '%s'", filename);
+ logger(LL_WARNING, "Unhandled component '%s'", filename);
return NULL;
}