summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2009-01-08 18:17:21 +0100
committerGravatar Jonathan Beck2009-01-08 18:17:21 +0100
commitef98ef7211bc6277e9a87349f0405957ab264936 (patch)
tree9b51d84d1d91f27734882cbc0f27c763721e6669
parent5cde55426112a8cb79d809dae5f61e347c007212 (diff)
downloadlibimobiledevice-ef98ef7211bc6277e9a87349f0405957ab264936.tar.gz
libimobiledevice-ef98ef7211bc6277e9a87349f0405957ab264936.tar.bz2
Perform proper goodby on lockdown shutdown.
-rw-r--r--src/iphone.c59
-rw-r--r--src/lockdown.c178
-rw-r--r--src/lockdown.h1
-rw-r--r--src/usbmux.c3
-rw-r--r--src/utils.c34
5 files changed, 260 insertions, 15 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 @@
28#include <stdlib.h> 28#include <stdlib.h>
29#include <string.h> 29#include <string.h>
30 30
31/**
32 * This function sets the configuration of the given device to 3
33 * and claims the interface 1. If usb_set_configuration fails, it detaches
34 * the kernel driver that blocks the device, and retries configuration.
35 *
36 * @param phone which device to configure
37 */
38static void iphone_config_usb_device(iphone_device_t phone)
39{
40 int ret;
41
42 log_debug_msg("setting configuration... ");
43 ret = usb_set_configuration(phone->device, 3);
44 if (ret != 0) {
45 log_debug_msg("Hm, usb_set_configuration returned %d: %s, trying to fix:\n", ret, strerror(-ret));
46 log_debug_msg("-> detaching kernel driver... ");
47 ret =
48 usb_detach_kernel_driver_np(phone->device,
49 phone->__device->config->interface->altsetting->bInterfaceNumber);
50 if (ret != 0) {
51 log_debug_msg("usb_detach_kernel_driver_np returned %d: %s\n", ret, strerror(-ret));
52 } else {
53 log_debug_msg("done.\n");
54 log_debug_msg("setting configuration again... ");
55 ret = usb_set_configuration(phone->device, 3);
56 if (ret != 0) {
57 log_debug_msg("Error: usb_set_configuration returned %d: %s\n", ret, strerror(-ret));
58 } else {
59 log_debug_msg("done.\n");
60 }
61 }
62 } else {
63 log_debug_msg("done.\n");
64 }
65
66 log_debug_msg("claiming interface... ");
67 ret = usb_claim_interface(phone->device, 1);
68 if (ret != 0) {
69 log_debug_msg("Error: usb_claim_interface returned %d: %s\n", ret, strerror(-ret));
70 } else {
71 log_debug_msg("done.\n");
72 }
73}
31 74
32/** 75/**
33 * Given a USB bus and device number, returns a device handle to the iPhone on 76 * 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,
73 if (dev->devnum == dev_n) { 116 if (dev->devnum == dev_n) {
74 phone->__device = dev; 117 phone->__device = dev;
75 phone->device = usb_open(phone->__device); 118 phone->device = usb_open(phone->__device);
76 usb_set_configuration(phone->device, 3); 119 iphone_config_usb_device(phone);
77 usb_claim_interface(phone->device, 1);
78 goto found; 120 goto found;
79 } 121 }
80 122
@@ -115,9 +157,10 @@ static iphone_error_t iphone_get_specific_device(unsigned int bus_n, int dev_n,
115 return IPHONE_E_SUCCESS; 157 return IPHONE_E_SUCCESS;
116 } else { 158 } else {
117 // Bad header 159 // Bad header
160 log_debug_msg("get_iPhone(): Received a bad header/invalid version number.\n");
161 log_debug_buffer((char *) version, sizeof(*version));
118 iphone_free_device(phone); 162 iphone_free_device(phone);
119 free(version); 163 free(version);
120 log_debug_msg("get_iPhone(): Received a bad header/invalid version number.");
121 return IPHONE_E_BAD_HEADER; 164 return IPHONE_E_BAD_HEADER;
122 } 165 }
123 166
@@ -173,13 +216,21 @@ iphone_error_t iphone_free_device(iphone_device_t device)
173 if (!device) 216 if (!device)
174 return IPHONE_E_INVALID_ARG; 217 return IPHONE_E_INVALID_ARG;
175 iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; 218 iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR;
219 int bytes;
220 unsigned char buf[512];
221
222 // read final package
223 bytes = usb_bulk_read(device->device, BULKIN, (void *) &buf, 512, 1000);
224 if (bytes > 0) {
225 log_debug_msg("iphone_free_device: final read returned\n");
226 log_debug_buffer(buf, bytes);
227 }
176 228
177 if (device->buffer) { 229 if (device->buffer) {
178 free(device->buffer); 230 free(device->buffer);
179 } 231 }
180 if (device->device) { 232 if (device->device) {
181 usb_release_interface(device->device, 1); 233 usb_release_interface(device->device, 1);
182 usb_reset(device->device);
183 usb_close(device->device); 234 usb_close(device->device);
184 ret = IPHONE_E_SUCCESS; 235 ret = IPHONE_E_SUCCESS;
185 } 236 }
diff --git a/src/lockdown.c b/src/lockdown.c
index cf0d99e..ab168a3 100644
--- a/src/lockdown.c
+++ b/src/lockdown.c
@@ -92,6 +92,97 @@ iphone_lckd_client_t new_lockdownd_client(iphone_device_t phone)
92 return control; 92 return control;
93} 93}
94 94
95/**
96 * Closes the lockdownd communication session, by sending
97 * the StopSession Request to the device.
98 *
99 * @param control The lockdown client
100 */
101static void iphone_lckd_stop_session(iphone_lckd_client_t control)
102{
103 if (!control)
104 return; // IPHONE_E_INVALID_ARG;
105 xmlDocPtr plist = new_plist();
106 xmlNode *dict, *key;
107 char **dictionary;
108 int bytes = 0, i = 0;
109 iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR;
110
111 log_debug_msg("lockdownd_stop_session() called\n");
112 dict = add_child_to_plist(plist, "dict", "\n", NULL, 0);
113 key = add_key_str_dict_element(plist, dict, "Request", "StopSession", 1);
114 key = add_key_str_dict_element(plist, dict, "SessionID", control->session_id, 1);
115
116 char *XML_content;
117 uint32 length;
118
119 xmlDocDumpMemory(plist, (xmlChar **) & XML_content, &length);
120 ret = iphone_lckd_send(control, XML_content, length, &bytes);
121
122 xmlFree(XML_content);
123 xmlFreeDoc(plist);
124 plist = NULL;
125 ret = iphone_lckd_recv(control, &XML_content, &bytes);
126
127 plist = xmlReadMemory(XML_content, bytes, NULL, NULL, 0);
128 if (!plist) {
129 fprintf(stderr, "lockdownd_stop_session(): IPHONE_E_PLIST_ERROR\n");
130 return; //IPHONE_E_PLIST_ERROR;
131 }
132 dict = xmlDocGetRootElement(plist);
133 for (dict = dict->children; dict; dict = dict->next) {
134 if (!xmlStrcmp(dict->name, "dict"))
135 break;
136 }
137 if (!dict) {
138 fprintf(stderr, "lockdownd_stop_session(): IPHONE_E_DICT_ERROR\n");
139 return; //IPHONE_E_DICT_ERROR;
140 }
141 dictionary = read_dict_element_strings(dict);
142 xmlFreeDoc(plist);
143 free(XML_content);
144
145 for (i = 0; dictionary[i]; i += 2) {
146 if (!strcmp(dictionary[i], "Result") && !strcmp(dictionary[i + 1], "Success")) {
147 log_debug_msg("lockdownd_stop_session(): success\n");
148 ret = IPHONE_E_SUCCESS;
149 break;
150 }
151 }
152
153 free_dictionary(dictionary);
154 return; //ret;
155}
156
157/**
158 * Shuts down the SSL session by first calling iphone_lckd_stop_session
159 * to cleanly close the lockdownd communication session, and then
160 * performing a close notify, which is done by "gnutls_bye".
161 *
162 * @param client The lockdown client
163 */
164static void iphone_lckd_stop_SSL_session(iphone_lckd_client_t client)
165{
166 if (!client) {
167 log_debug_msg("lockdownd_stop_SSL_session(): invalid argument!\n");
168 return;
169 }
170
171 if (client->in_SSL) {
172 log_debug_msg("Stopping SSL Session\n");
173 iphone_lckd_stop_session(client);
174 log_debug_msg("Sending SSL close notify\n");
175 gnutls_bye(*client->ssl_session, GNUTLS_SHUT_RDWR);
176 }
177 if (client->ssl_session) {
178 gnutls_deinit(*client->ssl_session);
179 free(client->ssl_session);
180 }
181 client->in_SSL = 0;
182 client->gtls_buffer_hack_len = 0; // dunno if required?!
183
184 return;
185}
95 186
96/** Closes the lockdownd client and does the necessary housekeeping. 187/** Closes the lockdownd client and does the necessary housekeeping.
97 * 188 *
@@ -103,13 +194,17 @@ iphone_error_t iphone_lckd_free_client(iphone_lckd_client_t client)
103 return IPHONE_E_INVALID_ARG; 194 return IPHONE_E_INVALID_ARG;
104 iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; 195 iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR;
105 196
197 iphone_lckd_stop_SSL_session(client);
198
106 if (client->connection) { 199 if (client->connection) {
200 lockdownd_close(client);
201
202 // IMO, read of final "sessionUpcall connection closed" packet
203 // should come here instead of in iphone_free_device
204
107 ret = iphone_mux_free_client(client->connection); 205 ret = iphone_mux_free_client(client->connection);
108 } 206 }
109 207
110 if (client->ssl_session)
111 gnutls_deinit(*client->ssl_session);
112 free(client->ssl_session);
113 free(client); 208 free(client);
114 return ret; 209 return ret;
115} 210}
@@ -520,6 +615,66 @@ iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, ch
520 return ret; 615 return ret;
521} 616}
522 617
618/**
619 * Performs the Goodbye Request to tell the device the communication
620 * session is now closed.
621 *
622 * @param control The lockdown client
623 */
624void lockdownd_close(iphone_lckd_client_t control)
625{
626 if (!control)
627 return; // IPHONE_E_INVALID_ARG;
628 xmlDocPtr plist = new_plist();
629 xmlNode *dict, *key;
630 char **dictionary;
631 int bytes = 0, i = 0;
632 iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR;
633
634 log_debug_msg("lockdownd_close() called\n");
635 dict = add_child_to_plist(plist, "dict", "\n", NULL, 0);
636 key = add_key_str_dict_element(plist, dict, "Request", "Goodbye", 1);
637 char *XML_content;
638 uint32 length;
639
640 xmlDocDumpMemory(plist, (xmlChar **) & XML_content, &length);
641 ret = iphone_lckd_send(control, XML_content, length, &bytes);
642
643 xmlFree(XML_content);
644 xmlFreeDoc(plist);
645 plist = NULL;
646 ret = iphone_lckd_recv(control, &XML_content, &bytes);
647
648 plist = xmlReadMemory(XML_content, bytes, NULL, NULL, 0);
649 if (!plist) {
650 fprintf(stderr, "lockdownd_close(): IPHONE_E_PLIST_ERROR\n");
651 return; //IPHONE_E_PLIST_ERROR;
652 }
653 dict = xmlDocGetRootElement(plist);
654 for (dict = dict->children; dict; dict = dict->next) {
655 if (!xmlStrcmp(dict->name, "dict"))
656 break;
657 }
658 if (!dict) {
659 fprintf(stderr, "lockdownd_close(): IPHONE_E_DICT_ERROR\n");
660 return; //IPHONE_E_DICT_ERROR;
661 }
662 dictionary = read_dict_element_strings(dict);
663 xmlFreeDoc(plist);
664 free(XML_content);
665
666 for (i = 0; dictionary[i]; i += 2) {
667 if (!strcmp(dictionary[i], "Result") && !strcmp(dictionary[i + 1], "Success")) {
668 log_debug_msg("lockdownd_close(): success\n");
669 ret = IPHONE_E_SUCCESS;
670 break;
671 }
672 }
673
674 free_dictionary(dictionary);
675 return; //ret;
676}
677
523/** Generates the device certificate from the public key as well as the host 678/** Generates the device certificate from the public key as well as the host
524 * and root certificates. 679 * and root certificates.
525 * 680 *
@@ -664,6 +819,8 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c
664 iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; 819 iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR;
665 // end variables 820 // end variables
666 821
822 control->session_id[0] = '\0';
823
667 key = add_key_str_dict_element(plist, dict, "HostID", HostID, 1); 824 key = add_key_str_dict_element(plist, dict, "HostID", HostID, 1);
668 if (!key) { 825 if (!key) {
669 log_debug_msg("Couldn't add a key.\n"); 826 log_debug_msg("Couldn't add a key.\n");
@@ -699,6 +856,7 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c
699 dictionary = read_dict_element_strings(dict); 856 dictionary = read_dict_element_strings(dict);
700 xmlFreeDoc(plist); 857 xmlFreeDoc(plist);
701 free(what2send); 858 free(what2send);
859 ret = IPHONE_E_SSL_ERROR;
702 for (i = 0; dictionary[i]; i += 2) { 860 for (i = 0; dictionary[i]; i += 2) {
703 if (!strcmp(dictionary[i], "Result") && !strcmp(dictionary[i + 1], "Success")) { 861 if (!strcmp(dictionary[i], "Result") && !strcmp(dictionary[i + 1], "Success")) {
704 // Set up GnuTLS... 862 // Set up GnuTLS...
@@ -741,8 +899,6 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c
741 return_me = gnutls_handshake(*control->ssl_session); 899 return_me = gnutls_handshake(*control->ssl_session);
742 log_debug_msg("GnuTLS handshake done...\n"); 900 log_debug_msg("GnuTLS handshake done...\n");
743 901
744 free_dictionary(dictionary);
745
746 if (return_me != GNUTLS_E_SUCCESS) { 902 if (return_me != GNUTLS_E_SUCCESS) {
747 log_debug_msg("GnuTLS reported something wrong.\n"); 903 log_debug_msg("GnuTLS reported something wrong.\n");
748 gnutls_perror(return_me); 904 gnutls_perror(return_me);
@@ -750,10 +906,20 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c
750 return IPHONE_E_SSL_ERROR; 906 return IPHONE_E_SSL_ERROR;
751 } else { 907 } else {
752 control->in_SSL = 1; 908 control->in_SSL = 1;
753 return IPHONE_E_SUCCESS; 909 ret = IPHONE_E_SUCCESS;
754 } 910 }
911 } else if (!strcmp(dictionary[i], "SessionID")) {
912 // we need to store the session ID for StopSession
913 strcpy(control->session_id, dictionary[i + 1]);
914 log_debug_msg("SessionID: %s\n", control->session_id);
915 free_dictionary(dictionary);
916 return ret;
755 } 917 }
756 } 918 }
919 if (ret == IPHONE_E_SUCCESS) {
920 log_debug_msg("Failed to get SessionID!\n");
921 return ret;
922 }
757 923
758 log_debug_msg("Apparently failed negotiating with lockdownd.\n"); 924 log_debug_msg("Apparently failed negotiating with lockdownd.\n");
759 log_debug_msg("Responding dictionary: \n"); 925 log_debug_msg("Responding dictionary: \n");
diff --git a/src/lockdown.h b/src/lockdown.h
index 79ca37e..8b4f27c 100644
--- a/src/lockdown.h
+++ b/src/lockdown.h
@@ -38,6 +38,7 @@ struct iphone_lckd_client_int {
38 int in_SSL; 38 int in_SSL;
39 char *gtls_buffer_hack; 39 char *gtls_buffer_hack;
40 int gtls_buffer_hack_len; 40 int gtls_buffer_hack_len;
41 char session_id[40];
41}; 42};
42 43
43char *lockdownd_generate_hostid(void); 44char *lockdownd_generate_hostid(void);
diff --git a/src/usbmux.c b/src/usbmux.c
index 770d0db..c7ac7ef 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)
182 return IPHONE_E_INVALID_ARG; 182 return IPHONE_E_INVALID_ARG;
183 183
184 client->header->tcp_flags = 0x04; 184 client->header->tcp_flags = 0x04;
185 client->header->length = htonl(0x1C);
185 client->header->scnt = htonl(client->header->scnt); 186 client->header->scnt = htonl(client->header->scnt);
186 client->header->ocnt = htonl(client->header->ocnt); 187 client->header->ocnt = htonl(client->header->ocnt);
188 client->header->window = 0;
189 client->header->length16 = htons(0x1C);
187 int bytes = 0; 190 int bytes = 0;
188 191
189 bytes = usb_bulk_write(client->phone->device, BULKOUT, (char *) client->header, sizeof(usbmux_tcp_header), 800); 192 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 049777a..fb98471 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -46,7 +46,7 @@ void log_debug_msg(const char *format, ...)
46 va_start(args, format); 46 va_start(args, format);
47 47
48 if (toto_debug) 48 if (toto_debug)
49 fprintf(stderr, format, args); 49 vfprintf(stderr, format, args);
50 50
51 va_end(args); 51 va_end(args);
52 52
@@ -56,11 +56,35 @@ void log_debug_msg(const char *format, ...)
56inline void log_debug_buffer(const char *data, const int length) 56inline void log_debug_buffer(const char *data, const int length)
57{ 57{
58#ifndef STRIP_DEBUG_CODE 58#ifndef STRIP_DEBUG_CODE
59 int i;
60 int j;
61 unsigned char c;
59 62
60 /* run the real fprintf */ 63 if (toto_debug) {
61 if (toto_debug) 64 for (i = 0; i < length; i += 16) {
62 fwrite(data, 1, length, stderr); 65 fprintf(stderr, "%04x: ", i);
63 66 for (j = 0; j < 16; j++) {
67 if (i + j >= length) {
68 fprintf(stderr, " ");
69 continue;
70 }
71 fprintf(stderr, "%02hhx ", *(data + i + j));
72 }
73 fprintf(stderr, " | ");
74 for (j = 0; j < 16; j++) {
75 if (i + j >= length)
76 break;
77 c = *(data + i + j);
78 if ((c < 32) || (c > 127)) {
79 fprintf(stderr, ".");
80 continue;
81 }
82 fprintf(stderr, "%c", c);
83 }
84 fprintf(stderr, "\n");
85 }
86 fprintf(stderr, "\n");
87 }
64#endif 88#endif
65} 89}
66 90