summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Jonathan Beck2009-01-08 18:51:42 +0100
committerGravatar Jonathan Beck2009-01-08 18:51:42 +0100
commitf53b61c82be8aa6223ab6a524c2287d892f9864c (patch)
tree99f67152a644ded15d0bd7cd16664c4eb1eb7c00
parent5514a3b2a9734d311e4f6014585f922e0b748cab (diff)
parentef98ef7211bc6277e9a87349f0405957ab264936 (diff)
downloadlibimobiledevice-f53b61c82be8aa6223ab6a524c2287d892f9864c.tar.gz
libimobiledevice-f53b61c82be8aa6223ab6a524c2287d892f9864c.tar.bz2
Merge branch 'nikias' into plist
Conflicts: src/lockdown.c
-rw-r--r--src/iphone.c59
-rw-r--r--src/lockdown.c201
-rw-r--r--src/lockdown.h1
-rw-r--r--src/usbmux.c3
-rw-r--r--src/utils.c32
5 files changed, 282 insertions, 14 deletions
diff --git a/src/iphone.c b/src/iphone.c
index 32d27f6..1f68180 100644
--- a/src/iphone.c
+++ b/src/iphone.c
@@ -28,6 +28,49 @@
#include <stdlib.h>
#include <string.h>
+/**
+ * This function sets the configuration of the given device to 3
+ * and claims the interface 1. If usb_set_configuration fails, it detaches
+ * the kernel driver that blocks the device, and retries configuration.
+ *
+ * @param phone which device to configure
+ */
+static void iphone_config_usb_device(iphone_device_t phone)
+{
+ int ret;
+
+ log_debug_msg("setting configuration... ");
+ ret = usb_set_configuration(phone->device, 3);
+ if (ret != 0) {
+ log_debug_msg("Hm, usb_set_configuration returned %d: %s, trying to fix:\n", ret, strerror(-ret));
+ log_debug_msg("-> detaching kernel driver... ");
+ ret =
+ usb_detach_kernel_driver_np(phone->device,
+ phone->__device->config->interface->altsetting->bInterfaceNumber);
+ if (ret != 0) {
+ log_debug_msg("usb_detach_kernel_driver_np returned %d: %s\n", ret, strerror(-ret));
+ } else {
+ log_debug_msg("done.\n");
+ log_debug_msg("setting configuration again... ");
+ ret = usb_set_configuration(phone->device, 3);
+ if (ret != 0) {
+ log_debug_msg("Error: usb_set_configuration returned %d: %s\n", ret, strerror(-ret));
+ } else {
+ log_debug_msg("done.\n");
+ }
+ }
+ } else {
+ log_debug_msg("done.\n");
+ }
+
+ log_debug_msg("claiming interface... ");
+ ret = usb_claim_interface(phone->device, 1);
+ if (ret != 0) {
+ log_debug_msg("Error: usb_claim_interface returned %d: %s\n", ret, strerror(-ret));
+ } else {
+ log_debug_msg("done.\n");
+ }
+}
/**
* Given a USB bus and device number, returns a device handle to the iPhone on
@@ -73,8 +116,7 @@ static iphone_error_t iphone_get_specific_device(unsigned int bus_n, int dev_n,
if (dev->devnum == dev_n) {
phone->__device = dev;
phone->device = usb_open(phone->__device);
- usb_set_configuration(phone->device, 3);
- usb_claim_interface(phone->device, 1);
+ iphone_config_usb_device(phone);
goto found;
}
@@ -115,9 +157,10 @@ static iphone_error_t iphone_get_specific_device(unsigned int bus_n, int dev_n,
return IPHONE_E_SUCCESS;
} else {
// Bad header
+ log_debug_msg("get_iPhone(): Received a bad header/invalid version number.\n");
+ log_debug_buffer((char *) version, sizeof(*version));
iphone_free_device(phone);
free(version);
- log_debug_msg("get_iPhone(): Received a bad header/invalid version number.");
return IPHONE_E_BAD_HEADER;
}
@@ -173,13 +216,21 @@ iphone_error_t iphone_free_device(iphone_device_t device)
if (!device)
return IPHONE_E_INVALID_ARG;
iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR;
+ int bytes;
+ unsigned char buf[512];
+
+ // read final package
+ bytes = usb_bulk_read(device->device, BULKIN, (void *) &buf, 512, 1000);
+ if (bytes > 0) {
+ log_debug_msg("iphone_free_device: final read returned\n");
+ log_debug_buffer(buf, bytes);
+ }
if (device->buffer) {
free(device->buffer);
}
if (device->device) {
usb_release_interface(device->device, 1);
- usb_reset(device->device);
usb_close(device->device);
ret = IPHONE_E_SUCCESS;
}
diff --git a/src/lockdown.c b/src/lockdown.c
index c6d5f80..872b7b0 100644
--- a/src/lockdown.c
+++ b/src/lockdown.c
@@ -65,6 +65,104 @@ iphone_lckd_client_t new_lockdownd_client(iphone_device_t phone)
return control;
}
+/**
+ * Closes the lockdownd communication session, by sending
+ * the StopSession Request to the device.
+ *
+ * @param control The lockdown client
+ */
+static void iphone_lckd_stop_session(iphone_lckd_client_t control)
+{
+ if (!control)
+ return; //IPHONE_E_INVALID_ARG;
+
+ int bytes = 0, i = 0;
+ iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR;
+
+ plist_t dict = plist_new_dict();
+ plist_add_sub_element(dict, PLIST_KEY, (void *) "Request", strlen("Request"));
+ plist_add_sub_element(dict, PLIST_STRING, (void *) "StopSession", strlen("StopSession"));
+ plist_add_sub_element(dict, PLIST_KEY, (void *) "SessionID", strlen("SessionID"));
+ plist_add_sub_element(dict, PLIST_STRING, (void *) control->session_id, strlen(control->session_id));
+
+ log_debug_msg("iphone_lckd_stop_session() called\n");
+ char *XML_content = NULL;
+ uint32_t length = 0;
+
+ plist_to_xml(dict, &XML_content, &length);
+ log_debug_msg("Send msg :\nsize : %i\nxml : %s", length, XML_content);
+ ret = iphone_lckd_send(control, XML_content, length, &bytes);
+
+ free(XML_content);
+ XML_content = NULL;
+ plist_free(dict);
+ dict = NULL;
+
+ ret = iphone_lckd_recv(control, &XML_content, &bytes);
+ log_debug_msg("Receive msg :\nsize : %i\nxml : %s", bytes, XML_content);
+ plist_from_xml(XML_content, bytes, &dict);
+
+ if (!dict) {
+ log_debug_msg("lockdownd_stop_session(): IPHONE_E_PLIST_ERROR\n");
+ return; // IPHONE_E_PLIST_ERROR;
+ }
+
+ plist_t query_node = plist_find_node(dict, PLIST_STRING, "StopSession", strlen("StopSession"));
+ plist_t result_node = plist_get_next_sibling(query_node);
+ plist_t value_node = plist_get_next_sibling(result_node);
+
+ plist_type result_type;
+ plist_type value_type;
+
+ char *result_value = NULL;
+ char *value_value = NULL;
+ uint64_t result_length = 0;
+ uint64_t value_length = 0;
+
+ plist_get_type_and_value(result_node, &result_type, (void *) (&result_value), &result_length);
+ plist_get_type_and_value(value_node, &value_type, (void *) (&value_value), &value_length);
+
+ if (result_type == PLIST_KEY &&
+ value_type == PLIST_STRING && !strcmp(result_value, "Result") && !strcmp(value_value, "Success")) {
+ log_debug_msg("lockdownd_stop_session(): success\n");
+ ret = IPHONE_E_SUCCESS;
+ }
+
+ return; // ret;
+}
+
+
+/**
+ * Shuts down the SSL session by first calling iphone_lckd_stop_session
+ * to cleanly close the lockdownd communication session, and then
+ * performing a close notify, which is done by "gnutls_bye".
+ *
+ * @param client The lockdown client
+ */
+static void iphone_lckd_stop_SSL_session(iphone_lckd_client_t client)
+{
+ if (!client) {
+ log_debug_msg("lockdownd_stop_SSL_session(): invalid argument!\n");
+ return;
+ }
+
+ if (client->in_SSL) {
+ log_debug_msg("Stopping SSL Session\n");
+ iphone_lckd_stop_session(client);
+ log_debug_msg("Sending SSL close notify\n");
+ gnutls_bye(*client->ssl_session, GNUTLS_SHUT_RDWR);
+ }
+ if (client->ssl_session) {
+ gnutls_deinit(*client->ssl_session);
+ free(client->ssl_session);
+ }
+ client->in_SSL = 0;
+ client->gtls_buffer_hack_len = 0; // dunno if required?!
+
+ return;
+}
+
+
/** Closes the lockdownd client and does the necessary housekeeping.
*
* @param control The lockdown client
@@ -75,13 +173,17 @@ iphone_error_t iphone_lckd_free_client(iphone_lckd_client_t client)
return IPHONE_E_INVALID_ARG;
iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR;
+ iphone_lckd_stop_SSL_session(client);
+
if (client->connection) {
+ lockdownd_close(client);
+
+ // IMO, read of final "sessionUpcall connection closed" packet
+ // should come here instead of in iphone_free_device
+
ret = iphone_mux_free_client(client->connection);
}
- if (client->ssl_session)
- gnutls_deinit(*client->ssl_session);
- free(client->ssl_session);
free(client);
return ret;
}
@@ -512,6 +614,70 @@ iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, ch
return ret;
}
+/**
+ * Performs the Goodbye Request to tell the device the communication
+ * session is now closed.
+ *
+ * @param control The lockdown client
+ */
+void lockdownd_close(iphone_lckd_client_t control)
+{
+ if (!control)
+ return; //IPHONE_E_INVALID_ARG;
+
+ int bytes = 0, i = 0;
+ iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR;
+
+ plist_t dict = plist_new_dict();
+ plist_add_sub_element(dict, PLIST_KEY, (void *) "Request", strlen("Request"));
+ plist_add_sub_element(dict, PLIST_STRING, (void *) "Goodbye", strlen("Goodbye"));
+
+ log_debug_msg("lockdownd_close() called\n");
+ char *XML_content = NULL;
+ uint32_t length = 0;
+
+ plist_to_xml(dict, &XML_content, &length);
+ log_debug_msg("Send msg :\nsize : %i\nxml : %s", length, XML_content);
+ ret = iphone_lckd_send(control, XML_content, length, &bytes);
+
+ free(XML_content);
+ XML_content = NULL;
+ plist_free(dict);
+ dict = NULL;
+
+ ret = iphone_lckd_recv(control, &XML_content, &bytes);
+ log_debug_msg("Receive msg :\nsize : %i\nxml : %s", bytes, XML_content);
+ plist_from_xml(XML_content, bytes, &dict);
+
+ if (!dict) {
+ log_debug_msg("lockdownd_close(): IPHONE_E_PLIST_ERROR\n");
+ return; // IPHONE_E_PLIST_ERROR;
+ }
+
+ plist_t query_node = plist_find_node(dict, PLIST_STRING, "Goodbye", strlen("Goodbye"));
+ plist_t result_node = plist_get_next_sibling(query_node);
+ plist_t value_node = plist_get_next_sibling(result_node);
+
+ plist_type result_type;
+ plist_type value_type;
+
+ char *result_value = NULL;
+ char *value_value = NULL;
+ uint64_t result_length = 0;
+ uint64_t value_length = 0;
+
+ plist_get_type_and_value(result_node, &result_type, (void *) (&result_value), &result_length);
+ plist_get_type_and_value(value_node, &value_type, (void *) (&value_value), &value_length);
+
+ if (result_type == PLIST_KEY &&
+ value_type == PLIST_STRING && !strcmp(result_value, "Result") && !strcmp(value_value, "Success")) {
+ log_debug_msg("lockdownd_close(): success\n");
+ ret = IPHONE_E_SUCCESS;
+ }
+
+ return; // ret;
+}
+
/** Generates the device certificate from the public key as well as the host
* and root certificates.
*
@@ -654,6 +820,7 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c
uint32_t length = 0, bytes = 0, return_me = 0;
iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR;
+ control->session_id[0] = '\0';
/* Setup DevicePublicKey request plist */
dict = plist_new_dict();
@@ -699,7 +866,7 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c
XML_content = NULL;
plist_free(dict);
dict = NULL;
-
+ ret = IPHONE_E_SSL_ERROR;
if (result_key_type == PLIST_KEY &&
result_value_type == PLIST_STRING && !strcmp(result_key, "Result") && !strcmp(result_value, "Success")) {
// Set up GnuTLS...
@@ -749,12 +916,34 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c
return IPHONE_E_SSL_ERROR;
} else {
control->in_SSL = 1;
- return IPHONE_E_SUCCESS;
+ ret = IPHONE_E_SUCCESS;
}
}
+ //store session id
+ plist_t session_node = plist_find_node(dict, PLIST_KEY, "SessionID", strlen("SessionID"));
+ if (session_node) {
+
+ plist_type session_node_val_type;
+ char *session_id = NULL;
+ uint64_t session_id_length = 0;
+ plist_t session_node_val = plist_get_next_sibling(session_node);
+
+ plist_get_type_and_value(session_node_val, &session_node_val_type, (void *) (&session_id),
+ &session_id_length);
+ if (session_node_val_type == PLIST_STRING && session_id_length > 0) {
+ // we need to store the session ID for StopSession
+ strcpy(control->session_id, session_id);
+ log_debug_msg("SessionID: %s\n", control->session_id);
+ return ret;
+ }
+ }
+
+ if (ret == IPHONE_E_SUCCESS) {
+ log_debug_msg("Failed to get SessionID!\n");
+ return ret;
+ }
log_debug_msg("Apparently failed negotiating with lockdownd.\n");
- log_debug_msg("Responding dictionary: \n");
return IPHONE_E_SSL_ERROR;
} else {
log_debug_msg("Didn't get enough bytes.\n");
diff --git a/src/lockdown.h b/src/lockdown.h
index 8ca8a7f..cdc46b8 100644
--- a/src/lockdown.h
+++ b/src/lockdown.h
@@ -37,6 +37,7 @@ struct iphone_lckd_client_int {
int in_SSL;
char *gtls_buffer_hack;
int gtls_buffer_hack_len;
+ char session_id[40];
};
iphone_lckd_client_t new_lockdownd_client(iphone_device_t phone);
diff --git a/src/usbmux.c b/src/usbmux.c
index 427b880..eb7ec97 100644
--- a/src/usbmux.c
+++ b/src/usbmux.c
@@ -182,8 +182,11 @@ iphone_error_t iphone_mux_free_client(iphone_umux_client_t client)
return IPHONE_E_INVALID_ARG;
client->header->tcp_flags = 0x04;
+ client->header->length = htonl(0x1C);
client->header->scnt = htonl(client->header->scnt);
client->header->ocnt = htonl(client->header->ocnt);
+ client->header->window = 0;
+ client->header->length16 = htons(0x1C);
int bytes = 0;
bytes = usb_bulk_write(client->phone->device, BULKOUT, (char *) client->header, sizeof(usbmux_tcp_header), 800);
diff --git a/src/utils.c b/src/utils.c
index ceb1f5d..fb98471 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -56,11 +56,35 @@ void log_debug_msg(const char *format, ...)
inline void log_debug_buffer(const char *data, const int length)
{
#ifndef STRIP_DEBUG_CODE
+ int i;
+ int j;
+ unsigned char c;
- /* run the real fprintf */
- if (toto_debug)
- fwrite(data, 1, length, stderr);
-
+ if (toto_debug) {
+ for (i = 0; i < length; i += 16) {
+ fprintf(stderr, "%04x: ", i);
+ for (j = 0; j < 16; j++) {
+ if (i + j >= length) {
+ fprintf(stderr, " ");
+ continue;
+ }
+ fprintf(stderr, "%02hhx ", *(data + i + j));
+ }
+ fprintf(stderr, " | ");
+ for (j = 0; j < 16; j++) {
+ if (i + j >= length)
+ break;
+ c = *(data + i + j);
+ if ((c < 32) || (c > 127)) {
+ fprintf(stderr, ".");
+ continue;
+ }
+ fprintf(stderr, "%c", c);
+ }
+ fprintf(stderr, "\n");
+ }
+ fprintf(stderr, "\n");
+ }
#endif
}