From bc6be463e4b1f8284c7fa8115920d41df4241569 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 16 Jul 2012 16:00:16 +0200 Subject: move ipsw on-demand download to ipsw.c --- src/idevicerestore.c | 228 +------------------------------------------------ src/ipsw.c | 235 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/ipsw.h | 2 + 3 files changed, 238 insertions(+), 227 deletions(-) (limited to 'src') diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 0726285..56bc44a 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -26,7 +26,6 @@ #include #include #include -#include #include "dfu.h" #include "tss.h" @@ -139,165 +138,6 @@ static int load_version_data(struct idevicerestore_client_t* client) return 0; } -int get_latest_fw(struct idevicerestore_client_t* client, char** fwurl, unsigned char* sha1buf) -{ - *fwurl = NULL; - memset(sha1buf, '\0', 20); - - plist_t n1 = plist_access_path(client->version_data, 2, "MobileDeviceMajorVersionsByProductType", client->device->product); - if (!n1 || (plist_dict_get_size(n1) == 0)) { - error("%s: ERROR: Can't find MobileDeviceMajorVersionsByProductType/%s dict in version data\n", __func__, client->device->product); - return -1; - } - - char* strval = NULL; - plist_t n2 = plist_dict_get_item(n1, "SameAs"); - if (n2) { - plist_get_string_val(n2, &strval); - } - if (strval) { - n1 = plist_access_path(client->version_data, 2, "MobileDeviceMajorVersionsByProductType", strval); - free(strval); - strval = NULL; - if (!n1 || (plist_dict_get_size(n1) == 0)) { - error("%s: ERROR: Can't find MobileDeviceMajorVersionsByProductType/%s dict in version data\n", __func__, client->device->product); - return -1; - } - } - - plist_dict_iter iter = NULL; - plist_dict_new_iter(n1, &iter); - if (!iter) { - error("%s: ERROR: Can't get dict iter\n", __func__); - return -1; - } - n2 = NULL; - char* key = NULL; - plist_t val = NULL; - do { - plist_dict_next_item(n1, iter, &key, &val); - if (key) { - n2 = val; - free(key); - } - } while (val); - free(iter); - - if (!n2) { - error("%s: ERROR: Can't get last node?!\n", __func__); - return -1; - } - - uint64_t major = 0; - if (plist_get_node_type(n2) == PLIST_ARRAY) { - uint32_t sz = plist_array_get_size(n2); - plist_t n3 = plist_array_get_item(n2, sz-1); - plist_get_uint_val(n3, &major); - } else { - plist_get_uint_val(n2, &major); - } - - if (major == 0) { - error("%s: ERROR: Can't find major version?!\n", __func__); - return -1; - } - - char majstr[32]; // should be enough for a uint64_t value - sprintf(majstr, FMT_qu, (long long unsigned int)major); - n1 = plist_access_path(client->version_data, 7, "MobileDeviceSoftwareVersionsByVersion", majstr, "MobileDeviceSoftwareVersions", client->device->product, "Unknown", "Universal", "Restore"); - if (!n1) { - error("%s: ERROR: Can't get Unknown/Universal/Restore node?!\n", __func__); - return -1; - } - - n2 = plist_dict_get_item(n1, "BuildVersion"); - if (!n2 || (plist_get_node_type(n2) != PLIST_STRING)) { - error("%s: ERROR: Can't get build version node?!\n", __func__); - return -1; - } - - strval = NULL; - plist_get_string_val(n2, &strval); - - n1 = plist_access_path(client->version_data, 5, "MobileDeviceSoftwareVersionsByVersion", majstr, "MobileDeviceSoftwareVersions", client->device->product, strval); - if (!n1) { - error("%s: ERROR: Can't get MobileDeviceSoftwareVersions/%s node?!\n", __func__, strval); - free(strval); - return -1; - } - free(strval); - - strval = NULL; - n2 = plist_dict_get_item(n1, "SameAs"); - if (n2) { - plist_get_string_val(n2, &strval); - } - if (strval) { - n1 = plist_access_path(client->version_data, 5, "MobileDeviceSoftwareVersionsByVersion", majstr, "MobileDeviceSoftwareVersions", client->device->product, strval); - free(strval); - strval = NULL; - if (!n1 || (plist_dict_get_size(n1) == 0)) { - error("%s: ERROR: Can't get MobileDeviceSoftwareVersions/%s dict\n", __func__, client->device->product); - return -1; - } - } - - n2 = plist_access_path(n1, 2, "Update", "BuildVersion"); - if (n2) { - strval = NULL; - plist_get_string_val(n2, &strval); - if (strval) { - n1 = plist_access_path(client->version_data, 5, "MobileDeviceSoftwareVersionsByVersion", majstr, "MobileDeviceSoftwareVersions", client->device->product, strval); - free(strval); - strval = NULL; - } - } - - n2 = plist_access_path(n1, 2, "Restore", "FirmwareURL"); - if (!n2 || (plist_get_node_type(n2) != PLIST_STRING)) { - error("%s: ERROR: Can't get FirmwareURL node\n", __func__); - return -1; - } - - plist_get_string_val(n2, fwurl); - - n2 = plist_access_path(n1, 2, "Restore", "FirmwareSHA1"); - if (n2 && plist_get_node_type(n2) == PLIST_STRING) { - strval = NULL; - plist_get_string_val(n2, &strval); - if (strval) { - if (strlen(strval) == 40) { - int i; - int v; - for (i = 0; i < 40; i+=2) { - v = 0; - sscanf(strval+i, "%02x", &v); - sha1buf[i/2] = (unsigned char)v; - } - } - free(strval); - } - } - - return 0; -} - -static int sha1_verify_fp(FILE* f, unsigned char* expected_sha1) -{ - unsigned char tsha1[20]; - char buf[8192]; - if (!f) return 0; - SHA_CTX sha1ctx; - SHA1_Init(&sha1ctx); - rewind(f); - while (!feof(f)) { - size_t sz = fread(buf, 1, 8192, f); - SHA1_Update(&sha1ctx, (const void*)buf, sz); - } - SHA1_Final(tsha1, &sha1ctx); - return (memcmp(expected_sha1, tsha1, 20) == 0) ? 1 : 0; -} - int main(int argc, char* argv[]) { int opt = 0; int optindex = 0; @@ -510,77 +350,11 @@ int main(int argc, char* argv[]) { } if (latest) { - char* fwurl = NULL; - unsigned char isha1[20]; - if ((get_latest_fw(client, &fwurl, isha1) < 0) || !fwurl) { - error("ERROR: can't get URL for latest firmware\n"); - return -1; - } - char* fwfn = strrchr(fwurl, '/'); - if (!fwfn) { - error("ERROR: can't get local filename for firmware ipsw\n"); - return -1; - } - fwfn++; - - info("Latest firmware is %s\n", fwfn); - - char fwlfn[256]; - sprintf(fwlfn, "cache/%s", fwfn); - - int need_dl = 0; - unsigned char zsha1[20] = {0, }; - FILE* f = fopen(fwlfn, "rb"); - if (f) { - if (memcmp(zsha1, isha1, 20) != 0) { - info("Verifying '%s'...\n", fwlfn); - if (sha1_verify_fp(f, isha1)) { - info("Checksum matches.\n"); - } else { - info("Checksum does not match.\n"); - need_dl = 1; - } - } - fclose(f); - } else { - need_dl = 1; - } - - int res = 0; - if (need_dl) { - if (strncmp(fwurl, "protected:", 10) == 0) { - error("ERROR: Can't download '%s' because it needs a purchase.\n", fwfn); - res = -1; - } else { - remove(fwlfn); - info("Downloading latest firmware (%s)\n", fwurl); - download_to_file(fwurl, fwlfn); - if (memcmp(isha1, zsha1, 20) != 0) { - info("\nVerifying '%s'...\n", fwlfn); - FILE* f = fopen(fwlfn, "rb"); - if (f) { - if (sha1_verify_fp(f, isha1)) { - info("Checksum matches.\n"); - } else { - error("ERROR: File download failed (checksum mismatch).\n"); - res = -1; - } - fclose(f); - } else { - error("ERROR: Can't open '%s' for checksum verification\n", fwlfn); - res = -1; - } - } - } - } - + int res = ipsw_download_latest_fw(client->version_data, client->device->product, "cache", &ipsw); if (res != 0) { - free(fwurl); return res; } else { - ipsw = strdup(fwlfn); client->ipsw = ipsw; - free(fwurl); } } diff --git a/src/ipsw.c b/src/ipsw.c index b9ebdff..033b894 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "ipsw.h" #include "idevicerestore.h" @@ -219,3 +220,237 @@ void ipsw_close(ipsw_archive* archive) { free(archive); } } + +static int get_latest_fw(plist_t version_data, const char* product, char** fwurl, unsigned char* sha1buf) +{ + *fwurl = NULL; + memset(sha1buf, '\0', 20); + + plist_t n1 = plist_access_path(version_data, 2, "MobileDeviceMajorVersionsByProductType", product); + if (!n1 || (plist_dict_get_size(n1) == 0)) { + error("%s: ERROR: Can't find MobileDeviceMajorVersionsByProductType/%s dict in version data\n", __func__, product); + return -1; + } + + char* strval = NULL; + plist_t n2 = plist_dict_get_item(n1, "SameAs"); + if (n2) { + plist_get_string_val(n2, &strval); + } + if (strval) { + n1 = plist_access_path(version_data, 2, "MobileDeviceMajorVersionsByProductType", strval); + free(strval); + strval = NULL; + if (!n1 || (plist_dict_get_size(n1) == 0)) { + error("%s: ERROR: Can't find MobileDeviceMajorVersionsByProductType/%s dict in version data\n", __func__, product); + return -1; + } + } + + plist_dict_iter iter = NULL; + plist_dict_new_iter(n1, &iter); + if (!iter) { + error("%s: ERROR: Can't get dict iter\n", __func__); + return -1; + } + n2 = NULL; + char* key = NULL; + plist_t val = NULL; + do { + plist_dict_next_item(n1, iter, &key, &val); + if (key) { + n2 = val; + free(key); + } + } while (val); + free(iter); + + if (!n2) { + error("%s: ERROR: Can't get last node?!\n", __func__); + return -1; + } + + uint64_t major = 0; + if (plist_get_node_type(n2) == PLIST_ARRAY) { + uint32_t sz = plist_array_get_size(n2); + plist_t n3 = plist_array_get_item(n2, sz-1); + plist_get_uint_val(n3, &major); + } else { + plist_get_uint_val(n2, &major); + } + + if (major == 0) { + error("%s: ERROR: Can't find major version?!\n", __func__); + return -1; + } + + char majstr[32]; // should be enough for a uint64_t value + sprintf(majstr, FMT_qu, (long long unsigned int)major); + n1 = plist_access_path(version_data, 7, "MobileDeviceSoftwareVersionsByVersion", majstr, "MobileDeviceSoftwareVersions", product, "Unknown", "Universal", "Restore"); + if (!n1) { + error("%s: ERROR: Can't get Unknown/Universal/Restore node?!\n", __func__); + return -1; + } + + n2 = plist_dict_get_item(n1, "BuildVersion"); + if (!n2 || (plist_get_node_type(n2) != PLIST_STRING)) { + error("%s: ERROR: Can't get build version node?!\n", __func__); + return -1; + } + + strval = NULL; + plist_get_string_val(n2, &strval); + + n1 = plist_access_path(version_data, 5, "MobileDeviceSoftwareVersionsByVersion", majstr, "MobileDeviceSoftwareVersions", product, strval); + if (!n1) { + error("%s: ERROR: Can't get MobileDeviceSoftwareVersions/%s node?!\n", __func__, strval); + free(strval); + return -1; + } + free(strval); + + strval = NULL; + n2 = plist_dict_get_item(n1, "SameAs"); + if (n2) { + plist_get_string_val(n2, &strval); + } + if (strval) { + n1 = plist_access_path(version_data, 5, "MobileDeviceSoftwareVersionsByVersion", majstr, "MobileDeviceSoftwareVersions", product, strval); + free(strval); + strval = NULL; + if (!n1 || (plist_dict_get_size(n1) == 0)) { + error("%s: ERROR: Can't get MobileDeviceSoftwareVersions/%s dict\n", __func__, product); + return -1; + } + } + + n2 = plist_access_path(n1, 2, "Update", "BuildVersion"); + if (n2) { + strval = NULL; + plist_get_string_val(n2, &strval); + if (strval) { + n1 = plist_access_path(version_data, 5, "MobileDeviceSoftwareVersionsByVersion", majstr, "MobileDeviceSoftwareVersions", product, strval); + free(strval); + strval = NULL; + } + } + + n2 = plist_access_path(n1, 2, "Restore", "FirmwareURL"); + if (!n2 || (plist_get_node_type(n2) != PLIST_STRING)) { + error("%s: ERROR: Can't get FirmwareURL node\n", __func__); + return -1; + } + + plist_get_string_val(n2, fwurl); + + n2 = plist_access_path(n1, 2, "Restore", "FirmwareSHA1"); + if (n2 && plist_get_node_type(n2) == PLIST_STRING) { + strval = NULL; + plist_get_string_val(n2, &strval); + if (strval) { + if (strlen(strval) == 40) { + int i; + int v; + for (i = 0; i < 40; i+=2) { + v = 0; + sscanf(strval+i, "%02x", &v); + sha1buf[i/2] = (unsigned char)v; + } + } + free(strval); + } + } + + return 0; +} + +static int sha1_verify_fp(FILE* f, unsigned char* expected_sha1) +{ + unsigned char tsha1[20]; + char buf[8192]; + if (!f) return 0; + SHA_CTX sha1ctx; + SHA1_Init(&sha1ctx); + rewind(f); + while (!feof(f)) { + size_t sz = fread(buf, 1, 8192, f); + SHA1_Update(&sha1ctx, (const void*)buf, sz); + } + SHA1_Final(tsha1, &sha1ctx); + return (memcmp(expected_sha1, tsha1, 20) == 0) ? 1 : 0; +} + +int ipsw_download_latest_fw(plist_t version_data, const char* product, const char* todir, char** ipswfile) +{ + char* fwurl = NULL; + unsigned char isha1[20]; + + *ipswfile = NULL; + + if ((get_latest_fw(version_data, product, &fwurl, isha1) < 0) || !fwurl) { + error("ERROR: can't get URL for latest firmware\n"); + return -1; + } + char* fwfn = strrchr(fwurl, '/'); + if (!fwfn) { + error("ERROR: can't get local filename for firmware ipsw\n"); + return -1; + } + fwfn++; + + info("Latest firmware is %s\n", fwfn); + + char fwlfn[256]; + sprintf(fwlfn, "%s/%s", todir, fwfn); + + int need_dl = 0; + unsigned char zsha1[20] = {0, }; + FILE* f = fopen(fwlfn, "rb"); + if (f) { + if (memcmp(zsha1, isha1, 20) != 0) { + info("Verifying '%s'...\n", fwlfn); + if (sha1_verify_fp(f, isha1)) { + info("Checksum matches.\n"); + } else { + info("Checksum does not match.\n"); + need_dl = 1; + } + } + fclose(f); + } else { + need_dl = 1; + } + + int res = 0; + if (need_dl) { + if (strncmp(fwurl, "protected:", 10) == 0) { + error("ERROR: Can't download '%s' because it needs a purchase.\n", fwfn); + res = -1; + } else { + remove(fwlfn); + info("Downloading latest firmware (%s)\n", fwurl); + download_to_file(fwurl, fwlfn); + if (memcmp(isha1, zsha1, 20) != 0) { + info("\nVerifying '%s'...\n", fwlfn); + FILE* f = fopen(fwlfn, "rb"); + if (f) { + if (sha1_verify_fp(f, isha1)) { + info("Checksum matches.\n"); + } else { + error("ERROR: File download failed (checksum mismatch).\n"); + res = -1; + } + fclose(f); + } else { + error("ERROR: Can't open '%s' for checksum verification\n", fwlfn); + res = -1; + } + } + } + } + free(fwurl); + if (res == 0) { + *ipswfile = strdup(fwlfn); + } + return res; +} diff --git a/src/ipsw.h b/src/ipsw.h index a77bc84..ab320be 100644 --- a/src/ipsw.h +++ b/src/ipsw.h @@ -42,6 +42,8 @@ int ipsw_extract_build_manifest(const char* ipsw, plist_t* buildmanifest, int *t int ipsw_extract_restore_plist(const char* ipsw, plist_t* restore_plist); void ipsw_free_file(ipsw_file* file); +int ipsw_download_latest_fw(plist_t version_data, const char* product, const char* todir, char** ipswfile); + #ifdef __cplusplus } #endif -- cgit v1.1-32-gdbae