summaryrefslogtreecommitdiffstats
path: root/src/iphone.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/iphone.c')
-rw-r--r--src/iphone.c528
1 files changed, 241 insertions, 287 deletions
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