summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/AFC.c128
-rw-r--r--src/InstallationProxy.c112
-rw-r--r--src/InstallationProxy.h3
-rw-r--r--src/Makefile.am4
-rw-r--r--src/MobileSync.c153
-rw-r--r--src/MobileSync.h3
-rw-r--r--src/NotificationProxy.c98
-rw-r--r--src/NotificationProxy.h17
-rw-r--r--src/SBServices.c139
-rw-r--r--src/SBServices.h3
-rw-r--r--src/debug.c (renamed from src/utils.c)106
-rw-r--r--src/debug.h45
-rw-r--r--src/device_link_service.c299
-rw-r--r--src/device_link_service.h51
-rw-r--r--src/iphone.c528
-rw-r--r--src/iphone.h18
-rw-r--r--src/lockdown.c777
-rw-r--r--src/lockdown.h14
-rw-r--r--src/property_list_service.c346
-rw-r--r--src/property_list_service.h59
-rw-r--r--src/userpref.c31
-rw-r--r--src/userpref.h1
-rw-r--r--src/utils.h33
23 files changed, 1905 insertions, 1063 deletions
diff --git a/src/AFC.c b/src/AFC.c
index 956c8fc..db00735 100644
--- a/src/AFC.c
+++ b/src/AFC.c
@@ -25,7 +25,7 @@
25 25
26#include "AFC.h" 26#include "AFC.h"
27#include "iphone.h" 27#include "iphone.h"
28#include "utils.h" 28#include "debug.h"
29 29
30// This is the maximum size an AFC data packet can be 30// This is the maximum size an AFC data packet can be
31static const int MAXIMUM_PACKET_SIZE = (2 << 15); 31static const int MAXIMUM_PACKET_SIZE = (2 << 15);
@@ -36,7 +36,7 @@ static const int MAXIMUM_PACKET_SIZE = (2 << 15);
36 */ 36 */
37static void afc_lock(afc_client_t client) 37static void afc_lock(afc_client_t client)
38{ 38{
39 log_debug_msg("%s: Locked\n", __func__); 39 debug_info("Locked");
40 g_mutex_lock(client->mutex); 40 g_mutex_lock(client->mutex);
41} 41}
42 42
@@ -46,30 +46,33 @@ static void afc_lock(afc_client_t client)
46 */ 46 */
47static void afc_unlock(afc_client_t client) 47static void afc_unlock(afc_client_t client)
48{ 48{
49 log_debug_msg("%s: Unlocked\n", __func__); 49 debug_info("Unlocked");
50 g_mutex_unlock(client->mutex); 50 g_mutex_unlock(client->mutex);
51} 51}
52 52
53/** Makes a connection to the AFC service on the phone. 53/** Makes a connection to the AFC service on the phone.
54 * 54 *
55 * @param phone The iPhone to connect on. 55 * @param device The device to connect to.
56 * @param s_port The source port. 56 * @param port The destination port.
57 * @param d_port The destination port. 57 * @param client Pointer that will be set to a newly allocated afc_client_t
58 * upon successful return.
58 * 59 *
59 * @return A handle to the newly-connected client or NULL upon error. 60 * @return AFC_E_SUCCESS on success, AFC_E_INVALID_ARGUMENT when device or port
61 * is invalid, AFC_E_MUX_ERROR when the connection failed, or AFC_E_NO_MEM
62 * when there's a memory allocation problem.
60 */ 63 */
61afc_error_t afc_client_new(iphone_device_t device, int dst_port, afc_client_t * client) 64afc_error_t afc_client_new(iphone_device_t device, uint16_t port, afc_client_t * client)
62{ 65{
63 /* makes sure thread environment is available */ 66 /* makes sure thread environment is available */
64 if (!g_thread_supported()) 67 if (!g_thread_supported())
65 g_thread_init(NULL); 68 g_thread_init(NULL);
66 69
67 if (!device) 70 if (!device || port==0)
68 return AFC_E_INVALID_ARGUMENT; 71 return AFC_E_INVALID_ARGUMENT;
69 72
70 /* attempt connection */ 73 /* attempt connection */
71 iphone_connection_t connection = NULL; 74 iphone_connection_t connection = NULL;
72 if (iphone_device_connect(device, dst_port, &connection) != IPHONE_E_SUCCESS) { 75 if (iphone_device_connect(device, port, &connection) != IPHONE_E_SUCCESS) {
73 return AFC_E_MUX_ERROR; 76 return AFC_E_MUX_ERROR;
74 } 77 }
75 78
@@ -155,12 +158,11 @@ static afc_error_t afc_dispatch_packet(afc_client_t client, const char *data, ui
155 if (client->afc_packet->this_length != client->afc_packet->entire_length) { 158 if (client->afc_packet->this_length != client->afc_packet->entire_length) {
156 offset = client->afc_packet->this_length - sizeof(AFCPacket); 159 offset = client->afc_packet->this_length - sizeof(AFCPacket);
157 160
158 log_debug_msg("%s: Offset: %i\n", __func__, offset); 161 debug_info("Offset: %i", offset);
159 if ((length) < (client->afc_packet->entire_length - client->afc_packet->this_length)) { 162 if ((length) < (client->afc_packet->entire_length - client->afc_packet->this_length)) {
160 log_debug_msg("%s: Length did not resemble what it was supposed", __func__); 163 debug_info("Length did not resemble what it was supposed to based on packet");
161 log_debug_msg("to based on the packet.\n"); 164 debug_info("length minus offset: %i", length - offset);
162 log_debug_msg("%s: length minus offset: %i\n", __func__, length - offset); 165 debug_info("rest of packet: %i\n", client->afc_packet->entire_length - client->afc_packet->this_length);
163 log_debug_msg("%s: rest of packet: %i\n", __func__, client->afc_packet->entire_length - client->afc_packet->this_length);
164 return AFC_E_INTERNAL_ERROR; 166 return AFC_E_INTERNAL_ERROR;
165 } 167 }
166 168
@@ -182,10 +184,10 @@ static afc_error_t afc_dispatch_packet(afc_client_t client, const char *data, ui
182 } 184 }
183 *bytes_sent += sent; 185 *bytes_sent += sent;
184 186
185 log_debug_msg("%s: sent the first now go with the second\n", __func__); 187 debug_info("sent the first now go with the second");
186 log_debug_msg("%s: Length: %i\n", __func__, length - offset); 188 debug_info("Length: %i", length - offset);
187 log_debug_msg("%s: Buffer: \n", __func__); 189 debug_info("Buffer: ");
188 log_debug_buffer(data + offset, length - offset); 190 debug_buffer(data + offset, length - offset);
189 191
190 sent = 0; 192 sent = 0;
191 iphone_device_send(client->connection, data + offset, length - offset, &sent); 193 iphone_device_send(client->connection, data + offset, length - offset, &sent);
@@ -193,11 +195,10 @@ static afc_error_t afc_dispatch_packet(afc_client_t client, const char *data, ui
193 *bytes_sent = sent; 195 *bytes_sent = sent;
194 return AFC_E_SUCCESS; 196 return AFC_E_SUCCESS;
195 } else { 197 } else {
196 log_debug_msg("%s: doin things the old way\n", __func__); 198 debug_info("doin things the old way");
197 log_debug_msg("%s: packet length = %i\n", __func__, client->afc_packet->this_length); 199 debug_info("packet length = %i", client->afc_packet->this_length);
198 200
199 log_debug_buffer((char*)client->afc_packet, sizeof(AFCPacket)); 201 debug_buffer((char*)client->afc_packet, sizeof(AFCPacket));
200 log_debug_msg("\n");
201 202
202 /* send AFC packet header */ 203 /* send AFC packet header */
203 AFCPacket_to_LE(client->afc_packet); 204 AFCPacket_to_LE(client->afc_packet);
@@ -209,10 +210,9 @@ static afc_error_t afc_dispatch_packet(afc_client_t client, const char *data, ui
209 *bytes_sent += sent; 210 *bytes_sent += sent;
210 /* send AFC packet data (if there's data to send) */ 211 /* send AFC packet data (if there's data to send) */
211 if (length > 0) { 212 if (length > 0) {
212 log_debug_msg("%s: packet data follows\n", __func__); 213 debug_info("packet data follows");
213 214
214 log_debug_buffer(data, length); 215 debug_buffer(data, length);
215 log_debug_msg("\n");
216 iphone_device_send(client->connection, data, length, &sent); 216 iphone_device_send(client->connection, data, length, &sent);
217 *bytes_sent += sent; 217 *bytes_sent += sent;
218 } 218 }
@@ -244,36 +244,36 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint3
244 iphone_device_recv(client->connection, (char*)&header, sizeof(AFCPacket), bytes_recv); 244 iphone_device_recv(client->connection, (char*)&header, sizeof(AFCPacket), bytes_recv);
245 AFCPacket_from_LE(&header); 245 AFCPacket_from_LE(&header);
246 if (*bytes_recv == 0) { 246 if (*bytes_recv == 0) {
247 log_debug_msg("%s: Just didn't get enough.\n", __func__); 247 debug_info("Just didn't get enough.");
248 *dump_here = NULL; 248 *dump_here = NULL;
249 return AFC_E_MUX_ERROR; 249 return AFC_E_MUX_ERROR;
250 } else if (*bytes_recv < sizeof(AFCPacket)) { 250 } else if (*bytes_recv < sizeof(AFCPacket)) {
251 log_debug_msg("%s: Did not even get the AFCPacket header\n", __func__); 251 debug_info("Did not even get the AFCPacket header");
252 *dump_here = NULL; 252 *dump_here = NULL;
253 return AFC_E_MUX_ERROR; 253 return AFC_E_MUX_ERROR;
254 } 254 }
255 255
256 /* check if it's a valid AFC header */ 256 /* check if it's a valid AFC header */
257 if (strncmp(header.magic, AFC_MAGIC, AFC_MAGIC_LEN)) { 257 if (strncmp(header.magic, AFC_MAGIC, AFC_MAGIC_LEN)) {
258 log_debug_msg("%s: Invalid AFC packet received (magic != " AFC_MAGIC ")!\n", __func__); 258 debug_info("Invalid AFC packet received (magic != " AFC_MAGIC ")!");
259 } 259 }
260 260
261 /* check if it has the correct packet number */ 261 /* check if it has the correct packet number */
262 if (header.packet_num != client->afc_packet->packet_num) { 262 if (header.packet_num != client->afc_packet->packet_num) {
263 /* otherwise print a warning but do not abort */ 263 /* otherwise print a warning but do not abort */
264 log_debug_msg("%s: ERROR: Unexpected packet number (%lld != %lld) aborting.\n", __func__, header.packet_num, client->afc_packet->packet_num); 264 debug_info("ERROR: Unexpected packet number (%lld != %lld) aborting.", header.packet_num, client->afc_packet->packet_num);
265 *dump_here = NULL; 265 *dump_here = NULL;
266 return AFC_E_OP_HEADER_INVALID; 266 return AFC_E_OP_HEADER_INVALID;
267 } 267 }
268 268
269 /* then, read the attached packet */ 269 /* then, read the attached packet */
270 if (header.this_length < sizeof(AFCPacket)) { 270 if (header.this_length < sizeof(AFCPacket)) {
271 log_debug_msg("%s: Invalid AFCPacket header received!\n", __func__); 271 debug_info("Invalid AFCPacket header received!");
272 *dump_here = NULL; 272 *dump_here = NULL;
273 return AFC_E_OP_HEADER_INVALID; 273 return AFC_E_OP_HEADER_INVALID;
274 } else if ((header.this_length == header.entire_length) 274 } else if ((header.this_length == header.entire_length)
275 && header.entire_length == sizeof(AFCPacket)) { 275 && header.entire_length == sizeof(AFCPacket)) {
276 log_debug_msg("%s: Empty AFCPacket received!\n", __func__); 276 debug_info("Empty AFCPacket received!");
277 *dump_here = NULL; 277 *dump_here = NULL;
278 *bytes_recv = 0; 278 *bytes_recv = 0;
279 if (header.operation == AFC_OP_DATA) { 279 if (header.operation == AFC_OP_DATA) {
@@ -283,14 +283,14 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint3
283 } 283 }
284 } 284 }
285 285
286 log_debug_msg("%s: received AFC packet, full len=%lld, this len=%lld, operation=0x%llx\n", __func__, header.entire_length, header.this_length, header.operation); 286 debug_info("received AFC packet, full len=%lld, this len=%lld, operation=0x%llx", header.entire_length, header.this_length, header.operation);
287 287
288 entire_len = (uint32_t)header.entire_length - sizeof(AFCPacket); 288 entire_len = (uint32_t)header.entire_length - sizeof(AFCPacket);
289 this_len = (uint32_t)header.this_length - sizeof(AFCPacket); 289 this_len = (uint32_t)header.this_length - sizeof(AFCPacket);
290 290
291 /* this is here as a check (perhaps a different upper limit is good?) */ 291 /* this is here as a check (perhaps a different upper limit is good?) */
292 if (entire_len > (uint32_t)MAXIMUM_PACKET_SIZE) { 292 if (entire_len > (uint32_t)MAXIMUM_PACKET_SIZE) {
293 fprintf(stderr, "%s: entire_len is larger than MAXIMUM_PACKET_SIZE, (%d > %d)!\n", __func__, entire_len, MAXIMUM_PACKET_SIZE); 293 fprintf(stderr, "%s: entire_len is larger than MAXIMUM_PACKET_SIZE, (%d > %d)!", __func__, entire_len, MAXIMUM_PACKET_SIZE);
294 } 294 }
295 295
296 *dump_here = (char*)malloc(entire_len); 296 *dump_here = (char*)malloc(entire_len);
@@ -299,12 +299,12 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint3
299 if (*bytes_recv <= 0) { 299 if (*bytes_recv <= 0) {
300 free(*dump_here); 300 free(*dump_here);
301 *dump_here = NULL; 301 *dump_here = NULL;
302 log_debug_msg("%s: Did not get packet contents!\n", __func__); 302 debug_info("Did not get packet contents!");
303 return AFC_E_NOT_ENOUGH_DATA; 303 return AFC_E_NOT_ENOUGH_DATA;
304 } else if (*bytes_recv < this_len) { 304 } else if (*bytes_recv < this_len) {
305 free(*dump_here); 305 free(*dump_here);
306 *dump_here = NULL; 306 *dump_here = NULL;
307 log_debug_msg("%s: Could not receive this_len=%d bytes\n", __func__, this_len); 307 debug_info("Could not receive this_len=%d bytes", this_len);
308 return AFC_E_NOT_ENOUGH_DATA; 308 return AFC_E_NOT_ENOUGH_DATA;
309 } 309 }
310 } 310 }
@@ -315,13 +315,13 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint3
315 while (current_count < entire_len) { 315 while (current_count < entire_len) {
316 iphone_device_recv(client->connection, (*dump_here)+current_count, entire_len - current_count, bytes_recv); 316 iphone_device_recv(client->connection, (*dump_here)+current_count, entire_len - current_count, bytes_recv);
317 if (*bytes_recv <= 0) { 317 if (*bytes_recv <= 0) {
318 log_debug_msg("%s: Error receiving data (recv returned %d)\n", __func__, *bytes_recv); 318 debug_info("Error receiving data (recv returned %d)", *bytes_recv);
319 break; 319 break;
320 } 320 }
321 current_count += *bytes_recv; 321 current_count += *bytes_recv;
322 } 322 }
323 if (current_count < entire_len) { 323 if (current_count < entire_len) {
324 log_debug_msg("%s: WARNING: could not receive full packet (read %s, size %d)\n", __func__, current_count, entire_len); 324 debug_info("WARNING: could not receive full packet (read %s, size %d)", current_count, entire_len);
325 } 325 }
326 } 326 }
327 327
@@ -329,14 +329,14 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint3
329 param1 = *(uint64_t*)(*dump_here); 329 param1 = *(uint64_t*)(*dump_here);
330 } 330 }
331 331
332 log_debug_msg("%s: packet data size = %i\n", __func__, current_count); 332 debug_info("packet data size = %i", current_count);
333 log_debug_msg("%s: packet data follows\n", __func__); 333 debug_info("packet data follows");
334 log_debug_buffer(*dump_here, current_count); 334 debug_buffer(*dump_here, current_count);
335 335
336 /* check operation types */ 336 /* check operation types */
337 if (header.operation == AFC_OP_STATUS) { 337 if (header.operation == AFC_OP_STATUS) {
338 /* status response */ 338 /* status response */
339 log_debug_msg("%s: got a status response, code=%lld\n", __func__, param1); 339 debug_info("got a status response, code=%lld", param1);
340 340
341 if (param1 != AFC_E_SUCCESS) { 341 if (param1 != AFC_E_SUCCESS) {
342 /* error status */ 342 /* error status */
@@ -347,21 +347,21 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint3
347 } 347 }
348 } else if (header.operation == AFC_OP_DATA) { 348 } else if (header.operation == AFC_OP_DATA) {
349 /* data response */ 349 /* data response */
350 log_debug_msg("%s: got a data response\n", __func__); 350 debug_info("got a data response");
351 } else if (header.operation == AFC_OP_FILE_OPEN_RES) { 351 } else if (header.operation == AFC_OP_FILE_OPEN_RES) {
352 /* file handle response */ 352 /* file handle response */
353 log_debug_msg("%s: got a file handle response, handle=%lld\n", __func__, param1); 353 debug_info("got a file handle response, handle=%lld", param1);
354 } else if (header.operation == AFC_OP_FILE_TELL_RES) { 354 } else if (header.operation == AFC_OP_FILE_TELL_RES) {
355 /* tell response */ 355 /* tell response */
356 log_debug_msg("%s: got a tell response, position=%lld\n", __func__, param1); 356 debug_info("got a tell response, position=%lld", param1);
357 } else { 357 } else {
358 /* unknown operation code received */ 358 /* unknown operation code received */
359 free(*dump_here); 359 free(*dump_here);
360 *dump_here = NULL; 360 *dump_here = NULL;
361 *bytes_recv = 0; 361 *bytes_recv = 0;
362 362
363 log_debug_msg("%s: WARNING: Unknown operation code received 0x%llx param1=%lld\n", __func__, header.operation, param1); 363 debug_info("WARNING: Unknown operation code received 0x%llx param1=%lld", header.operation, param1);
364 fprintf(stderr, "%s: WARNING: Unknown operation code received 0x%llx param1=%lld\n", __func__, (long long)header.operation, (long long)param1); 364 fprintf(stderr, "%s: WARNING: Unknown operation code received 0x%llx param1=%lld", __func__, (long long)header.operation, (long long)param1);
365 365
366 return AFC_E_OP_NOT_SUPPORTED; 366 return AFC_E_OP_NOT_SUPPORTED;
367 } 367 }
@@ -728,7 +728,7 @@ afc_file_open(afc_client_t client, const char *filename,
728 free(data); 728 free(data);
729 729
730 if (ret != AFC_E_SUCCESS) { 730 if (ret != AFC_E_SUCCESS) {
731 log_debug_msg("%s: Didn't receive a response to the command\n", __func__); 731 debug_info("Didn't receive a response to the command");
732 afc_unlock(client); 732 afc_unlock(client);
733 return AFC_E_NOT_ENOUGH_DATA; 733 return AFC_E_NOT_ENOUGH_DATA;
734 } 734 }
@@ -743,7 +743,7 @@ afc_file_open(afc_client_t client, const char *filename,
743 return ret; 743 return ret;
744 } 744 }
745 745
746 log_debug_msg("%s: Didn't get any further data\n", __func__); 746 debug_info("Didn't get any further data");
747 747
748 afc_unlock(client); 748 afc_unlock(client);
749 749
@@ -770,14 +770,14 @@ afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length,
770 770
771 if (!client || !client->afc_packet || !client->connection || handle == 0) 771 if (!client || !client->afc_packet || !client->connection || handle == 0)
772 return AFC_E_INVALID_ARGUMENT; 772 return AFC_E_INVALID_ARGUMENT;
773 log_debug_msg("%s: called for length %i\n", __func__, length); 773 debug_info("called for length %i", length);
774 774
775 afc_lock(client); 775 afc_lock(client);
776 776
777 // Looping here to get around the maximum amount of data that 777 // Looping here to get around the maximum amount of data that
778 // afc_receive_data can handle 778 // afc_receive_data can handle
779 while (current_count < length) { 779 while (current_count < length) {
780 log_debug_msg("%s: current count is %i but length is %i\n", __func__, current_count, length); 780 debug_info("current count is %i but length is %i", current_count, length);
781 781
782 // Send the read command 782 // Send the read command
783 AFCFilePacket *packet = (AFCFilePacket *) malloc(sizeof(AFCFilePacket)); 783 AFCFilePacket *packet = (AFCFilePacket *) malloc(sizeof(AFCFilePacket));
@@ -794,8 +794,8 @@ afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length,
794 } 794 }
795 // Receive the data 795 // Receive the data
796 ret = afc_receive_data(client, &input, &bytes_loc); 796 ret = afc_receive_data(client, &input, &bytes_loc);
797 log_debug_msg("%s: afc_receive_data returned error: %d\n", __func__, ret); 797 debug_info("afc_receive_data returned error: %d", ret);
798 log_debug_msg("%s: bytes returned: %i\n", __func__, bytes_loc); 798 debug_info("bytes returned: %i", bytes_loc);
799 if (ret != AFC_E_SUCCESS) { 799 if (ret != AFC_E_SUCCESS) {
800 afc_unlock(client); 800 afc_unlock(client);
801 return ret; 801 return ret;
@@ -808,7 +808,7 @@ afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length,
808 return ret; 808 return ret;
809 } else { 809 } else {
810 if (input) { 810 if (input) {
811 log_debug_msg("%s: %d\n", __func__, bytes_loc); 811 debug_info("%d", bytes_loc);
812 memcpy(data + current_count, input, (bytes_loc > length) ? length : bytes_loc); 812 memcpy(data + current_count, input, (bytes_loc > length) ? length : bytes_loc);
813 free(input); 813 free(input);
814 input = NULL; 814 input = NULL;
@@ -816,7 +816,7 @@ afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length,
816 } 816 }
817 } 817 }
818 } 818 }
819 log_debug_msg("%s: returning current_count as %i\n", __func__, current_count); 819 debug_info("returning current_count as %i", current_count);
820 820
821 afc_unlock(client); 821 afc_unlock(client);
822 *bytes_read = current_count; 822 *bytes_read = current_count;
@@ -849,7 +849,7 @@ afc_file_write(afc_client_t client, uint64_t handle, const char *data, uint32_t
849 849
850 afc_lock(client); 850 afc_lock(client);
851 851
852 log_debug_msg("%s: Write length: %i\n", __func__, length); 852 debug_info("Write length: %i", length);
853 853
854 // Divide the file into segments. 854 // Divide the file into segments.
855 for (i = 0; i < segments; i++) { 855 for (i = 0; i < segments; i++) {
@@ -909,7 +909,7 @@ afc_file_write(afc_client_t client, uint64_t handle, const char *data, uint32_t
909 ret = afc_receive_data(client, &acknowledgement, &bytes_loc); 909 ret = afc_receive_data(client, &acknowledgement, &bytes_loc);
910 afc_unlock(client); 910 afc_unlock(client);
911 if (ret != AFC_E_SUCCESS) { 911 if (ret != AFC_E_SUCCESS) {
912 log_debug_msg("%s: uh oh?\n", __func__); 912 debug_info("uh oh?");
913 } else { 913 } else {
914 free(acknowledgement); 914 free(acknowledgement);
915 } 915 }
@@ -933,7 +933,7 @@ afc_error_t afc_file_close(afc_client_t client, uint64_t handle)
933 933
934 afc_lock(client); 934 afc_lock(client);
935 935
936 log_debug_msg("%s: File handle %i\n", __func__, handle); 936 debug_info("File handle %i", handle);
937 937
938 // Send command 938 // Send command
939 memcpy(buffer, &handle, sizeof(uint64_t)); 939 memcpy(buffer, &handle, sizeof(uint64_t));
@@ -981,7 +981,7 @@ afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t op
981 981
982 afc_lock(client); 982 afc_lock(client);
983 983
984 log_debug_msg("%s: file handle %i\n", __func__, handle); 984 debug_info("file handle %i", handle);
985 985
986 // Send command 986 // Send command
987 memcpy(buffer, &handle, sizeof(uint64_t)); 987 memcpy(buffer, &handle, sizeof(uint64_t));
@@ -995,13 +995,13 @@ afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t op
995 995
996 if (ret != AFC_E_SUCCESS) { 996 if (ret != AFC_E_SUCCESS) {
997 afc_unlock(client); 997 afc_unlock(client);
998 log_debug_msg("%s: could not send lock command\n", __func__); 998 debug_info("could not send lock command");
999 return AFC_E_UNKNOWN_ERROR; 999 return AFC_E_UNKNOWN_ERROR;
1000 } 1000 }
1001 // Receive the response 1001 // Receive the response
1002 ret = afc_receive_data(client, &buffer, &bytes); 1002 ret = afc_receive_data(client, &buffer, &bytes);
1003 if (buffer) { 1003 if (buffer) {
1004 log_debug_buffer(buffer, bytes); 1004 debug_buffer(buffer, bytes);
1005 free(buffer); 1005 free(buffer);
1006 } 1006 }
1007 afc_unlock(client); 1007 afc_unlock(client);
@@ -1214,9 +1214,9 @@ afc_error_t afc_make_link(afc_client_t client, afc_link_type_t linktype, const c
1214 1214
1215 afc_lock(client); 1215 afc_lock(client);
1216 1216
1217 log_debug_msg("%s: link type: %lld\n", __func__, type); 1217 debug_info("link type: %lld", type);
1218 log_debug_msg("%s: target: %s, length:%d\n", __func__, target, strlen(target)); 1218 debug_info("target: %s, length:%d", target, strlen(target));
1219 log_debug_msg("%s: linkname: %s, length:%d\n", __func__, linkname, strlen(linkname)); 1219 debug_info("linkname: %s, length:%d", linkname, strlen(linkname));
1220 1220
1221 // Send command 1221 // Send command
1222 memcpy(send, &type, 8); 1222 memcpy(send, &type, 8);
diff --git a/src/InstallationProxy.c b/src/InstallationProxy.c
index 387f9ca..9ada994 100644
--- a/src/InstallationProxy.c
+++ b/src/InstallationProxy.c
@@ -26,8 +26,8 @@
26#include <plist/plist.h> 26#include <plist/plist.h>
27 27
28#include "InstallationProxy.h" 28#include "InstallationProxy.h"
29#include "iphone.h" 29#include "property_list_service.h"
30#include "utils.h" 30#include "debug.h"
31 31
32struct instproxy_status_data { 32struct instproxy_status_data {
33 instproxy_client_t client; 33 instproxy_client_t client;
@@ -41,7 +41,7 @@ struct instproxy_status_data {
41 */ 41 */
42static void instproxy_lock(instproxy_client_t client) 42static void instproxy_lock(instproxy_client_t client)
43{ 43{
44 log_debug_msg("InstallationProxy: Locked\n"); 44 debug_info("InstallationProxy: Locked");
45 g_mutex_lock(client->mutex); 45 g_mutex_lock(client->mutex);
46} 46}
47 47
@@ -51,29 +51,30 @@ static void instproxy_lock(instproxy_client_t client)
51 */ 51 */
52static void instproxy_unlock(instproxy_client_t client) 52static void instproxy_unlock(instproxy_client_t client)
53{ 53{
54 log_debug_msg("InstallationProxy: Unlocked\n"); 54 debug_info("InstallationProxy: Unlocked");
55 g_mutex_unlock(client->mutex); 55 g_mutex_unlock(client->mutex);
56} 56}
57 57
58/** 58/**
59 * Convert an iphone_error_t value to an instproxy_error_t value. 59 * Convert a property_list_service_error_t value to an instproxy_error_t value.
60 * Used internally to get correct error codes when using plist helper 60 * Used internally to get correct error codes.
61 * functions.
62 * 61 *
63 * @param err An iphone_error_t error code 62 * @param err A property_list_service_error_t error code
64 * 63 *
65 * @return A matching instproxy_error_t error code, 64 * @return A matching instproxy_error_t error code,
66 * INSTPROXY_E_UNKNOWN_ERROR otherwise. 65 * INSTPROXY_E_UNKNOWN_ERROR otherwise.
67 */ 66 */
68static instproxy_error_t iphone_to_instproxy_error(iphone_error_t err) 67static instproxy_error_t instproxy_error(property_list_service_error_t err)
69{ 68{
70 switch (err) { 69 switch (err) {
71 case IPHONE_E_SUCCESS: 70 case PROPERTY_LIST_SERVICE_E_SUCCESS:
72 return INSTPROXY_E_SUCCESS; 71 return INSTPROXY_E_SUCCESS;
73 case IPHONE_E_INVALID_ARG: 72 case PROPERTY_LIST_SERVICE_E_INVALID_ARG:
74 return INSTPROXY_E_INVALID_ARG; 73 return INSTPROXY_E_INVALID_ARG;
75 case IPHONE_E_PLIST_ERROR: 74 case PROPERTY_LIST_SERVICE_E_PLIST_ERROR:
76 return INSTPROXY_E_PLIST_ERROR; 75 return INSTPROXY_E_PLIST_ERROR;
76 case PROPERTY_LIST_SERVICE_E_MUX_ERROR:
77 return INSTPROXY_E_CONN_FAILED;
77 default: 78 default:
78 break; 79 break;
79 } 80 }
@@ -84,14 +85,14 @@ static instproxy_error_t iphone_to_instproxy_error(iphone_error_t err)
84 * Creates a new installation_proxy client 85 * Creates a new installation_proxy client
85 * 86 *
86 * @param device The device to connect to 87 * @param device The device to connect to
87 * @param dst_port Destination port (usually given by lockdownd_start_service). 88 * @param port Destination port (usually given by lockdownd_start_service).
88 * @param client Pointer that will be set to a newly allocated 89 * @param client Pointer that will be set to a newly allocated
89 * instproxy_client_t upon successful return. 90 * instproxy_client_t upon successful return.
90 * 91 *
91 * @return INSTPROXY_E_SUCCESS on success, or an INSTPROXY_E_* error value 92 * @return INSTPROXY_E_SUCCESS on success, or an INSTPROXY_E_* error value
92 * when an error occured. 93 * when an error occured.
93 */ 94 */
94instproxy_error_t instproxy_client_new(iphone_device_t device, int dst_port, instproxy_client_t *client) 95instproxy_error_t instproxy_client_new(iphone_device_t device, uint16_t port, instproxy_client_t *client)
95{ 96{
96 /* makes sure thread environment is available */ 97 /* makes sure thread environment is available */
97 if (!g_thread_supported()) 98 if (!g_thread_supported())
@@ -100,14 +101,13 @@ instproxy_error_t instproxy_client_new(iphone_device_t device, int dst_port, ins
100 if (!device) 101 if (!device)
101 return INSTPROXY_E_INVALID_ARG; 102 return INSTPROXY_E_INVALID_ARG;
102 103
103 /* Attempt connection */ 104 property_list_service_client_t plistclient = NULL;
104 iphone_connection_t connection = NULL; 105 if (property_list_service_client_new(device, port, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
105 if (iphone_device_connect(device, dst_port, &connection) != IPHONE_E_SUCCESS) {
106 return INSTPROXY_E_CONN_FAILED; 106 return INSTPROXY_E_CONN_FAILED;
107 } 107 }
108 108
109 instproxy_client_t client_loc = (instproxy_client_t) malloc(sizeof(struct instproxy_client_int)); 109 instproxy_client_t client_loc = (instproxy_client_t) malloc(sizeof(struct instproxy_client_int));
110 client_loc->connection = connection; 110 client_loc->parent = plistclient;
111 client_loc->mutex = g_mutex_new(); 111 client_loc->mutex = g_mutex_new();
112 client_loc->status_updater = NULL; 112 client_loc->status_updater = NULL;
113 113
@@ -128,10 +128,10 @@ instproxy_error_t instproxy_client_free(instproxy_client_t client)
128 if (!client) 128 if (!client)
129 return INSTPROXY_E_INVALID_ARG; 129 return INSTPROXY_E_INVALID_ARG;
130 130
131 iphone_device_disconnect(client->connection); 131 property_list_service_client_free(client->parent);
132 client->connection = NULL; 132 client->parent = NULL;
133 if (client->status_updater) { 133 if (client->status_updater) {
134 log_dbg_msg(DBGMASK_INSTPROXY, "joining status_updater"); 134 debug_info("joining status_updater");
135 g_thread_join(client->status_updater); 135 g_thread_join(client->status_updater);
136 } 136 }
137 if (client->mutex) { 137 if (client->mutex) {
@@ -155,7 +155,7 @@ instproxy_error_t instproxy_client_free(instproxy_client_t client)
155 */ 155 */
156instproxy_error_t instproxy_browse(instproxy_client_t client, instproxy_apptype_t apptype, plist_t *result) 156instproxy_error_t instproxy_browse(instproxy_client_t client, instproxy_apptype_t apptype, plist_t *result)
157{ 157{
158 if (!client || !client->connection || !result) 158 if (!client || !client->parent || !result)
159 return INSTPROXY_E_INVALID_ARG; 159 return INSTPROXY_E_INVALID_ARG;
160 160
161 instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; 161 instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR;
@@ -174,7 +174,7 @@ instproxy_error_t instproxy_browse(instproxy_client_t client, instproxy_apptype_
174 p_apptype = plist_new_string("User"); 174 p_apptype = plist_new_string("User");
175 break; 175 break;
176 default: 176 default:
177 log_dbg_msg(DBGMASK_INSTPROXY, "%s: unknown apptype %d given, using INSTPROXY_APPTYPE_USER instead\n", __func__, apptype); 177 debug_info("unknown apptype %d given, using INSTPROXY_APPTYPE_USER instead", apptype);
178 p_apptype = plist_new_string("User"); 178 p_apptype = plist_new_string("User");
179 break; 179 break;
180 } 180 }
@@ -184,10 +184,10 @@ instproxy_error_t instproxy_browse(instproxy_client_t client, instproxy_apptype_
184 plist_dict_insert_item(dict, "Command", plist_new_string("Browse")); 184 plist_dict_insert_item(dict, "Command", plist_new_string("Browse"));
185 185
186 instproxy_lock(client); 186 instproxy_lock(client);
187 res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); 187 res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict));
188 plist_free(dict); 188 plist_free(dict);
189 if (res != INSTPROXY_E_SUCCESS) { 189 if (res != INSTPROXY_E_SUCCESS) {
190 log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not send plist\n", __func__); 190 debug_info("could not send plist");
191 goto leave_unlock; 191 goto leave_unlock;
192 } 192 }
193 193
@@ -196,7 +196,7 @@ instproxy_error_t instproxy_browse(instproxy_client_t client, instproxy_apptype_
196 do { 196 do {
197 browsing = 0; 197 browsing = 0;
198 dict = NULL; 198 dict = NULL;
199 res = iphone_to_instproxy_error(iphone_device_receive_plist(client->connection, &dict)); 199 res = instproxy_error(property_list_service_receive_plist(client->parent, &dict));
200 if (res != INSTPROXY_E_SUCCESS) { 200 if (res != INSTPROXY_E_SUCCESS) {
201 break; 201 break;
202 } 202 }
@@ -223,7 +223,7 @@ instproxy_error_t instproxy_browse(instproxy_client_t client, instproxy_apptype_
223 if (!strcmp(status, "BrowsingApplications")) { 223 if (!strcmp(status, "BrowsingApplications")) {
224 browsing = 1; 224 browsing = 1;
225 } else if (!strcmp(status, "Complete")) { 225 } else if (!strcmp(status, "Complete")) {
226 log_dbg_msg(DBGMASK_INSTPROXY, "%s: Browsing applications completed\n"); 226 debug_info("Browsing applications completed");
227 res = INSTPROXY_E_SUCCESS; 227 res = INSTPROXY_E_SUCCESS;
228 } 228 }
229 free(status); 229 free(status);
@@ -261,10 +261,10 @@ static instproxy_error_t instproxy_perform_operation(instproxy_client_t client,
261 261
262 do { 262 do {
263 instproxy_lock(client); 263 instproxy_lock(client);
264 res = iphone_to_instproxy_error(iphone_device_receive_plist_with_timeout(client->connection, &dict, 30000)); 264 res = instproxy_error(property_list_service_receive_plist_with_timeout(client->parent, &dict, 30000));
265 instproxy_unlock(client); 265 instproxy_unlock(client);
266 if (res != INSTPROXY_E_SUCCESS) { 266 if (res != INSTPROXY_E_SUCCESS) {
267 log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not receive plist, error %d\n", __func__, res); 267 debug_info("could not receive plist, error %d", res);
268 break; 268 break;
269 } 269 }
270 if (dict) { 270 if (dict) {
@@ -279,7 +279,7 @@ static instproxy_error_t instproxy_perform_operation(instproxy_client_t client,
279 char *err_msg = NULL; 279 char *err_msg = NULL;
280 plist_get_string_val(err, &err_msg); 280 plist_get_string_val(err, &err_msg);
281 if (err_msg) { 281 if (err_msg) {
282 log_dbg_msg(DBGMASK_INSTPROXY, "%s(%s): ERROR: %s\n", __func__, operation, err_msg); 282 debug_info("(%s): ERROR: %s", operation, err_msg);
283 free(err_msg); 283 free(err_msg);
284 } 284 }
285#endif 285#endif
@@ -303,9 +303,9 @@ static instproxy_error_t instproxy_perform_operation(instproxy_client_t client,
303 int percent; 303 int percent;
304 plist_get_uint_val(npercent, &val); 304 plist_get_uint_val(npercent, &val);
305 percent = val; 305 percent = val;
306 log_dbg_msg(DBGMASK_INSTPROXY, "%s(%s): %s (%d%%)\n", __func__, operation, status_msg, percent); 306 debug_info("(%s): %s (%d%%)", operation, status_msg, percent);
307 } else { 307 } else {
308 log_dbg_msg(DBGMASK_INSTPROXY, "%s(%s): %s\n", __func__, operation, status_msg); 308 debug_info("(%s): %s", operation, status_msg);
309 } 309 }
310#endif 310#endif
311 free(status_msg); 311 free(status_msg);
@@ -314,7 +314,7 @@ static instproxy_error_t instproxy_perform_operation(instproxy_client_t client,
314 plist_free(dict); 314 plist_free(dict);
315 dict = NULL; 315 dict = NULL;
316 } 316 }
317 } while (ok && client->connection); 317 } while (ok && client->parent);
318 318
319 return res; 319 return res;
320} 320}
@@ -338,7 +338,7 @@ static gpointer instproxy_status_updater(gpointer arg)
338 338
339 /* cleanup */ 339 /* cleanup */
340 instproxy_lock(data->client); 340 instproxy_lock(data->client);
341 log_dbg_msg(DBGMASK_INSTPROXY, "%s: done, cleaning up.\n", __func__); 341 debug_info("done, cleaning up.");
342 if (data->operation) { 342 if (data->operation) {
343 free(data->operation); 343 free(data->operation);
344 } 344 }
@@ -404,15 +404,15 @@ static instproxy_error_t instproxy_create_status_updater(instproxy_client_t clie
404 */ 404 */
405static instproxy_error_t instproxy_install_or_upgrade(instproxy_client_t client, const char *pkg_path, plist_t sinf, plist_t metadata, instproxy_status_cb_t status_cb, const char *command) 405static instproxy_error_t instproxy_install_or_upgrade(instproxy_client_t client, const char *pkg_path, plist_t sinf, plist_t metadata, instproxy_status_cb_t status_cb, const char *command)
406{ 406{
407 if (!client || !client->connection || !pkg_path) { 407 if (!client || !client->parent || !pkg_path) {
408 return INSTPROXY_E_INVALID_ARG; 408 return INSTPROXY_E_INVALID_ARG;
409 } 409 }
410 if (sinf && (plist_get_node_type(sinf) != PLIST_DATA)) { 410 if (sinf && (plist_get_node_type(sinf) != PLIST_DATA)) {
411 log_dbg_msg(DBGMASK_INSTPROXY, "%s(%s): ERROR: sinf data is not a PLIST_DATA node!\n", __func__, command); 411 debug_info("(%s): ERROR: sinf data is not a PLIST_DATA node!", command);
412 return INSTPROXY_E_INVALID_ARG; 412 return INSTPROXY_E_INVALID_ARG;
413 } 413 }
414 if (metadata && (plist_get_node_type(metadata) != PLIST_DATA)) { 414 if (metadata && (plist_get_node_type(metadata) != PLIST_DATA)) {
415 log_dbg_msg(DBGMASK_INSTPROXY, "%s(%s): ERROR: metadata is not a PLIST_DATA node!\n", __func__, command); 415 debug_info("(%s): ERROR: metadata is not a PLIST_DATA node!", command);
416 return INSTPROXY_E_INVALID_ARG; 416 return INSTPROXY_E_INVALID_ARG;
417 } 417 }
418 418
@@ -433,13 +433,13 @@ static instproxy_error_t instproxy_install_or_upgrade(instproxy_client_t client,
433 plist_dict_insert_item(dict, "PackagePath", plist_new_string(pkg_path)); 433 plist_dict_insert_item(dict, "PackagePath", plist_new_string(pkg_path));
434 434
435 instproxy_lock(client); 435 instproxy_lock(client);
436 res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); 436 res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict));
437 instproxy_unlock(client); 437 instproxy_unlock(client);
438 438
439 plist_free(dict); 439 plist_free(dict);
440 440
441 if (res != INSTPROXY_E_SUCCESS) { 441 if (res != INSTPROXY_E_SUCCESS) {
442 log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not send plist, error %d\n", __func__, res); 442 debug_info("could not send plist, error %d", res);
443 return res; 443 return res;
444 } 444 }
445 445
@@ -512,7 +512,7 @@ instproxy_error_t instproxy_upgrade(instproxy_client_t client, const char *pkg_p
512 */ 512 */
513instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *appid, instproxy_status_cb_t status_cb) 513instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *appid, instproxy_status_cb_t status_cb)
514{ 514{
515 if (!client || !client->connection || !appid) { 515 if (!client || !client->parent || !appid) {
516 return INSTPROXY_E_INVALID_ARG; 516 return INSTPROXY_E_INVALID_ARG;
517 } 517 }
518 518
@@ -526,13 +526,13 @@ instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *app
526 plist_dict_insert_item(dict, "Command", plist_new_string("Uninstall")); 526 plist_dict_insert_item(dict, "Command", plist_new_string("Uninstall"));
527 527
528 instproxy_lock(client); 528 instproxy_lock(client);
529 res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); 529 res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict));
530 instproxy_unlock(client); 530 instproxy_unlock(client);
531 531
532 plist_free(dict); 532 plist_free(dict);
533 533
534 if (res != INSTPROXY_E_SUCCESS) { 534 if (res != INSTPROXY_E_SUCCESS) {
535 log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not send plist, error %d\n", __func__, res); 535 debug_info("could not send plist, error %d", res);
536 return res; 536 return res;
537 } 537 }
538 538
@@ -553,7 +553,7 @@ instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *app
553 */ 553 */
554instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist_t *result) 554instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist_t *result)
555{ 555{
556 if (!client || !client->connection || !result) 556 if (!client || !client->parent || !result)
557 return INSTPROXY_E_INVALID_ARG; 557 return INSTPROXY_E_INVALID_ARG;
558 558
559 instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; 559 instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR;
@@ -563,17 +563,17 @@ instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist_t *
563 563
564 instproxy_lock(client); 564 instproxy_lock(client);
565 565
566 res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); 566 res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict));
567 plist_free(dict); 567 plist_free(dict);
568 568
569 if (res != INSTPROXY_E_SUCCESS) { 569 if (res != INSTPROXY_E_SUCCESS) {
570 log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not send plist, error %d\n", __func__, res); 570 debug_info("could not send plist, error %d", res);
571 goto leave_unlock; 571 goto leave_unlock;
572 } 572 }
573 573
574 res = iphone_to_instproxy_error(iphone_device_receive_plist(client->connection, result)); 574 res = instproxy_error(property_list_service_receive_plist(client->parent, result));
575 if (res != INSTPROXY_E_SUCCESS) { 575 if (res != INSTPROXY_E_SUCCESS) {
576 log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not receive plist, error %d\n", __func__, res); 576 debug_info("could not receive plist, error %d", res);
577 goto leave_unlock; 577 goto leave_unlock;
578 } 578 }
579 579
@@ -610,7 +610,7 @@ leave_unlock:
610 */ 610 */
611instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid, uint32_t options, instproxy_status_cb_t status_cb) 611instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid, uint32_t options, instproxy_status_cb_t status_cb)
612{ 612{
613 if (!client || !client->connection || !appid) 613 if (!client || !client->parent || !appid)
614 return INSTPROXY_E_INVALID_ARG; 614 return INSTPROXY_E_INVALID_ARG;
615 615
616 if (client->status_updater) { 616 if (client->status_updater) {
@@ -634,13 +634,13 @@ instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid
634 plist_dict_insert_item(dict, "Command", plist_new_string("Archive")); 634 plist_dict_insert_item(dict, "Command", plist_new_string("Archive"));
635 635
636 instproxy_lock(client); 636 instproxy_lock(client);
637 res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); 637 res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict));
638 instproxy_unlock(client); 638 instproxy_unlock(client);
639 639
640 plist_free(dict); 640 plist_free(dict);
641 641
642 if (res != INSTPROXY_E_SUCCESS) { 642 if (res != INSTPROXY_E_SUCCESS) {
643 log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not send plist, error %d\n", __func__, res); 643 debug_info("could not send plist, error %d", res);
644 return res; 644 return res;
645 } 645 }
646 return instproxy_create_status_updater(client, status_cb, "Archive"); 646 return instproxy_create_status_updater(client, status_cb, "Archive");
@@ -666,7 +666,7 @@ instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid
666 */ 666 */
667instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid, instproxy_status_cb_t status_cb) 667instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid, instproxy_status_cb_t status_cb)
668{ 668{
669 if (!client || !client->connection || !appid) 669 if (!client || !client->parent || !appid)
670 return INSTPROXY_E_INVALID_ARG; 670 return INSTPROXY_E_INVALID_ARG;
671 671
672 if (client->status_updater) { 672 if (client->status_updater) {
@@ -680,13 +680,13 @@ instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid
680 plist_dict_insert_item(dict, "Command", plist_new_string("Restore")); 680 plist_dict_insert_item(dict, "Command", plist_new_string("Restore"));
681 681
682 instproxy_lock(client); 682 instproxy_lock(client);
683 res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); 683 res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict));
684 instproxy_unlock(client); 684 instproxy_unlock(client);
685 685
686 plist_free(dict); 686 plist_free(dict);
687 687
688 if (res != INSTPROXY_E_SUCCESS) { 688 if (res != INSTPROXY_E_SUCCESS) {
689 log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not send plist, error %d\n", __func__, res); 689 debug_info("could not send plist, error %d", res);
690 return res; 690 return res;
691 } 691 }
692 return instproxy_create_status_updater(client, status_cb, "Restore"); 692 return instproxy_create_status_updater(client, status_cb, "Restore");
@@ -712,7 +712,7 @@ instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid
712 */ 712 */
713instproxy_error_t instproxy_remove_archive(instproxy_client_t client, const char *appid, instproxy_status_cb_t status_cb) 713instproxy_error_t instproxy_remove_archive(instproxy_client_t client, const char *appid, instproxy_status_cb_t status_cb)
714{ 714{
715 if (!client || !client->connection || !appid) 715 if (!client || !client->parent || !appid)
716 return INSTPROXY_E_INVALID_ARG; 716 return INSTPROXY_E_INVALID_ARG;
717 717
718 if (client->status_updater) { 718 if (client->status_updater) {
@@ -726,13 +726,13 @@ instproxy_error_t instproxy_remove_archive(instproxy_client_t client, const char
726 plist_dict_insert_item(dict, "Command", plist_new_string("RemoveArchive")); 726 plist_dict_insert_item(dict, "Command", plist_new_string("RemoveArchive"));
727 727
728 instproxy_lock(client); 728 instproxy_lock(client);
729 res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); 729 res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict));
730 instproxy_unlock(client); 730 instproxy_unlock(client);
731 731
732 plist_free(dict); 732 plist_free(dict);
733 733
734 if (res != INSTPROXY_E_SUCCESS) { 734 if (res != INSTPROXY_E_SUCCESS) {
735 log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not send plist, error %d\n", __func__, res); 735 debug_info("could not send plist, error %d", res);
736 return res; 736 return res;
737 } 737 }
738 return instproxy_create_status_updater(client, status_cb, "RemoveArchive"); 738 return instproxy_create_status_updater(client, status_cb, "RemoveArchive");
diff --git a/src/InstallationProxy.h b/src/InstallationProxy.h
index c8c5ef1..f0b5691 100644
--- a/src/InstallationProxy.h
+++ b/src/InstallationProxy.h
@@ -24,9 +24,10 @@
24#include <glib.h> 24#include <glib.h>
25 25
26#include "libiphone/installation_proxy.h" 26#include "libiphone/installation_proxy.h"
27#include "property_list_service.h"
27 28
28struct instproxy_client_int { 29struct instproxy_client_int {
29 iphone_connection_t connection; 30 property_list_service_client_t parent;
30 GMutex *mutex; 31 GMutex *mutex;
31 GThread *status_updater; 32 GThread *status_updater;
32}; 33};
diff --git a/src/Makefile.am b/src/Makefile.am
index 9b42f1c..bb7252e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -5,11 +5,13 @@ AM_LDFLAGS = $(libglib2_LIBS) $(libgnutls_LIBS) $(libtasn1_LIBS) $(libgthread2_L
5 5
6lib_LTLIBRARIES = libiphone.la 6lib_LTLIBRARIES = libiphone.la
7libiphone_la_SOURCES = iphone.c iphone.h \ 7libiphone_la_SOURCES = iphone.c iphone.h \
8 property_list_service.c property_list_service.h\
9 device_link_service.c device_link_service.h\
8 lockdown.c lockdown.h\ 10 lockdown.c lockdown.h\
9 AFC.c AFC.h\ 11 AFC.c AFC.h\
10 NotificationProxy.c NotificationProxy.h\ 12 NotificationProxy.c NotificationProxy.h\
11 InstallationProxy.c InstallationProxy.h\ 13 InstallationProxy.c InstallationProxy.h\
12 SBServices.c SBServices.h\ 14 SBServices.c SBServices.h\
13 userpref.c userpref.h\ 15 userpref.c userpref.h\
14 utils.c utils.h\ 16 debug.c debug.h\
15 MobileSync.c MobileSync.h 17 MobileSync.c MobileSync.h
diff --git a/src/MobileSync.c b/src/MobileSync.c
index 76aefa0..827ed35 100644
--- a/src/MobileSync.c
+++ b/src/MobileSync.c
@@ -25,153 +25,76 @@
25#include <arpa/inet.h> 25#include <arpa/inet.h>
26 26
27#include "MobileSync.h" 27#include "MobileSync.h"
28#include "iphone.h" 28#include "device_link_service.h"
29#include "utils.h" 29#include "debug.h"
30 30
31#define MSYNC_VERSION_INT1 100 31#define MSYNC_VERSION_INT1 100
32#define MSYNC_VERSION_INT2 100 32#define MSYNC_VERSION_INT2 100
33 33
34/** 34/**
35 * Convert an iphone_error_t value to an mobilesync_error_t value. 35 * Convert an device_link_service_error_t value to an mobilesync_error_t value.
36 * Used internally to get correct error codes when using plist helper 36 * Used internally to get correct error codes when using device_link_service stuff.
37 * functions.
38 * 37 *
39 * @param err An iphone_error_t error code 38 * @param err An device_link_service_error_t error code
40 * 39 *
41 * @return A matching mobilesync_error_t error code, 40 * @return A matching mobilesync_error_t error code,
42 * MOBILESYNC_E_UNKNOWN_ERROR otherwise. 41 * MOBILESYNC_E_UNKNOWN_ERROR otherwise.
43 */ 42 */
44static mobilesync_error_t iphone_to_mobilesync_error(iphone_error_t err) 43static mobilesync_error_t mobilesync_error(device_link_service_error_t err)
45{ 44{
46 switch (err) { 45 switch (err) {
47 case IPHONE_E_SUCCESS: 46 case DEVICE_LINK_SERVICE_E_SUCCESS:
48 return MOBILESYNC_E_SUCCESS; 47 return MOBILESYNC_E_SUCCESS;
49 case IPHONE_E_INVALID_ARG: 48 case DEVICE_LINK_SERVICE_E_INVALID_ARG:
50 return MOBILESYNC_E_INVALID_ARG; 49 return MOBILESYNC_E_INVALID_ARG;
51 case IPHONE_E_PLIST_ERROR: 50 case DEVICE_LINK_SERVICE_E_PLIST_ERROR:
52 return MOBILESYNC_E_PLIST_ERROR; 51 return MOBILESYNC_E_PLIST_ERROR;
52 case DEVICE_LINK_SERVICE_E_MUX_ERROR:
53 return MOBILESYNC_E_MUX_ERROR;
54 case DEVICE_LINK_SERVICE_E_BAD_VERSION:
55 return MOBILESYNC_E_BAD_VERSION;
53 default: 56 default:
54 break; 57 break;
55 } 58 }
56 return MOBILESYNC_E_UNKNOWN_ERROR; 59 return MOBILESYNC_E_UNKNOWN_ERROR;
57} 60}
58 61
59mobilesync_error_t mobilesync_client_new(iphone_device_t device, int dst_port, 62mobilesync_error_t mobilesync_client_new(iphone_device_t device, uint16_t port,
60 mobilesync_client_t * client) 63 mobilesync_client_t * client)
61{ 64{
62 if (!device || dst_port == 0 || !client || *client) 65 if (!device || port == 0 || !client || *client)
63 return MOBILESYNC_E_INVALID_ARG; 66 return MOBILESYNC_E_INVALID_ARG;
64 67
65 mobilesync_error_t ret = MOBILESYNC_E_UNKNOWN_ERROR; 68 device_link_service_client_t dlclient = NULL;
66 69 mobilesync_error_t ret = mobilesync_error(device_link_service_client_new(device, port, &dlclient));
67 /* Attempt connection */ 70 if (ret != MOBILESYNC_E_SUCCESS) {
68 iphone_connection_t connection = NULL;
69 if (iphone_device_connect(device, dst_port, &connection) != IPHONE_E_SUCCESS) {
70 return ret; 71 return ret;
71 } 72 }
72 73
73 mobilesync_client_t client_loc = (mobilesync_client_t) malloc(sizeof(struct mobilesync_client_int)); 74 mobilesync_client_t client_loc = (mobilesync_client_t) malloc(sizeof(struct mobilesync_client_int));
74 client_loc->connection = connection; 75 client_loc->parent = dlclient;
75 76
76 /* perform handshake */ 77 /* perform handshake */
77 plist_t array = NULL; 78 ret = mobilesync_error(device_link_service_version_exchange(dlclient, MSYNC_VERSION_INT1, MSYNC_VERSION_INT2));
78 79 if (ret != MOBILESYNC_E_SUCCESS) {
79 /* first receive version */ 80 debug_info("version exchange failed, error %d", ret);
80 ret = mobilesync_recv(client_loc, &array); 81 mobilesync_client_free(client_loc);
81 82 return ret;
82 plist_t msg_node = plist_array_get_item(array, 0);
83
84 char* msg = NULL;
85 plist_type type = plist_get_node_type(msg_node);
86 if (PLIST_STRING == type) {
87 plist_get_string_val(msg_node, &msg);
88 }
89 if (PLIST_STRING != type || strcmp(msg, "DLMessageVersionExchange") || plist_array_get_size(array) < 3) {
90 log_debug_msg("%s: ERROR: MobileSync client expected a version exchange !\n", __func__);
91 }
92 free(msg);
93 msg = NULL;
94
95 plist_t ver_1 = plist_array_get_item(array, 1);
96 plist_t ver_2 = plist_array_get_item(array, 2);
97
98 plist_type ver_1_type = plist_get_node_type(ver_1);
99 plist_type ver_2_type = plist_get_node_type(ver_2);
100
101 if (PLIST_UINT == ver_1_type && PLIST_UINT == ver_2_type) {
102
103 uint64_t ver_1_val = 0;
104 uint64_t ver_2_val = 0;
105
106 plist_get_uint_val(ver_1, &ver_1_val);
107 plist_get_uint_val(ver_2, &ver_2_val);
108
109 plist_free(array);
110 array = NULL;
111
112 if (ver_1_type == PLIST_UINT && ver_2_type == PLIST_UINT && ver_1_val == MSYNC_VERSION_INT1
113 && ver_2_val == MSYNC_VERSION_INT2) {
114
115 array = plist_new_array();
116 plist_array_append_item(array, plist_new_string("DLMessageVersionExchange"));
117 plist_array_append_item(array, plist_new_string("DLVersionsOk"));
118
119 ret = mobilesync_send(client_loc, array);
120
121 plist_free(array);
122 array = NULL;
123
124 ret = mobilesync_recv(client_loc, &array);
125 plist_t rep_node = plist_array_get_item(array, 0);
126
127 type = plist_get_node_type(rep_node);
128 if (PLIST_STRING == type) {
129 plist_get_string_val(rep_node, &msg);
130 }
131 if (PLIST_STRING != type || strcmp(msg, "DLMessageDeviceReady")) {
132 log_debug_msg("%s: ERROR: MobileSync client failed to start session !\n", __func__);
133 ret = MOBILESYNC_E_BAD_VERSION;
134 }
135 else
136 {
137 ret = MOBILESYNC_E_SUCCESS;
138 *client = client_loc;
139 }
140 free(msg);
141 msg = NULL;
142
143 plist_free(array);
144 array = NULL;
145 }
146 } 83 }
147 84
148 if (MOBILESYNC_E_SUCCESS != ret) 85 *client = client_loc;
149 mobilesync_client_free(client_loc);
150 86
151 return ret; 87 return ret;
152} 88}
153 89
154static void mobilesync_disconnect(mobilesync_client_t client)
155{
156 if (!client)
157 return;
158
159 plist_t array = plist_new_array();
160 plist_array_append_item(array, plist_new_string("DLMessageDisconnect"));
161 plist_array_append_item(array, plist_new_string("All done, thanks for the memories"));
162
163 mobilesync_send(client, array);
164 plist_free(array);
165 array = NULL;
166}
167
168mobilesync_error_t mobilesync_client_free(mobilesync_client_t client) 90mobilesync_error_t mobilesync_client_free(mobilesync_client_t client)
169{ 91{
170 if (!client) 92 if (!client)
171 return IPHONE_E_INVALID_ARG; 93 return MOBILESYNC_E_INVALID_ARG;
172 94 device_link_service_disconnect(client->parent);
173 mobilesync_disconnect(client); 95 mobilesync_error_t err = mobilesync_error(device_link_service_client_free(client->parent));
174 return (iphone_device_disconnect(client->connection) == 0 ? MOBILESYNC_E_SUCCESS: MOBILESYNC_E_MUX_ERROR); 96 free(client);
97 return err;
175} 98}
176 99
177/** Polls the iPhone for MobileSync data. 100/** Polls the iPhone for MobileSync data.
@@ -183,19 +106,17 @@ mobilesync_error_t mobilesync_client_free(mobilesync_client_t client)
183 */ 106 */
184mobilesync_error_t mobilesync_recv(mobilesync_client_t client, plist_t * plist) 107mobilesync_error_t mobilesync_recv(mobilesync_client_t client, plist_t * plist)
185{ 108{
186 if (!client || !plist || (plist && *plist)) 109 if (!client)
187 return MOBILESYNC_E_INVALID_ARG; 110 return MOBILESYNC_E_INVALID_ARG;
188 111 mobilesync_error_t ret = mobilesync_error(device_link_service_receive(client->parent, plist));
189 mobilesync_error_t ret = iphone_to_mobilesync_error(iphone_device_receive_plist(client->connection, plist)); 112#ifndef STRIP_DEBUG_CODE
190 if (ret != MOBILESYNC_E_SUCCESS) { 113 if (ret != MOBILESYNC_E_SUCCESS) {
191 return MOBILESYNC_E_MUX_ERROR; 114 return ret;
192 } 115 }
193
194#ifndef STRIP_DEBUG_CODE
195 char *XMLContent = NULL; 116 char *XMLContent = NULL;
196 uint32_t length = 0; 117 uint32_t length = 0;
197 plist_to_xml(*plist, &XMLContent, &length); 118 plist_to_xml(*plist, &XMLContent, &length);
198 log_dbg_msg(DBGMASK_MOBILESYNC, "%s: plist size: %i\nbuffer :\n%s\n", __func__, length, XMLContent); 119 debug_info("plist size: %i\nbuffer :\n%s", length, XMLContent);
199 free(XMLContent); 120 free(XMLContent);
200#endif 121#endif
201 return ret; 122 return ret;
@@ -220,8 +141,8 @@ mobilesync_error_t mobilesync_send(mobilesync_client_t client, plist_t plist)
220 char *XMLContent = NULL; 141 char *XMLContent = NULL;
221 uint32_t length = 0; 142 uint32_t length = 0;
222 plist_to_xml(plist, &XMLContent, &length); 143 plist_to_xml(plist, &XMLContent, &length);
223 log_dbg_msg(DBGMASK_MOBILESYNC, "%s: plist size: %i\nbuffer :\n%s\n", __func__, length, XMLContent); 144 debug_info("plist size: %i\nbuffer :\n%s", length, XMLContent);
224 free(XMLContent); 145 free(XMLContent);
225#endif 146#endif
226 return (iphone_device_send_binary_plist(client->connection, plist) == IPHONE_E_SUCCESS ? MOBILESYNC_E_SUCCESS : MOBILESYNC_E_MUX_ERROR); 147 return mobilesync_error(device_link_service_send(client->parent, plist));
227} 148}
diff --git a/src/MobileSync.h b/src/MobileSync.h
index 605145f..6538343 100644
--- a/src/MobileSync.h
+++ b/src/MobileSync.h
@@ -22,9 +22,10 @@
22#define MOBILESYNC_H 22#define MOBILESYNC_H
23 23
24#include "libiphone/mobilesync.h" 24#include "libiphone/mobilesync.h"
25#include "device_link_service.h"
25 26
26struct mobilesync_client_int { 27struct mobilesync_client_int {
27 iphone_connection_t connection; 28 device_link_service_client_t parent;
28}; 29};
29 30
30#endif 31#endif
diff --git a/src/NotificationProxy.c b/src/NotificationProxy.c
index e2c1faa..e994c16 100644
--- a/src/NotificationProxy.c
+++ b/src/NotificationProxy.c
@@ -27,8 +27,8 @@
27#include <plist/plist.h> 27#include <plist/plist.h>
28 28
29#include "NotificationProxy.h" 29#include "NotificationProxy.h"
30#include "iphone.h" 30#include "property_list_service.h"
31#include "utils.h" 31#include "debug.h"
32 32
33struct np_thread { 33struct np_thread {
34 np_client_t client; 34 np_client_t client;
@@ -41,7 +41,7 @@ struct np_thread {
41 */ 41 */
42static void np_lock(np_client_t client) 42static void np_lock(np_client_t client)
43{ 43{
44 log_debug_msg("NP: Locked\n"); 44 debug_info("NP: Locked");
45 g_mutex_lock(client->mutex); 45 g_mutex_lock(client->mutex);
46} 46}
47 47
@@ -51,29 +51,30 @@ static void np_lock(np_client_t client)
51 */ 51 */
52static void np_unlock(np_client_t client) 52static void np_unlock(np_client_t client)
53{ 53{
54 log_debug_msg("NP: Unlocked\n"); 54 debug_info("NP: Unlocked");
55 g_mutex_unlock(client->mutex); 55 g_mutex_unlock(client->mutex);
56} 56}
57 57
58/** 58/**
59 * Convert an iphone_error_t value to an np_error_t value. 59 * Convert a property_list_service_error_t value to an np_error_t value.
60 * Used internally to get correct error codes when using plist helper 60 * Used internally to get correct error codes.
61 * functions.
62 * 61 *
63 * @param err An iphone_error_t error code 62 * @param err A property_list_service_error_t error code
64 * 63 *
65 * @return A matching np_error_t error code, 64 * @return A matching np_error_t error code,
66 * NP_E_UNKNOWN_ERROR otherwise. 65 * NP_E_UNKNOWN_ERROR otherwise.
67 */ 66 */
68static np_error_t iphone_to_np_error(iphone_error_t err) 67static np_error_t np_error(property_list_service_error_t err)
69{ 68{
70 switch (err) { 69 switch (err) {
71 case IPHONE_E_SUCCESS: 70 case PROPERTY_LIST_SERVICE_E_SUCCESS:
72 return NP_E_SUCCESS; 71 return NP_E_SUCCESS;
73 case IPHONE_E_INVALID_ARG: 72 case PROPERTY_LIST_SERVICE_E_INVALID_ARG:
74 return NP_E_INVALID_ARG; 73 return NP_E_INVALID_ARG;
75 case IPHONE_E_PLIST_ERROR: 74 case PROPERTY_LIST_SERVICE_E_PLIST_ERROR:
76 return NP_E_PLIST_ERROR; 75 return NP_E_PLIST_ERROR;
76 case PROPERTY_LIST_SERVICE_E_MUX_ERROR:
77 return NP_E_CONN_FAILED;
77 default: 78 default:
78 break; 79 break;
79 } 80 }
@@ -83,7 +84,7 @@ static np_error_t iphone_to_np_error(iphone_error_t err)
83/** Makes a connection to the NP service on the phone. 84/** Makes a connection to the NP service on the phone.
84 * 85 *
85 * @param device The device to connect to. 86 * @param device The device to connect to.
86 * @param dst_port Destination port (usually given by lockdownd_start_service). 87 * @param port Destination port (usually given by lockdownd_start_service).
87 * @param client Pointer that will be set to a newly allocated np_client_t 88 * @param client Pointer that will be set to a newly allocated np_client_t
88 * upon successful return. 89 * upon successful return.
89 * 90 *
@@ -91,7 +92,7 @@ static np_error_t iphone_to_np_error(iphone_error_t err)
91 * or NP_E_CONN_FAILED when the connection to the device could not be 92 * or NP_E_CONN_FAILED when the connection to the device could not be
92 * established. 93 * established.
93 */ 94 */
94np_error_t np_client_new(iphone_device_t device, int dst_port, np_client_t *client) 95np_error_t np_client_new(iphone_device_t device, uint16_t port, np_client_t *client)
95{ 96{
96 /* makes sure thread environment is available */ 97 /* makes sure thread environment is available */
97 if (!g_thread_supported()) 98 if (!g_thread_supported())
@@ -100,14 +101,13 @@ np_error_t np_client_new(iphone_device_t device, int dst_port, np_client_t *clie
100 if (!device) 101 if (!device)
101 return NP_E_INVALID_ARG; 102 return NP_E_INVALID_ARG;
102 103
103 /* Attempt connection */ 104 property_list_service_client_t plistclient = NULL;
104 iphone_connection_t connection = NULL; 105 if (property_list_service_client_new(device, port, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
105 if (iphone_device_connect(device, dst_port, &connection) != IPHONE_E_SUCCESS) {
106 return NP_E_CONN_FAILED; 106 return NP_E_CONN_FAILED;
107 } 107 }
108 108
109 np_client_t client_loc = (np_client_t) malloc(sizeof(struct np_client_int)); 109 np_client_t client_loc = (np_client_t) malloc(sizeof(struct np_client_int));
110 client_loc->connection = connection; 110 client_loc->parent = plistclient;
111 111
112 client_loc->mutex = g_mutex_new(); 112 client_loc->mutex = g_mutex_new();
113 113
@@ -128,10 +128,10 @@ np_error_t np_client_free(np_client_t client)
128 if (!client) 128 if (!client)
129 return NP_E_INVALID_ARG; 129 return NP_E_INVALID_ARG;
130 130
131 iphone_device_disconnect(client->connection); 131 property_list_service_client_free(client->parent);
132 client->connection = NULL; 132 client->parent = NULL;
133 if (client->notifier) { 133 if (client->notifier) {
134 log_debug_msg("joining np callback\n"); 134 debug_info("joining np callback");
135 g_thread_join(client->notifier); 135 g_thread_join(client->notifier);
136 } 136 }
137 if (client->mutex) { 137 if (client->mutex) {
@@ -144,10 +144,6 @@ np_error_t np_client_free(np_client_t client)
144 144
145/** Sends a notification to the device's Notification Proxy. 145/** Sends a notification to the device's Notification Proxy.
146 * 146 *
147 * notification messages seen so far:
148 * com.apple.itunes-mobdev.syncWillStart
149 * com.apple.itunes-mobdev.syncDidStart
150 *
151 * @param client The client to send to 147 * @param client The client to send to
152 * @param notification The notification message to send 148 * @param notification The notification message to send
153 * 149 *
@@ -164,17 +160,17 @@ np_error_t np_post_notification(np_client_t client, const char *notification)
164 plist_dict_insert_item(dict,"Command", plist_new_string("PostNotification")); 160 plist_dict_insert_item(dict,"Command", plist_new_string("PostNotification"));
165 plist_dict_insert_item(dict,"Name", plist_new_string(notification)); 161 plist_dict_insert_item(dict,"Name", plist_new_string(notification));
166 162
167 np_error_t res = iphone_to_np_error(iphone_device_send_xml_plist(client->connection, dict)); 163 np_error_t res = np_error(property_list_service_send_xml_plist(client->parent, dict));
168 plist_free(dict); 164 plist_free(dict);
169 165
170 dict = plist_new_dict(); 166 dict = plist_new_dict();
171 plist_dict_insert_item(dict,"Command", plist_new_string("Shutdown")); 167 plist_dict_insert_item(dict,"Command", plist_new_string("Shutdown"));
172 168
173 res = iphone_to_np_error(iphone_device_send_xml_plist(client->connection, dict)); 169 res = np_error(property_list_service_send_xml_plist(client->parent, dict));
174 plist_free(dict); 170 plist_free(dict);
175 171
176 if (res != NP_E_SUCCESS) { 172 if (res != NP_E_SUCCESS) {
177 log_debug_msg("%s: Error sending XML plist to device!\n", __func__); 173 debug_info("Error sending XML plist to device!");
178 } 174 }
179 175
180 np_unlock(client); 176 np_unlock(client);
@@ -200,9 +196,9 @@ np_error_t np_observe_notification( np_client_t client, const char *notification
200 plist_dict_insert_item(dict,"Command", plist_new_string("ObserveNotification")); 196 plist_dict_insert_item(dict,"Command", plist_new_string("ObserveNotification"));
201 plist_dict_insert_item(dict,"Name", plist_new_string(notification)); 197 plist_dict_insert_item(dict,"Name", plist_new_string(notification));
202 198
203 np_error_t res = iphone_to_np_error(iphone_device_send_xml_plist(client->connection, dict)); 199 np_error_t res = np_error(property_list_service_send_xml_plist(client->parent, dict));
204 if (res != NP_E_SUCCESS) { 200 if (res != NP_E_SUCCESS) {
205 log_debug_msg("%s: Error sending XML plist to device!\n", __func__); 201 debug_info("Error sending XML plist to device!");
206 } 202 }
207 plist_free(dict); 203 plist_free(dict);
208 204
@@ -212,22 +208,10 @@ np_error_t np_observe_notification( np_client_t client, const char *notification
212 208
213/** Notifies the iphone to send a notification on specified events. 209/** Notifies the iphone to send a notification on specified events.
214 * 210 *
215 * observation messages seen so far:
216 * com.apple.itunes-client.syncCancelRequest
217 * com.apple.itunes-client.syncSuspendRequest
218 * com.apple.itunes-client.syncResumeRequest
219 * com.apple.mobile.lockdown.phone_number_changed
220 * com.apple.mobile.lockdown.device_name_changed
221 * com.apple.springboard.attemptactivation
222 * com.apple.mobile.data_sync.domain_changed
223 * com.apple.mobile.application_installed
224 * com.apple.mobile.application_uninstalled
225 *
226 * @param client The client to send to 211 * @param client The client to send to
227 * @param notification_spec Specification of the notifications that should be 212 * @param notification_spec Specification of the notifications that should be
228 * observed. This is expected to be an array of const char* that MUST have a 213 * observed. This is expected to be an array of const char* that MUST have a
229 * terminating NULL entry. However this parameter can be NULL; in this case, 214 * terminating NULL entry.
230 * the default set of notifications will be used.
231 * 215 *
232 * @return NP_E_SUCCESS on success, NP_E_INVALID_ARG when client is null, 216 * @return NP_E_SUCCESS on success, NP_E_INVALID_ARG when client is null,
233 * or an error returned by np_observe_notification. 217 * or an error returned by np_observe_notification.
@@ -243,7 +227,7 @@ np_error_t np_observe_notifications(np_client_t client, const char **notificatio
243 } 227 }
244 228
245 if (!notifications) { 229 if (!notifications) {
246 notifications = np_default_notifications; 230 return NP_E_INVALID_ARG;
247 } 231 }
248 232
249 while (notifications[i]) { 233 while (notifications[i]) {
@@ -275,14 +259,14 @@ static int np_get_notification(np_client_t client, char **notification)
275 int res = 0; 259 int res = 0;
276 plist_t dict = NULL; 260 plist_t dict = NULL;
277 261
278 if (!client || !client->connection || *notification) 262 if (!client || !client->parent || *notification)
279 return -1; 263 return -1;
280 264
281 np_lock(client); 265 np_lock(client);
282 266
283 iphone_device_receive_plist_with_timeout(client->connection, &dict, 500); 267 property_list_service_receive_plist_with_timeout(client->parent, &dict, 500);
284 if (!dict) { 268 if (!dict) {
285 log_debug_msg("NotificationProxy: no notification received!\n"); 269 debug_info("NotificationProxy: no notification received!");
286 res = 0; 270 res = 0;
287 } else { 271 } else {
288 char *cmd_value = NULL; 272 char *cmd_value = NULL;
@@ -303,14 +287,14 @@ static int np_get_notification(np_client_t client, char **notification)
303 res = -2; 287 res = -2;
304 if (name_value_node && name_value) { 288 if (name_value_node && name_value) {
305 *notification = name_value; 289 *notification = name_value;
306 log_debug_msg("%s: got notification %s\n", __func__, name_value); 290 debug_info("got notification %s\n", __func__, name_value);
307 res = 0; 291 res = 0;
308 } 292 }
309 } else if (cmd_value && !strcmp(cmd_value, "ProxyDeath")) { 293 } else if (cmd_value && !strcmp(cmd_value, "ProxyDeath")) {
310 log_debug_msg("%s: ERROR: NotificationProxy died!\n", __func__); 294 debug_info("ERROR: NotificationProxy died!");
311 res = -1; 295 res = -1;
312 } else if (cmd_value) { 296 } else if (cmd_value) {
313 log_debug_msg("%d: unknown NotificationProxy command '%s' received!\n", __func__); 297 debug_info("unknown NotificationProxy command '%s' received!", cmd_value);
314 res = -1; 298 res = -1;
315 } else { 299 } else {
316 res = -2; 300 res = -2;
@@ -337,8 +321,8 @@ gpointer np_notifier( gpointer arg )
337 321
338 if (!npt) return NULL; 322 if (!npt) return NULL;
339 323
340 log_debug_msg("%s: starting callback.\n", __func__); 324 debug_info("starting callback.");
341 while (npt->client->connection) { 325 while (npt->client->parent) {
342 np_get_notification(npt->client, &notification); 326 np_get_notification(npt->client, &notification);
343 if (notification) { 327 if (notification) {
344 npt->cbfunc(notification); 328 npt->cbfunc(notification);
@@ -380,12 +364,12 @@ np_error_t np_set_notify_callback( np_client_t client, np_notify_cb_t notify_cb
380 364
381 np_lock(client); 365 np_lock(client);
382 if (client->notifier) { 366 if (client->notifier) {
383 log_debug_msg("%s: callback already set, removing\n"); 367 debug_info("callback already set, removing\n");
384 iphone_connection_t conn = client->connection; 368 property_list_service_client_t parent = client->parent;
385 client->connection = NULL; 369 client->parent = NULL;
386 g_thread_join(client->notifier); 370 g_thread_join(client->notifier);
387 client->notifier = NULL; 371 client->notifier = NULL;
388 client->connection = conn; 372 client->parent = parent;
389 } 373 }
390 374
391 if (notify_cb) { 375 if (notify_cb) {
@@ -400,7 +384,7 @@ np_error_t np_set_notify_callback( np_client_t client, np_notify_cb_t notify_cb
400 } 384 }
401 } 385 }
402 } else { 386 } else {
403 log_debug_msg("%s: no callback set\n", __func__); 387 debug_info("no callback set");
404 } 388 }
405 np_unlock(client); 389 np_unlock(client);
406 390
diff --git a/src/NotificationProxy.h b/src/NotificationProxy.h
index 84f1f89..a2b3001 100644
--- a/src/NotificationProxy.h
+++ b/src/NotificationProxy.h
@@ -24,27 +24,14 @@
24#include <glib.h> 24#include <glib.h>
25 25
26#include "libiphone/notification_proxy.h" 26#include "libiphone/notification_proxy.h"
27#include "property_list_service.h"
27 28
28struct np_client_int { 29struct np_client_int {
29 iphone_connection_t connection; 30 property_list_service_client_t parent;
30 GMutex *mutex; 31 GMutex *mutex;
31 GThread *notifier; 32 GThread *notifier;
32}; 33};
33 34
34static const char *np_default_notifications[11] = {
35 NP_SYNC_SUSPEND_REQUEST,
36 NP_SYNC_RESUME_REQUEST,
37 NP_PHONE_NUMBER_CHANGED,
38 NP_SYNC_CANCEL_REQUEST,
39 NP_DEVICE_NAME_CHANGED,
40 NP_ATTEMPTACTIVATION,
41 NP_DS_DOMAIN_CHANGED,
42 NP_APP_INSTALLED,
43 NP_APP_UNINSTALLED,
44 NP_ITDBPREP_DID_END,
45 NULL
46};
47
48gpointer np_notifier(gpointer arg); 35gpointer np_notifier(gpointer arg);
49 36
50#endif 37#endif
diff --git a/src/SBServices.c b/src/SBServices.c
index 1296245..69c7425 100644
--- a/src/SBServices.c
+++ b/src/SBServices.c
@@ -26,8 +26,8 @@
26#include <plist/plist.h> 26#include <plist/plist.h>
27 27
28#include "SBServices.h" 28#include "SBServices.h"
29#include "iphone.h" 29#include "property_list_service.h"
30#include "utils.h" 30#include "debug.h"
31 31
32/** Locks an sbservices client, done for thread safety stuff. 32/** Locks an sbservices client, done for thread safety stuff.
33 * 33 *
@@ -35,7 +35,7 @@
35 */ 35 */
36static void sbs_lock(sbservices_client_t client) 36static void sbs_lock(sbservices_client_t client)
37{ 37{
38 log_debug_msg("SBServices: Locked\n"); 38 debug_info("SBServices: Locked");
39 g_mutex_lock(client->mutex); 39 g_mutex_lock(client->mutex);
40} 40}
41 41
@@ -45,11 +45,48 @@ static void sbs_lock(sbservices_client_t client)
45 */ 45 */
46static void sbs_unlock(sbservices_client_t client) 46static void sbs_unlock(sbservices_client_t client)
47{ 47{
48 log_debug_msg("SBServices: Unlocked\n"); 48 debug_info("SBServices: Unlocked");
49 g_mutex_unlock(client->mutex); 49 g_mutex_unlock(client->mutex);
50} 50}
51 51
52sbservices_error_t sbservices_client_new(iphone_device_t device, int dst_port, sbservices_client_t *client) 52/**
53 * Convert a property_list_service_error_t value to a sbservices_error_t value.
54 * Used internally to get correct error codes.
55 *
56 * @param err A property_list_service_error_t error code
57 *
58 * @return A matching sbservices_error_t error code,
59 * SBSERVICES_E_UNKNOWN_ERROR otherwise.
60 */
61static sbservices_error_t sbservices_error(property_list_service_error_t err)
62{
63 switch (err) {
64 case PROPERTY_LIST_SERVICE_E_SUCCESS:
65 return SBSERVICES_E_SUCCESS;
66 case PROPERTY_LIST_SERVICE_E_INVALID_ARG:
67 return SBSERVICES_E_INVALID_ARG;
68 case PROPERTY_LIST_SERVICE_E_PLIST_ERROR:
69 return SBSERVICES_E_PLIST_ERROR;
70 case PROPERTY_LIST_SERVICE_E_MUX_ERROR:
71 return SBSERVICES_E_CONN_FAILED;
72 default:
73 break;
74 }
75 return SBSERVICES_E_UNKNOWN_ERROR;
76}
77
78/**
79 * Creates a new sbservices client.
80 *
81 * @param device The device to connect to.
82 * @param port The port on device to connect to.
83 * @param client Pointer that will point to a newly allocated
84 * sbservices_client_t upon successful return.
85 *
86 * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when
87 * client is NULL, or an SBSERVICES_E_* error code otherwise.
88 */
89sbservices_error_t sbservices_client_new(iphone_device_t device, uint16_t port, sbservices_client_t *client)
53{ 90{
54 /* makes sure thread environment is available */ 91 /* makes sure thread environment is available */
55 if (!g_thread_supported()) 92 if (!g_thread_supported())
@@ -58,38 +95,56 @@ sbservices_error_t sbservices_client_new(iphone_device_t device, int dst_port, s
58 if (!device) 95 if (!device)
59 return SBSERVICES_E_INVALID_ARG; 96 return SBSERVICES_E_INVALID_ARG;
60 97
61 /* Attempt connection */ 98 property_list_service_client_t plistclient = NULL;
62 iphone_connection_t connection = NULL; 99 sbservices_error_t err = sbservices_error(property_list_service_client_new(device, port, &plistclient));
63 if (iphone_device_connect(device, dst_port, &connection) != IPHONE_E_SUCCESS) { 100 if (err != SBSERVICES_E_SUCCESS) {
64 return SBSERVICES_E_CONN_FAILED; 101 return err;
65 } 102 }
66 103
67 sbservices_client_t client_loc = (sbservices_client_t) malloc(sizeof(struct sbservices_client_int)); 104 sbservices_client_t client_loc = (sbservices_client_t) malloc(sizeof(struct sbservices_client_int));
68 client_loc->connection = connection; 105 client_loc->parent = plistclient;
69 client_loc->mutex = g_mutex_new(); 106 client_loc->mutex = g_mutex_new();
70 107
71 *client = client_loc; 108 *client = client_loc;
72 return SBSERVICES_E_SUCCESS; 109 return SBSERVICES_E_SUCCESS;
73} 110}
74 111
112/**
113 * Frees an sbservices client.
114 *
115 * @param client The sbservices client to free.
116 *
117 * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when
118 * client is NULL, or an SBSERVICES_E_* error code otherwise.
119 */
75sbservices_error_t sbservices_client_free(sbservices_client_t client) 120sbservices_error_t sbservices_client_free(sbservices_client_t client)
76{ 121{
77 if (!client) 122 if (!client)
78 return SBSERVICES_E_INVALID_ARG; 123 return SBSERVICES_E_INVALID_ARG;
79 124
80 iphone_device_disconnect(client->connection); 125 sbservices_error_t err = sbservices_error(property_list_service_client_free(client->parent));
81 client->connection = NULL; 126 client->parent = NULL;
82 if (client->mutex) { 127 if (client->mutex) {
83 g_mutex_free(client->mutex); 128 g_mutex_free(client->mutex);
84 } 129 }
85 free(client); 130 free(client);
86 131
87 return SBSERVICES_E_SUCCESS; 132 return err;
88} 133}
89 134
135/**
136 * Gets the icon state of the connected device.
137 *
138 * @param client The connected sbservices client to use.
139 * @param state Pointer that will point to a newly allocated plist containing
140 * the current icon state. It is up to the caller to free the memory.
141 *
142 * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when
143 * client or state is invalid, or an SBSERVICES_E_* error code otherwise.
144 */
90sbservices_error_t sbservices_get_icon_state(sbservices_client_t client, plist_t *state) 145sbservices_error_t sbservices_get_icon_state(sbservices_client_t client, plist_t *state)
91{ 146{
92 if (!client || !client->connection || !state) 147 if (!client || !client->parent || !state)
93 return SBSERVICES_E_INVALID_ARG; 148 return SBSERVICES_E_INVALID_ARG;
94 149
95 sbservices_error_t res = SBSERVICES_E_UNKNOWN_ERROR; 150 sbservices_error_t res = SBSERVICES_E_UNKNOWN_ERROR;
@@ -99,17 +154,17 @@ sbservices_error_t sbservices_get_icon_state(sbservices_client_t client, plist_t
99 154
100 sbs_lock(client); 155 sbs_lock(client);
101 156
102 if (iphone_device_send_binary_plist(client->connection, dict) != IPHONE_E_SUCCESS) { 157 res = sbservices_error(property_list_service_send_binary_plist(client->parent, dict));
103 log_debug_msg("%s: could not send plist\n", __func__); 158 if (res != SBSERVICES_E_SUCCESS) {
159 debug_info("could not send plist, error %d", res);
104 goto leave_unlock; 160 goto leave_unlock;
105 } 161 }
106 plist_free(dict); 162 plist_free(dict);
107 dict = NULL; 163 dict = NULL;
108 164
109 if (iphone_device_receive_plist(client->connection, state) == IPHONE_E_SUCCESS) { 165 res = sbservices_error(property_list_service_receive_plist(client->parent, state));
110 res = SBSERVICES_E_SUCCESS; 166 if (res != SBSERVICES_E_SUCCESS) {
111 } else { 167 debug_info("could not get icon state, error %d", res);
112 log_debug_msg("%s: could not get icon state!\n", __func__);
113 if (*state) { 168 if (*state) {
114 plist_free(*state); 169 plist_free(*state);
115 *state = NULL; 170 *state = NULL;
@@ -124,9 +179,18 @@ leave_unlock:
124 return res; 179 return res;
125} 180}
126 181
182/**
183 * Sets the icon state of the connected device.
184 *
185 * @param client The connected sbservices client to use.
186 * @param newstate A plist containing the new iconstate.
187 *
188 * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when
189 * client or newstate is NULL, or an SBSERVICES_E_* error code otherwise.
190 */
127sbservices_error_t sbservices_set_icon_state(sbservices_client_t client, plist_t newstate) 191sbservices_error_t sbservices_set_icon_state(sbservices_client_t client, plist_t newstate)
128{ 192{
129 if (!client || !client->connection || !newstate) 193 if (!client || !client->parent || !newstate)
130 return SBSERVICES_E_INVALID_ARG; 194 return SBSERVICES_E_INVALID_ARG;
131 195
132 sbservices_error_t res = SBSERVICES_E_UNKNOWN_ERROR; 196 sbservices_error_t res = SBSERVICES_E_UNKNOWN_ERROR;
@@ -137,13 +201,12 @@ sbservices_error_t sbservices_set_icon_state(sbservices_client_t client, plist_t
137 201
138 sbs_lock(client); 202 sbs_lock(client);
139 203
140 if (iphone_device_send_binary_plist(client->connection, dict) != IPHONE_E_SUCCESS) { 204 res = sbservices_error(property_list_service_send_binary_plist(client->parent, dict));
141 log_debug_msg("%s: could not send plist\n", __func__); 205 if (res != SBSERVICES_E_SUCCESS) {
142 goto leave_unlock; 206 debug_info("could not send plist, error %d", res);
143 } 207 }
144 // NO RESPONSE 208 // NO RESPONSE
145 209
146leave_unlock:
147 if (dict) { 210 if (dict) {
148 plist_free(dict); 211 plist_free(dict);
149 } 212 }
@@ -151,9 +214,24 @@ leave_unlock:
151 return res; 214 return res;
152} 215}
153 216
217/**
218 * Get the icon of the specified app as PNG data.
219 *
220 * @param client The connected sbservices client to use.
221 * @param bundleId The bundle identifier of the app to retrieve the icon for.
222 * @param pngdata Pointer that will point to a newly allocated buffer
223 * containing the PNG data upon successful return. It is up to the caller
224 * to free the memory.
225 * @param pngsize Pointer to a uint64_t that will be set to the size of the
226 * buffer pngdata points to upon successful return.
227 *
228 * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when
229 * client, bundleId, or pngdata are invalid, or an SBSERVICES_E_* error
230 * code otherwise.
231 */
154sbservices_error_t sbservices_get_icon_pngdata(sbservices_client_t client, const char *bundleId, char **pngdata, uint64_t *pngsize) 232sbservices_error_t sbservices_get_icon_pngdata(sbservices_client_t client, const char *bundleId, char **pngdata, uint64_t *pngsize)
155{ 233{
156 if (!client || !client->connection || !pngdata) 234 if (!client || !client->parent || !bundleId || !pngdata)
157 return SBSERVICES_E_INVALID_ARG; 235 return SBSERVICES_E_INVALID_ARG;
158 236
159 sbservices_error_t res = SBSERVICES_E_UNKNOWN_ERROR; 237 sbservices_error_t res = SBSERVICES_E_UNKNOWN_ERROR;
@@ -164,19 +242,20 @@ sbservices_error_t sbservices_get_icon_pngdata(sbservices_client_t client, const
164 242
165 sbs_lock(client); 243 sbs_lock(client);
166 244
167 if (iphone_device_send_binary_plist(client->connection, dict) != IPHONE_E_SUCCESS) { 245 res = sbservices_error(property_list_service_send_binary_plist(client->parent, dict));
168 log_debug_msg("%s: could not send plist\n", __func__); 246 if (res != SBSERVICES_E_SUCCESS) {
247 debug_info("could not send plist, error %d", res);
169 goto leave_unlock; 248 goto leave_unlock;
170 } 249 }
171 plist_free(dict); 250 plist_free(dict);
172 251
173 dict = NULL; 252 dict = NULL;
174 if (iphone_device_receive_plist(client->connection, &dict) == IPHONE_E_SUCCESS) { 253 res = sbservices_error(property_list_service_receive_plist(client->parent, &dict));
254 if (res == SBSERVICES_E_SUCCESS) {
175 plist_t node = plist_dict_get_item(dict, "pngData"); 255 plist_t node = plist_dict_get_item(dict, "pngData");
176 if (node) { 256 if (node) {
177 plist_get_data_val(node, pngdata, pngsize); 257 plist_get_data_val(node, pngdata, pngsize);
178 } 258 }
179 res = SBSERVICES_E_SUCCESS;
180 } 259 }
181 260
182leave_unlock: 261leave_unlock:
diff --git a/src/SBServices.h b/src/SBServices.h
index 8f923b9..d24828a 100644
--- a/src/SBServices.h
+++ b/src/SBServices.h
@@ -24,9 +24,10 @@
24#include <glib.h> 24#include <glib.h>
25 25
26#include "libiphone/sbservices.h" 26#include "libiphone/sbservices.h"
27#include "property_list_service.h"
27 28
28struct sbservices_client_int { 29struct sbservices_client_int {
29 iphone_connection_t connection; 30 property_list_service_client_t parent;
30 GMutex *mutex; 31 GMutex *mutex;
31}; 32};
32 33
diff --git a/src/utils.c b/src/debug.c
index 3c08351..2cdeebf 100644
--- a/src/utils.c
+++ b/src/debug.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * utils.c 2 * debug.c
3 * contains utilitary methos for logging and debugging 3 * contains utilitary functions for debugging
4 * 4 *
5 * Copyright (c) 2008 Jonathan Beck All Rights Reserved. 5 * Copyright (c) 2008 Jonathan Beck All Rights Reserved.
6 * 6 *
@@ -18,15 +18,18 @@
18 * License along with this library; if not, write to the Free Software 18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */ 20 */
21
21#include <stdarg.h> 22#include <stdarg.h>
23#define _GNU_SOURCE 1
24#define __USE_GNU 1
22#include <stdio.h> 25#include <stdio.h>
23#include <stdint.h> 26#include <stdint.h>
27#include <stdlib.h>
24 28
25#include "utils.h" 29#include "debug.h"
26#include "libiphone/libiphone.h" 30#include "libiphone/libiphone.h"
27 31
28int toto_debug = 0; 32int debug_level = 0;
29uint16_t dbg_mask = 0;
30 33
31/** 34/**
32 * Sets the level of debugging. Currently the only acceptable values are 0 and 35 * Sets the level of debugging. Currently the only acceptable values are 0 and
@@ -36,59 +39,63 @@ uint16_t dbg_mask = 0;
36 */ 39 */
37void iphone_set_debug_level(int level) 40void iphone_set_debug_level(int level)
38{ 41{
39 toto_debug = level; 42 debug_level = level;
40} 43}
41 44
42 45static void debug_print_line(const char *func, const char *file, int line, const char *buffer)
43/**
44 * Set debug ids to display. Values can be OR-ed
45 *
46 * @param level Set to 0 for no debugging or 1 for debugging.
47 */
48void iphone_set_debug_mask(uint16_t mask)
49{ 46{
50 dbg_mask = mask; 47 char *str_time = NULL;
51} 48 char *header = NULL;
49 time_t the_time;
52 50
53void log_debug_msg(const char *format, ...) 51 time(&the_time);
54{ 52 str_time = g_new0 (gchar, 255);
55#ifndef STRIP_DEBUG_CODE 53 strftime(str_time, 254, "%H:%M:%S", localtime (&the_time));
56 54
57 va_list args; 55 /* generate header text */
58 /* run the real fprintf */ 56 (void)asprintf(&header, "%s %s:%d %s()", str_time, file, line, func);
59 va_start(args, format); 57 free (str_time);
60 58
61 if (toto_debug) 59 /* always in light green */
62 vfprintf(stderr, format, args); 60 printf ("%s: ", header);
63 61
64 va_end(args); 62 /* different colors according to the severity */
63 printf ("%s\n", buffer);
65 64
66#endif 65 /* flush this output, as we need to debug */
66 fflush (stdout);
67
68 free (header);
67} 69}
68 70
69void log_dbg_msg(uint16_t id, const char *format, ...) 71inline void debug_info_real(const char *func, const char *file, int line, const char *format, ...)
70{ 72{
71#ifndef STRIP_DEBUG_CODE 73#ifndef STRIP_DEBUG_CODE
72 if (id & dbg_mask) { 74 va_list args;
73 va_list args; 75 char *buffer = NULL;
74 /* run the real fprintf */
75 va_start(args, format);
76 76
77 vfprintf(stderr, format, args); 77 if (!debug_level)
78 return;
78 79
79 va_end(args); 80 /* run the real fprintf */
80 } 81 va_start(args, format);
82 (void)vasprintf(&buffer, format, args);
83 va_end(args);
84
85 debug_print_line(func, file, line, buffer);
86
87 free(buffer);
81#endif 88#endif
82} 89}
83 90
84inline void log_debug_buffer(const char *data, const int length) 91inline void debug_buffer(const char *data, const int length)
85{ 92{
86#ifndef STRIP_DEBUG_CODE 93#ifndef STRIP_DEBUG_CODE
87 int i; 94 int i;
88 int j; 95 int j;
89 unsigned char c; 96 unsigned char c;
90 97
91 if (toto_debug) { 98 if (debug_level) {
92 for (i = 0; i < length; i += 16) { 99 for (i = 0; i < length; i += 16) {
93 fprintf(stderr, "%04x: ", i); 100 fprintf(stderr, "%04x: ", i);
94 for (j = 0; j < 16; j++) { 101 for (j = 0; j < 16; j++) {
@@ -116,16 +123,29 @@ inline void log_debug_buffer(const char *data, const int length)
116#endif 123#endif
117} 124}
118 125
119inline void dump_debug_buffer(const char *file, const char *data, const int length) 126inline void debug_buffer_to_file(const char *file, const char *data, const int length)
120{ 127{
121#ifndef STRIP_DEBUG_CODE 128#ifndef STRIP_DEBUG_CODE
122 /* run the real fprintf */ 129 if (debug_level) {
123 if (toto_debug) { 130 FILE *f = fopen(file, "w+");
124 FILE *my_ssl_packet = fopen(file, "w+"); 131 fwrite(data, 1, length, f);
125 fwrite(data, 1, length, my_ssl_packet); 132 fflush(f);
126 fflush(my_ssl_packet); 133 fclose(f);
127 fprintf(stderr, "%s: Wrote SSL packet to drive, too.\n", __func__);
128 fclose(my_ssl_packet);
129 } 134 }
130#endif 135#endif
131} 136}
137
138inline void debug_plist(plist_t plist)
139{
140#ifndef STRIP_DEBUG_CODE
141 if (!plist)
142 return;
143
144 char *buffer = NULL;
145 uint32_t length = 0;
146 plist_to_xml(plist, &buffer, &length);
147 debug_info("plist size: %i\nbuffer :\n%s", length, buffer);
148 free(buffer);
149#endif
150}
151
diff --git a/src/debug.h b/src/debug.h
new file mode 100644
index 0000000..0a29be3
--- /dev/null
+++ b/src/debug.h
@@ -0,0 +1,45 @@
1/*
2 * debug.h
3 * contains utilitary functions for debugging
4 *
5 * Copyright (c) 2008 Jonathan Beck All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#ifndef DEBUG_H
23#define DEBUG_H
24
25#include <plist/plist.h>
26#include <glib.h>
27
28#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && !defined(STRIP_DEBUG_CODE)
29#define debug_info(...) debug_info_real (__func__, __FILE__, __LINE__, __VA_ARGS__)
30#elif defined(__GNUC__) && __GNUC__ >= 3 && !defined(STRIP_DEBUG_CODE)
31#define debug_info(...) debug_info_real (__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__)
32#else
33#define debug_info(...)
34#endif
35
36G_GNUC_INTERNAL inline void debug_info_real(const char *func,
37 const char *file,
38 int line,
39 const char *format, ...);
40
41G_GNUC_INTERNAL inline void debug_buffer(const char *data, const int length);
42G_GNUC_INTERNAL inline void debug_buffer_to_file(const char *file, const char *data, const int length);
43G_GNUC_INTERNAL inline void debug_plist(plist_t plist);
44
45#endif
diff --git a/src/device_link_service.c b/src/device_link_service.c
new file mode 100644
index 0000000..e1155a5
--- /dev/null
+++ b/src/device_link_service.c
@@ -0,0 +1,299 @@
1 /*
2 * device_link_service.c
3 * DeviceLink service implementation.
4 *
5 * Copyright (c) 2010 Nikias Bassen, All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21#include <string.h>
22#include <stdlib.h>
23#include "device_link_service.h"
24#include "property_list_service.h"
25#include "debug.h"
26
27/**
28 * Internally used function to extract the message string from a DLMessage*
29 * plist.
30 *
31 * @param dl_msg The DeviceLink property list to parse.
32 *
33 * @return An allocated char* with the DLMessage from the given plist,
34 * or NULL when the plist does not contain any DLMessage. It is up to
35 * the caller to free the allocated memory.
36 */
37static char *device_link_service_get_message(plist_t dl_msg)
38{
39 uint32_t cnt = 0;
40 plist_t cmd = 0;
41 char *cmd_str = NULL;
42
43 /* sanity check */
44 if ((plist_get_node_type(dl_msg) != PLIST_ARRAY) || ((cnt = plist_array_get_size(dl_msg)) < 1)) {
45 return NULL;
46 }
47
48 /* get dl command */
49 cmd = plist_array_get_item(dl_msg, 0);
50 if (!cmd || (plist_get_node_type(cmd) != PLIST_STRING)) {
51 return NULL;
52 }
53
54 plist_get_string_val(cmd, &cmd_str);
55 if (!cmd_str) {
56 return NULL;
57 }
58
59 if ((strlen(cmd_str) < (strlen("DLMessage")+1))
60 || (strncmp(cmd_str, "DLMessage", strlen("DLMessage")))) {
61 free(cmd_str);
62 return NULL;
63 }
64
65 /* we got a DLMessage* command */
66 return cmd_str;
67}
68
69/**
70 * Creates a new device link service client.
71 *
72 * @param device The device to connect to.
73 * @param port Port on device to connect to.
74 * @param client Reference that will point to a newly allocated
75 * device_link_service_client_t upon successful return.
76 *
77 * @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
78 * DEVICE_LINK_SERVICE_E_INVALID_ARG when one of the parameters is invalid,
79 * or DEVICE_LINK_SERVICE_E_MUX_ERROR when the connection failed.
80 */
81device_link_service_error_t device_link_service_client_new(iphone_device_t device, uint16_t port, device_link_service_client_t *client)
82{
83 if (!device || port == 0 || !client || *client) {
84 return DEVICE_LINK_SERVICE_E_INVALID_ARG;
85 }
86
87 property_list_service_client_t plistclient = NULL;
88 if (property_list_service_client_new(device, port, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
89 return DEVICE_LINK_SERVICE_E_MUX_ERROR;
90 }
91
92 /* create client object */
93 device_link_service_client_t client_loc = (device_link_service_client_t) malloc(sizeof(struct device_link_service_client_int));
94 client_loc->parent = plistclient;
95
96 /* all done, return success */
97 *client = client_loc;
98 return DEVICE_LINK_SERVICE_E_SUCCESS;
99}
100
101/**
102 * Frees a device link service client.
103 *
104 * @param client The device_link_service_client_t to free.
105 *
106 * @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
107 * DEVICE_LINK_SERVICE_E_INVALID_ARG when one of client or client->parent
108 * is invalid, or DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR when the was an error
109 * freeing the parent property_list_service client.
110 */
111device_link_service_error_t device_link_service_client_free(device_link_service_client_t client)
112{
113 if (!client)
114 return DEVICE_LINK_SERVICE_E_INVALID_ARG;
115
116 if (property_list_service_client_free(client->parent) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
117 return DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR;
118 }
119 return DEVICE_LINK_SERVICE_E_SUCCESS;
120}
121
122/**
123 * Performs the DLMessageVersionExchange with the connected device.
124 * This should be the first operation to be executed by an implemented
125 * device link service client.
126 *
127 * @param client The device_link_service client to use.
128 * @param version_major The major version number to check.
129 * @param version_minor The minor version number to check.
130 *
131 * @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
132 * DEVICE_LINK_SERVICE_E_INVALID_ARG when client is NULL,
133 * DEVICE_LINK_SERVICE_E_MUX_ERROR when a communication error occurs,
134 * DEVICE_LINK_SERVICE_E_PLIST_ERROR when the received plist has not the
135 * expected contents, DEVICE_LINK_SERVICE_E_BAD_VERSION when the version
136 * given by the device is larger than the given version,
137 * or DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR otherwise.
138 */
139device_link_service_error_t device_link_service_version_exchange(device_link_service_client_t client, uint64_t version_major, uint64_t version_minor)
140{
141 if (!client)
142 return DEVICE_LINK_SERVICE_E_INVALID_ARG;
143
144 device_link_service_error_t err = DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR;
145
146 /* perform version exchange */
147 plist_t array = NULL;
148 char *msg = NULL;
149
150 /* receive DLMessageVersionExchange from device */
151 if (property_list_service_receive_plist(client->parent, &array) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
152 debug_info("Did not receive initial message from device!");
153 err = DEVICE_LINK_SERVICE_E_MUX_ERROR;
154 goto leave;
155 }
156 msg = device_link_service_get_message(array);
157 if (!msg || strcmp(msg, "DLMessageVersionExchange")) {
158 debug_info("Did not receive DLMessageVersionExchange from device!");
159 err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
160 goto leave;
161 }
162 free(msg);
163 msg = NULL;
164
165 /* get major and minor version number */
166 if (plist_array_get_size(array) < 3) {
167 debug_info("DLMessageVersionExchange has unexpected format!");
168 err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
169 goto leave;
170 }
171 plist_t maj = plist_array_get_item(array, 1);
172 plist_t min = plist_array_get_item(array, 2);
173 uint64_t vmajor = 0;
174 uint64_t vminor = 0;
175 if (maj) {
176 plist_get_uint_val(maj, &vmajor);
177 }
178 if (min) {
179 plist_get_uint_val(min, &vminor);
180 }
181 if (vmajor > version_major) {
182 debug_info("Version mismatch: device=(%lld,%lld) > expected=(%lld,%lld)", vmajor, vminor, version_major, version_minor);
183 err = DEVICE_LINK_SERVICE_E_BAD_VERSION;
184 goto leave;
185 } else if ((vmajor == version_major) && (vminor > version_minor)) {
186 debug_info("WARNING: Version mismatch: device=(%lld,%lld) > expected=(%lld,%lld)", vmajor, vminor, version_major, version_minor);
187 err = DEVICE_LINK_SERVICE_E_BAD_VERSION;
188 goto leave;
189 }
190 plist_free(array);
191
192 /* version is ok, send reply */
193 array = plist_new_array();
194 plist_array_append_item(array, plist_new_string("DLMessageVersionExchange"));
195 plist_array_append_item(array, plist_new_string("DLVersionsOk"));
196 if (property_list_service_send_binary_plist(client->parent, array) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
197 debug_info("Error when sending DLVersionsOk");
198 err = DEVICE_LINK_SERVICE_E_MUX_ERROR;
199 goto leave;
200 }
201 plist_free(array);
202
203 /* receive DeviceReady message */
204 array = NULL;
205 if (property_list_service_receive_plist(client->parent, &array) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
206 debug_info("Error when receiving DLMessageDeviceReady!");
207 err = DEVICE_LINK_SERVICE_E_MUX_ERROR;
208 goto leave;
209 }
210 msg = device_link_service_get_message(array);
211 if (!msg || strcmp(msg, "DLMessageDeviceReady")) {
212 debug_info("Did not get DLMessageDeviceReady!");
213 err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
214 goto leave;
215 }
216 err = DEVICE_LINK_SERVICE_E_SUCCESS;
217
218leave:
219 if (msg) {
220 free(msg);
221 }
222 if (array) {
223 plist_free(array);
224 }
225 return err;
226}
227
228/**
229 * Performs a disconnect with the connected device link service client.
230 *
231 * @param client The device link service client to disconnect.
232 *
233 * @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
234 * DEVICE_LINK_SERVICE_E_INVALID_ARG if client is NULL,
235 * or DEVICE_LINK_SERVICE_E_MUX_ERROR when there's an error when sending
236 * the the disconnect message.
237 */
238device_link_service_error_t device_link_service_disconnect(device_link_service_client_t client)
239{
240 if (!client)
241 return DEVICE_LINK_SERVICE_E_INVALID_ARG;
242
243 plist_t array = plist_new_array();
244 plist_array_append_item(array, plist_new_string("DLMessageDisconnect"));
245 plist_array_append_item(array, plist_new_string("All done, thanks for the memories"));
246
247 device_link_service_error_t err = DEVICE_LINK_SERVICE_E_SUCCESS;
248 if (property_list_service_send_binary_plist(client->parent, array) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
249 err = DEVICE_LINK_SERVICE_E_MUX_ERROR;
250 }
251 plist_free(array);
252 return err;
253}
254
255/**
256 * Generic device link service send function.
257 *
258 * @param client The device link service client to use for sending
259 * @param plist The property list to send
260 *
261 * @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
262 * DEVICE_LINK_SERVICE_E_INVALID_ARG when client or plist is NULL,
263 * or DEVICE_LINK_SERVICE_E_MUX_ERROR when the given property list could
264 * not be sent.
265 */
266device_link_service_error_t device_link_service_send(device_link_service_client_t client, plist_t plist)
267{
268 if (!client || !plist) {
269 return DEVICE_LINK_SERVICE_E_INVALID_ARG;
270 }
271 if (property_list_service_send_binary_plist(client->parent, plist) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
272 return DEVICE_LINK_SERVICE_E_MUX_ERROR;
273 }
274 return DEVICE_LINK_SERVICE_E_SUCCESS;
275}
276
277/* Generic device link service receive function.
278 *
279 * @param client The device link service client to use for sending
280 * @param plist Pointer that will point to the property list received upon
281 * successful return.
282 *
283 * @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
284 * DEVICE_LINK_SERVICE_E_INVALID_ARG when client or plist is NULL,
285 * or DEVICE_LINK_SERVICE_E_MUX_ERROR when no property list could be
286 * received.
287 */
288device_link_service_error_t device_link_service_receive(device_link_service_client_t client, plist_t *plist)
289{
290 if (!client || !plist || (plist && *plist)) {
291 return DEVICE_LINK_SERVICE_E_INVALID_ARG;
292 }
293
294 if (property_list_service_receive_plist(client->parent, plist) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
295 return DEVICE_LINK_SERVICE_E_MUX_ERROR;
296 }
297 return DEVICE_LINK_SERVICE_E_SUCCESS;
298}
299
diff --git a/src/device_link_service.h b/src/device_link_service.h
new file mode 100644
index 0000000..e14d897
--- /dev/null
+++ b/src/device_link_service.h
@@ -0,0 +1,51 @@
1 /*
2 * device_link_service.h
3 * Definitions for the DeviceLink service
4 *
5 * Copyright (c) 2010 Nikias Bassen, All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21#ifndef DEVICE_LINK_SERVICE_H
22#define DEVICE_LINK_SERVICE_H
23
24#include "property_list_service.h"
25
26/* Error Codes */
27#define DEVICE_LINK_SERVICE_E_SUCCESS 0
28#define DEVICE_LINK_SERVICE_E_INVALID_ARG -1
29#define DEVICE_LINK_SERVICE_E_PLIST_ERROR -2
30#define DEVICE_LINK_SERVICE_E_MUX_ERROR -3
31#define DEVICE_LINK_SERVICE_E_BAD_VERSION -4
32
33#define DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR -256
34
35
36struct device_link_service_client_int {
37 property_list_service_client_t parent;
38};
39
40typedef struct device_link_service_client_int *device_link_service_client_t;
41
42typedef int16_t device_link_service_error_t;
43
44device_link_service_error_t device_link_service_client_new(iphone_device_t device, uint16_t port, device_link_service_client_t *client);
45device_link_service_error_t device_link_service_client_free(device_link_service_client_t client);
46device_link_service_error_t device_link_service_version_exchange(device_link_service_client_t client, uint64_t version_major, uint64_t version_minor);
47device_link_service_error_t device_link_service_disconnect(device_link_service_client_t client);
48device_link_service_error_t device_link_service_send(device_link_service_client_t client, plist_t plist);
49device_link_service_error_t device_link_service_receive(device_link_service_client_t client, plist_t *plist);
50
51#endif
diff --git a/src/iphone.c b/src/iphone.c
index 4a54848..6d95c45 100644
--- a/src/iphone.c
+++ b/src/iphone.c
@@ -26,8 +26,9 @@
26#include <arpa/inet.h> 26#include <arpa/inet.h>
27 27
28#include <usbmuxd.h> 28#include <usbmuxd.h>
29#include <gnutls/gnutls.h>
29#include "iphone.h" 30#include "iphone.h"
30#include "utils.h" 31#include "debug.h"
31 32
32static iphone_event_cb_t event_cb = NULL; 33static iphone_event_cb_t event_cb = NULL;
33 34
@@ -60,7 +61,7 @@ iphone_error_t iphone_event_subscribe(iphone_event_cb_t callback, void *user_dat
60 int res = usbmuxd_subscribe(usbmux_event_cb, user_data); 61 int res = usbmuxd_subscribe(usbmux_event_cb, user_data);
61 if (res != 0) { 62 if (res != 0) {
62 event_cb = NULL; 63 event_cb = NULL;
63 log_debug_msg("%s: Error %d when subscribing usbmux event callback!\n", __func__, res); 64 debug_info("Error %d when subscribing usbmux event callback!", res);
64 return IPHONE_E_UNKNOWN_ERROR; 65 return IPHONE_E_UNKNOWN_ERROR;
65 } 66 }
66 return IPHONE_E_SUCCESS; 67 return IPHONE_E_SUCCESS;
@@ -77,7 +78,7 @@ iphone_error_t iphone_event_unsubscribe()
77 event_cb = NULL; 78 event_cb = NULL;
78 int res = usbmuxd_unsubscribe(); 79 int res = usbmuxd_unsubscribe();
79 if (res != 0) { 80 if (res != 0) {
80 log_debug_msg("%s: Error %d when unsubscribing usbmux event callback!\n", __func__, res); 81 debug_info("Error %d when unsubscribing usbmux event callback!", res);
81 return IPHONE_E_UNKNOWN_ERROR; 82 return IPHONE_E_UNKNOWN_ERROR;
82 } 83 }
83 return IPHONE_E_SUCCESS; 84 return IPHONE_E_SUCCESS;
@@ -100,7 +101,7 @@ iphone_error_t iphone_get_device_list(char ***devices, int *count)
100 *count = 0; 101 *count = 0;
101 102
102 if (usbmuxd_get_device_list(&dev_list) < 0) { 103 if (usbmuxd_get_device_list(&dev_list) < 0) {
103 log_debug_msg("%s: ERROR: usbmuxd is not running!\n", __func__); 104 debug_info("ERROR: usbmuxd is not running!\n", __func__);
104 return IPHONE_E_NO_DEVICE; 105 return IPHONE_E_NO_DEVICE;
105 } 106 }
106 107
@@ -201,31 +202,32 @@ iphone_error_t iphone_device_free(iphone_device_t device)
201 * Set up a connection to the given device. 202 * Set up a connection to the given device.
202 * 203 *
203 * @param device The device to connect to. 204 * @param device The device to connect to.
204 * @param dst_port The destination port to connect to. 205 * @param port The destination port to connect to.
205 * @param connection Pointer to an iphone_connection_t that will be filled 206 * @param connection Pointer to an iphone_connection_t that will be filled
206 * with the necessary data of the connection. 207 * with the necessary data of the connection.
207 * 208 *
208 * @return IPHONE_E_SUCCESS if ok, otherwise an error code. 209 * @return IPHONE_E_SUCCESS if ok, otherwise an error code.
209 */ 210 */
210iphone_error_t iphone_device_connect(iphone_device_t device, uint16_t dst_port, iphone_connection_t *connection) 211iphone_error_t iphone_device_connect(iphone_device_t device, uint16_t port, iphone_connection_t *connection)
211{ 212{
212 if (!device) { 213 if (!device) {
213 return IPHONE_E_INVALID_ARG; 214 return IPHONE_E_INVALID_ARG;
214 } 215 }
215 216
216 if (device->conn_type == CONNECTION_USBMUXD) { 217 if (device->conn_type == CONNECTION_USBMUXD) {
217 int sfd = usbmuxd_connect((uint32_t)(device->conn_data), dst_port); 218 int sfd = usbmuxd_connect((uint32_t)(device->conn_data), port);
218 if (sfd < 0) { 219 if (sfd < 0) {
219 log_debug_msg("%s: ERROR: Connecting to usbmuxd failed: %d (%s)\n", __func__, sfd, strerror(-sfd)); 220 debug_info("ERROR: Connecting to usbmuxd failed: %d (%s)", sfd, strerror(-sfd));
220 return IPHONE_E_UNKNOWN_ERROR; 221 return IPHONE_E_UNKNOWN_ERROR;
221 } 222 }
222 iphone_connection_t new_connection = (iphone_connection_t)malloc(sizeof(struct iphone_connection_int)); 223 iphone_connection_t new_connection = (iphone_connection_t)malloc(sizeof(struct iphone_connection_int));
223 new_connection->type = CONNECTION_USBMUXD; 224 new_connection->type = CONNECTION_USBMUXD;
224 new_connection->data = (void*)sfd; 225 new_connection->data = (void*)sfd;
226 new_connection->ssl_data = NULL;
225 *connection = new_connection; 227 *connection = new_connection;
226 return IPHONE_E_SUCCESS; 228 return IPHONE_E_SUCCESS;
227 } else { 229 } else {
228 log_debug_msg("%s: Unknown connection type %d\n", __func__, device->conn_type); 230 debug_info("Unknown connection type %d", device->conn_type);
229 } 231 }
230 232
231 return IPHONE_E_UNKNOWN_ERROR; 233 return IPHONE_E_UNKNOWN_ERROR;
@@ -243,18 +245,45 @@ iphone_error_t iphone_device_disconnect(iphone_connection_t connection)
243 if (!connection) { 245 if (!connection) {
244 return IPHONE_E_INVALID_ARG; 246 return IPHONE_E_INVALID_ARG;
245 } 247 }
248 /* shut down ssl if enabled */
249 if (connection->ssl_data) {
250 iphone_connection_disable_ssl(connection);
251 }
246 iphone_error_t result = IPHONE_E_UNKNOWN_ERROR; 252 iphone_error_t result = IPHONE_E_UNKNOWN_ERROR;
247 if (connection->type == CONNECTION_USBMUXD) { 253 if (connection->type == CONNECTION_USBMUXD) {
248 usbmuxd_disconnect((int)(connection->data)); 254 usbmuxd_disconnect((int)(connection->data));
249 result = IPHONE_E_SUCCESS; 255 result = IPHONE_E_SUCCESS;
250 } else { 256 } else {
251 log_debug_msg("%s: Unknown connection type %d\n", __func__, connection->type); 257 debug_info("Unknown connection type %d", connection->type);
252 } 258 }
253 free(connection); 259 free(connection);
254 return result; 260 return result;
255} 261}
256 262
257/** 263/**
264 * Internally used function to send raw data over the given connection.
265 */
266static iphone_error_t internal_connection_send(iphone_connection_t connection, const char *data, uint32_t len, uint32_t *sent_bytes)
267{
268 if (!connection || !data) {
269 return IPHONE_E_INVALID_ARG;
270 }
271
272 if (connection->type == CONNECTION_USBMUXD) {
273 int res = usbmuxd_send((int)(connection->data), data, len, sent_bytes);
274 if (res < 0) {
275 debug_info("ERROR: usbmuxd_send returned %d (%s)", res, strerror(-res));
276 return IPHONE_E_UNKNOWN_ERROR;
277 }
278 return IPHONE_E_SUCCESS;
279 } else {
280 debug_info("Unknown connection type %d", connection->type);
281 }
282 return IPHONE_E_UNKNOWN_ERROR;
283
284}
285
286/**
258 * Send data to a device via the given connection. 287 * Send data to a device via the given connection.
259 * 288 *
260 * @param connection The connection to send data over. 289 * @param connection The connection to send data over.
@@ -267,19 +296,41 @@ iphone_error_t iphone_device_disconnect(iphone_connection_t connection)
267 */ 296 */
268iphone_error_t iphone_device_send(iphone_connection_t connection, const char *data, uint32_t len, uint32_t *sent_bytes) 297iphone_error_t iphone_device_send(iphone_connection_t connection, const char *data, uint32_t len, uint32_t *sent_bytes)
269{ 298{
270 if (!connection || !data) { 299 if (!connection || !data || (connection->ssl_data && !connection->ssl_data->session)) {
300 return IPHONE_E_INVALID_ARG;
301 }
302
303 if (connection->ssl_data) {
304 ssize_t sent = gnutls_record_send(connection->ssl_data->session, (void*)data, (size_t)len);
305 if ((uint32_t)sent == (uint32_t)len) {
306 *sent_bytes = sent;
307 return IPHONE_E_SUCCESS;
308 }
309 *sent_bytes = 0;
310 return IPHONE_E_SSL_ERROR;
311 }
312 return internal_connection_send(connection, data, len, sent_bytes);
313}
314
315/**
316 * Internally used function for receiving raw data over the given connection
317 * using a timeout.
318 */
319static iphone_error_t internal_connection_recv_timeout(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout)
320{
321 if (!connection) {
271 return IPHONE_E_INVALID_ARG; 322 return IPHONE_E_INVALID_ARG;
272 } 323 }
273 324
274 if (connection->type == CONNECTION_USBMUXD) { 325 if (connection->type == CONNECTION_USBMUXD) {
275 int res = usbmuxd_send((int)(connection->data), data, len, sent_bytes); 326 int res = usbmuxd_recv_timeout((int)(connection->data), data, len, recv_bytes, timeout);
276 if (res < 0) { 327 if (res < 0) {
277 log_debug_msg("%s: ERROR: usbmuxd_send returned %d (%s)\n", __func__, res, strerror(-res)); 328 debug_info("ERROR: usbmuxd_recv_timeout returned %d (%s)", res, strerror(-res));
278 return IPHONE_E_UNKNOWN_ERROR; 329 return IPHONE_E_UNKNOWN_ERROR;
279 } 330 }
280 return IPHONE_E_SUCCESS; 331 return IPHONE_E_SUCCESS;
281 } else { 332 } else {
282 log_debug_msg("%s: Unknown connection type %d\n", __func__, connection->type); 333 debug_info("Unknown connection type %d", connection->type);
283 } 334 }
284 return IPHONE_E_UNKNOWN_ERROR; 335 return IPHONE_E_UNKNOWN_ERROR;
285} 336}
@@ -301,19 +352,41 @@ iphone_error_t iphone_device_send(iphone_connection_t connection, const char *da
301 */ 352 */
302iphone_error_t iphone_device_recv_timeout(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout) 353iphone_error_t iphone_device_recv_timeout(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout)
303{ 354{
355 if (!connection || (connection->ssl_data && !connection->ssl_data->session)) {
356 return IPHONE_E_INVALID_ARG;
357 }
358
359 if (connection->ssl_data) {
360 ssize_t received = gnutls_record_recv(connection->ssl_data->session, (void*)data, (size_t)len);
361 if (received > 0) {
362 *recv_bytes = received;
363 return IPHONE_E_SUCCESS;
364 }
365 *recv_bytes = 0;
366 return IPHONE_E_SSL_ERROR;
367 }
368 return internal_connection_recv_timeout(connection, data, len, recv_bytes, timeout);
369}
370
371/**
372 * Internally used function for receiving raw data over the given connection.
373 */
374static iphone_error_t internal_connection_recv(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes)
375{
304 if (!connection) { 376 if (!connection) {
305 return IPHONE_E_INVALID_ARG; 377 return IPHONE_E_INVALID_ARG;
306 } 378 }
307 379
308 if (connection->type == CONNECTION_USBMUXD) { 380 if (connection->type == CONNECTION_USBMUXD) {
309 int res = usbmuxd_recv_timeout((int)(connection->data), data, len, recv_bytes, timeout); 381 int res = usbmuxd_recv((int)(connection->data), data, len, recv_bytes);
310 if (res < 0) { 382 if (res < 0) {
311 log_debug_msg("%s: ERROR: usbmuxd_recv_timeout returned %d (%s)\n", __func__, res, strerror(-res)); 383 debug_info("ERROR: usbmuxd_recv returned %d (%s)", res, strerror(-res));
312 return IPHONE_E_UNKNOWN_ERROR; 384 return IPHONE_E_UNKNOWN_ERROR;
313 } 385 }
386
314 return IPHONE_E_SUCCESS; 387 return IPHONE_E_SUCCESS;
315 } else { 388 } else {
316 log_debug_msg("%s: Unknown connection type %d\n", __func__, connection->type); 389 debug_info("Unknown connection type %d", connection->type);
317 } 390 }
318 return IPHONE_E_UNKNOWN_ERROR; 391 return IPHONE_E_UNKNOWN_ERROR;
319} 392}
@@ -333,332 +406,213 @@ iphone_error_t iphone_device_recv_timeout(iphone_connection_t connection, char *
333 */ 406 */
334iphone_error_t iphone_device_recv(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes) 407iphone_error_t iphone_device_recv(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes)
335{ 408{
336 if (!connection) { 409 if (!connection || (connection->ssl_data && !connection->ssl_data->session)) {
337 return -EINVAL; 410 return IPHONE_E_INVALID_ARG;
338 } 411 }
339 412
340 if (connection->type == CONNECTION_USBMUXD) { 413 if (connection->ssl_data) {
341 int res = usbmuxd_recv((int)(connection->data), data, len, recv_bytes); 414 ssize_t received = gnutls_record_recv(connection->ssl_data->session, (void*)data, (size_t)len);
342 if (res < 0) { 415 if (received > 0) {
343 log_debug_msg("%s: ERROR: usbmuxd_recv returned %d (%s)\n", __func__, res, strerror(-res)); 416 *recv_bytes = received;
344 return IPHONE_E_UNKNOWN_ERROR; 417 return IPHONE_E_SUCCESS;
345 } 418 }
419 *recv_bytes = 0;
420 return IPHONE_E_SSL_ERROR;
421 }
422 return internal_connection_recv(connection, data, len, recv_bytes);
423}
346 424
425iphone_error_t iphone_device_get_handle(iphone_device_t device, uint32_t *handle)
426{
427 if (!device)
428 return IPHONE_E_INVALID_ARG;
429
430 if (device->conn_type == CONNECTION_USBMUXD) {
431 *handle = (uint32_t)device->conn_data;
347 return IPHONE_E_SUCCESS; 432 return IPHONE_E_SUCCESS;
348 } else { 433 } else {
349 log_debug_msg("%s: Unknown connection type %d\n", __func__, connection->type); 434 debug_info("Unknown connection type %d", device->conn_type);
350 } 435 }
351 return IPHONE_E_UNKNOWN_ERROR; 436 return IPHONE_E_UNKNOWN_ERROR;
352} 437}
353 438
439iphone_error_t iphone_device_get_uuid(iphone_device_t device, char **uuid)
440{
441 if (!device)
442 return IPHONE_E_INVALID_ARG;
443
444 *uuid = strdup(device->uuid);
445 return IPHONE_E_SUCCESS;
446}
447
354/** 448/**
355 * Sends a plist over the given connection. 449 * Internally used gnutls callback function for receiving encrypted data.
356 * Internally used generic plist send function.
357 *
358 * @param connection The connection to use for sending.
359 * Can be NULL if ssl_session is non-NULL.
360 * @param plist plist to send
361 * @param binary 1 = send binary plist, 0 = send xml plist
362 * @param ssl_session If set to NULL, the communication will be unencrypted.
363 * For encrypted communication, pass a valid and properly initialized
364 * gnutls_session_t. connection is ignored when ssl_session is non-NULL.
365 *
366 * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when one or more
367 * parameters are invalid, IPHONE_E_PLIST_ERROR when dict is not a valid
368 * plist, or IPHONE_E_UNKNOWN_ERROR when an unspecified error occurs.
369 */ 450 */
370static iphone_error_t internal_plist_send(iphone_connection_t connection, plist_t plist, int binary, gnutls_session_t ssl_session) 451static ssize_t internal_ssl_read(gnutls_transport_ptr_t transport, char *buffer, size_t length)
371{ 452{
372 iphone_error_t res = IPHONE_E_UNKNOWN_ERROR; 453 int bytes = 0, pos_start_fill = 0;
373 char *content = NULL; 454 size_t tbytes = 0;
374 uint32_t length = 0; 455 int this_len = length;
375 uint32_t nlen = 0; 456 iphone_error_t res;
376 int bytes = 0; 457 iphone_connection_t connection = (iphone_connection_t)transport;
458 char *recv_buffer;
459
460 debug_info("pre-read client wants %zi bytes", length);
461
462 recv_buffer = (char *) malloc(sizeof(char) * this_len);
463
464 /* repeat until we have the full data or an error occurs */
465 do {
466 if ((res = internal_connection_recv(connection, recv_buffer, this_len, (uint32_t*)&bytes)) != IPHONE_E_SUCCESS) {
467 debug_info("ERROR: iphone_device_recv returned %d", res);
468 return res;
469 }
470 debug_info("post-read we got %i bytes", bytes);
377 471
378 if ((!connection && !ssl_session) || !plist) { 472 // increase read count
379 return IPHONE_E_INVALID_ARG; 473 tbytes += bytes;
380 }
381 474
382 if (binary) { 475 // fill the buffer with what we got right now
383 plist_to_bin(plist, &content, &length); 476 memcpy(buffer + pos_start_fill, recv_buffer, bytes);
384 } else { 477 pos_start_fill += bytes;
385 plist_to_xml(plist, &content, &length);
386 }
387 478
388 if (!content || length == 0) { 479 if (tbytes >= length) {
389 return IPHONE_E_PLIST_ERROR; 480 break;
390 }
391
392 nlen = htonl(length);
393 log_debug_msg("%s: sending %d bytes\n", __func__, length);
394 if (ssl_session) {
395 bytes = gnutls_record_send(ssl_session, (const char*)&nlen, sizeof(nlen));
396 } else {
397 iphone_device_send(connection, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes);
398 }
399 if (bytes == sizeof(nlen)) {
400 if (ssl_session) {
401 bytes = gnutls_record_send(ssl_session, content, length);
402 } else {
403 iphone_device_send(connection, content, length, (uint32_t*)&bytes);
404 }
405 if (bytes > 0) {
406 log_debug_msg("%s: sent %d bytes\n", __func__, bytes);
407 log_debug_buffer(content, bytes);
408 if ((uint32_t)bytes == length) {
409 res = IPHONE_E_SUCCESS;
410 } else {
411 log_debug_msg("%s: ERROR: Could not send all data (%d of %d)!\n", __func__, bytes, length);
412 }
413 } 481 }
414 }
415 if (bytes <= 0) {
416 log_debug_msg("%s: ERROR: sending to device failed.\n", __func__);
417 }
418 482
419 free(content); 483 this_len = length - tbytes;
484 debug_info("re-read trying to read missing %i bytes", this_len);
485 } while (tbytes < length);
420 486
421 return res; 487 if (recv_buffer) {
488 free(recv_buffer);
489 }
490 return tbytes;
422} 491}
423 492
424/** 493/**
425 * Sends an XML plist over the given connection. 494 * Internally used gnutls callback function for sending encrypted data.
426 *
427 * @param connection The connection to send data over
428 * @param plist plist to send
429 *
430 * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when connection
431 * or plist is NULL, IPHONE_E_PLIST_ERROR when dict is not a valid plist,
432 * or IPHONE_E_UNKNOWN_ERROR when an unspecified error occurs.
433 */ 495 */
434iphone_error_t iphone_device_send_xml_plist(iphone_connection_t connection, plist_t plist) 496static ssize_t internal_ssl_write(gnutls_transport_ptr_t transport, char *buffer, size_t length)
435{ 497{
436 return internal_plist_send(connection, plist, 0, NULL); 498 uint32_t bytes = 0;
499 iphone_connection_t connection = (iphone_connection_t)transport;
500 debug_info("pre-send length = %zi", length);
501 internal_connection_send(connection, buffer, length, &bytes);
502 debug_info("post-send sent %i bytes", bytes);
503 return bytes;
437} 504}
438 505
439/** 506/**
440 * Sends a binary plist over the given connection. 507 * Internally used function for cleaning up SSL stuff.
441 *
442 * @param connection The connection to send data over
443 * @param plist plist to send
444 *
445 * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when connection
446 * or plist is NULL, IPHONE_E_PLIST_ERROR when dict is not a valid plist,
447 * or IPHONE_E_UNKNOWN_ERROR when an unspecified error occurs.
448 */ 508 */
449iphone_error_t iphone_device_send_binary_plist(iphone_connection_t connection, plist_t plist) 509static void internal_ssl_cleanup(ssl_data_t ssl_data)
450{ 510{
451 return internal_plist_send(connection, plist, 1, NULL); 511 if (!ssl_data)
452} 512 return;
453 513
454/** 514 if (ssl_data->session) {
455 * Sends an encrypted XML plist. 515 gnutls_deinit(ssl_data->session);
456 * 516 }
457 * @param ssl_session Valid and properly initialized gnutls_session_t. 517 if (ssl_data->certificate) {
458 * @param plist plist to send 518 gnutls_certificate_free_credentials(ssl_data->certificate);
459 * 519 }
460 * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when ssl_session
461 * or plist is NULL, IPHONE_E_PLIST_ERROR when dict is not a valid plist,
462 * or IPHONE_E_UNKNOWN_ERROR when an unspecified error occurs.
463 */
464iphone_error_t iphone_device_send_encrypted_xml_plist(gnutls_session_t ssl_session, plist_t plist)
465{
466 return internal_plist_send(NULL, plist, 0, ssl_session);
467}
468
469/**
470 * Sends an encrypted binary plist.
471 *
472 * @param ssl_session Valid and properly initialized gnutls_session_t.
473 * @param plist plist to send
474 *
475 * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when ssl_session
476 * or plist is NULL, IPHONE_E_PLIST_ERROR when dict is not a valid plist,
477 * or IPHONE_E_UNKNOWN_ERROR when an unspecified error occurs.
478 */
479iphone_error_t iphone_device_send_encrypted_binary_plist(gnutls_session_t ssl_session, plist_t plist)
480{
481 return internal_plist_send(NULL, plist, 1, ssl_session);
482} 520}
483 521
484/** 522/**
485 * Receives a plist over the given connection. 523 * Enables SSL for the given connection.
486 * Internally used generic plist send function.
487 * 524 *
488 * @param connection The connection to receive data on 525 * @param connection The connection to enable SSL for.
489 * @param plist pointer to a plist_t that will point to the received plist
490 * upon successful return
491 * @param timeout Maximum time in milliseconds to wait for data.
492 * @param ssl_session If set to NULL, the communication will be unencrypted.
493 * For encrypted communication, pass a valid and properly initialized
494 * gnutls_session_t.
495 * 526 *
496 * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when connection 527 * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when connection
497 * or *plist is NULL, IPHONE_E_PLIST_ERROR when the received data cannot be 528 * is NULL or connection->ssl_data is non-NULL, or IPHONE_E_SSL_ERROR when
498 * converted to a plist, or IPHONE_E_UNKNOWN_ERROR when an unspecified 529 * SSL initialization, setup, or handshake fails.
499 * error occurs.
500 */ 530 */
501static iphone_error_t internal_plist_recv_timeout(iphone_connection_t connection, plist_t *plist, unsigned int timeout, gnutls_session_t ssl_session) 531iphone_error_t iphone_connection_enable_ssl(iphone_connection_t connection)
502{ 532{
503 iphone_error_t res = IPHONE_E_UNKNOWN_ERROR; 533 if (!connection || connection->ssl_data)
504 uint32_t pktlen = 0;
505 uint32_t bytes = 0;
506
507 if ((!connection && !ssl_session) || !plist) {
508 return IPHONE_E_INVALID_ARG; 534 return IPHONE_E_INVALID_ARG;
509 }
510 535
511 if (ssl_session) { 536 iphone_error_t ret = IPHONE_E_SSL_ERROR;
512 bytes = gnutls_record_recv(ssl_session, (char*)&pktlen, sizeof(pktlen)); 537 uint32_t return_me = 0;
513 } else { 538
514 iphone_device_recv_timeout(connection, (char*)&pktlen, sizeof(pktlen), &bytes, timeout); 539 ssl_data_t ssl_data_loc = (ssl_data_t)malloc(sizeof(struct ssl_data_int));
540
541 // Set up GnuTLS...
542 debug_info("enabling SSL mode");
543 errno = 0;
544 gnutls_global_init();
545 gnutls_certificate_allocate_credentials(&ssl_data_loc->certificate);
546 gnutls_certificate_set_x509_trust_file(ssl_data_loc->certificate, "hostcert.pem", GNUTLS_X509_FMT_PEM);
547 gnutls_init(&ssl_data_loc->session, GNUTLS_CLIENT);
548 {
549 int protocol_priority[16] = { GNUTLS_SSL3, 0 };
550 int kx_priority[16] = { GNUTLS_KX_ANON_DH, GNUTLS_KX_RSA, 0 };
551 int cipher_priority[16] = { GNUTLS_CIPHER_AES_128_CBC, GNUTLS_CIPHER_AES_256_CBC, 0 };
552 int mac_priority[16] = { GNUTLS_MAC_SHA1, GNUTLS_MAC_MD5, 0 };
553 int comp_priority[16] = { GNUTLS_COMP_NULL, 0 };
554
555 gnutls_cipher_set_priority(ssl_data_loc->session, cipher_priority);
556 gnutls_compression_set_priority(ssl_data_loc->session, comp_priority);
557 gnutls_kx_set_priority(ssl_data_loc->session, kx_priority);
558 gnutls_protocol_set_priority(ssl_data_loc->session, protocol_priority);
559 gnutls_mac_set_priority(ssl_data_loc->session, mac_priority);
515 } 560 }
516 log_debug_msg("%s: initial read=%i\n", __func__, bytes); 561 gnutls_credentials_set(ssl_data_loc->session, GNUTLS_CRD_CERTIFICATE, ssl_data_loc->certificate); // this part is killing me.
517 if (bytes < 4) { 562
518 log_debug_msg("%s: initial read failed!\n", __func__); 563 debug_info("GnuTLS step 1...");
519 return IPHONE_E_NOT_ENOUGH_DATA; 564 gnutls_transport_set_ptr(ssl_data_loc->session, (gnutls_transport_ptr_t)connection);
565 debug_info("GnuTLS step 2...");
566 gnutls_transport_set_push_function(ssl_data_loc->session, (gnutls_push_func) & internal_ssl_write);
567 debug_info("GnuTLS step 3...");
568 gnutls_transport_set_pull_function(ssl_data_loc->session, (gnutls_pull_func) & internal_ssl_read);
569 debug_info("GnuTLS step 4 -- now handshaking...");
570 if (errno)
571 debug_info("WARN: errno says %s before handshake!", strerror(errno));
572 return_me = gnutls_handshake(ssl_data_loc->session);
573 debug_info("GnuTLS handshake done...");
574
575 if (return_me != GNUTLS_E_SUCCESS) {
576 internal_ssl_cleanup(ssl_data_loc);
577 free(ssl_data_loc);
578 debug_info("GnuTLS reported something wrong.");
579 gnutls_perror(return_me);
580 debug_info("oh.. errno says %s", strerror(errno));
520 } else { 581 } else {
521 if ((char)pktlen == 0) { /* prevent huge buffers */ 582 connection->ssl_data = ssl_data_loc;
522 uint32_t curlen = 0; 583 ret = IPHONE_E_SUCCESS;
523 char *content = NULL; 584 debug_info("SSL mode enabled");
524 pktlen = ntohl(pktlen);
525 log_debug_msg("%s: %d bytes following\n", __func__, pktlen);
526 content = (char*)malloc(pktlen);
527
528 while (curlen < pktlen) {
529 if (ssl_session) {
530 bytes = gnutls_record_recv(ssl_session, content+curlen, pktlen-curlen);
531 } else {
532 iphone_device_recv(connection, content+curlen, pktlen-curlen, &bytes);
533 }
534 if (bytes <= 0) {
535 res = IPHONE_E_UNKNOWN_ERROR;
536 break;
537 }
538 log_debug_msg("%s: received %d bytes\n", __func__, bytes);
539 curlen += bytes;
540 }
541 log_debug_buffer(content, pktlen);
542 if (!memcmp(content, "bplist00", 8)) {
543 plist_from_bin(content, pktlen, plist);
544 } else {
545 plist_from_xml(content, pktlen, plist);
546 }
547 if (*plist) {
548 res = IPHONE_E_SUCCESS;
549 } else {
550 res = IPHONE_E_PLIST_ERROR;
551 }
552 free(content);
553 content = NULL;
554 } else {
555 res = IPHONE_E_UNKNOWN_ERROR;
556 }
557 } 585 }
558 return res; 586 return ret;
559}
560
561/**
562 * Receives a plist over the given connection with specified timeout.
563 * Binary or XML plists are automatically handled.
564 *
565 * @param connection The connection to receive data on
566 * @param plist pointer to a plist_t that will point to the received plist
567 * upon successful return
568 * @param timeout Maximum time in milliseconds to wait for data.
569 *
570 * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when connection
571 * or *plist is NULL, IPHONE_E_PLIST_ERROR when the received data cannot be
572 * converted to a plist, or IPHONE_E_UNKNOWN_ERROR when an unspecified
573 * error occurs.
574 */
575iphone_error_t iphone_device_receive_plist_with_timeout(iphone_connection_t connection, plist_t *plist, unsigned int timeout)
576{
577 return internal_plist_recv_timeout(connection, plist, timeout, NULL);
578} 587}
579 588
580/** 589/**
581 * Receives a plist over the given connection. 590 * Disable SSL for the given connection.
582 * Binary or XML plists are automatically handled.
583 * 591 *
584 * This function is like iphone_device_receive_plist_with_timeout 592 * @param connection The connection to disable SSL for.
585 * using a timeout of 10 seconds.
586 * @see iphone_device_receive_plist_with_timeout
587 *
588 * @param connection The connection to receive data on
589 * @param plist pointer to a plist_t that will point to the received plist
590 * upon successful return
591 * 593 *
592 * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when connection 594 * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when connection
593 * or *plist is NULL, IPHONE_E_PLIST_ERROR when the received data cannot be 595 * is NULL. This function also returns IPHONE_E_SUCCESS when SSL is not
594 * converted to a plist, or IPHONE_E_UNKNOWN_ERROR when an unspecified 596 * enabled and does no further error checking on cleanup.
595 * error occurs.
596 */
597iphone_error_t iphone_device_receive_plist(iphone_connection_t connection, plist_t *plist)
598{
599 return internal_plist_recv_timeout(connection, plist, 10000, NULL);
600}
601
602/**
603 * Receives an encrypted plist with specified timeout.
604 * Binary or XML plists are automatically handled.
605 *
606 * @param ssl_session Valid and properly initialized gnutls_session_t.
607 * @param plist pointer to a plist_t that will point to the received plist
608 * upon successful return
609 * @param timeout Maximum time in milliseconds to wait for data.
610 *
611 * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when ssl_session
612 * or *plist is NULL, IPHONE_E_PLIST_ERROR when the received data cannot be
613 * converted to a plist, or IPHONE_E_UNKNOWN_ERROR when an unspecified
614 * error occurs.
615 */
616iphone_error_t iphone_device_receive_encrypted_plist_with_timeout(gnutls_session_t ssl_session, plist_t *plist, unsigned int timeout)
617{
618 return internal_plist_recv_timeout(NULL, plist, timeout, ssl_session);
619}
620
621/**
622 * Receives an encrypted plist.
623 * Binary or XML plists are automatically handled.
624 * This function is like iphone_device_receive_encrypted_plist_with_timeout
625 * with a timeout value of 10 seconds.
626 *
627 * @param ssl_session Valid and properly initialized gnutls_session_t.
628 * @param connection The connection to receive data on
629 * @param plist pointer to a plist_t that will point to the received plist
630 * upon successful return
631 *
632 * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when ssl_session
633 * or *plist is NULL, IPHONE_E_PLIST_ERROR when the received data cannot be
634 * converted to a plist, or IPHONE_E_UNKNOWN_ERROR when an unspecified
635 * error occurs.
636 */ 597 */
637iphone_error_t iphone_device_receive_encrypted_plist(gnutls_session_t ssl_session, plist_t *plist) 598iphone_error_t iphone_connection_disable_ssl(iphone_connection_t connection)
638{
639 return internal_plist_recv_timeout(NULL, plist, 10000, ssl_session);
640}
641
642iphone_error_t iphone_device_get_handle(iphone_device_t device, uint32_t *handle)
643{ 599{
644 if (!device) 600 if (!connection)
645 return IPHONE_E_INVALID_ARG; 601 return IPHONE_E_INVALID_ARG;
646 602 if (!connection->ssl_data) {
647 if (device->conn_type == CONNECTION_USBMUXD) { 603 /* ignore if ssl is not enabled */
648 *handle = (uint32_t)device->conn_data;
649 return IPHONE_E_SUCCESS; 604 return IPHONE_E_SUCCESS;
650 } else {
651 log_debug_msg("%s: Unknown connection type %d\n", __func__, device->conn_type);
652 } 605 }
653 return IPHONE_E_UNKNOWN_ERROR;
654}
655 606
656iphone_error_t iphone_device_get_uuid(iphone_device_t device, char **uuid) 607 if (connection->ssl_data->session) {
657{ 608 gnutls_bye(connection->ssl_data->session, GNUTLS_SHUT_RDWR);
658 if (!device) 609 }
659 return IPHONE_E_INVALID_ARG; 610 internal_ssl_cleanup(connection->ssl_data);
611 free(connection->ssl_data);
612 connection->ssl_data = NULL;
613
614 debug_info("SSL mode disabled");
660 615
661 *uuid = strdup(device->uuid);
662 return IPHONE_E_SUCCESS; 616 return IPHONE_E_SUCCESS;
663} 617}
664 618
diff --git a/src/iphone.h b/src/iphone.h
index 7ffc811..2755349 100644
--- a/src/iphone.h
+++ b/src/iphone.h
@@ -30,9 +30,16 @@ enum connection_type {
30 CONNECTION_USBMUXD = 1 30 CONNECTION_USBMUXD = 1
31}; 31};
32 32
33struct ssl_data_int {
34 gnutls_certificate_credentials_t certificate;
35 gnutls_session_t session;
36};
37typedef struct ssl_data_int *ssl_data_t;
38
33struct iphone_connection_int { 39struct iphone_connection_int {
34 enum connection_type type; 40 enum connection_type type;
35 void *data; 41 void *data;
42 ssl_data_t ssl_data;
36}; 43};
37 44
38struct iphone_device_int { 45struct iphone_device_int {
@@ -41,14 +48,7 @@ struct iphone_device_int {
41 void *conn_data; 48 void *conn_data;
42}; 49};
43 50
44iphone_error_t iphone_device_send_xml_plist(iphone_connection_t connection, plist_t plist); 51iphone_error_t iphone_connection_enable_ssl(iphone_connection_t connection);
45iphone_error_t iphone_device_send_binary_plist(iphone_connection_t connection, plist_t plist); 52iphone_error_t iphone_connection_disable_ssl(iphone_connection_t connection);
46iphone_error_t iphone_device_send_encrypted_xml_plist(gnutls_session_t ssl_session, plist_t plist);
47iphone_error_t iphone_device_send_encrypted_binary_plist(gnutls_session_t ssl_session, plist_t plist);
48
49iphone_error_t iphone_device_receive_plist_with_timeout(iphone_connection_t connection, plist_t *plist, unsigned int timeout);
50iphone_error_t iphone_device_receive_plist(iphone_connection_t connection, plist_t *plist);
51iphone_error_t iphone_device_receive_encrypted_plist_with_timeout(gnutls_session_t ssl_session, plist_t *plist, unsigned int timeout);
52iphone_error_t iphone_device_receive_encrypted_plist(gnutls_session_t ssl_session, plist_t *plist);
53 53
54#endif 54#endif
diff --git a/src/lockdown.c b/src/lockdown.c
index 2532999..1befb72 100644
--- a/src/lockdown.c
+++ b/src/lockdown.c
@@ -28,9 +28,10 @@
28#include <gnutls/x509.h> 28#include <gnutls/x509.h>
29#include <plist/plist.h> 29#include <plist/plist.h>
30 30
31#include "property_list_service.h"
31#include "lockdown.h" 32#include "lockdown.h"
32#include "iphone.h" 33#include "iphone.h"
33#include "utils.h" 34#include "debug.h"
34#include "userpref.h" 35#include "userpref.h"
35 36
36#define RESULT_SUCCESS 0 37#define RESULT_SUCCESS 0
@@ -98,7 +99,7 @@ static int lockdown_check_result(plist_t dict, const char *query_match)
98 } else if (!strcmp(result_value, "Failure")) { 99 } else if (!strcmp(result_value, "Failure")) {
99 ret = RESULT_FAILURE; 100 ret = RESULT_FAILURE;
100 } else { 101 } else {
101 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: ERROR: unknown result value '%s'\n", __func__, result_value); 102 debug_info("ERROR: unknown result value '%s'", result_value);
102 } 103 }
103 } 104 }
104 if (result_value) 105 if (result_value)
@@ -108,30 +109,49 @@ static int lockdown_check_result(plist_t dict, const char *query_match)
108} 109}
109 110
110/** 111/**
111 * Closes the lockdownd communication session, by sending 112 * Adds a label key with the passed value to a plist dict node.
112 * the StopSession Request to the device. 113 *
114 * @param plist The plist to add the key to
115 * @param label The value for the label key
116 *
117 */
118static void plist_dict_add_label(plist_t plist, const char *label)
119{
120 if (plist && label) {
121 if (plist_get_node_type(plist) == PLIST_DICT)
122 plist_dict_insert_item(plist, "Label", plist_new_string(label));
123 }
124}
125
126/**
127 * Closes the lockdownd communication session, by sending the StopSession
128 * Request to the device.
129 *
130 * @see lockdownd_start_session
113 * 131 *
114 * @param control The lockdown client 132 * @param control The lockdown client
133 * @param session_id The id of a running session
115 * 134 *
116 * @return an error code (LOCKDOWN_E_SUCCESS on success) 135 * @return an error code (LOCKDOWN_E_SUCCESS on success)
117 */ 136 */
118lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client) 137lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client, const char *session_id)
119{ 138{
120 if (!client) 139 if (!client)
121 return LOCKDOWN_E_INVALID_ARG; 140 return LOCKDOWN_E_INVALID_ARG;
122 141
123 if (!client->session_id) { 142 if (!session_id) {
124 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: no session_id given, cannot stop session\n", __func__); 143 debug_info("no session_id given, cannot stop session");
125 return LOCKDOWN_E_INVALID_ARG; 144 return LOCKDOWN_E_INVALID_ARG;
126 } 145 }
127 146
128 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; 147 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
129 148
130 plist_t dict = plist_new_dict(); 149 plist_t dict = plist_new_dict();
150 plist_dict_add_label(dict, client->label);
131 plist_dict_insert_item(dict,"Request", plist_new_string("StopSession")); 151 plist_dict_insert_item(dict,"Request", plist_new_string("StopSession"));
132 plist_dict_insert_item(dict,"SessionID", plist_new_string(client->session_id)); 152 plist_dict_insert_item(dict,"SessionID", plist_new_string(session_id));
133 153
134 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: stopping session %s\n", __func__, client->session_id); 154 debug_info("stopping session %s", session_id);
135 155
136 ret = lockdownd_send(client, dict); 156 ret = lockdownd_send(client, dict);
137 157
@@ -141,55 +161,20 @@ lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client)
141 ret = lockdownd_recv(client, &dict); 161 ret = lockdownd_recv(client, &dict);
142 162
143 if (!dict) { 163 if (!dict) {
144 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: LOCKDOWN_E_PLIST_ERROR\n", __func__); 164 debug_info("LOCKDOWN_E_PLIST_ERROR");
145 return LOCKDOWN_E_PLIST_ERROR; 165 return LOCKDOWN_E_PLIST_ERROR;
146 } 166 }
147 167
148 ret = LOCKDOWN_E_UNKNOWN_ERROR; 168 ret = LOCKDOWN_E_UNKNOWN_ERROR;
149 if (lockdown_check_result(dict, "StopSession") == RESULT_SUCCESS) { 169 if (lockdown_check_result(dict, "StopSession") == RESULT_SUCCESS) {
150 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); 170 debug_info("success");
151 ret = LOCKDOWN_E_SUCCESS; 171 ret = LOCKDOWN_E_SUCCESS;
152 } 172 }
153 plist_free(dict); 173 plist_free(dict);
154 dict = NULL; 174 dict = NULL;
155 175 if (client->ssl_enabled) {
156 free(client->session_id); 176 property_list_service_disable_ssl(client->parent);
157 client->session_id = NULL;
158
159 return ret;
160}
161
162/**
163 * Shuts down the SSL session by first calling iphone_lckd_stop_session
164 * to cleanly close the lockdownd communication session, and then
165 * performing a close notify, which is done by "gnutls_bye".
166 *
167 * @param client The lockdown client
168 *
169 * @return an error code (LOCKDOWN_E_SUCCESS on success)
170 */
171static lockdownd_error_t lockdownd_stop_ssl_session(lockdownd_client_t client)
172{
173 if (!client) {
174 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: invalid argument!\n", __func__);
175 return LOCKDOWN_E_INVALID_ARG;
176 } 177 }
177 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;
178
179 if (client->in_SSL) {
180 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: stopping SSL session\n", __func__);
181 ret = lockdownd_stop_session(client);
182 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: sending SSL close notify\n", __func__);
183 gnutls_bye(client->ssl_session, GNUTLS_SHUT_RDWR);
184 }
185 if (client->ssl_session) {
186 gnutls_deinit(client->ssl_session);
187 }
188 if (client->ssl_certificate) {
189 gnutls_certificate_free_credentials(client->ssl_certificate);
190 }
191 client->in_SSL = 0;
192
193 return ret; 178 return ret;
194} 179}
195 180
@@ -205,29 +190,45 @@ lockdownd_error_t lockdownd_client_free(lockdownd_client_t client)
205 return LOCKDOWN_E_INVALID_ARG; 190 return LOCKDOWN_E_INVALID_ARG;
206 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; 191 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
207 192
208 lockdownd_stop_ssl_session(client); 193 if (client->session_id)
194 lockdownd_stop_session(client, client->session_id);
209 195
210 if (client->connection) { 196 if (client->parent) {
211 lockdownd_goodbye(client); 197 lockdownd_goodbye(client);
212 198
213 // IMO, read of final "sessionUpcall connection closed" packet 199 if (property_list_service_client_free(client->parent) == PROPERTY_LIST_SERVICE_E_SUCCESS) {
214 // should come here instead of in iphone_free_device 200 ret = LOCKDOWN_E_SUCCESS;
215 if ((ret = iphone_device_disconnect(client->connection)) != IPHONE_E_SUCCESS) {
216 ret = LOCKDOWN_E_UNKNOWN_ERROR;
217 } 201 }
218 } 202 }
219 203
220 if (client->session_id) {
221 free(client->session_id);
222 }
223 if (client->uuid) { 204 if (client->uuid) {
224 free(client->uuid); 205 free(client->uuid);
225 } 206 }
207 if (client->label) {
208 free(client->label);
209 }
226 210
227 free(client); 211 free(client);
228 return ret; 212 return ret;
229} 213}
230 214
215/**
216 * Sets the label to send for requests to lockdownd.
217 *
218 * @param client The lockdown client
219 * @param label The label to set or NULL to disable sending a label
220 *
221 */
222void lockdownd_client_set_label(lockdownd_client_t client, const char *label)
223{
224 if (client) {
225 if (client->label)
226 free(client->label);
227
228 client->label = (label != NULL) ? strdup(label): NULL;
229 }
230}
231
231/** Polls the iPhone for lockdownd data. 232/** Polls the iPhone for lockdownd data.
232 * 233 *
233 * @param control The lockdownd client 234 * @param control The lockdownd client
@@ -240,18 +241,11 @@ lockdownd_error_t lockdownd_recv(lockdownd_client_t client, plist_t *plist)
240 if (!client || !plist || (plist && *plist)) 241 if (!client || !plist || (plist && *plist))
241 return LOCKDOWN_E_INVALID_ARG; 242 return LOCKDOWN_E_INVALID_ARG;
242 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS; 243 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;
243 iphone_error_t err; 244 property_list_service_error_t err;
244 245
245 if (!client->in_SSL) { 246 err = property_list_service_receive_plist(client->parent, plist);
246 err = iphone_device_receive_plist(client->connection, plist); 247 if (err != PROPERTY_LIST_SERVICE_E_SUCCESS) {
247 if (err != IPHONE_E_SUCCESS) { 248 ret = LOCKDOWN_E_UNKNOWN_ERROR;
248 ret = LOCKDOWN_E_UNKNOWN_ERROR;
249 }
250 } else {
251 err = iphone_device_receive_encrypted_plist(client->ssl_session, plist);
252 if (err != IPHONE_E_SUCCESS) {
253 return LOCKDOWN_E_SSL_ERROR;
254 }
255 } 249 }
256 250
257 if (!*plist) 251 if (!*plist)
@@ -278,27 +272,22 @@ lockdownd_error_t lockdownd_send(lockdownd_client_t client, plist_t plist)
278 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS; 272 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;
279 iphone_error_t err; 273 iphone_error_t err;
280 274
281 if (!client->in_SSL) { 275 err = property_list_service_send_xml_plist(client->parent, plist);
282 err = iphone_device_send_xml_plist(client->connection, plist); 276 if (err != PROPERTY_LIST_SERVICE_E_SUCCESS) {
283 if (err != IPHONE_E_SUCCESS) { 277 ret = LOCKDOWN_E_UNKNOWN_ERROR;
284 ret = LOCKDOWN_E_UNKNOWN_ERROR;
285 }
286 } else {
287 err = iphone_device_send_encrypted_xml_plist(client->ssl_session, plist);
288 if (err != IPHONE_E_SUCCESS) {
289 ret = LOCKDOWN_E_SSL_ERROR;
290 }
291 } 278 }
292 return ret; 279 return ret;
293} 280}
294 281
295/** Initiates the handshake for the lockdown session. Part of the lockdownd handshake. 282/** Query the type of the service daemon. Depending on whether the device is
283 * queried in normal mode or restore mode, different types will be returned.
296 * 284 *
297 * @param client The lockdownd client 285 * @param client The lockdownd client
286 * @param type The type returned by the service daemon. Can be NULL to ignore.
298 * 287 *
299 * @return an error code (LOCKDOWN_E_SUCCESS on success) 288 * @return an error code (LOCKDOWN_E_SUCCESS on success)
300 */ 289 */
301lockdownd_error_t lockdownd_query_type(lockdownd_client_t client) 290lockdownd_error_t lockdownd_query_type(lockdownd_client_t client, char **type)
302{ 291{
303 if (!client) 292 if (!client)
304 return LOCKDOWN_E_INVALID_ARG; 293 return LOCKDOWN_E_INVALID_ARG;
@@ -306,9 +295,10 @@ lockdownd_error_t lockdownd_query_type(lockdownd_client_t client)
306 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; 295 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
307 296
308 plist_t dict = plist_new_dict(); 297 plist_t dict = plist_new_dict();
298 plist_dict_add_label(dict, client->label);
309 plist_dict_insert_item(dict,"Request", plist_new_string("QueryType")); 299 plist_dict_insert_item(dict,"Request", plist_new_string("QueryType"));
310 300
311 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: called\n", __func__); 301 debug_info("called");
312 ret = lockdownd_send(client, dict); 302 ret = lockdownd_send(client, dict);
313 303
314 plist_free(dict); 304 plist_free(dict);
@@ -321,7 +311,12 @@ lockdownd_error_t lockdownd_query_type(lockdownd_client_t client)
321 311
322 ret = LOCKDOWN_E_UNKNOWN_ERROR; 312 ret = LOCKDOWN_E_UNKNOWN_ERROR;
323 if (lockdown_check_result(dict, "QueryType") == RESULT_SUCCESS) { 313 if (lockdown_check_result(dict, "QueryType") == RESULT_SUCCESS) {
324 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); 314 /* return the type if requested */
315 if (type != NULL) {
316 plist_t type_node = plist_dict_get_item(dict, "Type");
317 plist_get_string_val(type_node, type);
318 }
319 debug_info("success with type %s", *type);
325 ret = LOCKDOWN_E_SUCCESS; 320 ret = LOCKDOWN_E_SUCCESS;
326 } 321 }
327 plist_free(dict); 322 plist_free(dict);
@@ -349,6 +344,7 @@ lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *dom
349 344
350 /* setup request plist */ 345 /* setup request plist */
351 dict = plist_new_dict(); 346 dict = plist_new_dict();
347 plist_dict_add_label(dict, client->label);
352 if (domain) { 348 if (domain) {
353 plist_dict_insert_item(dict,"Domain", plist_new_string(domain)); 349 plist_dict_insert_item(dict,"Domain", plist_new_string(domain));
354 } 350 }
@@ -372,7 +368,7 @@ lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *dom
372 return ret; 368 return ret;
373 369
374 if (lockdown_check_result(dict, "GetValue") == RESULT_SUCCESS) { 370 if (lockdown_check_result(dict, "GetValue") == RESULT_SUCCESS) {
375 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); 371 debug_info("success");
376 ret = LOCKDOWN_E_SUCCESS; 372 ret = LOCKDOWN_E_SUCCESS;
377 } 373 }
378 if (ret != LOCKDOWN_E_SUCCESS) { 374 if (ret != LOCKDOWN_E_SUCCESS) {
@@ -383,7 +379,7 @@ lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *dom
383 plist_t value_node = plist_dict_get_item(dict, "Value"); 379 plist_t value_node = plist_dict_get_item(dict, "Value");
384 380
385 if (value_node) { 381 if (value_node) {
386 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: has a value\n", __func__); 382 debug_info("has a value");
387 *value = plist_copy(value_node); 383 *value = plist_copy(value_node);
388 } 384 }
389 385
@@ -410,6 +406,7 @@ lockdownd_error_t lockdownd_set_value(lockdownd_client_t client, const char *dom
410 406
411 /* setup request plist */ 407 /* setup request plist */
412 dict = plist_new_dict(); 408 dict = plist_new_dict();
409 plist_dict_add_label(dict, client->label);
413 if (domain) { 410 if (domain) {
414 plist_dict_insert_item(dict,"Domain", plist_new_string(domain)); 411 plist_dict_insert_item(dict,"Domain", plist_new_string(domain));
415 } 412 }
@@ -434,7 +431,7 @@ lockdownd_error_t lockdownd_set_value(lockdownd_client_t client, const char *dom
434 return ret; 431 return ret;
435 432
436 if (lockdown_check_result(dict, "SetValue") == RESULT_SUCCESS) { 433 if (lockdown_check_result(dict, "SetValue") == RESULT_SUCCESS) {
437 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); 434 debug_info("success");
438 ret = LOCKDOWN_E_SUCCESS; 435 ret = LOCKDOWN_E_SUCCESS;
439 } 436 }
440 437
@@ -467,6 +464,7 @@ lockdownd_error_t lockdownd_remove_value(lockdownd_client_t client, const char *
467 464
468 /* setup request plist */ 465 /* setup request plist */
469 dict = plist_new_dict(); 466 dict = plist_new_dict();
467 plist_dict_add_label(dict, client->label);
470 if (domain) { 468 if (domain) {
471 plist_dict_insert_item(dict,"Domain", plist_new_string(domain)); 469 plist_dict_insert_item(dict,"Domain", plist_new_string(domain));
472 } 470 }
@@ -490,7 +488,7 @@ lockdownd_error_t lockdownd_remove_value(lockdownd_client_t client, const char *
490 return ret; 488 return ret;
491 489
492 if (lockdown_check_result(dict, "RemoveValue") == RESULT_SUCCESS) { 490 if (lockdown_check_result(dict, "RemoveValue") == RESULT_SUCCESS) {
493 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); 491 debug_info("success");
494 ret = LOCKDOWN_E_SUCCESS; 492 ret = LOCKDOWN_E_SUCCESS;
495 } 493 }
496 494
@@ -572,44 +570,85 @@ lockdownd_error_t lockdownd_get_device_name(lockdownd_client_t client, char **de
572 return ret; 570 return ret;
573} 571}
574 572
575/** Creates a lockdownd client for the give iPhone 573/** Creates a lockdownd client for the device.
576 * 574 *
577 * @param phone The iPhone to create a lockdownd client for 575 * @param phone The device to create a lockdownd client for
578 * @param client The pointer to the location of the new lockdownd_client 576 * @param client The pointer to the location of the new lockdownd_client
577 * @param label The label to use for communication. Usually the program name
579 * 578 *
580 * @return an error code (LOCKDOWN_E_SUCCESS on success) 579 * @return an error code (LOCKDOWN_E_SUCCESS on success)
581 */ 580 */
582lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_t *client) 581lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_t *client, const char *label)
583{ 582{
584 if (!client) 583 if (!client)
585 return LOCKDOWN_E_INVALID_ARG; 584 return LOCKDOWN_E_INVALID_ARG;
585
586 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS; 586 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;
587 char *host_id = NULL;
588 587
589 iphone_connection_t connection; 588 property_list_service_client_t plistclient = NULL;
590 if (iphone_device_connect(device, 0xf27e, &connection) != IPHONE_E_SUCCESS) { 589 if (property_list_service_client_new(device, 0xf27e, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
591 log_debug_msg("%s: could not connect to lockdownd (device %s)\n", __func__, device->uuid); 590 debug_info("could not connect to lockdownd (device %s)", device->uuid);
592 return LOCKDOWN_E_MUX_ERROR; 591 return LOCKDOWN_E_MUX_ERROR;
593 } 592 }
594 593
595 lockdownd_client_t client_loc = (lockdownd_client_t) malloc(sizeof(struct lockdownd_client_int)); 594 lockdownd_client_t client_loc = (lockdownd_client_t) malloc(sizeof(struct lockdownd_client_int));
596 client_loc->connection = connection; 595 client_loc->parent = plistclient;
597 client_loc->ssl_session = NULL; 596 client_loc->ssl_enabled = 0;
598 client_loc->ssl_certificate = NULL;
599 client_loc->in_SSL = 0;
600 client_loc->session_id = NULL; 597 client_loc->session_id = NULL;
601 client_loc->uuid = NULL; 598 client_loc->uuid = NULL;
599 client_loc->label = NULL;
600 if (label != NULL)
601 strdup(label);
602
603 if (LOCKDOWN_E_SUCCESS == ret) {
604 *client = client_loc;
605 } else {
606 lockdownd_client_free(client_loc);
607 }
608
609 return ret;
610}
611
612/** Creates a lockdownd client for the device and starts initial handshake.
613 * The handshake consists of query_type, validate_pair, pair and
614 * start_session calls.
615 *
616 * @param phone The device to create a lockdownd client for
617 * @param client The pointer to the location of the new lockdownd_client
618 * @param label The label to use for communication. Usually the program name
619 *
620 * @return an error code (LOCKDOWN_E_SUCCESS on success)
621 */
622lockdownd_error_t lockdownd_client_new_with_handshake(iphone_device_t device, lockdownd_client_t *client, const char *label)
623{
624 if (!client)
625 return LOCKDOWN_E_INVALID_ARG;
626
627 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;
628 lockdownd_client_t client_loc = NULL;
629 char *host_id = NULL;
630 char *type = NULL;
602 631
603 if (LOCKDOWN_E_SUCCESS != lockdownd_query_type(client_loc)) { 632
604 log_debug_msg("%s: QueryType failed in the lockdownd client.\n", __func__); 633 ret = lockdownd_client_new(device, &client_loc, label);
634
635 /* perform handshake */
636 if (LOCKDOWN_E_SUCCESS != lockdownd_query_type(client_loc, &type)) {
637 debug_info("QueryType failed in the lockdownd client.");
605 ret = LOCKDOWN_E_NOT_ENOUGH_DATA; 638 ret = LOCKDOWN_E_NOT_ENOUGH_DATA;
639 } else {
640 if (strcmp("com.apple.mobile.lockdown", type)) {
641 debug_info("Warning QueryType request returned \"%s\".", type);
642 }
643 if (type)
644 free(type);
606 } 645 }
607 646
608 ret = iphone_device_get_uuid(device, &client_loc->uuid); 647 ret = iphone_device_get_uuid(device, &client_loc->uuid);
609 if (LOCKDOWN_E_SUCCESS != ret) { 648 if (LOCKDOWN_E_SUCCESS != ret) {
610 log_debug_msg("%s: failed to get device uuid.\n", __func__); 649 debug_info("failed to get device uuid.");
611 } 650 }
612 log_debug_msg("%s: device uuid: %s\n", __func__, client_loc->uuid); 651 debug_info("device uuid: %s", client_loc->uuid);
613 652
614 userpref_get_host_id(&host_id); 653 userpref_get_host_id(&host_id);
615 if (LOCKDOWN_E_SUCCESS == ret && !host_id) { 654 if (LOCKDOWN_E_SUCCESS == ret && !host_id) {
@@ -617,77 +656,135 @@ lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_
617 } 656 }
618 657
619 if (LOCKDOWN_E_SUCCESS == ret && !userpref_has_device_public_key(client_loc->uuid)) 658 if (LOCKDOWN_E_SUCCESS == ret && !userpref_has_device_public_key(client_loc->uuid))
620 ret = lockdownd_pair(client_loc, host_id); 659 ret = lockdownd_pair(client_loc, NULL);
660
661 /* in any case, we need to validate pairing to receive trusted host status */
662 ret = lockdownd_validate_pair(client_loc, NULL);
621 663
622 if (LOCKDOWN_E_SUCCESS == ret) { 664 if (LOCKDOWN_E_SUCCESS == ret) {
623 ret = lockdownd_start_ssl_session(client_loc, host_id); 665 ret = lockdownd_start_session(client_loc, host_id, NULL, NULL);
624 if (LOCKDOWN_E_SUCCESS != ret) { 666 if (LOCKDOWN_E_SUCCESS != ret) {
625 ret = LOCKDOWN_E_SSL_ERROR; 667 debug_info("Session opening failed.");
626 log_debug_msg("%s: SSL Session opening failed.\n", __func__);
627 } 668 }
628 669
629 if (host_id) { 670 if (host_id) {
630 free(host_id); 671 free(host_id);
631 host_id = NULL; 672 host_id = NULL;
632 } 673 }
674 }
675
676 if (LOCKDOWN_E_SUCCESS == ret) {
677 *client = client_loc;
678 } else {
679 lockdownd_client_free(client_loc);
680 }
633 681
634 if (LOCKDOWN_E_SUCCESS == ret) 682 return ret;
635 *client = client_loc; 683}
684
685static plist_t lockdownd_pair_record_to_plist(lockdownd_pair_record_t pair_record)
686{
687 if (!pair_record)
688 return NULL;
689
690 char *host_id_loc = pair_record->host_id;
691
692 /* setup request plist */
693 plist_t dict = plist_new_dict();
694 plist_dict_insert_item(dict, "DeviceCertificate", plist_new_data(pair_record->device_certificate, strlen(pair_record->device_certificate)));
695 plist_dict_insert_item(dict, "HostCertificate", plist_new_data(pair_record->host_certificate, strlen(pair_record->host_certificate)));
696 if (!pair_record->host_id)
697 userpref_get_host_id(&host_id_loc);
698 plist_dict_insert_item(dict, "HostID", plist_new_string(host_id_loc));
699 plist_dict_insert_item(dict, "RootCertificate", plist_new_data(pair_record->root_certificate, strlen(pair_record->root_certificate)));
700
701 if (!pair_record->host_id)
702 free(host_id_loc);
703
704 return dict;
705}
706
707static lockdownd_error_t generate_pair_record_plist(gnutls_datum_t public_key, char *host_id, plist_t *pair_record_plist)
708{
709 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
710
711 gnutls_datum_t device_cert = { NULL, 0 };
712 gnutls_datum_t host_cert = { NULL, 0 };
713 gnutls_datum_t root_cert = { NULL, 0 };
714
715 ret = lockdownd_gen_pair_cert(public_key, &device_cert, &host_cert, &root_cert);
716 if (ret != LOCKDOWN_E_SUCCESS) {
717 return ret;
636 } 718 }
637 719
720 char *host_id_loc = host_id;
721
722 if (!host_id)
723 userpref_get_host_id(&host_id_loc);
724
725 /* setup request plist */
726 *pair_record_plist = plist_new_dict();
727 plist_dict_insert_item(*pair_record_plist, "DeviceCertificate", plist_new_data((const char*)device_cert.data, device_cert.size));
728 plist_dict_insert_item(*pair_record_plist, "HostCertificate", plist_new_data((const char*)host_cert.data, host_cert.size));
729 plist_dict_insert_item(*pair_record_plist, "HostID", plist_new_string(host_id_loc));
730 plist_dict_insert_item(*pair_record_plist, "RootCertificate", plist_new_data((const char*)root_cert.data, root_cert.size));
731
732 if (!host_id)
733 free(host_id_loc);
734
638 return ret; 735 return ret;
639} 736}
640 737
641/** Function used internally by lockdownd_pair() and lockdownd_validate_pair() 738/** Function used internally by lockdownd_pair() and lockdownd_validate_pair()
642 * 739 *
643 * @param client The lockdown client to pair with. 740 * @param client The lockdown client to pair with.
644 * @param host_id The HostID to use for pairing. If NULL is passed, then 741 * @param pair_record The pair record to use for pairing. If NULL is passed, then
645 * the HostID of the current machine is used. A new HostID will be 742 * the pair records from the current machine are used. New records will be
646 * generated automatically when pairing is done for the first time. 743 * generated automatically when pairing is done for the first time.
647 * @param verb This is either "Pair" or "ValidatePair". 744 * @param verb This is either "Pair", "ValidatePair" or "Unpair".
648 * 745 *
649 * @return an error code (LOCKDOWN_E_SUCCESS on success) 746 * @return an error code (LOCKDOWN_E_SUCCESS on success)
650 */ 747 */
651static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, char *host_id, const char *verb) 748static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record, const char *verb)
652{ 749{
653 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; 750 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
654 plist_t dict = NULL; 751 plist_t dict = NULL;
655 plist_t dict_record = NULL; 752 plist_t dict_record = NULL;
656
657 gnutls_datum_t device_cert = { NULL, 0 };
658 gnutls_datum_t host_cert = { NULL, 0 };
659 gnutls_datum_t root_cert = { NULL, 0 };
660 gnutls_datum_t public_key = { NULL, 0 }; 753 gnutls_datum_t public_key = { NULL, 0 };
754 int pairing_mode = 0; /* 0 = libiphone, 1 = external */
661 755
662 char *host_id_loc = host_id; 756 if (pair_record && pair_record->host_id) {
663 757 /* valid pair_record passed? */
664 ret = lockdownd_get_device_public_key(client, &public_key); 758 if (!pair_record->device_certificate || !pair_record->host_certificate || !pair_record->root_certificate) {
665 if (ret != LOCKDOWN_E_SUCCESS) { 759 return LOCKDOWN_E_PLIST_ERROR;
666 log_debug_msg("%s: device refused to send public key.\n", __func__); 760 }
667 return ret;
668 }
669 log_debug_msg("%s: device public key follows:\n%s\n", __func__, public_key.data);
670 761
671 ret = lockdownd_gen_pair_cert(public_key, &device_cert, &host_cert, &root_cert); 762 /* use passed pair_record */
672 if (ret != LOCKDOWN_E_SUCCESS) { 763 dict_record = lockdownd_pair_record_to_plist(pair_record);
673 free(public_key.data);
674 return ret;
675 }
676 764
677 if (!host_id) { 765 pairing_mode = 1;
678 userpref_get_host_id(&host_id_loc); 766 } else {
767 ret = lockdownd_get_device_public_key(client, &public_key);
768 if (ret != LOCKDOWN_E_SUCCESS) {
769 if (public_key.data)
770 free(public_key.data);
771 debug_info("device refused to send public key.");
772 return ret;
773 }
774 debug_info("device public key follows:\n%s", public_key.data);
775 /* get libiphone pair_record */
776 ret = generate_pair_record_plist(public_key, NULL, &dict_record);
777 if (ret != LOCKDOWN_E_SUCCESS) {
778 if (dict_record)
779 plist_free(dict_record);
780 return ret;
781 }
679 } 782 }
680 783
681 /* Setup Pair request plist */ 784 /* Setup Pair request plist */
682 dict = plist_new_dict(); 785 dict = plist_new_dict();
683 dict_record = plist_new_dict(); 786 plist_dict_add_label(dict, client->label);
684 plist_dict_insert_item(dict,"PairRecord", dict_record); 787 plist_dict_insert_item(dict,"PairRecord", dict_record);
685
686 plist_dict_insert_item(dict_record, "DeviceCertificate", plist_new_data((const char*)device_cert.data, device_cert.size));
687 plist_dict_insert_item(dict_record, "HostCertificate", plist_new_data((const char*)host_cert.data, host_cert.size));
688 plist_dict_insert_item(dict_record, "HostID", plist_new_string(host_id_loc));
689 plist_dict_insert_item(dict_record, "RootCertificate", plist_new_data((const char*)root_cert.data, root_cert.size));
690
691 plist_dict_insert_item(dict, "Request", plist_new_string(verb)); 788 plist_dict_insert_item(dict, "Request", plist_new_string(verb));
692 789
693 /* send to iPhone */ 790 /* send to iPhone */
@@ -695,10 +792,6 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, char *host
695 plist_free(dict); 792 plist_free(dict);
696 dict = NULL; 793 dict = NULL;
697 794
698 if (!host_id) {
699 free(host_id_loc);
700 }
701
702 if (ret != LOCKDOWN_E_SUCCESS) 795 if (ret != LOCKDOWN_E_SUCCESS)
703 return ret; 796 return ret;
704 797
@@ -711,17 +804,40 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, char *host
711 if (lockdown_check_result(dict, verb) != RESULT_SUCCESS) { 804 if (lockdown_check_result(dict, verb) != RESULT_SUCCESS) {
712 ret = LOCKDOWN_E_PAIRING_FAILED; 805 ret = LOCKDOWN_E_PAIRING_FAILED;
713 } 806 }
714 plist_free(dict);
715 dict = NULL;
716 807
717 /* store public key in config if pairing succeeded */ 808 /* if pairing succeeded */
718 if (ret == LOCKDOWN_E_SUCCESS) { 809 if (ret == LOCKDOWN_E_SUCCESS) {
719 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: %s success\n", __func__, verb); 810 debug_info("%s success", verb);
720 userpref_set_device_public_key(client->uuid, public_key); 811 if (!pairing_mode) {
812 if (!strcmp("Unpair", verb)) {
813 /* remove public key from config */
814 userpref_remove_device_public_key(client->uuid);
815 } else {
816 /* store public key in config */
817 userpref_set_device_public_key(client->uuid, public_key);
818 }
819 }
721 } else { 820 } else {
722 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: %s failure\n", __func__, verb); 821 debug_info("%s failure", verb);
822 plist_t error_node = NULL;
823 /* verify error condition */
824 error_node = plist_dict_get_item(dict, "Error");
825 if (error_node) {
826 char *value = NULL;
827 plist_get_string_val(error_node, &value);
828 /* the first pairing fails if the device is password protected */
829 if (value && !strcmp(value, "PasswordProtected")) {
830 ret = LOCKDOWN_E_PASSWORD_PROTECTED;
831 free(value);
832 }
833 plist_free(error_node);
834 error_node = NULL;
835 }
723 } 836 }
724 free(public_key.data); 837 plist_free(dict);
838 dict = NULL;
839 if (public_key.data)
840 free(public_key.data);
725 return ret; 841 return ret;
726} 842}
727 843
@@ -730,15 +846,15 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, char *host
730 * It's part of the lockdownd handshake. 846 * It's part of the lockdownd handshake.
731 * 847 *
732 * @param client The lockdown client to pair with. 848 * @param client The lockdown client to pair with.
733 * @param host_id The HostID to use for pairing. If NULL is passed, then 849 * @param pair_record The pair record to use for pairing. If NULL is passed, then
734 * the HostID of the current machine is used. A new HostID will be 850 * the pair records from the current machine are used. New records will be
735 * generated automatically when pairing is done for the first time. 851 * generated automatically when pairing is done for the first time.
736 * 852 *
737 * @return an error code (LOCKDOWN_E_SUCCESS on success) 853 * @return an error code (LOCKDOWN_E_SUCCESS on success)
738 */ 854 */
739lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *host_id) 855lockdownd_error_t lockdownd_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record)
740{ 856{
741 return lockdownd_do_pair(client, host_id, "Pair"); 857 return lockdownd_do_pair(client, pair_record, "Pair");
742} 858}
743 859
744/** 860/**
@@ -747,15 +863,31 @@ lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *host_id)
747 * It's part of the lockdownd handshake. 863 * It's part of the lockdownd handshake.
748 * 864 *
749 * @param client The lockdown client to pair with. 865 * @param client The lockdown client to pair with.
750 * @param host_id The HostID to use for pairing. If NULL is passed, then 866 * @param pair_record The pair record to validate pairing with. If NULL is
751 * the HostID of the current machine is used. A new HostID will be 867 * passed, then the pair records from the current machine are used.
752 * generated automatically when pairing is done for the first time. 868 * New records will be generated automatically when pairing is done
869 * for the first time.
753 * 870 *
754 * @return an error code (LOCKDOWN_E_SUCCESS on success) 871 * @return an error code (LOCKDOWN_E_SUCCESS on success)
755 */ 872 */
756lockdownd_error_t lockdownd_validate_pair(lockdownd_client_t client, char *host_id) 873lockdownd_error_t lockdownd_validate_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record)
757{ 874{
758 return lockdownd_do_pair(client, host_id, "ValidatePair"); 875 return lockdownd_do_pair(client, pair_record, "ValidatePair");
876}
877
878/**
879 * Unpairs the device with the given HostID and removes the pairing records
880 * from the device and host.
881 *
882 * @param client The lockdown client to pair with.
883 * @param pair_record The pair record to use for unpair. If NULL is passed, then
884 * the pair records from the current machine are used.
885 *
886 * @return an error code (LOCKDOWN_E_SUCCESS on success)
887 */
888lockdownd_error_t lockdownd_unpair(lockdownd_client_t client, lockdownd_pair_record_t pair_record)
889{
890 return lockdownd_do_pair(client, pair_record, "Unpair");
759} 891}
760 892
761/** 893/**
@@ -773,9 +905,10 @@ lockdownd_error_t lockdownd_enter_recovery(lockdownd_client_t client)
773 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; 905 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
774 906
775 plist_t dict = plist_new_dict(); 907 plist_t dict = plist_new_dict();
908 plist_dict_add_label(dict, client->label);
776 plist_dict_insert_item(dict,"Request", plist_new_string("EnterRecovery")); 909 plist_dict_insert_item(dict,"Request", plist_new_string("EnterRecovery"));
777 910
778 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: telling device to enter recovery mode\n", __func__); 911 debug_info("telling device to enter recovery mode");
779 912
780 ret = lockdownd_send(client, dict); 913 ret = lockdownd_send(client, dict);
781 plist_free(dict); 914 plist_free(dict);
@@ -784,7 +917,7 @@ lockdownd_error_t lockdownd_enter_recovery(lockdownd_client_t client)
784 ret = lockdownd_recv(client, &dict); 917 ret = lockdownd_recv(client, &dict);
785 918
786 if (lockdown_check_result(dict, "EnterRecovery") == RESULT_SUCCESS) { 919 if (lockdown_check_result(dict, "EnterRecovery") == RESULT_SUCCESS) {
787 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); 920 debug_info("success");
788 ret = LOCKDOWN_E_SUCCESS; 921 ret = LOCKDOWN_E_SUCCESS;
789 } 922 }
790 plist_free(dict); 923 plist_free(dict);
@@ -808,9 +941,10 @@ lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client)
808 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; 941 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
809 942
810 plist_t dict = plist_new_dict(); 943 plist_t dict = plist_new_dict();
944 plist_dict_add_label(dict, client->label);
811 plist_dict_insert_item(dict,"Request", plist_new_string("Goodbye")); 945 plist_dict_insert_item(dict,"Request", plist_new_string("Goodbye"));
812 946
813 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: called\n", __func__); 947 debug_info("called");
814 948
815 ret = lockdownd_send(client, dict); 949 ret = lockdownd_send(client, dict);
816 plist_free(dict); 950 plist_free(dict);
@@ -818,12 +952,12 @@ lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client)
818 952
819 ret = lockdownd_recv(client, &dict); 953 ret = lockdownd_recv(client, &dict);
820 if (!dict) { 954 if (!dict) {
821 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: did not get goodbye response back\n", __func__); 955 debug_info("did not get goodbye response back");
822 return LOCKDOWN_E_PLIST_ERROR; 956 return LOCKDOWN_E_PLIST_ERROR;
823 } 957 }
824 958
825 if (lockdown_check_result(dict, "Goodbye") == RESULT_SUCCESS) { 959 if (lockdown_check_result(dict, "Goodbye") == RESULT_SUCCESS) {
826 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); 960 debug_info("success");
827 ret = LOCKDOWN_E_SUCCESS; 961 ret = LOCKDOWN_E_SUCCESS;
828 } 962 }
829 plist_free(dict); 963 plist_free(dict);
@@ -879,7 +1013,7 @@ lockdownd_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datu
879 asn1_delete_structure(&pkcs1); 1013 asn1_delete_structure(&pkcs1);
880 } 1014 }
881 1015
882 /* now generate certifcates */ 1016 /* now generate certificates */
883 if (LOCKDOWN_E_SUCCESS == ret && 0 != modulus.size && 0 != exponent.size) { 1017 if (LOCKDOWN_E_SUCCESS == ret && 0 != modulus.size && 0 != exponent.size) {
884 1018
885 gnutls_global_init(); 1019 gnutls_global_init();
@@ -973,24 +1107,29 @@ lockdownd_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datu
973 * and if the device requires it, switches to SSL mode. 1107 * and if the device requires it, switches to SSL mode.
974 * 1108 *
975 * @param client The lockdownd client 1109 * @param client The lockdownd client
976 * @param HostID The HostID used with this phone 1110 * @param host_id The HostID of the computer
1111 * @param session_id The session_id of the created session
1112 * @param ssl_enabled Whether SSL communication is used in the session
977 * 1113 *
978 * @return an error code (LOCKDOWN_E_SUCCESS on success) 1114 * @return an error code (LOCKDOWN_E_SUCCESS on success)
979 */ 1115 */
980lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const char *HostID) 1116lockdownd_error_t lockdownd_start_session(lockdownd_client_t client, const char *host_id, char **session_id, int *ssl_enabled)
981{ 1117{
1118 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;
982 plist_t dict = NULL; 1119 plist_t dict = NULL;
983 uint32_t return_me = 0;
984 1120
985 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; 1121 if (!client || !host_id)
1122 ret = LOCKDOWN_E_INVALID_ARG;
1123
1124 /* if we have a running session, stop current one first */
986 if (client->session_id) { 1125 if (client->session_id) {
987 free(client->session_id); 1126 lockdownd_stop_session(client, client->session_id);
988 client->session_id = NULL;
989 } 1127 }
990 1128
991 /* Setup DevicePublicKey request plist */ 1129 /* setup request plist */
992 dict = plist_new_dict(); 1130 dict = plist_new_dict();
993 plist_dict_insert_item(dict,"HostID", plist_new_string(HostID)); 1131 plist_dict_add_label(dict, client->label);
1132 plist_dict_insert_item(dict,"HostID", plist_new_string(host_id));
994 plist_dict_insert_item(dict,"Request", plist_new_string("StartSession")); 1133 plist_dict_insert_item(dict,"Request", plist_new_string("StartSession"));
995 1134
996 ret = lockdownd_send(client, dict); 1135 ret = lockdownd_send(client, dict);
@@ -1010,183 +1149,54 @@ lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const c
1010 if (error_node && PLIST_STRING == plist_get_node_type(error_node)) { 1149 if (error_node && PLIST_STRING == plist_get_node_type(error_node)) {
1011 char *error = NULL; 1150 char *error = NULL;
1012 plist_get_string_val(error_node, &error); 1151 plist_get_string_val(error_node, &error);
1013
1014 if (!strcmp(error, "InvalidHostID")) { 1152 if (!strcmp(error, "InvalidHostID")) {
1015 /* hostid is unknown. Pair and try again */ 1153 ret = LOCKDOWN_E_INVALID_HOST_ID;
1016 char *host_id = NULL;
1017 userpref_get_host_id(&host_id);
1018
1019 if (LOCKDOWN_E_SUCCESS == lockdownd_pair(client, host_id) ) {
1020 /* start session again */
1021 plist_free(dict);
1022 dict = plist_new_dict();
1023 plist_dict_insert_item(dict,"HostID", plist_new_string(HostID));
1024 plist_dict_insert_item(dict,"Request", plist_new_string("StartSession"));
1025
1026 ret = lockdownd_send(client, dict);
1027 plist_free(dict);
1028 dict = NULL;
1029
1030 ret = lockdownd_recv(client, &dict);
1031 }
1032 free(host_id);
1033 } 1154 }
1034 free(error); 1155 free(error);
1035 } 1156 }
1036 } 1157 } else {
1037 1158 uint8_t use_ssl = 0;
1038 ret = LOCKDOWN_E_SSL_ERROR;
1039
1040 int session_ok = 0;
1041 uint8_t UseSSL = 0;
1042 1159
1043 if (lockdown_check_result(dict, "StartSession") == RESULT_SUCCESS) {
1044 plist_t enable_ssl = plist_dict_get_item(dict, "EnableSessionSSL"); 1160 plist_t enable_ssl = plist_dict_get_item(dict, "EnableSessionSSL");
1045 if (enable_ssl && (plist_get_node_type(enable_ssl) == PLIST_BOOLEAN)) { 1161 if (enable_ssl && (plist_get_node_type(enable_ssl) == PLIST_BOOLEAN)) {
1046 plist_get_bool_val(enable_ssl, &UseSSL); 1162 plist_get_bool_val(enable_ssl, &use_ssl);
1047 } 1163 }
1048 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Session startup OK\n", __func__); 1164 debug_info("Session startup OK");
1049 session_ok = 1; 1165
1050 } 1166 if (ssl_enabled != NULL)
1051 if (session_ok && !UseSSL) { 1167 *ssl_enabled = use_ssl;
1052 client->in_SSL = 0; 1168
1053 ret = LOCKDOWN_E_SUCCESS; 1169 /* store session id, we need it for StopSession */
1054 } else if (session_ok) { 1170 plist_t session_node = plist_dict_get_item(dict, "SessionID");
1055 // Set up GnuTLS... 1171 if (session_node && (plist_get_node_type(session_node) == PLIST_STRING)) {
1056 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Switching to SSL mode\n", __func__); 1172 plist_get_string_val(session_node, &client->session_id);
1057 errno = 0;
1058 gnutls_global_init();
1059 //gnutls_anon_allocate_client_credentials(&anoncred);
1060 gnutls_certificate_allocate_credentials(&client->ssl_certificate);
1061 gnutls_certificate_set_x509_trust_file(client->ssl_certificate, "hostcert.pem", GNUTLS_X509_FMT_PEM);
1062 gnutls_init(&client->ssl_session, GNUTLS_CLIENT);
1063 {
1064 int protocol_priority[16] = { GNUTLS_SSL3, 0 };
1065 int kx_priority[16] = { GNUTLS_KX_ANON_DH, GNUTLS_KX_RSA, 0 };
1066 int cipher_priority[16] = { GNUTLS_CIPHER_AES_128_CBC, GNUTLS_CIPHER_AES_256_CBC, 0 };
1067 int mac_priority[16] = { GNUTLS_MAC_SHA1, GNUTLS_MAC_MD5, 0 };
1068 int comp_priority[16] = { GNUTLS_COMP_NULL, 0 };
1069
1070 gnutls_cipher_set_priority(client->ssl_session, cipher_priority);
1071 gnutls_compression_set_priority(client->ssl_session, comp_priority);
1072 gnutls_kx_set_priority(client->ssl_session, kx_priority);
1073 gnutls_protocol_set_priority(client->ssl_session, protocol_priority);
1074 gnutls_mac_set_priority(client->ssl_session, mac_priority);
1075 } 1173 }
1076 gnutls_credentials_set(client->ssl_session, GNUTLS_CRD_CERTIFICATE, client->ssl_certificate); // this part is killing me. 1174 if (client->session_id) {
1077 1175 debug_info("SessionID: %s", client->session_id);
1078 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS step 1...\n", __func__); 1176 if (session_id != NULL)
1079 gnutls_transport_set_ptr(client->ssl_session, (gnutls_transport_ptr_t) client); 1177 *session_id = strdup(client->session_id);
1080 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS step 2...\n", __func__);
1081 gnutls_transport_set_push_function(client->ssl_session, (gnutls_push_func) & lockdownd_secuwrite);
1082 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS step 3...\n", __func__);
1083 gnutls_transport_set_pull_function(client->ssl_session, (gnutls_pull_func) & lockdownd_securead);
1084 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS step 4 -- now handshaking...\n", __func__);
1085 if (errno)
1086 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: WARN: errno says %s before handshake!\n", __func__, strerror(errno));
1087 return_me = gnutls_handshake(client->ssl_session);
1088 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS handshake done...\n", __func__);
1089
1090 if (return_me != GNUTLS_E_SUCCESS) {
1091 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS reported something wrong.\n", __func__);
1092 gnutls_perror(return_me);
1093 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: oh.. errno says %s\n", __func__, strerror(errno));
1094 return LOCKDOWN_E_SSL_ERROR;
1095 } else { 1178 } else {
1096 client->in_SSL = 1; 1179 debug_info("Failed to get SessionID!");
1180 }
1181 debug_info("Enable SSL Session: %s", (use_ssl?"true":"false"));
1182 if (use_ssl) {
1183 ret = property_list_service_enable_ssl(client->parent);
1184 if (ret == PROPERTY_LIST_SERVICE_E_SUCCESS) {
1185 client->ssl_enabled = 1;
1186 } else {
1187 ret = LOCKDOWN_E_SSL_ERROR;
1188 client->ssl_enabled = 0;
1189 }
1190 } else {
1191 client->ssl_enabled = 0;
1097 ret = LOCKDOWN_E_SUCCESS; 1192 ret = LOCKDOWN_E_SUCCESS;
1098 } 1193 }
1099 } 1194 }
1100 /* store session id, we need it for StopSession */ 1195
1101 plist_t session_node = plist_dict_get_item(dict, "SessionID");
1102 if (session_node && (plist_get_node_type(session_node) == PLIST_STRING)) {
1103 plist_get_string_val(session_node, &client->session_id);
1104 }
1105 if (client->session_id) {
1106 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: SessionID: %s\n", __func__, client->session_id);
1107 } else {
1108 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Failed to get SessionID!\n", __func__);
1109 }
1110 plist_free(dict); 1196 plist_free(dict);
1111 dict = NULL; 1197 dict = NULL;
1112 1198
1113 if (ret == LOCKDOWN_E_SUCCESS) 1199 return ret;
1114 return ret;
1115
1116 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Apparently failed negotiating with lockdownd.\n", __func__);
1117 return LOCKDOWN_E_SSL_ERROR;
1118}
1119
1120/** gnutls callback for writing data to the iPhone.
1121 *
1122 * @param transport It's really the lockdownd client, but the method signature has to match
1123 * @param buffer The data to send
1124 * @param length The length of data to send in bytes
1125 *
1126 * @return The number of bytes sent
1127 */
1128ssize_t lockdownd_secuwrite(gnutls_transport_ptr_t transport, char *buffer, size_t length)
1129{
1130 uint32_t bytes = 0;
1131 lockdownd_client_t client;
1132 client = (lockdownd_client_t) transport;
1133 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: called\n", __func__);
1134 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: pre-send length = %zi\n", __func__, length);
1135 iphone_device_send(client->connection, buffer, length, &bytes);
1136 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: post-send sent %i bytes\n", __func__, bytes);
1137 return bytes;
1138}
1139
1140/** gnutls callback for reading data from the iPhone
1141 *
1142 * @param transport It's really the lockdownd client, but the method signature has to match
1143 * @param buffer The buffer to store data in
1144 * @param length The length of data to read in bytes
1145 *
1146 * @return The number of bytes read
1147 */
1148ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_t length)
1149{
1150 int bytes = 0, pos_start_fill = 0;
1151 size_t tbytes = 0;
1152 int this_len = length;
1153 iphone_error_t res;
1154 lockdownd_client_t client;
1155 client = (lockdownd_client_t) transport;
1156 char *recv_buffer;
1157
1158 log_debug_msg("%s: pre-read client wants %zi bytes\n", __func__, length);
1159
1160 recv_buffer = (char *) malloc(sizeof(char) * this_len);
1161
1162 // repeat until we have the full data or an error occurs.
1163 do {
1164 if ((res = iphone_device_recv(client->connection, recv_buffer, this_len, (uint32_t*)&bytes)) != LOCKDOWN_E_SUCCESS) {
1165 log_debug_msg("%s: ERROR: usbmux_recv returned %d\n", __func__, res);
1166 return res;
1167 }
1168 log_debug_msg("%s: post-read we got %i bytes\n", __func__, bytes);
1169
1170 // increase read count
1171 tbytes += bytes;
1172
1173 // fill the buffer with what we got right now
1174 memcpy(buffer + pos_start_fill, recv_buffer, bytes);
1175 pos_start_fill += bytes;
1176
1177 if (tbytes >= length) {
1178 break;
1179 }
1180
1181 this_len = length - tbytes;
1182 log_debug_msg("%s: re-read trying to read missing %i bytes\n", __func__, this_len);
1183 } while (tbytes < length);
1184
1185 if (recv_buffer) {
1186 free(recv_buffer);
1187 }
1188
1189 return tbytes;
1190} 1200}
1191 1201
1192/** Command to start the desired service 1202/** Command to start the desired service
@@ -1197,7 +1207,7 @@ ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_
1197 1207
1198 * @return an error code (LOCKDOWN_E_SUCCESS on success) 1208 * @return an error code (LOCKDOWN_E_SUCCESS on success)
1199 */ 1209 */
1200lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char *service, int *port) 1210lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char *service, uint16_t *port)
1201{ 1211{
1202 if (!client || !service || !port) 1212 if (!client || !service || !port)
1203 return LOCKDOWN_E_INVALID_ARG; 1213 return LOCKDOWN_E_INVALID_ARG;
@@ -1206,17 +1216,18 @@ lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char
1206 userpref_get_host_id(&host_id); 1216 userpref_get_host_id(&host_id);
1207 if (!host_id) 1217 if (!host_id)
1208 return LOCKDOWN_E_INVALID_CONF; 1218 return LOCKDOWN_E_INVALID_CONF;
1209 if (!client->in_SSL && !lockdownd_start_ssl_session(client, host_id)) 1219 if (!client->session_id)
1210 return LOCKDOWN_E_SSL_ERROR; 1220 return LOCKDOWN_E_NO_RUNNING_SESSION;
1211 1221
1212 plist_t dict = NULL; 1222 plist_t dict = NULL;
1213 uint32_t port_loc = 0; 1223 uint16_t port_loc = 0;
1214 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; 1224 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
1215 1225
1216 free(host_id); 1226 free(host_id);
1217 host_id = NULL; 1227 host_id = NULL;
1218 1228
1219 dict = plist_new_dict(); 1229 dict = plist_new_dict();
1230 plist_dict_add_label(dict, client->label);
1220 plist_dict_insert_item(dict,"Request", plist_new_string("StartService")); 1231 plist_dict_insert_item(dict,"Request", plist_new_string("StartService"));
1221 plist_dict_insert_item(dict,"Service", plist_new_string(service)); 1232 plist_dict_insert_item(dict,"Service", plist_new_string(service));
1222 1233
@@ -1260,3 +1271,97 @@ lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char
1260 return ret; 1271 return ret;
1261} 1272}
1262 1273
1274/**
1275 * Activates the device. Only works within an open session.
1276 * The ActivationRecord plist dictionary must be obtained using the
1277 * activation protocol requesting from Apple's https webservice.
1278 *
1279 * @see http://iphone-docs.org/doku.php?id=docs:protocols:activation
1280 *
1281 * @param control The lockdown client
1282 * @param activation_record The activation record plist dictionary
1283 *
1284 * @return an error code (LOCKDOWN_E_SUCCESS on success)
1285 */
1286lockdownd_error_t lockdownd_activate(lockdownd_client_t client, plist_t activation_record)
1287{
1288 if (!client)
1289 return LOCKDOWN_E_INVALID_ARG;
1290
1291 if (!client->session_id)
1292 return LOCKDOWN_E_NO_RUNNING_SESSION;
1293
1294 if (!activation_record)
1295 return LOCKDOWN_E_INVALID_ARG;
1296
1297 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
1298
1299 plist_t dict = plist_new_dict();
1300 plist_dict_add_label(dict, client->label);
1301 plist_dict_insert_item(dict,"Request", plist_new_string("Activate"));
1302 plist_dict_insert_item(dict,"ActivationRecord", activation_record);
1303
1304 ret = lockdownd_send(client, dict);
1305 plist_free(dict);
1306 dict = NULL;
1307
1308 ret = lockdownd_recv(client, &dict);
1309 if (!dict) {
1310 debug_info("LOCKDOWN_E_PLIST_ERROR");
1311 return LOCKDOWN_E_PLIST_ERROR;
1312 }
1313
1314 ret = LOCKDOWN_E_ACTIVATION_FAILED;
1315 if (lockdown_check_result(dict, "Activate") == RESULT_SUCCESS) {
1316 debug_info("success");
1317 ret = LOCKDOWN_E_SUCCESS;
1318 }
1319 plist_free(dict);
1320 dict = NULL;
1321
1322 return ret;
1323}
1324
1325/**
1326 * Deactivates the device, returning it to the locked
1327 * “Activate with iTunes” screen.
1328 *
1329 * @param control The lockdown client
1330 *
1331 * @return an error code (LOCKDOWN_E_SUCCESS on success)
1332 */
1333lockdownd_error_t lockdownd_deactivate(lockdownd_client_t client)
1334{
1335 if (!client)
1336 return LOCKDOWN_E_INVALID_ARG;
1337
1338 if (!client->session_id)
1339 return LOCKDOWN_E_NO_RUNNING_SESSION;
1340
1341 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
1342
1343 plist_t dict = plist_new_dict();
1344 plist_dict_add_label(dict, client->label);
1345 plist_dict_insert_item(dict,"Request", plist_new_string("Deactivate"));
1346
1347 ret = lockdownd_send(client, dict);
1348 plist_free(dict);
1349 dict = NULL;
1350
1351 ret = lockdownd_recv(client, &dict);
1352 if (!dict) {
1353 debug_info("LOCKDOWN_E_PLIST_ERROR");
1354 return LOCKDOWN_E_PLIST_ERROR;
1355 }
1356
1357 ret = LOCKDOWN_E_UNKNOWN_ERROR;
1358 if (lockdown_check_result(dict, "Deactivate") == RESULT_SUCCESS) {
1359 debug_info("success");
1360 ret = LOCKDOWN_E_SUCCESS;
1361 }
1362 plist_free(dict);
1363 dict = NULL;
1364
1365 return ret;
1366}
1367
diff --git a/src/lockdown.h b/src/lockdown.h
index 931623a..82ea01f 100644
--- a/src/lockdown.h
+++ b/src/lockdown.h
@@ -26,24 +26,18 @@
26#include <string.h> 26#include <string.h>
27 27
28#include "libiphone/lockdown.h" 28#include "libiphone/lockdown.h"
29#include "property_list_service.h"
29 30
30struct lockdownd_client_int { 31struct lockdownd_client_int {
31 iphone_connection_t connection; 32 property_list_service_client_t parent;
32 gnutls_session_t ssl_session; 33 int ssl_enabled;
33 gnutls_certificate_credentials_t ssl_certificate;
34 int in_SSL;
35 char *session_id; 34 char *session_id;
36 char *uuid; 35 char *uuid;
36 char *label;
37}; 37};
38 38
39lockdownd_error_t lockdownd_get_device_public_key(lockdownd_client_t client, gnutls_datum_t * public_key); 39lockdownd_error_t lockdownd_get_device_public_key(lockdownd_client_t client, gnutls_datum_t * public_key);
40lockdownd_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datum_t * device_cert, 40lockdownd_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datum_t * device_cert,
41 gnutls_datum_t * host_cert, gnutls_datum_t * root_cert); 41 gnutls_datum_t * host_cert, gnutls_datum_t * root_cert);
42 42
43/* SSL functions */
44lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const char *HostID);
45ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_t length);
46ssize_t lockdownd_secuwrite(gnutls_transport_ptr_t transport, char *buffer, size_t length);
47
48
49#endif 43#endif
diff --git a/src/property_list_service.c b/src/property_list_service.c
new file mode 100644
index 0000000..852ed9c
--- /dev/null
+++ b/src/property_list_service.c
@@ -0,0 +1,346 @@
1/*
2 * property_list_service.c
3 * PropertyList service implementation.
4 *
5 * Copyright (c) 2010 Nikias Bassen. All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21#include <stdlib.h>
22#include <string.h>
23#include <errno.h>
24#include <arpa/inet.h>
25
26#include "property_list_service.h"
27#include "iphone.h"
28#include "debug.h"
29
30/**
31 * Convert an iphone_error_t value to an property_list_service_error_t value.
32 * Used internally to get correct error codes.
33 *
34 * @param err An iphone_error_t error code
35 *
36 * @return A matching property_list_service_error_t error code,
37 * PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR otherwise.
38 */
39static property_list_service_error_t iphone_to_property_list_service_error(iphone_error_t err)
40{
41 switch (err) {
42 case IPHONE_E_SUCCESS:
43 return PROPERTY_LIST_SERVICE_E_SUCCESS;
44 case IPHONE_E_INVALID_ARG:
45 return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
46 case IPHONE_E_SSL_ERROR:
47 return PROPERTY_LIST_SERVICE_E_SSL_ERROR;
48 default:
49 break;
50 }
51 return PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR;
52}
53
54/**
55 * Creates a new property list service for the specified port.
56 *
57 * @param device The device to connect to.
58 * @param port The port on the device to connect to, usually opened by a call to
59 * lockdownd_start_service.
60 * @param client Pointer that will be set to a newly allocated
61 * property_list_service_client_t upon successful return.
62 *
63 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
64 * PROPERTY_LIST_SERVICE_E_INVALID_ARG when one of the arguments is invalid,
65 * or PROPERTY_LIST_SERVICE_E_MUX_ERROR when connecting to the device failed.
66 */
67property_list_service_error_t property_list_service_client_new(iphone_device_t device, uint16_t port, property_list_service_client_t *client)
68{
69 if (!device || port == 0 || !client || *client)
70 return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
71
72 /* Attempt connection */
73 iphone_connection_t connection = NULL;
74 if (iphone_device_connect(device, port, &connection) != IPHONE_E_SUCCESS) {
75 return PROPERTY_LIST_SERVICE_E_MUX_ERROR;
76 }
77
78 /* create client object */
79 property_list_service_client_t client_loc = (property_list_service_client_t)malloc(sizeof(struct property_list_service_client_int));
80 client_loc->connection = connection;
81
82 *client = client_loc;
83
84 return PROPERTY_LIST_SERVICE_E_SUCCESS;
85}
86
87/**
88 * Frees a PropertyList service.
89 *
90 * @param client The property list service to free.
91 *
92 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
93 * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client is invalid, or a
94 * PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when another error occured.
95 */
96property_list_service_error_t property_list_service_client_free(property_list_service_client_t client)
97{
98 if (!client)
99 return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
100
101 property_list_service_error_t err = iphone_to_property_list_service_error(iphone_device_disconnect(client->connection));
102 free(client);
103 return err;
104}
105
106/**
107 * Sends a plist using the given property list service client.
108 * Internally used generic plist send function.
109 *
110 * @param client The property list service client to use for sending.
111 * @param plist plist to send
112 * @param binary 1 = send binary plist, 0 = send xml plist
113 *
114 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
115 * PROPERTY_LIST_SERVICE_E_INVALID_ARG when one or more parameters are
116 * invalid, PROPERTY_LIST_SERVICE_E_PLIST_ERROR when dict is not a valid
117 * plist, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when an unspecified
118 * error occurs.
119 */
120static property_list_service_error_t internal_plist_send(property_list_service_client_t client, plist_t plist, int binary)
121{
122 property_list_service_error_t res = PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR;
123 char *content = NULL;
124 uint32_t length = 0;
125 uint32_t nlen = 0;
126 int bytes = 0;
127
128 if (!client || (client && !client->connection) || !plist) {
129 return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
130 }
131
132 if (binary) {
133 plist_to_bin(plist, &content, &length);
134 } else {
135 plist_to_xml(plist, &content, &length);
136 }
137
138 if (!content || length == 0) {
139 return PROPERTY_LIST_SERVICE_E_PLIST_ERROR;
140 }
141
142 nlen = htonl(length);
143 debug_info("sending %d bytes", length);
144 iphone_device_send(client->connection, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes);
145 if (bytes == sizeof(nlen)) {
146 iphone_device_send(client->connection, content, length, (uint32_t*)&bytes);
147 if (bytes > 0) {
148 debug_info("sent %d bytes", bytes);
149 debug_plist(plist);
150 if ((uint32_t)bytes == length) {
151 res = PROPERTY_LIST_SERVICE_E_SUCCESS;
152 } else {
153 debug_info("ERROR: Could not send all data (%d of %d)!", bytes, length);
154 }
155 }
156 }
157 if (bytes <= 0) {
158 debug_info("ERROR: sending to device failed.");
159 }
160
161 free(content);
162
163 return res;
164}
165
166/**
167 * Sends an XML plist.
168 *
169 * @param client The property list service client to use for sending.
170 * @param plist plist to send
171 *
172 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
173 * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or plist is NULL,
174 * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when dict is not a valid plist,
175 * or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when an unspecified error occurs.
176 */
177property_list_service_error_t property_list_service_send_xml_plist(property_list_service_client_t client, plist_t plist)
178{
179 return internal_plist_send(client, plist, 0);
180}
181
182/**
183 * Sends a binary plist.
184 *
185 * @param client The property list service client to use for sending.
186 * @param plist plist to send
187 *
188 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
189 * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or plist is NULL,
190 * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when dict is not a valid plist,
191 * or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when an unspecified error occurs.
192 */
193property_list_service_error_t property_list_service_send_binary_plist(property_list_service_client_t client, plist_t plist)
194{
195 return internal_plist_send(client, plist, 1);
196}
197
198/**
199 * Receives a plist using the given property list service client.
200 * Internally used generic plist receive function.
201 *
202 * @param client The property list service client to use for receiving
203 * @param plist pointer to a plist_t that will point to the received plist
204 * upon successful return
205 * @param timeout Maximum time in milliseconds to wait for data.
206 *
207 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
208 * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or *plist is NULL,
209 * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when the received data cannot be
210 * converted to a plist, PROPERTY_LIST_SERVICE_E_MUX_ERROR when a
211 * communication error occurs, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR
212 * when an unspecified error occurs.
213 */
214static property_list_service_error_t internal_plist_recv_timeout(property_list_service_client_t client, plist_t *plist, unsigned int timeout)
215{
216 property_list_service_error_t res = PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR;
217 uint32_t pktlen = 0;
218 uint32_t bytes = 0;
219
220 if (!client || (client && !client->connection) || !plist) {
221 return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
222 }
223
224 iphone_device_recv_timeout(client->connection, (char*)&pktlen, sizeof(pktlen), &bytes, timeout);
225 debug_info("initial read=%i", bytes);
226 if (bytes < 4) {
227 debug_info("initial read failed!");
228 return PROPERTY_LIST_SERVICE_E_MUX_ERROR;
229 } else {
230 if ((char)pktlen == 0) { /* prevent huge buffers */
231 uint32_t curlen = 0;
232 char *content = NULL;
233 pktlen = ntohl(pktlen);
234 debug_info("%d bytes following", pktlen);
235 content = (char*)malloc(pktlen);
236
237 while (curlen < pktlen) {
238 iphone_device_recv(client->connection, content+curlen, pktlen-curlen, &bytes);
239 if (bytes <= 0) {
240 res = PROPERTY_LIST_SERVICE_E_MUX_ERROR;
241 break;
242 }
243 debug_info("received %d bytes", bytes);
244 curlen += bytes;
245 }
246 if (!memcmp(content, "bplist00", 8)) {
247 plist_from_bin(content, pktlen, plist);
248 } else {
249 plist_from_xml(content, pktlen, plist);
250 }
251 if (*plist) {
252 debug_plist(*plist);
253 res = PROPERTY_LIST_SERVICE_E_SUCCESS;
254 } else {
255 res = PROPERTY_LIST_SERVICE_E_PLIST_ERROR;
256 }
257 free(content);
258 content = NULL;
259 } else {
260 res = PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR;
261 }
262 }
263 return res;
264}
265
266/**
267 * Receives a plist using the given property list service client with specified
268 * timeout.
269 * Binary or XML plists are automatically handled.
270 *
271 * @param client The property list service client to use for receiving
272 * @param plist pointer to a plist_t that will point to the received plist
273 * upon successful return
274 * @param timeout Maximum time in milliseconds to wait for data.
275 *
276 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
277 * PROPERTY_LIST_SERVICE_E_INVALID_ARG when connection or *plist is NULL,
278 * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when the received data cannot be
279 * converted to a plist, PROPERTY_LIST_SERVICE_E_MUX_ERROR when a
280 * communication error occurs, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when
281 * an unspecified error occurs.
282 */
283property_list_service_error_t property_list_service_receive_plist_with_timeout(property_list_service_client_t client, plist_t *plist, unsigned int timeout)
284{
285 return internal_plist_recv_timeout(client, plist, timeout);
286}
287
288/**
289 * Receives a plist using the given property list service client.
290 * Binary or XML plists are automatically handled.
291 *
292 * This function is like property_list_service_receive_plist_with_timeout
293 * using a timeout of 10 seconds.
294 * @see property_list_service_receive_plist_with_timeout
295 *
296 * @param client The property list service client to use for receiving
297 * @param plist pointer to a plist_t that will point to the received plist
298 * upon successful return
299 *
300 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
301 * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or *plist is NULL,
302 * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when the received data cannot be
303 * converted to a plist, PROPERTY_LIST_SERVICE_E_MUX_ERROR when a
304 * communication error occurs, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when
305 * an unspecified error occurs.
306 */
307property_list_service_error_t property_list_service_receive_plist(property_list_service_client_t client, plist_t *plist)
308{
309 return internal_plist_recv_timeout(client, plist, 10000);
310}
311
312/**
313 * Enable SSL for the given property list service client.
314 *
315 * @param client The connected property list service client for which SSL
316 * should be enabled.
317 *
318 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
319 * PROPERTY_LIST_SERVICE_E_INVALID_ARG if client or client->connection is
320 * NULL, PROPERTY_LIST_SERVICE_E_SSL_ERROR when SSL could not be enabled,
321 * or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR otherwise.
322 */
323property_list_service_error_t property_list_service_enable_ssl(property_list_service_client_t client)
324{
325 if (!client || !client->connection)
326 return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
327 return iphone_to_property_list_service_error(iphone_connection_enable_ssl(client->connection));
328}
329
330/**
331 * Disable SSL for the given property list service client.
332 *
333 * @param client The connected property list service client for which SSL
334 * should be disabled.
335 *
336 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
337 * PROPERTY_LIST_SERVICE_E_INVALID_ARG if client or client->connection is
338 * NULL, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR otherwise.
339 */
340property_list_service_error_t property_list_service_disable_ssl(property_list_service_client_t client)
341{
342 if (!client || !client->connection)
343 return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
344 return iphone_to_property_list_service_error(iphone_connection_disable_ssl(client->connection));
345}
346
diff --git a/src/property_list_service.h b/src/property_list_service.h
new file mode 100644
index 0000000..bc3122b
--- /dev/null
+++ b/src/property_list_service.h
@@ -0,0 +1,59 @@
1 /*
2 * property_list_service.h
3 * Definitions for the PropertyList service
4 *
5 * Copyright (c) 2010 Nikias Bassen, All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21#ifndef PROPERTY_LIST_SERVICE_H
22#define PROPERTY_LIST_SERVICE_H
23
24#include "iphone.h"
25
26/* Error Codes */
27#define PROPERTY_LIST_SERVICE_E_SUCCESS 0
28#define PROPERTY_LIST_SERVICE_E_INVALID_ARG -1
29#define PROPERTY_LIST_SERVICE_E_PLIST_ERROR -2
30#define PROPERTY_LIST_SERVICE_E_MUX_ERROR -3
31#define PROPERTY_LIST_SERVICE_E_SSL_ERROR -4
32
33#define PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR -256
34
35struct property_list_service_client_int {
36 iphone_connection_t connection;
37};
38
39typedef struct property_list_service_client_int *property_list_service_client_t;
40
41typedef int16_t property_list_service_error_t;
42
43/* creation and destruction */
44property_list_service_error_t property_list_service_client_new(iphone_device_t device, uint16_t port, property_list_service_client_t *client);
45property_list_service_error_t property_list_service_client_free(property_list_service_client_t client);
46
47/* sending */
48property_list_service_error_t property_list_service_send_xml_plist(property_list_service_client_t client, plist_t plist);
49property_list_service_error_t property_list_service_send_binary_plist(property_list_service_client_t client, plist_t plist);
50
51/* receiving */
52property_list_service_error_t property_list_service_receive_plist_with_timeout(property_list_service_client_t client, plist_t *plist, unsigned int timeout);
53property_list_service_error_t property_list_service_receive_plist(property_list_service_client_t client, plist_t *plist);
54
55/* misc */
56property_list_service_error_t property_list_service_enable_ssl(property_list_service_client_t client);
57property_list_service_error_t property_list_service_disable_ssl(property_list_service_client_t client);
58
59#endif
diff --git a/src/userpref.c b/src/userpref.c
index 10c14a0..6eff534 100644
--- a/src/userpref.c
+++ b/src/userpref.c
@@ -20,6 +20,7 @@
20 */ 20 */
21 21
22#include <glib.h> 22#include <glib.h>
23#include <glib/gstdio.h>
23#include <glib/gprintf.h> 24#include <glib/gprintf.h>
24#include <stdio.h> 25#include <stdio.h>
25#include <stdint.h> 26#include <stdint.h>
@@ -30,7 +31,7 @@
30#include <gcrypt.h> 31#include <gcrypt.h>
31 32
32#include "userpref.h" 33#include "userpref.h"
33#include "utils.h" 34#include "debug.h"
34 35
35#define LIBIPHONE_CONF_DIR "libiphone" 36#define LIBIPHONE_CONF_DIR "libiphone"
36#define LIBIPHONE_CONF_FILE "libiphonerc" 37#define LIBIPHONE_CONF_FILE "libiphonerc"
@@ -105,7 +106,7 @@ static int userpref_set_host_id(const char *host_id)
105 key_file = g_key_file_new(); 106 key_file = g_key_file_new();
106 107
107 /* Store in config file */ 108 /* Store in config file */
108 log_debug_msg("%s: setting hostID to %s\n", __func__, host_id); 109 debug_info("setting hostID to %s", host_id);
109 g_key_file_set_value(key_file, "Global", "HostID", host_id); 110 g_key_file_set_value(key_file, "Global", "HostID", host_id);
110 111
111 /* Write config file on disk */ 112 /* Write config file on disk */
@@ -154,7 +155,7 @@ void userpref_get_host_id(char **host_id)
154 userpref_set_host_id(*host_id); 155 userpref_set_host_id(*host_id);
155 } 156 }
156 157
157 log_debug_msg("%s: Using %s as HostID\n", __func__, *host_id); 158 debug_info("Using %s as HostID", *host_id);
158} 159}
159 160
160/** Determines whether this iPhone has been connected to this system before. 161/** Determines whether this iPhone has been connected to this system before.
@@ -212,6 +213,30 @@ userpref_error_t userpref_set_device_public_key(const char *uuid, gnutls_datum_t
212 return USERPREF_E_SUCCESS; 213 return USERPREF_E_SUCCESS;
213} 214}
214 215
216/** Remove the public key stored for the device with uuid from this host.
217 *
218 * @param uuid The uuid of the device
219 *
220 * @return USERPREF_E_SUCCESS on success.
221 */
222userpref_error_t userpref_remove_device_public_key(const char *uuid)
223{
224 if (!userpref_has_device_public_key(uuid))
225 return USERPREF_E_SUCCESS;
226
227 /* build file path */
228 gchar *device_file = g_strconcat(uuid, ".pem", NULL);
229 gchar *pem = g_build_path(G_DIR_SEPARATOR_S, g_get_user_config_dir(), LIBIPHONE_CONF_DIR, device_file, NULL);
230
231 /* remove file */
232 g_remove(pem);
233
234 g_free(pem);
235 g_free(device_file);
236
237 return USERPREF_E_SUCCESS;
238}
239
215/** Private function which reads the given file into a gnutls structure. 240/** Private function which reads the given file into a gnutls structure.
216 * 241 *
217 * @param file The filename of the file to read 242 * @param file The filename of the file to read
diff --git a/src/userpref.h b/src/userpref.h
index 3540468..48b8969 100644
--- a/src/userpref.h
+++ b/src/userpref.h
@@ -38,6 +38,7 @@ G_GNUC_INTERNAL userpref_error_t userpref_get_keys_and_certs(gnutls_x509_privkey
38G_GNUC_INTERNAL userpref_error_t userpref_set_keys_and_certs(gnutls_datum_t * root_key, gnutls_datum_t * root_cert, gnutls_datum_t * host_key, gnutls_datum_t * host_cert); 38G_GNUC_INTERNAL userpref_error_t userpref_set_keys_and_certs(gnutls_datum_t * root_key, gnutls_datum_t * root_cert, gnutls_datum_t * host_key, gnutls_datum_t * host_cert);
39G_GNUC_INTERNAL userpref_error_t userpref_get_certs_as_pem(gnutls_datum_t *pem_root_cert, gnutls_datum_t *pem_host_cert); 39G_GNUC_INTERNAL userpref_error_t userpref_get_certs_as_pem(gnutls_datum_t *pem_root_cert, gnutls_datum_t *pem_host_cert);
40G_GNUC_INTERNAL userpref_error_t userpref_set_device_public_key(const char *uuid, gnutls_datum_t public_key); 40G_GNUC_INTERNAL userpref_error_t userpref_set_device_public_key(const char *uuid, gnutls_datum_t public_key);
41G_GNUC_INTERNAL userpref_error_t userpref_remove_device_public_key(const char *uuid);
41G_GNUC_INTERNAL int userpref_has_device_public_key(const char *uuid); 42G_GNUC_INTERNAL int userpref_has_device_public_key(const char *uuid);
42G_GNUC_INTERNAL void userpref_get_host_id(char **host_id); 43G_GNUC_INTERNAL void userpref_get_host_id(char **host_id);
43 44
diff --git a/src/utils.h b/src/utils.h
deleted file mode 100644
index c99730a..0000000
--- a/src/utils.h
+++ /dev/null
@@ -1,33 +0,0 @@
1/*
2 * utils.h
3 * contains utilitary methos for logging and debugging
4 *
5 * Copyright (c) 2008 Jonathan Beck All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#ifndef UTILS_H
23#define UTILS_H
24
25#include <glib.h>
26
27G_GNUC_INTERNAL inline void log_debug_msg(const char *format, ...);
28G_GNUC_INTERNAL inline void log_dbg_msg(uint16_t id, const char *format, ...);
29
30G_GNUC_INTERNAL inline void log_debug_buffer(const char *data, const int length);
31G_GNUC_INTERNAL inline void dump_debug_buffer(const char *file, const char *data, const int length);
32
33#endif