From fdea23960ae9ea99fa28db49c4da5791a8affca7 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 5 Feb 2012 22:18:15 +0100 Subject: download and cache version information from itunes.com --- src/Makefile.am | 2 +- src/common.h | 7 ++++ src/download.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/download.h | 24 ++++++++++++ src/idevicerestore.c | 61 +++++++++++++++++++++++++++++- 5 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 src/download.c create mode 100644 src/download.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 5fbcdef..93b0d98 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,6 +18,6 @@ AM_LDFLAGS =\ bin_PROGRAMS = idevicerestore -idevicerestore_SOURCES = idevicerestore.c common.c tss.c img3.c ipsw.c normal.c dfu.c recovery.c restore.c asr.c libirecovery.c limera1n.c +idevicerestore_SOURCES = idevicerestore.c common.c tss.c img3.c ipsw.c normal.c dfu.c recovery.c restore.c asr.c libirecovery.c limera1n.c download.c idevicerestore_CFLAGS = $(AM_CFLAGS) idevicerestore_LDFLAGS = $(AM_LDFLAGS) -lusb-1.0 diff --git a/src/common.h b/src/common.h index 9a84188..19ce881 100644 --- a/src/common.h +++ b/src/common.h @@ -129,6 +129,7 @@ struct idevicerestore_device_t { struct idevicerestore_client_t { int flags; plist_t tss; + plist_t version_data; uint64_t ecid; unsigned char* nonce; int nonce_size; @@ -183,6 +184,12 @@ int write_file(const char* filename, const void* data, size_t size); char *generate_guid(); +#ifdef WIN32 +#define __mkdir(path, mode) mkdir(path) +#else +#define __mkdir(path, mode) mkdir(path, mode) +#endif + extern struct idevicerestore_client_t* idevicerestore; #ifdef __cplusplus diff --git a/src/download.c b/src/download.c new file mode 100644 index 0000000..211987a --- /dev/null +++ b/src/download.c @@ -0,0 +1,104 @@ +/* + * download.c + * file download helper functions + * + * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include +#include + +#include "download.h" + +typedef struct { + int length; + char* content; +} curl_response; + +static size_t download_write_buffer_callback(char* data, size_t size, size_t nmemb, curl_response* response) { + size_t total = size * nmemb; + if (total != 0) { + response->content = realloc(response->content, response->length + total + 1); + memcpy(response->content + response->length, data, total); + response->content[response->length + total] = '\0'; + response->length += total; + } + return total; +} + +int download_to_buffer(const char* url, char** buf, uint32_t* length) +{ + curl_global_init(CURL_GLOBAL_ALL); + CURL* handle = curl_easy_init(); + if (handle == NULL) { + error("ERROR: could not initialize CURL\n"); + return -1; + } + + curl_response response; + response.length = 0; + response.content = malloc(1); + response.content[0] = '\0'; + + curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, (curl_write_callback)&download_write_buffer_callback); + curl_easy_setopt(handle, CURLOPT_WRITEDATA, &response); + curl_easy_setopt(handle, CURLOPT_USERAGENT, "InetURL/1.0"); + curl_easy_setopt(handle, CURLOPT_URL, url); + + curl_easy_perform(handle); + curl_easy_cleanup(handle); + + if (response.content) { + *length = response.length; + *buf = response.content; + } + + curl_global_cleanup(); + + return 0; +} + +int download_to_file(const char* url, const char* filename) +{ + curl_global_init(CURL_GLOBAL_ALL); + CURL* handle = curl_easy_init(); + if (handle == NULL) { + error("ERROR: could not initialize CURL\n"); + return -1; + } + + FILE* f = fopen(filename, "wb"); + if (!f) { + error("ERROR: cannot open '%s' for writing\n", filename); + return -1; + } + + curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, (curl_write_callback)&fwrite); + curl_easy_setopt(handle, CURLOPT_WRITEDATA, f); + curl_easy_setopt(handle, CURLOPT_USERAGENT, "InetURL/1.0"); + curl_easy_setopt(handle, CURLOPT_URL, url); + + curl_easy_perform(handle); + curl_easy_cleanup(handle); + + fclose(f); + + curl_global_cleanup(); + + return 0; +} diff --git a/src/download.h b/src/download.h new file mode 100644 index 0000000..4900b18 --- /dev/null +++ b/src/download.h @@ -0,0 +1,24 @@ +/* + * download.h + * file download helper functions (header file) + * + * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include + +int download_to_buffer(const char* url, char** buf, uint32_t* length); +int download_to_file(const char* url, const char* filename); diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 23e49f5..93c6766 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -34,11 +34,14 @@ #include "common.h" #include "normal.h" #include "restore.h" +#include "download.h" #include "recovery.h" #include "idevicerestore.h" #include "limera1n.h" +#define VERSION_XML "cache/version.xml" + int use_apple_server; static struct option longopts[] = { @@ -70,6 +73,59 @@ void usage(int argc, char* argv[]) { printf("\n"); } +static int load_version_data(struct idevicerestore_client_t* client) +{ + if (!client) { + return -1; + } + + struct stat fst; + int cached = 0; + + if ((stat(VERSION_XML, &fst) < 0) || ((time(NULL)-86400) > fst.st_mtime)) { + char tmpf[256]; + tmpf[0] = '\0'; + if (!tmpnam(tmpf) || (tmpf[0] == '\0')) { + error("ERROR: Could not get temporary filename\n"); + return -1; + } + + if (download_to_file("http://itunes.com/version", tmpf) == 0) { + __mkdir("cache", 0755); + remove(VERSION_XML); + if (rename(tmpf, VERSION_XML) < 0) { + error("ERROR: Could not update '" VERSION_XML "'\n"); + } else { + info("NOTE: Updated version data.\n"); + } + } + } else { + cached = 1; + } + + char *verbuf = NULL; + size_t verlen = 0; + read_file(VERSION_XML, (void**)&verbuf, &verlen); + if (!verbuf) { + error("ERROR: Could not load '" VERSION_XML "'.\n"); + return -1; + } + + client->version_data = NULL; + plist_from_xml(verbuf, verlen, &client->version_data); + + if (!client->version_data) { + error("ERROR: Cannot parse plist data from '" VERSION_XML "'.\n"); + return -1; + } + + if (cached) { + info("NOTE: using cached version data\n"); + } + + return 0; +} + int main(int argc, char* argv[]) { int opt = 0; int optindex = 0; @@ -151,6 +207,9 @@ int main(int argc, char* argv[]) { client->uuid = uuid; client->ipsw = ipsw; + // update version data (from cache, or apple if too old) + load_version_data(client); + // check which mode the device is currently in so we know where to start if (check_mode(client) < 0 || client->mode->index == MODE_UNKNOWN) { error("ERROR: Unable to discover device mode. Please make sure a device is attached.\n"); @@ -428,7 +487,7 @@ int main(int argc, char* argv[]) { if (bin) { char zfn[512]; sprintf(zfn, "shsh/%lld-%s-%s.shsh", (long long int)client->ecid, client->device->product, client->version); - mkdir("shsh", 0755); + __mkdir("shsh", 0755); struct stat fst; if (stat(zfn, &fst) != 0) { gzFile zf = gzopen(zfn, "wb"); -- cgit v1.1-32-gdbae