summaryrefslogtreecommitdiffstats
path: root/src/normal.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/normal.c')
-rw-r--r--src/normal.c312
1 files changed, 310 insertions, 2 deletions
diff --git a/src/normal.c b/src/normal.c
index c7baefd..c9a1b45 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -19,10 +19,318 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libirecovery.h>
+#include <libimobiledevice/lockdown.h>
+#include <libimobiledevice/libimobiledevice.h>
+#include "common.h"
#include "normal.h"
+#include "recovery.h"
-int normal_get_ecid(uint64_t* ecid) {
+static int normal_device_connected = 0;
+
+void normal_device_callback(const idevice_event_t* event, void* userdata) {
+ struct idevicerestore_client_t* client = (struct idevicerestore_client_t*) userdata;
+ if (event->event == IDEVICE_DEVICE_ADD) {
+ normal_device_connected = 1;
+
+ } else if (event->event == IDEVICE_DEVICE_REMOVE) {
+ normal_device_connected = 0;
+ client->flags &= FLAG_QUIT;
+ }
+}
+
+int normal_client_new(struct idevicerestore_client_t* client) {
+ struct normal_client_t* normal = (struct normal_client_t*) malloc(sizeof(struct normal_client_t));
+ if (normal == NULL) {
+ error("ERROR: Out of memory\n");
+ return -1;
+ }
+
+ if (normal_open_with_timeout(client) < 0) {
+ normal_client_free(client);
+ return -1;
+ }
+
+ client->normal = normal;
+ return 0;
+}
+
+void normal_client_free(struct idevicerestore_client_t* client) {
+ struct normal_client_t* normal = NULL;
+ if (client) {
+ normal = client->normal;
+ if(normal) {
+ if(normal->client) {
+ lockdownd_client_free(normal->client);
+ normal->client = NULL;
+ }
+ if(normal->device) {
+ idevice_free(normal->device);
+ normal->device = NULL;
+ }
+ }
+ free(normal);
+ client->normal = NULL;
+ }
+}
+
+int normal_check_mode(const char* uuid) {
+ char* type = NULL;
+ idevice_t device = NULL;
+ lockdownd_client_t lockdown = NULL;
+ idevice_error_t device_error = IDEVICE_E_SUCCESS;
+ lockdownd_error_t lockdown_error = IDEVICE_E_SUCCESS;
+
+ device_error = idevice_new(&device, uuid);
+ if (device_error != IDEVICE_E_SUCCESS) {
+ return -1;
+ }
+
+ lockdown_error = lockdownd_client_new(device, &lockdown, "idevicerestore");
+ if (lockdown_error != LOCKDOWN_E_SUCCESS) {
+ idevice_free(device);
+ return -1;
+ }
+
+ lockdown_error = lockdownd_query_type(lockdown, &type);
+ if (lockdown_error != LOCKDOWN_E_SUCCESS) {
+ lockdownd_client_free(lockdown);
+ idevice_free(device);
+ return -1;
+ }
+
+ lockdownd_client_free(lockdown);
+ idevice_free(device);
+ lockdown = NULL;
+ device = NULL;
+ return 0;
+}
+
+int normal_open_with_timeout(struct idevicerestore_client_t* client) {
+ int i = 0;
+ int attempts = 10;
+ idevice_t device = NULL;
+ lockdownd_client_t lockdownd = NULL;
+ idevice_error_t device_error = IDEVICE_E_SUCCESS;
+ lockdownd_error_t lockdownd_error = LOCKDOWN_E_SUCCESS;
+
+ // no context exists so bail
+ if(client == NULL) {
+ return -1;
+ }
+
+ // create our normal client if it doesn't yet exist
+ if(client->normal == NULL) {
+ client->normal = (struct normal_client_t*) malloc(sizeof(struct normal_client_t));
+ if(client->normal == NULL) {
+ error("ERROR: Out of memory\n");
+ return -1;
+ }
+ }
+
+ device_error = idevice_event_subscribe(&normal_device_callback, NULL);
+ if (device_error != IDEVICE_E_SUCCESS) {
+ error("ERROR: Unable to subscribe to device events\n");
+ return -1;
+ }
+
+ for (i = 1; i <= attempts; i++) {
+ if (normal_device_connected == 1) {
+ break;
+ }
+
+ if (i == attempts) {
+ error("ERROR: Unable to connect to device in normal mode\n");
+ return -1;
+ }
+
+ sleep(2);
+ }
+
+ device_error = idevice_new(&device, client->uuid);
+ if (device_error != IDEVICE_E_SUCCESS) {
+ return -1;
+ }
+
+ lockdownd_error = lockdownd_client_new(device, &lockdownd, "idevicerestore");
+ if (lockdownd_error != LOCKDOWN_E_SUCCESS) {
+ //idevice_event_unsubscribe();
+ idevice_free(device);
+ return -1;
+ }
+
+ char* type = NULL;
+ lockdownd_error = lockdownd_query_type(lockdownd, &type);
+ if (lockdownd_error != LOCKDOWN_E_SUCCESS) {
+ lockdownd_client_free(lockdownd);
+ //idevice_event_unsubscribe();
+ idevice_free(device);
+ return -1;
+ }
+
+ client->normal->device = device;
+ client->normal->client = lockdownd;
+ return 0;
+}
+
+int normal_check_device(const char* uuid) {
+ int i = 0;
+ idevice_t device = NULL;
+ char* product_type = NULL;
+ plist_t product_type_node = NULL;
+ lockdownd_client_t lockdown = NULL;
+ idevice_error_t device_error = IDEVICE_E_SUCCESS;
+ lockdownd_error_t lockdown_error = IDEVICE_E_SUCCESS;
+
+ device_error = idevice_new(&device, uuid);
+ if (device_error != IDEVICE_E_SUCCESS) {
+ return -1;
+ }
+
+ lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore");
+ if (lockdown_error != LOCKDOWN_E_SUCCESS) {
+ idevice_free(device);
+ return -1;
+ }
+
+ lockdown_error = lockdownd_get_value(lockdown, NULL, "ProductType", &product_type_node);
+ if (lockdown_error != LOCKDOWN_E_SUCCESS) {
+ lockdownd_client_free(lockdown);
+ idevice_free(device);
+ return -1;
+ }
+
+ lockdownd_client_free(lockdown);
+ idevice_free(device);
+ lockdown = NULL;
+ device = NULL;
+
+ if (!product_type_node || plist_get_node_type(product_type_node) != PLIST_STRING) {
+ if (product_type_node) plist_free(product_type_node);
+ return -1;
+ }
+ plist_get_string_val(product_type_node, &product_type);
+ plist_free(product_type_node);
+
+ for (i = 0; idevicerestore_devices[i].product != NULL; i++) {
+ if (!strcmp(product_type, idevicerestore_devices[i].product)) {
+ break;
+ }
+ }
+
+ return idevicerestore_devices[i].index;
+}
+
+int normal_enter_recovery(struct idevicerestore_client_t* client) {
+ idevice_t device = NULL;
+ irecv_client_t recovery = NULL;
+ lockdownd_client_t lockdown = NULL;
+ irecv_error_t recovery_error = IRECV_E_SUCCESS;
+ idevice_error_t device_error = IDEVICE_E_SUCCESS;
+ lockdownd_error_t lockdown_error = LOCKDOWN_E_SUCCESS;
+
+ device_error = idevice_new(&device, client->uuid);
+ if (device_error != IDEVICE_E_SUCCESS) {
+ error("ERROR: Unable to find device\n");
+ return -1;
+ }
+
+ lockdown_error = lockdownd_client_new(device, &lockdown, "idevicerestore");
+ if (lockdown_error != LOCKDOWN_E_SUCCESS) {
+ error("ERROR: Unable to connect to lockdownd service\n");
+ idevice_free(device);
+ return -1;
+ }
+
+ lockdown_error = lockdownd_enter_recovery(lockdown);
+ if (lockdown_error != LOCKDOWN_E_SUCCESS) {
+ error("ERROR: Unable to place device in recovery mode\n");
+ lockdownd_client_free(lockdown);
+ idevice_free(device);
+ return -1;
+ }
+
+ lockdownd_client_free(lockdown);
+ idevice_free(device);
+ lockdown = NULL;
+ device = NULL;
+
+ if (recovery_open_with_timeout(client) < 0) {
+ error("ERROR: Unable to enter recovery mode\n");
+ return -1;
+ }
+
+ recovery_error = irecv_send_command(recovery, "setenv auto-boot true");
+ if (recovery_error != IRECV_E_SUCCESS) {
+ error("ERROR: Unable to reset auto-boot variable\n");
+ irecv_close(recovery);
+ return -1;
+ }
+
+ recovery_error = irecv_send_command(recovery, "saveenv");
+ if (recovery_error != IRECV_E_SUCCESS) {
+ error("ERROR: Unable to save auto-boot variable\n");
+ irecv_close(recovery);
+ return -1;
+ }
+
+ //client->mode = &idevicerestore_modes[MODE_RECOVERY];
+ irecv_close(recovery);
+ recovery = NULL;
+ return 0;
+}
+
+int normal_get_cpid(const char* uuid, uint32_t* cpid) {
+ return 0;
+}
+
+int normal_get_bdid(const char* uuid, uint32_t* bdid) {
+ return 0;
+}
+
+int normal_get_ecid(const char* uuid, uint64_t* ecid) {
+ idevice_t device = NULL;
+ plist_t unique_chip_node = NULL;
+ lockdownd_client_t lockdown = NULL;
+ idevice_error_t device_error = IDEVICE_E_SUCCESS;
+ lockdownd_error_t lockdown_error = IDEVICE_E_SUCCESS;
+
+ device_error = idevice_new(&device, uuid);
+ if (device_error != IDEVICE_E_SUCCESS) {
+ return -1;
+ }
+
+ lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore");
+ if (lockdown_error != LOCKDOWN_E_SUCCESS) {
+ error("ERROR: Unable to connect to lockdownd\n");
+ idevice_free(device);
+ return -1;
+ }
+
+ lockdown_error = lockdownd_get_value(lockdown, NULL, "UniqueChipID", &unique_chip_node);
+ if (lockdown_error != LOCKDOWN_E_SUCCESS) {
+ error("ERROR: Unable to get UniqueChipID from lockdownd\n");
+ lockdownd_client_free(lockdown);
+ idevice_free(device);
+ return -1;
+ }
+
+ if (!unique_chip_node || plist_get_node_type(unique_chip_node) != PLIST_UINT) {
+ error("ERROR: Unable to get ECID\n");
+ lockdownd_client_free(lockdown);
+ idevice_free(device);
+ return -1;
+ }
+ plist_get_uint_val(unique_chip_node, ecid);
+ plist_free(unique_chip_node);
+
+ lockdownd_client_free(lockdown);
+ idevice_free(device);
+ lockdown = NULL;
+ device = NULL;
return 0;
}