diff options
43 files changed, 2109 insertions, 1175 deletions
| @@ -1,22 +1,103 @@ -Release 0.9.2 -------------- - -iFuse: -* Moved some libiphone logic into iFuse and adopted to new API -* Add hard/symlink support - -libiphone: -* Migrate to use the new usbmuxd daemon -* Refactor whole API -* Add iPhone 3GS support -* Add hard/symlink support for AFC -* New iphone_id tool to list connected devices and get the device name -* iphoneinfo now allows plist/xml output and queries by domain/key -* Fix a lot of bugs/crashes, compiler warnings and comments - -usbmuxd: -* New daemon to allow multiple connections to devices -* Add iPhone 3GS support and expose new tethering USB interface -* First public release available -* Fix race condition using multiple clients simultaneously -* Fix various usbmux protocol bugs +Version 0.9.6 +~~~~~~~~~~~~~ + +* Changes: +  - Rename some code for consistency +  - Refactor pairing to allow custom pair records +  - Move SSL handling out of lockdownd code +  - Refactor lockdown session handling code +  - Remove debug mask support +  - No longer do a full lockdown handshake on client_new +  - Refactor debug code to be consistent and easier to use +  - Run validate_pair by default during lockdown handshake +  - Allow retrieving the type for lockdown query_type request +  - Add new property_list_service and device_link_service abstractions +  - Detect pairing failure due to having a password set on the device +  - Implement lockdown phone activation and deactivation +  - Fix iphoneinfo not printing values in key/value mode +  - Implement lockdown_unpair() request +  - Add more notification ids and lockdown domains +  - Implement label support for lockdown requests +  - Add new installation_proxy interface +  - Add new sbservices interface +  - Implement lockdownd_validate_pair() request +  - Add endian safety to AFC +  - Make lockdown sessions without SSL work +  - Fix linking on Mandriva Linux +  - Minor bugfixes and documentation updates + +Version 0.9.5 +~~~~~~~~~~~~~ + +* Changes: +  - Updated to the latest libplist 0.16 API +  - Fixed various minor leaks and issues +  - Updated Python bindings and module name + +Version 0.9.4 +~~~~~~~~~~~~~ + +* Changes: +  - Update to libplist 0.15 API rework +  - Update Python bindings +  - Bufixes around usbmuxd daemon usage +  - Use automake 1.11 silent rules if available +  - Various bugfixes + +Version 0.9.3 +~~~~~~~~~~~~~ + +* Changes: +  - Bump libplist requirement to 0.13 and remove deprecated code + +Version 0.9.2 +~~~~~~~~~~~~~ + +* Changes: +  - Migrate to use the new usbmuxd daemon +  - Refactor whole API +  - Add iPhone 3GS support +  - Add hard/symlink support for AFC +  - New iphone_id tool to list connected devices and get the device +    name +  - iphoneinfo now allows plist/xml output and queries by +    domain/key +  - Fix a lot of bugs/crashes, compiler warnings and comments + +Version 0.9.1 +~~~~~~~~~~~~~ + +* Changes: +  - Fix make distcheck +  - Bump libplist requirement to 0.12 and remove deprecated code +  - A bunch of autotools fixes + +Version 0.9.0 +~~~~~~~~~~~~~ + +* Changes: +  - Fix pkg-config dependancies +  - Fix Python binding generation +  - AFC cleanup and improved error handling +  - Add support for the notification proxy service +  - Add tools to show device information and relay syslog +  - More robust pairing implementation +  - Remove libiphone-initconf, SSL implementation handles it at +    runtime now +  - Fix receive of plists larger than a packet +  - Return an error if failed to start a service on the device +  - Fix usb enumeration +  - Fix udev rule to catch usb hubs, too +  - Add large file support +  - Move out plist handling into libplist and depend on it +  - Add Python bindings +  - Lots of bugfixes + +Version 0.1.0 +~~~~~~~~~~~~~ + +* Changes: +  - Use udev to set usb configuration; iphone kmod is obsolete now +  - Remove HAL mounting +  - Bugfixes + diff --git a/configure.ac b/configure.ac index 32a55f7..bb5634c 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@  # Process this file with autoconf to produce a configure script.  AC_PREREQ(2.61) -AC_INIT(libiphone, 0.9.5, nospam@nowhere.com) +AC_INIT(libiphone, 0.9.6, nospam@nowhere.com)  AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip])  m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES])  AC_CONFIG_SRCDIR([src/]) diff --git a/dev/afccheck.c b/dev/afccheck.c index 88935a0..569acf1 100644 --- a/dev/afccheck.c +++ b/dev/afccheck.c @@ -93,15 +93,13 @@ int main(int argc, char *argv[])  	lockdownd_client_t client = NULL;  	iphone_device_t phone = NULL;  	GError *err; -	int port = 0; +	uint16_t port = 0;  	afc_client_t afc = NULL;  	if (argc > 1 && !strcasecmp(argv[1], "--debug")) {  		iphone_set_debug_level(1); -		iphone_set_debug_mask(DBGMASK_ALL);  	} else {  		iphone_set_debug_level(0); -		iphone_set_debug_mask(DBGMASK_NONE);  	}  	if (IPHONE_E_SUCCESS != iphone_device_new(&phone, NULL)) { @@ -109,7 +107,7 @@ int main(int argc, char *argv[])  		return 1;  	} -	if (LOCKDOWN_E_SUCCESS != lockdownd_client_new(phone, &client)) { +	if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(phone, &client, "afccheck")) {  		iphone_device_free(phone);  		return 1;  	} diff --git a/dev/iphoneclient.c b/dev/iphoneclient.c index d62d23f..eab903c 100644 --- a/dev/iphoneclient.c +++ b/dev/iphoneclient.c @@ -29,7 +29,6 @@  #include <libiphone/lockdown.h>  #include <libiphone/afc.h>  #include <libiphone/notification_proxy.h> -#include "../src/utils.h"  static void notifier(const char *notification)  { @@ -40,7 +39,7 @@ static void notifier(const char *notification)  static void perform_notification(iphone_device_t phone, lockdownd_client_t client, const char *notification)  { -	int nport = 0; +	uint16_t nport = 0;  	np_client_t np;  	lockdownd_start_service(client, "com.apple.mobile.notification_proxy", &nport); @@ -60,8 +59,8 @@ static void perform_notification(iphone_device_t phone, lockdownd_client_t clien  int main(int argc, char *argv[])  {  	unsigned int bytes = 0; -	int port = 0, i = 0; -	int npp; +	uint16_t port = 0, i = 0; +	uint16_t npp;  	lockdownd_client_t client = NULL;  	iphone_device_t phone = NULL;  	uint64_t lockfile = 0; @@ -69,10 +68,8 @@ int main(int argc, char *argv[])  	if (argc > 1 && !strcasecmp(argv[1], "--debug")) {  		iphone_set_debug_level(1); -		iphone_set_debug_mask(DBGMASK_ALL);  	} else {  		iphone_set_debug_level(0); -		iphone_set_debug_mask(DBGMASK_NONE);  	}  	if (IPHONE_E_SUCCESS != iphone_device_new(&phone, NULL)) { @@ -87,7 +84,7 @@ int main(int argc, char *argv[])  	if (uuid)  		free(uuid); -	if (LOCKDOWN_E_SUCCESS != lockdownd_client_new(phone, &client)) { +	if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(phone, &client, "iphoneclient")) {  		iphone_device_free(phone);  		printf("Exiting.\n");  		return -1; diff --git a/dev/iphoneenterrecovery.c b/dev/iphoneenterrecovery.c index 1d4d332..153df15 100644 --- a/dev/iphoneenterrecovery.c +++ b/dev/iphoneenterrecovery.c @@ -51,7 +51,6 @@ int main(int argc, char *argv[])  	/* parse cmdline args */  	for (i = 1; i < argc; i++) {  		if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) { -			iphone_set_debug_mask(DBGMASK_ALL);  			iphone_set_debug_level(1);  			continue;  		} @@ -74,7 +73,7 @@ int main(int argc, char *argv[])  		return -1;  	} -	if (LOCKDOWN_E_SUCCESS != lockdownd_client_new(phone, &client)) { +	if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(phone, &client, "iphoneenterrecovery")) {  		iphone_device_free(phone);  		return -1;  	} diff --git a/dev/lckdclient.c b/dev/lckdclient.c index d866435..7b7604e 100644 --- a/dev/lckdclient.c +++ b/dev/lckdclient.c @@ -48,7 +48,7 @@ int main(int argc, char *argv[])  	if (uuid)  		free(uuid); -	if (LOCKDOWN_E_SUCCESS != lockdownd_client_new(phone, &client)) { +	if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(phone, &client, "lckdclient")) {  		iphone_device_free(phone);  		return -1;  	} @@ -92,7 +92,7 @@ int main(int argc, char *argv[])  				}  				if (!strcmp(*args, "start") && len == 2) { -					int port = 0; +					uint16_t port = 0;  					if(LOCKDOWN_E_SUCCESS == lockdownd_start_service(client, *(args + 1), &port)) {  						printf("started service %s on port %i\n", *(args + 1), port);  					} diff --git a/dev/msync.py b/dev/msync.py index fe7f1fd..6bb85d7 100755 --- a/dev/msync.py +++ b/dev/msync.py @@ -1,6 +1,7 @@  #! /usr/bin/env python -from libiphone.iPhone import * +from iphone import * +from plist import *  # get msync client  def GetMobileSyncClient() : @@ -24,17 +25,18 @@ msync = GetMobileSyncClient()  if not msync :      exit(1) -array = PListNode(PLIST_ARRAY) -array.add_sub_string("SDMessageSyncDataClassWithDevice") -array.add_sub_string("com.apple.Contacts"); -array.add_sub_string("---"); -array.add_sub_string("2009-01-13 22:25:58 +0100"); -array.add_sub_uint(106); -array.add_sub_string("___EmptyParameterString___"); - -msync.send(array) -array = msync.receive() -print array.to_xml() +a = Array() +a.append( String("SDMessageSyncDataClassWithDevice") ) +a.append( String("") ) +a.append( String("com.apple.Contacts") ) +a.append( String("---") ) +a.append( String("2009-01-13 22:25:58 +0100") ) +a.append( Integer(106) ) +a.append( String("___EmptyParameterString___") ) + +msync.send(a) +a = msync.receive() +print a.to_xml() diff --git a/dev/msyncclient.c b/dev/msyncclient.c index 53018ac..c136ef2 100644 --- a/dev/msyncclient.c +++ b/dev/msyncclient.c @@ -141,19 +141,19 @@ static mobilesync_error_t mobilesync_get_all_contacts(mobilesync_client_t client  int main(int argc, char *argv[])  { -	int port = 0; +	uint16_t port = 0;  	lockdownd_client_t client = NULL;  	iphone_device_t phone = NULL;  	if (argc > 1 && !strcasecmp(argv[1], "--debug")) -		iphone_set_debug_mask(DBGMASK_MOBILESYNC); +		iphone_set_debug_level(1);  	if (IPHONE_E_SUCCESS != iphone_device_new(&phone, NULL)) {  		printf("No iPhone found, is it plugged in?\n");  		return -1;  	} -	if (LOCKDOWN_E_SUCCESS != lockdownd_client_new(phone, &client)) { +	if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(phone, &client, "msyncclient")) {  		iphone_device_free(phone);  		return -1;  	} diff --git a/doxygen.cfg b/doxygen.cfg index c411c3d..b270b5d 100644 --- a/doxygen.cfg +++ b/doxygen.cfg @@ -31,7 +31,7 @@ PROJECT_NAME           = libiphone  # This could be handy for archiving the generated documentation or   # if some version control system is used. -PROJECT_NUMBER         = 0.9.5 +PROJECT_NUMBER         = 0.9.6  # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)   # base path where the generated documentation will be put.  diff --git a/include/libiphone/afc.h b/include/libiphone/afc.h index 7eff678..5d09b40 100644 --- a/include/libiphone/afc.h +++ b/include/libiphone/afc.h @@ -87,7 +87,7 @@ struct afc_client_int;  typedef struct afc_client_int *afc_client_t;  /* Interface */ -afc_error_t afc_client_new(iphone_device_t device, int dst_port, afc_client_t *client); +afc_error_t afc_client_new(iphone_device_t device, uint16_t port, afc_client_t *client);  afc_error_t afc_client_free(afc_client_t client);  afc_error_t afc_get_device_info(afc_client_t client, char ***infos);  afc_error_t afc_read_directory(afc_client_t client, const char *dir, char ***list); diff --git a/include/libiphone/installation_proxy.h b/include/libiphone/installation_proxy.h index f432e8a..f796054 100644 --- a/include/libiphone/installation_proxy.h +++ b/include/libiphone/installation_proxy.h @@ -56,7 +56,7 @@ typedef struct instproxy_client_int *instproxy_client_t;  typedef void (*instproxy_status_cb_t) (const char *operation, plist_t status);  /* Interface */ -instproxy_error_t instproxy_client_new(iphone_device_t device, int dst_port, instproxy_client_t *client); +instproxy_error_t instproxy_client_new(iphone_device_t device, uint16_t port, instproxy_client_t *client);  instproxy_error_t instproxy_client_free(instproxy_client_t client);  instproxy_error_t instproxy_browse(instproxy_client_t client, instproxy_apptype_t apptype, plist_t *result); diff --git a/include/libiphone/libiphone.h b/include/libiphone/libiphone.h index eb58d5c..b67fcd4 100644 --- a/include/libiphone/libiphone.h +++ b/include/libiphone/libiphone.h @@ -39,7 +39,7 @@ extern "C" {  #define IPHONE_E_NO_DEVICE             -3  #define IPHONE_E_NOT_ENOUGH_DATA       -4  #define IPHONE_E_BAD_HEADER            -5 -#define IPHONE_E_PLIST_ERROR           -6 +#define IPHONE_E_SSL_ERROR             -6  typedef int16_t iphone_error_t; @@ -49,15 +49,7 @@ typedef struct iphone_device_int *iphone_device_t;  struct iphone_connection_int;  typedef struct iphone_connection_int *iphone_connection_t; -/* Debugging */ -#define DBGMASK_ALL        0xFFFF -#define DBGMASK_NONE       0x0000 -#define DBGMASK_LOCKDOWND  (1 << 1) -#define DBGMASK_MOBILESYNC (1 << 2) -#define DBGMASK_INSTPROXY  (1 << 3) -  /* generic */ -void iphone_set_debug_mask(uint16_t mask);  void iphone_set_debug_level(int level);  /* discovery (events/asynchronous) */ @@ -90,7 +82,7 @@ iphone_error_t iphone_device_new(iphone_device_t *device, const char *uuid);  iphone_error_t iphone_device_free(iphone_device_t device);  /* connection/disconnection and communication */ -iphone_error_t iphone_device_connect(iphone_device_t device, uint16_t dst_port, iphone_connection_t *connection); +iphone_error_t iphone_device_connect(iphone_device_t device, uint16_t port, iphone_connection_t *connection);  iphone_error_t iphone_device_disconnect(iphone_connection_t connection);  iphone_error_t iphone_device_send(iphone_connection_t connection, const char *data, uint32_t len, uint32_t *sent_bytes);  iphone_error_t iphone_device_recv_timeout(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout); diff --git a/include/libiphone/lockdown.h b/include/libiphone/lockdown.h index 31ffeab..7fa5384 100644 --- a/include/libiphone/lockdown.h +++ b/include/libiphone/lockdown.h @@ -44,6 +44,10 @@ extern "C" {  #define LOCKDOWN_E_GET_VALUE_PROHIBITED     -10  #define LOCKDOWN_E_REMOVE_VALUE_PROHIBITED  -11  #define LOCKDOWN_E_MUX_ERROR                -12 +#define LOCKDOWN_E_ACTIVATION_FAILED        -13 +#define LOCKDOWN_E_PASSWORD_PROTECTED       -14 +#define LOCKDOWN_E_NO_RUNNING_SESSION       -15 +#define LOCKDOWN_E_INVALID_HOST_ID          -16  #define LOCKDOWN_E_UNKNOWN_ERROR           -256 @@ -52,24 +56,41 @@ typedef int16_t lockdownd_error_t;  struct lockdownd_client_int;  typedef struct lockdownd_client_int *lockdownd_client_t; +struct lockdownd_pair_record { +	char *device_certificate; +	char *host_certificate; +	char *host_id; +	char *root_certificate; +}; +typedef struct lockdownd_pair_record *lockdownd_pair_record_t; +  /* Interface */ -lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_t *client); +lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_t *client, const char *label); +lockdownd_error_t lockdownd_client_new_with_handshake(iphone_device_t device, lockdownd_client_t *client, const char *label);  lockdownd_error_t lockdownd_client_free(lockdownd_client_t client); -lockdownd_error_t lockdownd_query_type(lockdownd_client_t client); + +lockdownd_error_t lockdownd_query_type(lockdownd_client_t client, char **type);  lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *domain, const char *key, plist_t *value);  lockdownd_error_t lockdownd_set_value(lockdownd_client_t client, const char *domain, const char *key, plist_t value);  lockdownd_error_t lockdownd_remove_value(lockdownd_client_t client, const char *domain, const char *key); -lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char *service, int *port); -lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client); +lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char *service, uint16_t *port); +lockdownd_error_t lockdownd_start_session(lockdownd_client_t client, const char *host_id, char **session_id, int *ssl_enabled); +lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client, const char *session_id);  lockdownd_error_t lockdownd_send(lockdownd_client_t client, plist_t plist);  lockdownd_error_t lockdownd_recv(lockdownd_client_t client, plist_t *plist); -lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *host_id); -lockdownd_error_t lockdownd_validate_pair(lockdownd_client_t client, char *host_id); -lockdownd_error_t lockdownd_get_device_uuid(lockdownd_client_t control, char **uuid); -lockdownd_error_t lockdownd_get_device_name(lockdownd_client_t client, char **device_name); +lockdownd_error_t lockdownd_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record); +lockdownd_error_t lockdownd_validate_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record); +lockdownd_error_t lockdownd_unpair(lockdownd_client_t client, lockdownd_pair_record_t pair_record); +lockdownd_error_t lockdownd_activate(lockdownd_client_t client, plist_t activation_record); +lockdownd_error_t lockdownd_deactivate(lockdownd_client_t client);  lockdownd_error_t lockdownd_enter_recovery(lockdownd_client_t client);  lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client); +/* Helper */ +void lockdownd_client_set_label(lockdownd_client_t client, const char *label); +lockdownd_error_t lockdownd_get_device_uuid(lockdownd_client_t control, char **uuid); +lockdownd_error_t lockdownd_get_device_name(lockdownd_client_t client, char **device_name); +  #ifdef __cplusplus  }  #endif diff --git a/include/libiphone/mobilesync.h b/include/libiphone/mobilesync.h index 662036c..94fbedc 100644 --- a/include/libiphone/mobilesync.h +++ b/include/libiphone/mobilesync.h @@ -43,7 +43,7 @@ typedef int16_t mobilesync_error_t;  struct mobilesync_client_int;  typedef struct mobilesync_client_int *mobilesync_client_t; -mobilesync_error_t mobilesync_client_new(iphone_device_t device, int dst_port, mobilesync_client_t * client); +mobilesync_error_t mobilesync_client_new(iphone_device_t device, uint16_t port, mobilesync_client_t * client);  mobilesync_error_t mobilesync_client_free(mobilesync_client_t client);  mobilesync_error_t mobilesync_recv(mobilesync_client_t client, plist_t *plist);  mobilesync_error_t mobilesync_send(mobilesync_client_t client, plist_t plist); diff --git a/include/libiphone/notification_proxy.h b/include/libiphone/notification_proxy.h index 96af5fd..b58fc68 100644 --- a/include/libiphone/notification_proxy.h +++ b/include/libiphone/notification_proxy.h @@ -40,21 +40,32 @@ extern "C" {  typedef int16_t np_error_t;  /* Notification IDs for use with post_notification (client --> device) */ -#define NP_SYNC_WILL_START      "com.apple.itunes-mobdev.syncWillStart" -#define NP_SYNC_DID_START       "com.apple.itunes-mobdev.syncDidStart" -#define NP_SYNC_DID_FINISH      "com.apple.itunes-mobdev.syncDidFinish" +#define NP_SYNC_WILL_START           "com.apple.itunes-mobdev.syncWillStart" +#define NP_SYNC_DID_START            "com.apple.itunes-mobdev.syncDidStart" +#define NP_SYNC_DID_FINISH           "com.apple.itunes-mobdev.syncDidFinish"  /* Notification IDs for use with observe_notification (device --> client) */ -#define NP_SYNC_CANCEL_REQUEST  "com.apple.itunes-client.syncCancelRequest" -#define NP_SYNC_SUSPEND_REQUEST "com.apple.itunes-client.syncSuspendRequest" -#define NP_SYNC_RESUME_REQUEST  "com.apple.itunes-client.syncResumeRequest" -#define NP_PHONE_NUMBER_CHANGED "com.apple.mobile.lockdown.phone_number_changed" -#define NP_DEVICE_NAME_CHANGED  "com.apple.mobile.lockdown.device_name_changed" -#define NP_ATTEMPTACTIVATION    "com.apple.springboard.attemptactivation" -#define NP_DS_DOMAIN_CHANGED    "com.apple.mobile.data_sync.domain_changed" -#define NP_APP_INSTALLED        "com.apple.mobile.application_installed" -#define NP_APP_UNINSTALLED      "com.apple.mobile.application_uninstalled" -#define NP_ITDBPREP_DID_END     "com.apple.itdbprep.notification.didEnd" +#define NP_SYNC_CANCEL_REQUEST       "com.apple.itunes-client.syncCancelRequest" +#define NP_SYNC_SUSPEND_REQUEST      "com.apple.itunes-client.syncSuspendRequest" +#define NP_SYNC_RESUME_REQUEST       "com.apple.itunes-client.syncResumeRequest" +#define NP_PHONE_NUMBER_CHANGED      "com.apple.mobile.lockdown.phone_number_changed" +#define NP_DEVICE_NAME_CHANGED       "com.apple.mobile.lockdown.device_name_changed" +#define NP_TIMEZONE_CHANGED          "com.apple.mobile.lockdown.timezone_changed" +#define NP_TRUSTED_HOST_ATTACHED     "com.apple.mobile.lockdown.trusted_host_attached" +#define NP_HOST_DETACHED             "com.apple.mobile.lockdown.host_detached" +#define NP_HOST_ATTACHED             "com.apple.mobile.lockdown.host_attached" +#define NP_REGISTRATION_FAILED       "com.apple.mobile.lockdown.registration_failed" +#define NP_ACTIVATION_STATE          "com.apple.mobile.lockdown.activation_state" +#define NP_BRICK_STATE               "com.apple.mobile.lockdown.brick_state" +#define NP_DS_DOMAIN_CHANGED         "com.apple.mobile.data_sync.domain_changed" +#define NP_BACKUP_DOMAIN_CHANGED     "com.apple.mobile.backup.domain_changed" +#define NP_APP_INSTALLED             "com.apple.mobile.application_installed" +#define NP_APP_UNINSTALLED           "com.apple.mobile.application_uninstalled" +#define NP_DEV_IMAGE_MOUNTED         "com.apple.mobile.developer_image_mounted" +#define NP_ATTEMPTACTIVATION         "com.apple.springboard.attemptactivation" +#define NP_ITDBPREP_DID_END          "com.apple.itdbprep.notification.didEnd" +#define NP_LANGUAGE_CHANGED          "com.apple.language.changed" +#define NP_ADDRESS_BOOK_PREF_CHANGED "com.apple.AddressBook.PreferenceChanged"  struct np_client_int;  typedef struct np_client_int *np_client_t; @@ -62,7 +73,7 @@ typedef struct np_client_int *np_client_t;  typedef void (*np_notify_cb_t) (const char *notification);  /* Interface */ -np_error_t np_client_new(iphone_device_t device, int dst_port, np_client_t *client); +np_error_t np_client_new(iphone_device_t device, uint16_t port, np_client_t *client);  np_error_t np_client_free(np_client_t client);  np_error_t np_post_notification(np_client_t client, const char *notification);  np_error_t np_observe_notification(np_client_t client, const char *notification); diff --git a/include/libiphone/sbservices.h b/include/libiphone/sbservices.h index 6ea8189..3e4accb 100644 --- a/include/libiphone/sbservices.h +++ b/include/libiphone/sbservices.h @@ -43,7 +43,7 @@ struct sbservices_client_int;  typedef struct sbservices_client_int *sbservices_client_t;  /* Interface */ -sbservices_error_t sbservices_client_new(iphone_device_t device, int dst_port, sbservices_client_t *client); +sbservices_error_t sbservices_client_new(iphone_device_t device, uint16_t port, sbservices_client_t *client);  sbservices_error_t sbservices_client_free(sbservices_client_t client);  sbservices_error_t sbservices_get_icon_state(sbservices_client_t client, plist_t *state);  sbservices_error_t sbservices_set_icon_state(sbservices_client_t client, plist_t newstate); @@ -25,7 +25,7 @@  #include "AFC.h"  #include "iphone.h" -#include "utils.h" +#include "debug.h"  // This is the maximum size an AFC data packet can be  static const int MAXIMUM_PACKET_SIZE = (2 << 15); @@ -36,7 +36,7 @@ static const int MAXIMUM_PACKET_SIZE = (2 << 15);   */  static void afc_lock(afc_client_t client)  { -	log_debug_msg("%s: Locked\n", __func__); +	debug_info("Locked");  	g_mutex_lock(client->mutex);  } @@ -46,30 +46,33 @@ static void afc_lock(afc_client_t client)   */  static void afc_unlock(afc_client_t client)  { -	log_debug_msg("%s: Unlocked\n", __func__); +	debug_info("Unlocked");  	g_mutex_unlock(client->mutex);  }  /** Makes a connection to the AFC service on the phone.    *  - * @param phone The iPhone to connect on. - * @param s_port The source port.  - * @param d_port The destination port.  + * @param device The device to connect to. + * @param port The destination port. + * @param client Pointer that will be set to a newly allocated afc_client_t + *     upon successful return.   *  - * @return A handle to the newly-connected client or NULL upon error. + * @return AFC_E_SUCCESS on success, AFC_E_INVALID_ARGUMENT when device or port + *     is invalid, AFC_E_MUX_ERROR when the connection failed, or AFC_E_NO_MEM + *     when there's a memory allocation problem.   */ -afc_error_t afc_client_new(iphone_device_t device, int dst_port, afc_client_t * client) +afc_error_t afc_client_new(iphone_device_t device, uint16_t port, afc_client_t * client)  {  	/* makes sure thread environment is available */  	if (!g_thread_supported())  		g_thread_init(NULL); -	if (!device) +	if (!device || port==0)  		return AFC_E_INVALID_ARGUMENT;  	/* attempt connection */  	iphone_connection_t connection = NULL; -	if (iphone_device_connect(device, dst_port, &connection) != IPHONE_E_SUCCESS) { +	if (iphone_device_connect(device, port, &connection) != IPHONE_E_SUCCESS) {  		return AFC_E_MUX_ERROR;  	} @@ -155,12 +158,11 @@ static afc_error_t afc_dispatch_packet(afc_client_t client, const char *data, ui  	if (client->afc_packet->this_length != client->afc_packet->entire_length) {  		offset = client->afc_packet->this_length - sizeof(AFCPacket); -		log_debug_msg("%s: Offset: %i\n", __func__, offset); +		debug_info("Offset: %i", offset);  		if ((length) < (client->afc_packet->entire_length - client->afc_packet->this_length)) { -			log_debug_msg("%s: Length did not resemble what it was supposed", __func__); -			log_debug_msg("to based on the packet.\n"); -			log_debug_msg("%s: length minus offset: %i\n", __func__, length - offset); -			log_debug_msg("%s: rest of packet: %i\n", __func__, client->afc_packet->entire_length - client->afc_packet->this_length); +			debug_info("Length did not resemble what it was supposed to based on packet"); +			debug_info("length minus offset: %i", length - offset); +			debug_info("rest of packet: %i\n", client->afc_packet->entire_length - client->afc_packet->this_length);  			return AFC_E_INTERNAL_ERROR;  		} @@ -182,10 +184,10 @@ static afc_error_t afc_dispatch_packet(afc_client_t client, const char *data, ui  		}  		*bytes_sent += sent; -		log_debug_msg("%s: sent the first now go with the second\n", __func__); -		log_debug_msg("%s: Length: %i\n", __func__, length - offset); -		log_debug_msg("%s: Buffer: \n", __func__); -		log_debug_buffer(data + offset, length - offset); +		debug_info("sent the first now go with the second"); +		debug_info("Length: %i", length - offset); +		debug_info("Buffer: "); +		debug_buffer(data + offset, length - offset);  		sent = 0;  		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  		*bytes_sent = sent;  		return AFC_E_SUCCESS;  	} else { -		log_debug_msg("%s: doin things the old way\n", __func__); -		log_debug_msg("%s: packet length = %i\n", __func__, client->afc_packet->this_length); +		debug_info("doin things the old way"); +		debug_info("packet length = %i", client->afc_packet->this_length); -		log_debug_buffer((char*)client->afc_packet, sizeof(AFCPacket)); -		log_debug_msg("\n"); +		debug_buffer((char*)client->afc_packet, sizeof(AFCPacket));  		/* send AFC packet header */  		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  		*bytes_sent += sent;  		/* send AFC packet data (if there's data to send) */  		if (length > 0) { -			log_debug_msg("%s: packet data follows\n", __func__);	 +			debug_info("packet data follows"); -			log_debug_buffer(data, length); -			log_debug_msg("\n"); +			debug_buffer(data, length);  			iphone_device_send(client->connection, data, length, &sent);  			*bytes_sent += sent;  		} @@ -244,36 +244,36 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint3  	iphone_device_recv(client->connection, (char*)&header, sizeof(AFCPacket), bytes_recv);  	AFCPacket_from_LE(&header);  	if (*bytes_recv == 0) { -		log_debug_msg("%s: Just didn't get enough.\n", __func__); +		debug_info("Just didn't get enough.");  		*dump_here = NULL;  		return AFC_E_MUX_ERROR;  	} else if (*bytes_recv < sizeof(AFCPacket)) { -		log_debug_msg("%s: Did not even get the AFCPacket header\n", __func__); +		debug_info("Did not even get the AFCPacket header");  		*dump_here = NULL;  		return AFC_E_MUX_ERROR;  	}  	/* check if it's a valid AFC header */  	if (strncmp(header.magic, AFC_MAGIC, AFC_MAGIC_LEN)) { -		log_debug_msg("%s: Invalid AFC packet received (magic != " AFC_MAGIC ")!\n", __func__); +		debug_info("Invalid AFC packet received (magic != " AFC_MAGIC ")!");  	}  	/* check if it has the correct packet number */  	if (header.packet_num != client->afc_packet->packet_num) {  		/* otherwise print a warning but do not abort */ -		log_debug_msg("%s: ERROR: Unexpected packet number (%lld != %lld) aborting.\n", __func__, header.packet_num, client->afc_packet->packet_num); +		debug_info("ERROR: Unexpected packet number (%lld != %lld) aborting.", header.packet_num, client->afc_packet->packet_num);  		*dump_here = NULL;  		return AFC_E_OP_HEADER_INVALID;  	}  	/* then, read the attached packet */  	if (header.this_length < sizeof(AFCPacket)) { -		log_debug_msg("%s: Invalid AFCPacket header received!\n", __func__); +		debug_info("Invalid AFCPacket header received!");  		*dump_here = NULL;  		return AFC_E_OP_HEADER_INVALID;  	} else if ((header.this_length == header.entire_length)  			&& header.entire_length == sizeof(AFCPacket)) { -		log_debug_msg("%s: Empty AFCPacket received!\n", __func__); +		debug_info("Empty AFCPacket received!");  		*dump_here = NULL;  		*bytes_recv = 0;  		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  		}  	} -	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); +	debug_info("received AFC packet, full len=%lld, this len=%lld, operation=0x%llx", header.entire_length, header.this_length, header.operation);  	entire_len = (uint32_t)header.entire_length - sizeof(AFCPacket);  	this_len = (uint32_t)header.this_length - sizeof(AFCPacket);  	/* this is here as a check (perhaps a different upper limit is good?) */  	if (entire_len > (uint32_t)MAXIMUM_PACKET_SIZE) { -		fprintf(stderr, "%s: entire_len is larger than MAXIMUM_PACKET_SIZE, (%d > %d)!\n", __func__, entire_len, MAXIMUM_PACKET_SIZE); +		fprintf(stderr, "%s: entire_len is larger than MAXIMUM_PACKET_SIZE, (%d > %d)!", __func__, entire_len, MAXIMUM_PACKET_SIZE);  	}  	*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  		if (*bytes_recv <= 0) {  			free(*dump_here);  			*dump_here = NULL; -			log_debug_msg("%s: Did not get packet contents!\n", __func__); +			debug_info("Did not get packet contents!");  			return AFC_E_NOT_ENOUGH_DATA;  		} else if (*bytes_recv < this_len) {  			free(*dump_here);  			*dump_here = NULL; -			log_debug_msg("%s: Could not receive this_len=%d bytes\n", __func__, this_len); +			debug_info("Could not receive this_len=%d bytes", this_len);  			return AFC_E_NOT_ENOUGH_DATA;  		}  	} @@ -315,13 +315,13 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint3  		while (current_count < entire_len) {  			iphone_device_recv(client->connection, (*dump_here)+current_count, entire_len - current_count, bytes_recv);  			if (*bytes_recv <= 0) { -				log_debug_msg("%s: Error receiving data (recv returned %d)\n", __func__, *bytes_recv); +				debug_info("Error receiving data (recv returned %d)", *bytes_recv);  				break;  			}  			current_count += *bytes_recv;  		}  		if (current_count < entire_len) { -			log_debug_msg("%s: WARNING: could not receive full packet (read %s, size %d)\n", __func__, current_count, entire_len); +			debug_info("WARNING: could not receive full packet (read %s, size %d)", current_count, entire_len);  		}  	} @@ -329,14 +329,14 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint3  		param1 = *(uint64_t*)(*dump_here);  	} -	log_debug_msg("%s: packet data size = %i\n", __func__, current_count); -	log_debug_msg("%s: packet data follows\n", __func__); -	log_debug_buffer(*dump_here, current_count); +	debug_info("packet data size = %i", current_count); +	debug_info("packet data follows"); +	debug_buffer(*dump_here, current_count);  	/* check operation types */  	if (header.operation == AFC_OP_STATUS) {  		/* status response */ -		log_debug_msg("%s: got a status response, code=%lld\n", __func__, param1); +		debug_info("got a status response, code=%lld", param1);  		if (param1 != AFC_E_SUCCESS) {  			/* error status */ @@ -347,21 +347,21 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint3  		}  	} else if (header.operation == AFC_OP_DATA) {  		/* data response */ -		log_debug_msg("%s: got a data response\n", __func__); +		debug_info("got a data response");  	} else if (header.operation == AFC_OP_FILE_OPEN_RES) {  		/* file handle response */ -		log_debug_msg("%s: got a file handle response, handle=%lld\n", __func__, param1); +		debug_info("got a file handle response, handle=%lld", param1);  	} else if (header.operation == AFC_OP_FILE_TELL_RES) {  		/* tell response */ -		log_debug_msg("%s: got a tell response, position=%lld\n", __func__, param1); +		debug_info("got a tell response, position=%lld", param1);  	} else {  		/* unknown operation code received */  		free(*dump_here);  		*dump_here = NULL;  		*bytes_recv = 0; -		log_debug_msg("%s: WARNING: Unknown operation code received 0x%llx param1=%lld\n", __func__, header.operation, param1); -		fprintf(stderr, "%s: WARNING: Unknown operation code received 0x%llx param1=%lld\n", __func__, (long long)header.operation, (long long)param1); +		debug_info("WARNING: Unknown operation code received 0x%llx param1=%lld", header.operation, param1); +		fprintf(stderr, "%s: WARNING: Unknown operation code received 0x%llx param1=%lld", __func__, (long long)header.operation, (long long)param1);  		return AFC_E_OP_NOT_SUPPORTED;  	} @@ -728,7 +728,7 @@ afc_file_open(afc_client_t client, const char *filename,  	free(data);  	if (ret != AFC_E_SUCCESS) { -		log_debug_msg("%s: Didn't receive a response to the command\n", __func__); +		debug_info("Didn't receive a response to the command");  		afc_unlock(client);  		return AFC_E_NOT_ENOUGH_DATA;  	} @@ -743,7 +743,7 @@ afc_file_open(afc_client_t client, const char *filename,  		return ret;  	} -	log_debug_msg("%s: Didn't get any further data\n", __func__); +	debug_info("Didn't get any further data");  	afc_unlock(client); @@ -770,14 +770,14 @@ afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length,  	if (!client || !client->afc_packet || !client->connection || handle == 0)  		return AFC_E_INVALID_ARGUMENT; -	log_debug_msg("%s: called for length %i\n", __func__, length); +	debug_info("called for length %i", length);  	afc_lock(client);  	// Looping here to get around the maximum amount of data that  	// afc_receive_data can handle  	while (current_count < length) { -		log_debug_msg("%s: current count is %i but length is %i\n", __func__, current_count, length); +		debug_info("current count is %i but length is %i", current_count, length);  		// Send the read command  		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,  		}  		// Receive the data  		ret = afc_receive_data(client, &input, &bytes_loc); -		log_debug_msg("%s: afc_receive_data returned error: %d\n", __func__, ret); -		log_debug_msg("%s: bytes returned: %i\n", __func__, bytes_loc); +		debug_info("afc_receive_data returned error: %d", ret); +		debug_info("bytes returned: %i", bytes_loc);  		if (ret != AFC_E_SUCCESS) {  			afc_unlock(client);  			return ret; @@ -808,7 +808,7 @@ afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length,  			return ret;  		} else {  			if (input) { -				log_debug_msg("%s: %d\n", __func__, bytes_loc); +				debug_info("%d", bytes_loc);  				memcpy(data + current_count, input, (bytes_loc > length) ? length : bytes_loc);  				free(input);  				input = NULL; @@ -816,7 +816,7 @@ afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length,  			}  		}  	} -	log_debug_msg("%s: returning current_count as %i\n", __func__, current_count); +	debug_info("returning current_count as %i", current_count);  	afc_unlock(client);  	*bytes_read = current_count; @@ -849,7 +849,7 @@ afc_file_write(afc_client_t client, uint64_t handle, const char *data, uint32_t  	afc_lock(client); -	log_debug_msg("%s: Write length: %i\n", __func__, length); +	debug_info("Write length: %i", length);  	// Divide the file into segments.  	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  	ret = afc_receive_data(client, &acknowledgement, &bytes_loc);  	afc_unlock(client);  	if (ret != AFC_E_SUCCESS) { -		log_debug_msg("%s: uh oh?\n", __func__); +		debug_info("uh oh?");  	} else {  		free(acknowledgement);  	} @@ -933,7 +933,7 @@ afc_error_t afc_file_close(afc_client_t client, uint64_t handle)  	afc_lock(client); -	log_debug_msg("%s: File handle %i\n", __func__, handle); +	debug_info("File handle %i", handle);  	// Send command  	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  	afc_lock(client); -	log_debug_msg("%s: file handle %i\n", __func__, handle); +	debug_info("file handle %i", handle);  	// Send command  	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  	if (ret != AFC_E_SUCCESS) {  		afc_unlock(client); -		log_debug_msg("%s: could not send lock command\n", __func__); +		debug_info("could not send lock command");  		return AFC_E_UNKNOWN_ERROR;  	}  	// Receive the response  	ret = afc_receive_data(client, &buffer, &bytes);  	if (buffer) { -		log_debug_buffer(buffer, bytes); +		debug_buffer(buffer, bytes);  		free(buffer);  	}  	afc_unlock(client); @@ -1214,9 +1214,9 @@ afc_error_t afc_make_link(afc_client_t client, afc_link_type_t linktype, const c  	afc_lock(client); -	log_debug_msg("%s: link type: %lld\n", __func__, type); -	log_debug_msg("%s: target: %s, length:%d\n", __func__, target, strlen(target)); -	log_debug_msg("%s: linkname: %s, length:%d\n", __func__, linkname, strlen(linkname)); +	debug_info("link type: %lld", type); +	debug_info("target: %s, length:%d", target, strlen(target)); +	debug_info("linkname: %s, length:%d", linkname, strlen(linkname));  	// Send command  	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 @@  #include <plist/plist.h>  #include "InstallationProxy.h" -#include "iphone.h" -#include "utils.h" +#include "property_list_service.h" +#include "debug.h"  struct instproxy_status_data {  	instproxy_client_t client; @@ -41,7 +41,7 @@ struct instproxy_status_data {   */  static void instproxy_lock(instproxy_client_t client)  { -	log_debug_msg("InstallationProxy: Locked\n"); +	debug_info("InstallationProxy: Locked");  	g_mutex_lock(client->mutex);  } @@ -51,29 +51,30 @@ static void instproxy_lock(instproxy_client_t client)   */  static void instproxy_unlock(instproxy_client_t client)  { -	log_debug_msg("InstallationProxy: Unlocked\n"); +	debug_info("InstallationProxy: Unlocked");  	g_mutex_unlock(client->mutex);  }  /** - * Convert an iphone_error_t value to an instproxy_error_t value. - * Used internally to get correct error codes when using plist helper - * functions. + * Convert a property_list_service_error_t value to an instproxy_error_t value. + * Used internally to get correct error codes.   * - * @param err An iphone_error_t error code + * @param err A property_list_service_error_t error code   *   * @return A matching instproxy_error_t error code,   *     INSTPROXY_E_UNKNOWN_ERROR otherwise.   */ -static instproxy_error_t iphone_to_instproxy_error(iphone_error_t err) +static instproxy_error_t instproxy_error(property_list_service_error_t err)  {  	switch (err) { -		case IPHONE_E_SUCCESS: +		case PROPERTY_LIST_SERVICE_E_SUCCESS:  			return INSTPROXY_E_SUCCESS; -		case IPHONE_E_INVALID_ARG: +		case PROPERTY_LIST_SERVICE_E_INVALID_ARG:  			return INSTPROXY_E_INVALID_ARG; -		case IPHONE_E_PLIST_ERROR: +		case PROPERTY_LIST_SERVICE_E_PLIST_ERROR:  			return INSTPROXY_E_PLIST_ERROR; +		case PROPERTY_LIST_SERVICE_E_MUX_ERROR: +			return INSTPROXY_E_CONN_FAILED;  		default:  			break;  	} @@ -84,14 +85,14 @@ static instproxy_error_t iphone_to_instproxy_error(iphone_error_t err)   * Creates a new installation_proxy client   *   * @param device The device to connect to - * @param dst_port Destination port (usually given by lockdownd_start_service). + * @param port Destination port (usually given by lockdownd_start_service).   * @param client Pointer that will be set to a newly allocated   *     instproxy_client_t upon successful return.   *   * @return INSTPROXY_E_SUCCESS on success, or an INSTPROXY_E_* error value   *     when an error occured.   */ -instproxy_error_t instproxy_client_new(iphone_device_t device, int dst_port, instproxy_client_t *client) +instproxy_error_t instproxy_client_new(iphone_device_t device, uint16_t port, instproxy_client_t *client)  {  	/* makes sure thread environment is available */  	if (!g_thread_supported()) @@ -100,14 +101,13 @@ instproxy_error_t instproxy_client_new(iphone_device_t device, int dst_port, ins  	if (!device)  		return INSTPROXY_E_INVALID_ARG; -	/* Attempt connection */ -	iphone_connection_t connection = NULL; -	if (iphone_device_connect(device, dst_port, &connection) != IPHONE_E_SUCCESS) { +	property_list_service_client_t plistclient = NULL; +	if (property_list_service_client_new(device, port, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) {  		return INSTPROXY_E_CONN_FAILED;  	}  	instproxy_client_t client_loc = (instproxy_client_t) malloc(sizeof(struct instproxy_client_int)); -	client_loc->connection = connection; +	client_loc->parent = plistclient;  	client_loc->mutex = g_mutex_new();  	client_loc->status_updater = NULL; @@ -128,10 +128,10 @@ instproxy_error_t instproxy_client_free(instproxy_client_t client)  	if (!client)  		return INSTPROXY_E_INVALID_ARG; -	iphone_device_disconnect(client->connection); -	client->connection = NULL; +	property_list_service_client_free(client->parent); +	client->parent = NULL;  	if (client->status_updater) { -		log_dbg_msg(DBGMASK_INSTPROXY, "joining status_updater"); +		debug_info("joining status_updater");  		g_thread_join(client->status_updater);  	}  	if (client->mutex) { @@ -155,7 +155,7 @@ instproxy_error_t instproxy_client_free(instproxy_client_t client)   */  instproxy_error_t instproxy_browse(instproxy_client_t client, instproxy_apptype_t apptype, plist_t *result)  { -	if (!client || !client->connection || !result) +	if (!client || !client->parent || !result)  		return INSTPROXY_E_INVALID_ARG;  	instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; @@ -174,7 +174,7 @@ instproxy_error_t instproxy_browse(instproxy_client_t client, instproxy_apptype_  				p_apptype = plist_new_string("User");  				break;  			default: -				log_dbg_msg(DBGMASK_INSTPROXY, "%s: unknown apptype %d given, using INSTPROXY_APPTYPE_USER instead\n", __func__, apptype); +				debug_info("unknown apptype %d given, using INSTPROXY_APPTYPE_USER instead", apptype);  				p_apptype = plist_new_string("User");  				break;  		} @@ -184,10 +184,10 @@ instproxy_error_t instproxy_browse(instproxy_client_t client, instproxy_apptype_  	plist_dict_insert_item(dict, "Command", plist_new_string("Browse"));  	instproxy_lock(client); -	res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); +	res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict));  	plist_free(dict);  	if (res != INSTPROXY_E_SUCCESS) { -		log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not send plist\n", __func__); +		debug_info("could not send plist");  		goto leave_unlock;  	} @@ -196,7 +196,7 @@ instproxy_error_t instproxy_browse(instproxy_client_t client, instproxy_apptype_  	do {  		browsing = 0;  		dict = NULL; -		res = iphone_to_instproxy_error(iphone_device_receive_plist(client->connection, &dict)); +		res = instproxy_error(property_list_service_receive_plist(client->parent, &dict));  		if (res != INSTPROXY_E_SUCCESS) {  			break;  		} @@ -223,7 +223,7 @@ instproxy_error_t instproxy_browse(instproxy_client_t client, instproxy_apptype_  				if (!strcmp(status, "BrowsingApplications")) {  					browsing = 1;  				} else if (!strcmp(status, "Complete")) { -					log_dbg_msg(DBGMASK_INSTPROXY, "%s: Browsing applications completed\n"); +					debug_info("Browsing applications completed");  					res = INSTPROXY_E_SUCCESS;  				}  				free(status); @@ -261,10 +261,10 @@ static instproxy_error_t instproxy_perform_operation(instproxy_client_t client,  	do {  		instproxy_lock(client); -		res = iphone_to_instproxy_error(iphone_device_receive_plist_with_timeout(client->connection, &dict, 30000)); +		res = instproxy_error(property_list_service_receive_plist_with_timeout(client->parent, &dict, 30000));  		instproxy_unlock(client);  		if (res != INSTPROXY_E_SUCCESS) { -			log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not receive plist, error %d\n", __func__, res); +			debug_info("could not receive plist, error %d", res);  			break;  		}  		if (dict) { @@ -279,7 +279,7 @@ static instproxy_error_t instproxy_perform_operation(instproxy_client_t client,  				char *err_msg = NULL;  				plist_get_string_val(err, &err_msg);  				if (err_msg) { -					log_dbg_msg(DBGMASK_INSTPROXY, "%s(%s): ERROR: %s\n", __func__, operation, err_msg); +					debug_info("(%s): ERROR: %s", operation, err_msg);  					free(err_msg);  				}  #endif @@ -303,9 +303,9 @@ static instproxy_error_t instproxy_perform_operation(instproxy_client_t client,  						int percent;  						plist_get_uint_val(npercent, &val);  						percent = val; -						log_dbg_msg(DBGMASK_INSTPROXY, "%s(%s): %s (%d%%)\n", __func__, operation, status_msg, percent); +						debug_info("(%s): %s (%d%%)", operation, status_msg, percent);  					} else { -						log_dbg_msg(DBGMASK_INSTPROXY, "%s(%s): %s\n", __func__, operation, status_msg); +						debug_info("(%s): %s", operation, status_msg);  					}  #endif  					free(status_msg); @@ -314,7 +314,7 @@ static instproxy_error_t instproxy_perform_operation(instproxy_client_t client,  			plist_free(dict);  			dict = NULL;  		} -	} while (ok && client->connection); +	} while (ok && client->parent);  	return res;  } @@ -338,7 +338,7 @@ static gpointer instproxy_status_updater(gpointer arg)  	/* cleanup */  	instproxy_lock(data->client); -	log_dbg_msg(DBGMASK_INSTPROXY, "%s: done, cleaning up.\n", __func__); +	debug_info("done, cleaning up.");  	if (data->operation) {  	    free(data->operation);  	} @@ -404,15 +404,15 @@ static instproxy_error_t instproxy_create_status_updater(instproxy_client_t clie   */  static 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)  { -	if (!client || !client->connection || !pkg_path) { +	if (!client || !client->parent || !pkg_path) {  		return INSTPROXY_E_INVALID_ARG;  	}  	if (sinf && (plist_get_node_type(sinf) != PLIST_DATA)) { -		log_dbg_msg(DBGMASK_INSTPROXY, "%s(%s): ERROR: sinf data is not a PLIST_DATA node!\n", __func__, command); +		debug_info("(%s): ERROR: sinf data is not a PLIST_DATA node!", command);  		return INSTPROXY_E_INVALID_ARG;  	}  	if (metadata && (plist_get_node_type(metadata) != PLIST_DATA)) { -		log_dbg_msg(DBGMASK_INSTPROXY, "%s(%s): ERROR: metadata is not a PLIST_DATA node!\n", __func__, command); +		debug_info("(%s): ERROR: metadata is not a PLIST_DATA node!", command);  		return INSTPROXY_E_INVALID_ARG;  	} @@ -433,13 +433,13 @@ static instproxy_error_t instproxy_install_or_upgrade(instproxy_client_t client,  	plist_dict_insert_item(dict, "PackagePath", plist_new_string(pkg_path));  	instproxy_lock(client); -	res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); +	res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict));  	instproxy_unlock(client);  	plist_free(dict);  	if (res != INSTPROXY_E_SUCCESS) { -		log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not send plist, error %d\n", __func__, res); +		debug_info("could not send plist, error %d", res);  		return res;  	} @@ -512,7 +512,7 @@ instproxy_error_t instproxy_upgrade(instproxy_client_t client, const char *pkg_p   */  instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *appid, instproxy_status_cb_t status_cb)  { -	if (!client || !client->connection || !appid) { +	if (!client || !client->parent || !appid) {  		return INSTPROXY_E_INVALID_ARG;  	} @@ -526,13 +526,13 @@ instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *app  	plist_dict_insert_item(dict, "Command", plist_new_string("Uninstall"));  	instproxy_lock(client); -	res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); +	res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict));  	instproxy_unlock(client);  	plist_free(dict);  	if (res != INSTPROXY_E_SUCCESS) { -		log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not send plist, error %d\n", __func__, res); +		debug_info("could not send plist, error %d", res);  		return res;  	} @@ -553,7 +553,7 @@ instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *app   */  instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist_t *result)  { -	if (!client || !client->connection || !result) +	if (!client || !client->parent || !result)  		return INSTPROXY_E_INVALID_ARG;  	instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; @@ -563,17 +563,17 @@ instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist_t *  	instproxy_lock(client); -	res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); +	res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict));  	plist_free(dict);  	if (res != INSTPROXY_E_SUCCESS) { -		log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not send plist, error %d\n", __func__, res); +		debug_info("could not send plist, error %d", res);  		goto leave_unlock;  	} -	res = iphone_to_instproxy_error(iphone_device_receive_plist(client->connection, result)); +	res = instproxy_error(property_list_service_receive_plist(client->parent, result));  	if (res != INSTPROXY_E_SUCCESS) { -		log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not receive plist, error %d\n", __func__, res); +		debug_info("could not receive plist, error %d", res);  		goto leave_unlock;  	} @@ -610,7 +610,7 @@ leave_unlock:   */  instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid, uint32_t options, instproxy_status_cb_t status_cb)  { -	if (!client || !client->connection || !appid) +	if (!client || !client->parent || !appid)  		return INSTPROXY_E_INVALID_ARG;  	if (client->status_updater) { @@ -634,13 +634,13 @@ instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid  	plist_dict_insert_item(dict, "Command", plist_new_string("Archive"));  	instproxy_lock(client); -	res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); +	res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict));  	instproxy_unlock(client);  	plist_free(dict);  	if (res != INSTPROXY_E_SUCCESS) { -		log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not send plist, error %d\n", __func__, res); +		debug_info("could not send plist, error %d", res);  		return res;  	}  	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   */  instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid, instproxy_status_cb_t status_cb)  { -	if (!client || !client->connection || !appid) +	if (!client || !client->parent || !appid)  		return INSTPROXY_E_INVALID_ARG;  	if (client->status_updater) { @@ -680,13 +680,13 @@ instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid  	plist_dict_insert_item(dict, "Command", plist_new_string("Restore"));  	instproxy_lock(client); -	res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); +	res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict));  	instproxy_unlock(client);  	plist_free(dict);  	if (res != INSTPROXY_E_SUCCESS) { -		log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not send plist, error %d\n", __func__, res); +		debug_info("could not send plist, error %d", res);  		return res;  	}  	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   */  instproxy_error_t instproxy_remove_archive(instproxy_client_t client, const char *appid, instproxy_status_cb_t status_cb)  { -	if (!client || !client->connection || !appid) +	if (!client || !client->parent || !appid)  		return INSTPROXY_E_INVALID_ARG;  	if (client->status_updater) { @@ -726,13 +726,13 @@ instproxy_error_t instproxy_remove_archive(instproxy_client_t client, const char  	plist_dict_insert_item(dict, "Command", plist_new_string("RemoveArchive"));  	instproxy_lock(client); -	res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); +	res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict));  	instproxy_unlock(client);  	plist_free(dict);  	if (res != INSTPROXY_E_SUCCESS) { -		log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not send plist, error %d\n", __func__, res); +		debug_info("could not send plist, error %d", res);  		return res;  	}  	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 @@  #include <glib.h>  #include "libiphone/installation_proxy.h" +#include "property_list_service.h"  struct instproxy_client_int { -	iphone_connection_t connection; +	property_list_service_client_t parent;  	GMutex *mutex;  	GThread *status_updater;  }; 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  lib_LTLIBRARIES = libiphone.la  libiphone_la_SOURCES = iphone.c iphone.h \ +		       property_list_service.c property_list_service.h\ +		       device_link_service.c device_link_service.h\  		       lockdown.c lockdown.h\  		       AFC.c AFC.h\  		       NotificationProxy.c NotificationProxy.h\  		       InstallationProxy.c InstallationProxy.h\  		       SBServices.c SBServices.h\  		       userpref.c userpref.h\ -		       utils.c utils.h\ +		       debug.c debug.h\  		       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 @@  #include <arpa/inet.h>  #include "MobileSync.h" -#include "iphone.h" -#include "utils.h" +#include "device_link_service.h" +#include "debug.h"  #define MSYNC_VERSION_INT1 100  #define MSYNC_VERSION_INT2 100  /** - * Convert an iphone_error_t value to an mobilesync_error_t value. - * Used internally to get correct error codes when using plist helper - * functions. + * Convert an device_link_service_error_t value to an mobilesync_error_t value. + * Used internally to get correct error codes when using device_link_service stuff.   * - * @param err An iphone_error_t error code + * @param err An device_link_service_error_t error code   *   * @return A matching mobilesync_error_t error code,   *     MOBILESYNC_E_UNKNOWN_ERROR otherwise.   */ -static mobilesync_error_t iphone_to_mobilesync_error(iphone_error_t err) +static mobilesync_error_t mobilesync_error(device_link_service_error_t err)  {  	switch (err) { -		case IPHONE_E_SUCCESS: +		case DEVICE_LINK_SERVICE_E_SUCCESS:  			return MOBILESYNC_E_SUCCESS; -		case IPHONE_E_INVALID_ARG: +		case DEVICE_LINK_SERVICE_E_INVALID_ARG:  			return MOBILESYNC_E_INVALID_ARG; -		case IPHONE_E_PLIST_ERROR: +		case DEVICE_LINK_SERVICE_E_PLIST_ERROR:  			return MOBILESYNC_E_PLIST_ERROR; +		case DEVICE_LINK_SERVICE_E_MUX_ERROR: +			return MOBILESYNC_E_MUX_ERROR; +		case DEVICE_LINK_SERVICE_E_BAD_VERSION: +			return MOBILESYNC_E_BAD_VERSION;  		default:  			break;  	}  	return MOBILESYNC_E_UNKNOWN_ERROR;  } -mobilesync_error_t mobilesync_client_new(iphone_device_t device, int dst_port, +mobilesync_error_t mobilesync_client_new(iphone_device_t device, uint16_t port,  						   mobilesync_client_t * client)  { -	if (!device || dst_port == 0 || !client || *client) +	if (!device || port == 0 || !client || *client)  		return MOBILESYNC_E_INVALID_ARG; -	mobilesync_error_t ret = MOBILESYNC_E_UNKNOWN_ERROR; - -	/* Attempt connection */ -	iphone_connection_t connection = NULL; -	if (iphone_device_connect(device, dst_port, &connection) != IPHONE_E_SUCCESS) { +	device_link_service_client_t dlclient = NULL; +	mobilesync_error_t ret = mobilesync_error(device_link_service_client_new(device, port, &dlclient)); +	if (ret != MOBILESYNC_E_SUCCESS) {  		return ret;  	}  	mobilesync_client_t client_loc = (mobilesync_client_t) malloc(sizeof(struct mobilesync_client_int)); -	client_loc->connection = connection; +	client_loc->parent = dlclient;  	/* perform handshake */ -	plist_t array = NULL; - -	/* first receive version */ -	ret = mobilesync_recv(client_loc, &array); - -	plist_t msg_node = plist_array_get_item(array, 0); - -	char* msg = NULL; -	plist_type type = plist_get_node_type(msg_node); -	if (PLIST_STRING == type) { -		plist_get_string_val(msg_node, &msg); -	} -	if (PLIST_STRING != type || strcmp(msg, "DLMessageVersionExchange") || plist_array_get_size(array) < 3) { -		log_debug_msg("%s: ERROR: MobileSync client expected a version exchange !\n", __func__); -	} -	free(msg); -	msg = NULL; - -	plist_t ver_1 = plist_array_get_item(array, 1); -	plist_t ver_2 = plist_array_get_item(array, 2); - -	plist_type ver_1_type = plist_get_node_type(ver_1); -	plist_type ver_2_type = plist_get_node_type(ver_2); - -	if (PLIST_UINT == ver_1_type && PLIST_UINT == ver_2_type) { - -		uint64_t ver_1_val = 0; -		uint64_t ver_2_val = 0; - -		plist_get_uint_val(ver_1, &ver_1_val); -		plist_get_uint_val(ver_2, &ver_2_val); - -		plist_free(array); -		array = NULL; - -		if (ver_1_type == PLIST_UINT && ver_2_type == PLIST_UINT && ver_1_val == MSYNC_VERSION_INT1 -			&& ver_2_val == MSYNC_VERSION_INT2) { - -			array = plist_new_array(); -			plist_array_append_item(array, plist_new_string("DLMessageVersionExchange")); -			plist_array_append_item(array, plist_new_string("DLVersionsOk")); - -			ret = mobilesync_send(client_loc, array); - -			plist_free(array); -			array = NULL; - -			ret = mobilesync_recv(client_loc, &array); -			plist_t rep_node = plist_array_get_item(array, 0); - -			type = plist_get_node_type(rep_node); -			if (PLIST_STRING == type) { -				plist_get_string_val(rep_node, &msg); -			} -			if (PLIST_STRING != type || strcmp(msg, "DLMessageDeviceReady")) { -				log_debug_msg("%s: ERROR: MobileSync client failed to start session !\n", __func__); -				ret = MOBILESYNC_E_BAD_VERSION; -			} -			else -			{ -				ret = MOBILESYNC_E_SUCCESS; -				*client = client_loc; -			} -			free(msg); -			msg = NULL; - -			plist_free(array); -			array = NULL; -		} +	ret = mobilesync_error(device_link_service_version_exchange(dlclient, MSYNC_VERSION_INT1, MSYNC_VERSION_INT2)); +	if (ret != MOBILESYNC_E_SUCCESS) { +		debug_info("version exchange failed, error %d", ret); +		mobilesync_client_free(client_loc); +		return ret;  	} -	if (MOBILESYNC_E_SUCCESS != ret) -		mobilesync_client_free(client_loc); +	*client = client_loc;  	return ret;  } -static void mobilesync_disconnect(mobilesync_client_t client) -{ -	if (!client) -		return; - -	plist_t array = plist_new_array(); -	plist_array_append_item(array, plist_new_string("DLMessageDisconnect")); -	plist_array_append_item(array, plist_new_string("All done, thanks for the memories")); - -	mobilesync_send(client, array); -	plist_free(array); -	array = NULL; -} -  mobilesync_error_t mobilesync_client_free(mobilesync_client_t client)  {  	if (!client) -		return IPHONE_E_INVALID_ARG; - -	mobilesync_disconnect(client); -	return (iphone_device_disconnect(client->connection) == 0 ? MOBILESYNC_E_SUCCESS: MOBILESYNC_E_MUX_ERROR); +		return MOBILESYNC_E_INVALID_ARG; +	device_link_service_disconnect(client->parent); +	mobilesync_error_t err = mobilesync_error(device_link_service_client_free(client->parent)); +	free(client); +	return err;  }  /** Polls the iPhone for MobileSync data. @@ -183,19 +106,17 @@ mobilesync_error_t mobilesync_client_free(mobilesync_client_t client)   */  mobilesync_error_t mobilesync_recv(mobilesync_client_t client, plist_t * plist)  { -	if (!client || !plist || (plist && *plist)) +	if (!client)  		return MOBILESYNC_E_INVALID_ARG; - -	mobilesync_error_t ret = iphone_to_mobilesync_error(iphone_device_receive_plist(client->connection, plist)); +	mobilesync_error_t ret = mobilesync_error(device_link_service_receive(client->parent, plist)); +#ifndef STRIP_DEBUG_CODE  	if (ret != MOBILESYNC_E_SUCCESS) { -		return MOBILESYNC_E_MUX_ERROR; +		return ret;  	} - -#ifndef STRIP_DEBUG_CODE  	char *XMLContent = NULL;  	uint32_t length = 0;  	plist_to_xml(*plist, &XMLContent, &length); -	log_dbg_msg(DBGMASK_MOBILESYNC, "%s: plist size: %i\nbuffer :\n%s\n", __func__, length, XMLContent); +	debug_info("plist size: %i\nbuffer :\n%s", length, XMLContent);  	free(XMLContent);  #endif  	return ret; @@ -220,8 +141,8 @@ mobilesync_error_t mobilesync_send(mobilesync_client_t client, plist_t plist)  	char *XMLContent = NULL;  	uint32_t length = 0;  	plist_to_xml(plist, &XMLContent, &length); -	log_dbg_msg(DBGMASK_MOBILESYNC, "%s: plist size: %i\nbuffer :\n%s\n", __func__, length, XMLContent); +	debug_info("plist size: %i\nbuffer :\n%s", length, XMLContent);  	free(XMLContent);  #endif -	return (iphone_device_send_binary_plist(client->connection, plist) == IPHONE_E_SUCCESS ? MOBILESYNC_E_SUCCESS : MOBILESYNC_E_MUX_ERROR); +	return mobilesync_error(device_link_service_send(client->parent, plist));  } 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 @@  #define MOBILESYNC_H  #include "libiphone/mobilesync.h" +#include "device_link_service.h"  struct mobilesync_client_int { -	iphone_connection_t connection; +	device_link_service_client_t parent;  };  #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 @@  #include <plist/plist.h>  #include "NotificationProxy.h" -#include "iphone.h" -#include "utils.h" +#include "property_list_service.h" +#include "debug.h"  struct np_thread {  	np_client_t client; @@ -41,7 +41,7 @@ struct np_thread {   */  static void np_lock(np_client_t client)  { -	log_debug_msg("NP: Locked\n"); +	debug_info("NP: Locked");  	g_mutex_lock(client->mutex);  } @@ -51,29 +51,30 @@ static void np_lock(np_client_t client)   */  static void np_unlock(np_client_t client)  { -	log_debug_msg("NP: Unlocked\n"); +	debug_info("NP: Unlocked");  	g_mutex_unlock(client->mutex);  }  /** - * Convert an iphone_error_t value to an np_error_t value. - * Used internally to get correct error codes when using plist helper - * functions. + * Convert a property_list_service_error_t value to an np_error_t value. + * Used internally to get correct error codes.   * - * @param err An iphone_error_t error code + * @param err A property_list_service_error_t error code   *   * @return A matching np_error_t error code,   *     NP_E_UNKNOWN_ERROR otherwise.   */ -static np_error_t iphone_to_np_error(iphone_error_t err) +static np_error_t np_error(property_list_service_error_t err)  {  	switch (err) { -		case IPHONE_E_SUCCESS: +		case PROPERTY_LIST_SERVICE_E_SUCCESS:  			return NP_E_SUCCESS; -		case IPHONE_E_INVALID_ARG: +		case PROPERTY_LIST_SERVICE_E_INVALID_ARG:  			return NP_E_INVALID_ARG; -		case IPHONE_E_PLIST_ERROR: +		case PROPERTY_LIST_SERVICE_E_PLIST_ERROR:  			return NP_E_PLIST_ERROR; +		case PROPERTY_LIST_SERVICE_E_MUX_ERROR: +			return NP_E_CONN_FAILED;  		default:  			break;  	} @@ -83,7 +84,7 @@ static np_error_t iphone_to_np_error(iphone_error_t err)  /** Makes a connection to the NP service on the phone.    *    * @param device The device to connect to. - * @param dst_port Destination port (usually given by lockdownd_start_service). + * @param port Destination port (usually given by lockdownd_start_service).   * @param client Pointer that will be set to a newly allocated np_client_t   *    upon successful return.   *  @@ -91,7 +92,7 @@ static np_error_t iphone_to_np_error(iphone_error_t err)   *   or NP_E_CONN_FAILED when the connection to the device could not be   *   established.   */ -np_error_t np_client_new(iphone_device_t device, int dst_port, np_client_t *client) +np_error_t np_client_new(iphone_device_t device, uint16_t port, np_client_t *client)  {  	/* makes sure thread environment is available */  	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  	if (!device)  		return NP_E_INVALID_ARG; -	/* Attempt connection */ -	iphone_connection_t connection = NULL; -	if (iphone_device_connect(device, dst_port, &connection) != IPHONE_E_SUCCESS) { +	property_list_service_client_t plistclient = NULL; +	if (property_list_service_client_new(device, port, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) {  		return NP_E_CONN_FAILED;  	}  	np_client_t client_loc = (np_client_t) malloc(sizeof(struct np_client_int)); -	client_loc->connection = connection; +	client_loc->parent = plistclient;  	client_loc->mutex = g_mutex_new(); @@ -128,10 +128,10 @@ np_error_t np_client_free(np_client_t client)  	if (!client)  		return NP_E_INVALID_ARG; -	iphone_device_disconnect(client->connection); -	client->connection = NULL; +	property_list_service_client_free(client->parent); +	client->parent = NULL;  	if (client->notifier) { -		log_debug_msg("joining np callback\n"); +		debug_info("joining np callback");  		g_thread_join(client->notifier);  	}  	if (client->mutex) { @@ -144,10 +144,6 @@ np_error_t np_client_free(np_client_t client)  /** Sends a notification to the device's Notification Proxy.   * - * notification messages seen so far: - *   com.apple.itunes-mobdev.syncWillStart - *   com.apple.itunes-mobdev.syncDidStart - *   * @param client The client to send to   * @param notification The notification message to send   * @@ -164,17 +160,17 @@ np_error_t np_post_notification(np_client_t client, const char *notification)  	plist_dict_insert_item(dict,"Command", plist_new_string("PostNotification"));  	plist_dict_insert_item(dict,"Name", plist_new_string(notification)); -	np_error_t res = iphone_to_np_error(iphone_device_send_xml_plist(client->connection, dict)); +	np_error_t res = np_error(property_list_service_send_xml_plist(client->parent, dict));  	plist_free(dict);  	dict = plist_new_dict();  	plist_dict_insert_item(dict,"Command", plist_new_string("Shutdown")); -	res = iphone_to_np_error(iphone_device_send_xml_plist(client->connection, dict)); +	res = np_error(property_list_service_send_xml_plist(client->parent, dict));  	plist_free(dict);  	if (res != NP_E_SUCCESS) { -		log_debug_msg("%s: Error sending XML plist to device!\n", __func__); +		debug_info("Error sending XML plist to device!");  	}  	np_unlock(client); @@ -200,9 +196,9 @@ np_error_t np_observe_notification( np_client_t client, const char *notification  	plist_dict_insert_item(dict,"Command", plist_new_string("ObserveNotification"));  	plist_dict_insert_item(dict,"Name", plist_new_string(notification)); -	np_error_t res = iphone_to_np_error(iphone_device_send_xml_plist(client->connection, dict)); +	np_error_t res = np_error(property_list_service_send_xml_plist(client->parent, dict));  	if (res != NP_E_SUCCESS) { -		log_debug_msg("%s: Error sending XML plist to device!\n", __func__); +		debug_info("Error sending XML plist to device!");  	}  	plist_free(dict); @@ -212,22 +208,10 @@ np_error_t np_observe_notification( np_client_t client, const char *notification  /** Notifies the iphone to send a notification on specified events.   * - * observation messages seen so far: - *   com.apple.itunes-client.syncCancelRequest - *   com.apple.itunes-client.syncSuspendRequest - *   com.apple.itunes-client.syncResumeRequest - *   com.apple.mobile.lockdown.phone_number_changed - *   com.apple.mobile.lockdown.device_name_changed - *   com.apple.springboard.attemptactivation - *   com.apple.mobile.data_sync.domain_changed - *   com.apple.mobile.application_installed - *   com.apple.mobile.application_uninstalled - *   * @param client The client to send to   * @param notification_spec Specification of the notifications that should be   *  observed. This is expected to be an array of const char* that MUST have a - *  terminating NULL entry. However this parameter can be NULL; in this case, - *  the default set of notifications will be used. + *  terminating NULL entry.   *   * @return NP_E_SUCCESS on success, NP_E_INVALID_ARG when client is null,   *   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  	}  	if (!notifications) { -		notifications = np_default_notifications; +		return NP_E_INVALID_ARG;  	}  	while (notifications[i]) { @@ -275,14 +259,14 @@ static int np_get_notification(np_client_t client, char **notification)  	int res = 0;  	plist_t dict = NULL; -	if (!client || !client->connection || *notification) +	if (!client || !client->parent || *notification)  		return -1;  	np_lock(client); -	iphone_device_receive_plist_with_timeout(client->connection, &dict, 500); +	property_list_service_receive_plist_with_timeout(client->parent, &dict, 500);  	if (!dict) { -		log_debug_msg("NotificationProxy: no notification received!\n"); +		debug_info("NotificationProxy: no notification received!");  		res = 0;  	} else {  		char *cmd_value = NULL; @@ -303,14 +287,14 @@ static int np_get_notification(np_client_t client, char **notification)  			res = -2;  			if (name_value_node && name_value) {  				*notification = name_value; -				log_debug_msg("%s: got notification %s\n", __func__, name_value); +				debug_info("got notification %s\n", __func__, name_value);  				res = 0;  			}  		} else if (cmd_value && !strcmp(cmd_value, "ProxyDeath")) { -			log_debug_msg("%s: ERROR: NotificationProxy died!\n", __func__); +			debug_info("ERROR: NotificationProxy died!");  			res = -1;  		} else if (cmd_value) { -			log_debug_msg("%d: unknown NotificationProxy command '%s' received!\n", __func__); +			debug_info("unknown NotificationProxy command '%s' received!", cmd_value);  			res = -1;  		} else {  			res = -2; @@ -337,8 +321,8 @@ gpointer np_notifier( gpointer arg )  	if (!npt) return NULL; -	log_debug_msg("%s: starting callback.\n", __func__); -	while (npt->client->connection) { +	debug_info("starting callback."); +	while (npt->client->parent) {  		np_get_notification(npt->client, ¬ification);  		if (notification) {  			npt->cbfunc(notification); @@ -380,12 +364,12 @@ np_error_t np_set_notify_callback( np_client_t client, np_notify_cb_t notify_cb  	np_lock(client);  	if (client->notifier) { -		log_debug_msg("%s: callback already set, removing\n"); -		iphone_connection_t conn = client->connection; -		client->connection = NULL; +		debug_info("callback already set, removing\n"); +		property_list_service_client_t parent = client->parent; +		client->parent = NULL;  		g_thread_join(client->notifier);  		client->notifier = NULL; -		client->connection = conn; +		client->parent = parent;  	}  	if (notify_cb) { @@ -400,7 +384,7 @@ np_error_t np_set_notify_callback( np_client_t client, np_notify_cb_t notify_cb  			}  		}  	} else { -		log_debug_msg("%s: no callback set\n", __func__); +		debug_info("no callback set");  	}  	np_unlock(client); 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 @@  #include <glib.h>  #include "libiphone/notification_proxy.h" +#include "property_list_service.h"  struct np_client_int { -	iphone_connection_t connection; +	property_list_service_client_t parent;  	GMutex *mutex;  	GThread *notifier;  }; -static const char *np_default_notifications[11] = { -	NP_SYNC_SUSPEND_REQUEST, -	NP_SYNC_RESUME_REQUEST, -	NP_PHONE_NUMBER_CHANGED, -	NP_SYNC_CANCEL_REQUEST, -	NP_DEVICE_NAME_CHANGED, -	NP_ATTEMPTACTIVATION, -	NP_DS_DOMAIN_CHANGED, -	NP_APP_INSTALLED, -	NP_APP_UNINSTALLED, -	NP_ITDBPREP_DID_END, -	NULL -}; -  gpointer np_notifier(gpointer arg);  #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 @@  #include <plist/plist.h>  #include "SBServices.h" -#include "iphone.h" -#include "utils.h" +#include "property_list_service.h" +#include "debug.h"  /** Locks an sbservices client, done for thread safety stuff.   * @@ -35,7 +35,7 @@   */  static void sbs_lock(sbservices_client_t client)  { -	log_debug_msg("SBServices: Locked\n"); +	debug_info("SBServices: Locked");  	g_mutex_lock(client->mutex);  } @@ -45,11 +45,48 @@ static void sbs_lock(sbservices_client_t client)   */  static void sbs_unlock(sbservices_client_t client)  { -	log_debug_msg("SBServices: Unlocked\n"); +	debug_info("SBServices: Unlocked");  	g_mutex_unlock(client->mutex);  } -sbservices_error_t sbservices_client_new(iphone_device_t device, int dst_port, sbservices_client_t *client) +/** + * Convert a property_list_service_error_t value to a sbservices_error_t value. + * Used internally to get correct error codes. + * + * @param err A property_list_service_error_t error code + * + * @return A matching sbservices_error_t error code, + *     SBSERVICES_E_UNKNOWN_ERROR otherwise. + */ +static sbservices_error_t sbservices_error(property_list_service_error_t err) +{ +       switch (err) { +                case PROPERTY_LIST_SERVICE_E_SUCCESS: +                        return SBSERVICES_E_SUCCESS; +                case PROPERTY_LIST_SERVICE_E_INVALID_ARG: +                        return SBSERVICES_E_INVALID_ARG; +                case PROPERTY_LIST_SERVICE_E_PLIST_ERROR: +                        return SBSERVICES_E_PLIST_ERROR; +                case PROPERTY_LIST_SERVICE_E_MUX_ERROR: +                        return SBSERVICES_E_CONN_FAILED; +                default: +                        break; +        } +        return SBSERVICES_E_UNKNOWN_ERROR; +} + +/** + * Creates a new sbservices client. + * + * @param device The device to connect to. + * @param port The port on device to connect to. + * @param client Pointer that will point to a newly allocated + *     sbservices_client_t upon successful return. + * + * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when + *     client is NULL, or an SBSERVICES_E_* error code otherwise. + */ +sbservices_error_t sbservices_client_new(iphone_device_t device, uint16_t port, sbservices_client_t *client)  {  	/* makes sure thread environment is available */  	if (!g_thread_supported()) @@ -58,38 +95,56 @@ sbservices_error_t sbservices_client_new(iphone_device_t device, int dst_port, s  	if (!device)  		return SBSERVICES_E_INVALID_ARG; -	/* Attempt connection */ -	iphone_connection_t connection = NULL; -	if (iphone_device_connect(device, dst_port, &connection) != IPHONE_E_SUCCESS) { -		return SBSERVICES_E_CONN_FAILED; +	property_list_service_client_t plistclient = NULL; +	sbservices_error_t err = sbservices_error(property_list_service_client_new(device, port, &plistclient)); +	if (err != SBSERVICES_E_SUCCESS) { +		return err;  	}  	sbservices_client_t client_loc = (sbservices_client_t) malloc(sizeof(struct sbservices_client_int)); -	client_loc->connection = connection; +	client_loc->parent = plistclient;  	client_loc->mutex = g_mutex_new();  	*client = client_loc;  	return SBSERVICES_E_SUCCESS;  } +/** + * Frees an sbservices client. + * + * @param client The sbservices client to free. + * + * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when + *     client is NULL, or an SBSERVICES_E_* error code otherwise. + */  sbservices_error_t sbservices_client_free(sbservices_client_t client)  {  	if (!client)  		return SBSERVICES_E_INVALID_ARG; -	iphone_device_disconnect(client->connection); -	client->connection = NULL; +	sbservices_error_t err = sbservices_error(property_list_service_client_free(client->parent)); +	client->parent = NULL;  	if (client->mutex) {  		g_mutex_free(client->mutex);  	}  	free(client); -	return SBSERVICES_E_SUCCESS; +	return err;  } +/** + * Gets the icon state of the connected device. + * + * @param client The connected sbservices client to use. + * @param state Pointer that will point to a newly allocated plist containing + *     the current icon state. It is up to the caller to free the memory. + * + * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when + *     client or state is invalid, or an SBSERVICES_E_* error code otherwise. + */  sbservices_error_t sbservices_get_icon_state(sbservices_client_t client, plist_t *state)  { -	if (!client || !client->connection || !state) +	if (!client || !client->parent || !state)  		return SBSERVICES_E_INVALID_ARG;  	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  	sbs_lock(client); -	if (iphone_device_send_binary_plist(client->connection, dict) != IPHONE_E_SUCCESS) { -		log_debug_msg("%s: could not send plist\n", __func__); +	res = sbservices_error(property_list_service_send_binary_plist(client->parent, dict)); +	if (res != SBSERVICES_E_SUCCESS) { +		debug_info("could not send plist, error %d", res);  		goto leave_unlock;  	}  	plist_free(dict);  	dict = NULL; -	if (iphone_device_receive_plist(client->connection, state) == IPHONE_E_SUCCESS) { -		res = SBSERVICES_E_SUCCESS; -	} else { -		log_debug_msg("%s: could not get icon state!\n", __func__); +	res = sbservices_error(property_list_service_receive_plist(client->parent, state)); +	if (res != SBSERVICES_E_SUCCESS) { +		debug_info("could not get icon state, error %d", res);  		if (*state) {  			plist_free(*state);  			*state = NULL; @@ -124,9 +179,18 @@ leave_unlock:  	return res;  } +/** + * Sets the icon state of the connected device. + * + * @param client The connected sbservices client to use. + * @param newstate A plist containing the new iconstate. + * + * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when + *     client or newstate is NULL, or an SBSERVICES_E_* error code otherwise. + */  sbservices_error_t sbservices_set_icon_state(sbservices_client_t client, plist_t newstate)  { -	if (!client || !client->connection || !newstate) +	if (!client || !client->parent || !newstate)  		return SBSERVICES_E_INVALID_ARG;  	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  	sbs_lock(client); -	if (iphone_device_send_binary_plist(client->connection, dict) != IPHONE_E_SUCCESS) { -		log_debug_msg("%s: could not send plist\n", __func__); -		goto leave_unlock; +	res = sbservices_error(property_list_service_send_binary_plist(client->parent, dict)); +	if (res != SBSERVICES_E_SUCCESS) { +		debug_info("could not send plist, error %d", res);  	}  	// NO RESPONSE -leave_unlock:  	if (dict) {  		plist_free(dict);  	} @@ -151,9 +214,24 @@ leave_unlock:  	return res;  } +/** + * Get the icon of the specified app as PNG data. + * + * @param client The connected sbservices client to use. + * @param bundleId The bundle identifier of the app to retrieve the icon for. + * @param pngdata Pointer that will point to a newly allocated buffer + *     containing the PNG data upon successful return. It is up to the caller + *     to free the memory. + * @param pngsize Pointer to a uint64_t that will be set to the size of the + *     buffer pngdata points to upon successful return. + * + * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when + *     client, bundleId, or pngdata are invalid, or an SBSERVICES_E_* error + *     code otherwise. + */  sbservices_error_t sbservices_get_icon_pngdata(sbservices_client_t client, const char *bundleId, char **pngdata, uint64_t *pngsize)  { -	if (!client || !client->connection || !pngdata) +	if (!client || !client->parent || !bundleId || !pngdata)  		return SBSERVICES_E_INVALID_ARG;  	sbservices_error_t res = SBSERVICES_E_UNKNOWN_ERROR; @@ -164,19 +242,20 @@ sbservices_error_t sbservices_get_icon_pngdata(sbservices_client_t client, const  	sbs_lock(client); -	if (iphone_device_send_binary_plist(client->connection, dict) != IPHONE_E_SUCCESS) { -		log_debug_msg("%s: could not send plist\n", __func__); +	res = sbservices_error(property_list_service_send_binary_plist(client->parent, dict)); +	if (res != SBSERVICES_E_SUCCESS) { +		debug_info("could not send plist, error %d", res);  		goto leave_unlock;  	}  	plist_free(dict);  	dict = NULL; -	if (iphone_device_receive_plist(client->connection, &dict) == IPHONE_E_SUCCESS) { +	res = sbservices_error(property_list_service_receive_plist(client->parent, &dict)); +	if (res	== SBSERVICES_E_SUCCESS) {  		plist_t node = plist_dict_get_item(dict, "pngData");  		if (node) {  			plist_get_data_val(node, pngdata, pngsize);  		} -		res = SBSERVICES_E_SUCCESS;  	}  leave_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 @@  #include <glib.h>  #include "libiphone/sbservices.h" +#include "property_list_service.h"  struct sbservices_client_int { -	iphone_connection_t connection; +	property_list_service_client_t parent;  	GMutex *mutex;  }; 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 @@  /* - * utils.c - * contains utilitary methos for logging and debugging + * debug.c + * contains utilitary functions for debugging   *   * Copyright (c) 2008 Jonathan Beck All Rights Reserved.   * @@ -18,15 +18,18 @@   * License along with this library; if not, write to the Free Software   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA    */ +  #include <stdarg.h> +#define _GNU_SOURCE 1 +#define __USE_GNU 1  #include <stdio.h>  #include <stdint.h> +#include <stdlib.h> -#include "utils.h" +#include "debug.h"  #include "libiphone/libiphone.h" -int toto_debug = 0; -uint16_t dbg_mask = 0; +int debug_level = 0;  /**   * Sets the level of debugging. Currently the only acceptable values are 0 and @@ -36,59 +39,63 @@ uint16_t dbg_mask = 0;   */  void iphone_set_debug_level(int level)  { -	toto_debug = level; +	debug_level = level;  } - -/** - * Set debug ids to display. Values can be OR-ed - * - * @param level Set to 0 for no debugging or 1 for debugging. - */ -void iphone_set_debug_mask(uint16_t mask) +static void debug_print_line(const char *func, const char *file, int line, const char *buffer)  { -	dbg_mask = mask; -} +	char *str_time = NULL; +	char *header = NULL; +	time_t the_time; -void log_debug_msg(const char *format, ...) -{ -#ifndef STRIP_DEBUG_CODE +	time(&the_time); +	str_time = g_new0 (gchar, 255); +	strftime(str_time, 254, "%H:%M:%S", localtime (&the_time)); -	va_list args; -	/* run the real fprintf */ -	va_start(args, format); +	/* generate header text */ +	(void)asprintf(&header, "%s %s:%d %s()", str_time, file, line, func); +	free (str_time); -	if (toto_debug) -		vfprintf(stderr, format, args); +	/* always in light green */ +	printf ("%s: ", header); -	va_end(args); +	/* different colors according to the severity */ +	printf ("%s\n", buffer); -#endif +	/* flush this output, as we need to debug */ +	fflush (stdout); + +	free (header);  } -void log_dbg_msg(uint16_t id, const char *format, ...) +inline void debug_info_real(const char *func, const char *file, int line, const char *format, ...)  {  #ifndef STRIP_DEBUG_CODE -	if (id & dbg_mask) { -		va_list args; -		/* run the real fprintf */ -		va_start(args, format); +	va_list args; +	char *buffer = NULL; -		vfprintf(stderr, format, args); +	if (!debug_level) +		return; -		va_end(args); -	} +	/* run the real fprintf */ +	va_start(args, format); +	(void)vasprintf(&buffer, format, args); +	va_end(args); + +	debug_print_line(func, file, line, buffer); + +	free(buffer);  #endif  } -inline void log_debug_buffer(const char *data, const int length) +inline void debug_buffer(const char *data, const int length)  {  #ifndef STRIP_DEBUG_CODE  	int i;  	int j;  	unsigned char c; -	if (toto_debug) { +	if (debug_level) {  		for (i = 0; i < length; i += 16) {  			fprintf(stderr, "%04x: ", i);  			for (j = 0; j < 16; j++) { @@ -116,16 +123,29 @@ inline void log_debug_buffer(const char *data, const int length)  #endif  } -inline void dump_debug_buffer(const char *file, const char *data, const int length) +inline void debug_buffer_to_file(const char *file, const char *data, const int length)  {  #ifndef STRIP_DEBUG_CODE -	/* run the real fprintf */ -	if (toto_debug) { -		FILE *my_ssl_packet = fopen(file, "w+"); -		fwrite(data, 1, length, my_ssl_packet); -		fflush(my_ssl_packet); -		fprintf(stderr, "%s: Wrote SSL packet to drive, too.\n", __func__); -		fclose(my_ssl_packet); +	if (debug_level) { +		FILE *f = fopen(file, "w+"); +		fwrite(data, 1, length, f); +		fflush(f); +		fclose(f);  	}  #endif  } + +inline void debug_plist(plist_t plist) +{ +#ifndef STRIP_DEBUG_CODE +	if (!plist) +		return; + +	char *buffer = NULL; +	uint32_t length = 0; +	plist_to_xml(plist, &buffer, &length); +	debug_info("plist size: %i\nbuffer :\n%s", length, buffer); +	free(buffer); +#endif +} + 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 @@ +/* + * debug.h + * contains utilitary functions for debugging + * + * Copyright (c) 2008 Jonathan Beck All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA  + */ + +#ifndef DEBUG_H +#define DEBUG_H + +#include <plist/plist.h> +#include <glib.h> + +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && !defined(STRIP_DEBUG_CODE) +#define debug_info(...) debug_info_real (__func__, __FILE__, __LINE__, __VA_ARGS__) +#elif defined(__GNUC__) && __GNUC__ >= 3 && !defined(STRIP_DEBUG_CODE) +#define debug_info(...) debug_info_real (__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__) +#else +#define debug_info(...) +#endif + +G_GNUC_INTERNAL inline void debug_info_real(const char *func, +											const char *file, +											int	line, +											const char *format, ...); + +G_GNUC_INTERNAL inline void debug_buffer(const char *data, const int length); +G_GNUC_INTERNAL inline void debug_buffer_to_file(const char *file, const char *data, const int length); +G_GNUC_INTERNAL inline void debug_plist(plist_t plist); + +#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 @@ + /*  + * device_link_service.c + * DeviceLink service implementation. + *  + * Copyright (c) 2010 Nikias Bassen, All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA  + */ +#include <string.h> +#include <stdlib.h> +#include "device_link_service.h" +#include "property_list_service.h" +#include "debug.h" + +/** + * Internally used function to extract the message string from a DLMessage* + * plist. + * + * @param dl_msg The DeviceLink property list to parse. + * + * @return An allocated char* with the DLMessage from the given plist, + *     or NULL when the plist does not contain any DLMessage. It is up to + *     the caller to free the allocated memory. + */ +static char *device_link_service_get_message(plist_t dl_msg) +{ +	uint32_t cnt = 0; +	plist_t cmd = 0; +	char *cmd_str = NULL; + +	/* sanity check */ +	if ((plist_get_node_type(dl_msg) != PLIST_ARRAY) || ((cnt = plist_array_get_size(dl_msg)) < 1)) { +		return NULL; +	} + +	/* get dl command */ +	cmd = plist_array_get_item(dl_msg, 0); +	if (!cmd || (plist_get_node_type(cmd) != PLIST_STRING)) { +		return NULL; +	} + +	plist_get_string_val(cmd, &cmd_str); +	if (!cmd_str) { +		return NULL; +	} + +	if ((strlen(cmd_str) < (strlen("DLMessage")+1)) +	    || (strncmp(cmd_str, "DLMessage", strlen("DLMessage")))) { +		free(cmd_str); +		return NULL; +	} + +	/* we got a DLMessage* command */ +	return cmd_str; +} + +/** + * Creates a new device link service client. + * + * @param device The device to connect to. + * @param port Port on device to connect to. + * @param client Reference that will point to a newly allocated + *     device_link_service_client_t upon successful return. + * + * @return DEVICE_LINK_SERVICE_E_SUCCESS on success, + *     DEVICE_LINK_SERVICE_E_INVALID_ARG when one of the parameters is invalid, + *     or DEVICE_LINK_SERVICE_E_MUX_ERROR when the connection failed. + */ +device_link_service_error_t device_link_service_client_new(iphone_device_t device, uint16_t port, device_link_service_client_t *client) +{ +	if (!device || port == 0 || !client || *client) { +		return DEVICE_LINK_SERVICE_E_INVALID_ARG; +	} + +	property_list_service_client_t plistclient = NULL; +	if (property_list_service_client_new(device, port, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) { +		return DEVICE_LINK_SERVICE_E_MUX_ERROR; +	} + +	/* create client object */ +	device_link_service_client_t client_loc = (device_link_service_client_t) malloc(sizeof(struct device_link_service_client_int)); +	client_loc->parent = plistclient; + +	/* all done, return success */ +	*client = client_loc; +	return DEVICE_LINK_SERVICE_E_SUCCESS; +} + +/** + * Frees a device link service client. + * + * @param client The device_link_service_client_t to free. + * + * @return DEVICE_LINK_SERVICE_E_SUCCESS on success, + *     DEVICE_LINK_SERVICE_E_INVALID_ARG when one of client or client->parent + *     is invalid, or DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR when the was an error + *     freeing the parent property_list_service client. + */ +device_link_service_error_t device_link_service_client_free(device_link_service_client_t client) +{ +	if (!client) +		return DEVICE_LINK_SERVICE_E_INVALID_ARG; + +	if (property_list_service_client_free(client->parent) != PROPERTY_LIST_SERVICE_E_SUCCESS) { +		return DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR; +	} +	return DEVICE_LINK_SERVICE_E_SUCCESS; +} + +/** + * Performs the DLMessageVersionExchange with the connected device. + * This should be the first operation to be executed by an implemented + * device link service client. + * + * @param client The device_link_service client to use. + * @param version_major The major version number to check. + * @param version_minor The minor version number to check. + * + * @return DEVICE_LINK_SERVICE_E_SUCCESS on success, + *     DEVICE_LINK_SERVICE_E_INVALID_ARG when client is NULL, + *     DEVICE_LINK_SERVICE_E_MUX_ERROR when a communication error occurs, + *     DEVICE_LINK_SERVICE_E_PLIST_ERROR when the received plist has not the + *     expected contents, DEVICE_LINK_SERVICE_E_BAD_VERSION when the version + *     given by the device is larger than the given version, + *     or DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR otherwise. + */ +device_link_service_error_t device_link_service_version_exchange(device_link_service_client_t client, uint64_t version_major, uint64_t version_minor) +{ +	if (!client) +		return DEVICE_LINK_SERVICE_E_INVALID_ARG; +	 +	device_link_service_error_t err = DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR; + +	/* perform version exchange */ +	plist_t array = NULL; +	char *msg = NULL; + +	/* receive DLMessageVersionExchange from device */ +	if (property_list_service_receive_plist(client->parent, &array) != PROPERTY_LIST_SERVICE_E_SUCCESS) { +		debug_info("Did not receive initial message from device!"); +		err = DEVICE_LINK_SERVICE_E_MUX_ERROR; +		goto leave; +	} +	msg = device_link_service_get_message(array); +	if (!msg || strcmp(msg, "DLMessageVersionExchange")) { +		debug_info("Did not receive DLMessageVersionExchange from device!"); +		err = DEVICE_LINK_SERVICE_E_PLIST_ERROR; +		goto leave; +	} +	free(msg); +	msg = NULL; + +	/* get major and minor version number */ +	if (plist_array_get_size(array) < 3) { +		debug_info("DLMessageVersionExchange has unexpected format!"); +		err = DEVICE_LINK_SERVICE_E_PLIST_ERROR; +		goto leave; +	} +	plist_t maj = plist_array_get_item(array, 1); +	plist_t min = plist_array_get_item(array, 2); +	uint64_t vmajor = 0; +	uint64_t vminor = 0; +	if (maj) { +		plist_get_uint_val(maj, &vmajor); +	} +	if (min) { +		plist_get_uint_val(min, &vminor); +	} +	if (vmajor > version_major) { +		debug_info("Version mismatch: device=(%lld,%lld) > expected=(%lld,%lld)", vmajor, vminor, version_major, version_minor); +		err = DEVICE_LINK_SERVICE_E_BAD_VERSION; +		goto leave; +	} else if ((vmajor == version_major) && (vminor > version_minor)) { +		debug_info("WARNING: Version mismatch: device=(%lld,%lld) > expected=(%lld,%lld)", vmajor, vminor, version_major, version_minor); +		err = DEVICE_LINK_SERVICE_E_BAD_VERSION; +		goto leave; +	} +	plist_free(array); + +	/* version is ok, send reply */ +	array = plist_new_array(); +	plist_array_append_item(array, plist_new_string("DLMessageVersionExchange")); +	plist_array_append_item(array, plist_new_string("DLVersionsOk")); +	if (property_list_service_send_binary_plist(client->parent, array) != PROPERTY_LIST_SERVICE_E_SUCCESS) { +		debug_info("Error when sending DLVersionsOk"); +		err = DEVICE_LINK_SERVICE_E_MUX_ERROR; +		goto leave; +	} +	plist_free(array); + +	/* receive DeviceReady message */ +	array = NULL; +	if (property_list_service_receive_plist(client->parent, &array) != PROPERTY_LIST_SERVICE_E_SUCCESS) { +		debug_info("Error when receiving DLMessageDeviceReady!"); +		err = DEVICE_LINK_SERVICE_E_MUX_ERROR; +		goto leave; +	} +	msg = device_link_service_get_message(array); +	if (!msg || strcmp(msg, "DLMessageDeviceReady")) { +		debug_info("Did not get DLMessageDeviceReady!"); +		err = DEVICE_LINK_SERVICE_E_PLIST_ERROR; +		goto leave; +	} +	err = DEVICE_LINK_SERVICE_E_SUCCESS; + +leave: +	if (msg) { +		free(msg); +	} +	if (array) { +		plist_free(array); +	} +	return err; +} + +/** + * Performs a disconnect with the connected device link service client. + * + * @param client The device link service client to disconnect. + *  + * @return DEVICE_LINK_SERVICE_E_SUCCESS on success, + *     DEVICE_LINK_SERVICE_E_INVALID_ARG if client is NULL, + *     or DEVICE_LINK_SERVICE_E_MUX_ERROR when there's an error when sending + *     the the disconnect message. + */ +device_link_service_error_t device_link_service_disconnect(device_link_service_client_t client) +{ +	if (!client) +		return DEVICE_LINK_SERVICE_E_INVALID_ARG; + +	plist_t array = plist_new_array(); +	plist_array_append_item(array, plist_new_string("DLMessageDisconnect")); +	plist_array_append_item(array, plist_new_string("All done, thanks for the memories")); + +	device_link_service_error_t err = DEVICE_LINK_SERVICE_E_SUCCESS; +	if (property_list_service_send_binary_plist(client->parent, array) != PROPERTY_LIST_SERVICE_E_SUCCESS) { +		err = DEVICE_LINK_SERVICE_E_MUX_ERROR; +	} +	plist_free(array); +	return err; +} + +/** + * Generic device link service send function. + * + * @param client The device link service client to use for sending + * @param plist The property list to send + * + * @return DEVICE_LINK_SERVICE_E_SUCCESS on success, + *     DEVICE_LINK_SERVICE_E_INVALID_ARG when client or plist is NULL, + *     or DEVICE_LINK_SERVICE_E_MUX_ERROR when the given property list could + *     not be sent. + */ +device_link_service_error_t device_link_service_send(device_link_service_client_t client, plist_t plist) +{ +	if (!client || !plist) { +		return DEVICE_LINK_SERVICE_E_INVALID_ARG; +	} +	if (property_list_service_send_binary_plist(client->parent, plist) != PROPERTY_LIST_SERVICE_E_SUCCESS) { +		return DEVICE_LINK_SERVICE_E_MUX_ERROR; +	} +	return DEVICE_LINK_SERVICE_E_SUCCESS; +} + +/* Generic device link service receive function. + * + * @param client The device link service client to use for sending + * @param plist Pointer that will point to the property list received upon + *     successful return. + * + * @return DEVICE_LINK_SERVICE_E_SUCCESS on success, + *     DEVICE_LINK_SERVICE_E_INVALID_ARG when client or plist is NULL, + *     or DEVICE_LINK_SERVICE_E_MUX_ERROR when no property list could be + *     received. + */ +device_link_service_error_t device_link_service_receive(device_link_service_client_t client, plist_t *plist) +{ +	if (!client || !plist || (plist && *plist)) { +		return DEVICE_LINK_SERVICE_E_INVALID_ARG; +	} + +	if (property_list_service_receive_plist(client->parent, plist) != PROPERTY_LIST_SERVICE_E_SUCCESS) { +		return DEVICE_LINK_SERVICE_E_MUX_ERROR; +	} +	return DEVICE_LINK_SERVICE_E_SUCCESS; +} + 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 @@ + /*  + * device_link_service.h + * Definitions for the DeviceLink service + *  + * Copyright (c) 2010 Nikias Bassen, All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA  + */ +#ifndef DEVICE_LINK_SERVICE_H +#define DEVICE_LINK_SERVICE_H + +#include "property_list_service.h" + +/* Error Codes */ +#define DEVICE_LINK_SERVICE_E_SUCCESS                0 +#define DEVICE_LINK_SERVICE_E_INVALID_ARG           -1 +#define DEVICE_LINK_SERVICE_E_PLIST_ERROR           -2 +#define DEVICE_LINK_SERVICE_E_MUX_ERROR             -3 +#define DEVICE_LINK_SERVICE_E_BAD_VERSION           -4 + +#define DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR       -256 + + +struct device_link_service_client_int { +	property_list_service_client_t parent; +}; + +typedef struct device_link_service_client_int *device_link_service_client_t; + +typedef int16_t device_link_service_error_t; + +device_link_service_error_t device_link_service_client_new(iphone_device_t device, uint16_t port, device_link_service_client_t *client); +device_link_service_error_t device_link_service_client_free(device_link_service_client_t client); +device_link_service_error_t device_link_service_version_exchange(device_link_service_client_t client, uint64_t version_major, uint64_t version_minor); +device_link_service_error_t device_link_service_disconnect(device_link_service_client_t client); +device_link_service_error_t device_link_service_send(device_link_service_client_t client, plist_t plist); +device_link_service_error_t device_link_service_receive(device_link_service_client_t client, plist_t *plist); + +#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 @@  #include <arpa/inet.h>  #include <usbmuxd.h> +#include <gnutls/gnutls.h>  #include "iphone.h" -#include "utils.h" +#include "debug.h"  static iphone_event_cb_t event_cb = NULL; @@ -60,7 +61,7 @@ iphone_error_t iphone_event_subscribe(iphone_event_cb_t callback, void *user_dat  	int res = usbmuxd_subscribe(usbmux_event_cb, user_data);          if (res != 0) {  		event_cb = NULL; -		log_debug_msg("%s: Error %d when subscribing usbmux event callback!\n", __func__, res); +		debug_info("Error %d when subscribing usbmux event callback!", res);  		return IPHONE_E_UNKNOWN_ERROR;  	}  	return IPHONE_E_SUCCESS; @@ -77,7 +78,7 @@ iphone_error_t iphone_event_unsubscribe()  	event_cb = NULL;  	int res = usbmuxd_unsubscribe();  	if (res != 0) { -		log_debug_msg("%s: Error %d when unsubscribing usbmux event callback!\n", __func__, res); +		debug_info("Error %d when unsubscribing usbmux event callback!", res);  		return IPHONE_E_UNKNOWN_ERROR;  	}  	return IPHONE_E_SUCCESS; @@ -100,7 +101,7 @@ iphone_error_t iphone_get_device_list(char ***devices, int *count)  	*count = 0;  	if (usbmuxd_get_device_list(&dev_list) < 0) { -		log_debug_msg("%s: ERROR: usbmuxd is not running!\n", __func__); +		debug_info("ERROR: usbmuxd is not running!\n", __func__);  		return IPHONE_E_NO_DEVICE;  	} @@ -201,31 +202,32 @@ iphone_error_t iphone_device_free(iphone_device_t device)   * Set up a connection to the given device.   *   * @param device The device to connect to. - * @param dst_port The destination port to connect to. + * @param port The destination port to connect to.   * @param connection Pointer to an iphone_connection_t that will be filled   *   with the necessary data of the connection.   *   * @return IPHONE_E_SUCCESS if ok, otherwise an error code.   */ -iphone_error_t iphone_device_connect(iphone_device_t device, uint16_t dst_port, iphone_connection_t *connection) +iphone_error_t iphone_device_connect(iphone_device_t device, uint16_t port, iphone_connection_t *connection)  {  	if (!device) {  		return IPHONE_E_INVALID_ARG;  	}  	if (device->conn_type == CONNECTION_USBMUXD) { -		int sfd = usbmuxd_connect((uint32_t)(device->conn_data), dst_port); +		int sfd = usbmuxd_connect((uint32_t)(device->conn_data), port);  		if (sfd < 0) { -			log_debug_msg("%s: ERROR: Connecting to usbmuxd failed: %d (%s)\n", __func__, sfd, strerror(-sfd)); +			debug_info("ERROR: Connecting to usbmuxd failed: %d (%s)", sfd, strerror(-sfd));  			return IPHONE_E_UNKNOWN_ERROR;  		}  		iphone_connection_t new_connection = (iphone_connection_t)malloc(sizeof(struct iphone_connection_int));  		new_connection->type = CONNECTION_USBMUXD;  		new_connection->data = (void*)sfd; +		new_connection->ssl_data = NULL;  		*connection = new_connection;  		return IPHONE_E_SUCCESS;  	} else { -		log_debug_msg("%s: Unknown connection type %d\n", __func__, device->conn_type); +		debug_info("Unknown connection type %d", device->conn_type);  	}  	return IPHONE_E_UNKNOWN_ERROR; @@ -243,18 +245,45 @@ iphone_error_t iphone_device_disconnect(iphone_connection_t connection)  	if (!connection) {  		return IPHONE_E_INVALID_ARG;  	} +	/* shut down ssl if enabled */ +	if (connection->ssl_data) { +		iphone_connection_disable_ssl(connection); +	}  	iphone_error_t result = IPHONE_E_UNKNOWN_ERROR;  	if (connection->type == CONNECTION_USBMUXD) {  		usbmuxd_disconnect((int)(connection->data));  		result = IPHONE_E_SUCCESS;  	} else { -		log_debug_msg("%s: Unknown connection type %d\n", __func__, connection->type); +		debug_info("Unknown connection type %d", connection->type);  	}  	free(connection);  	return result;  }  /** + * Internally used function to send raw data over the given connection. + */ +static iphone_error_t internal_connection_send(iphone_connection_t connection, const char *data, uint32_t len, uint32_t *sent_bytes) +{ +	if (!connection || !data) { +		return IPHONE_E_INVALID_ARG; +	} + +	if (connection->type == CONNECTION_USBMUXD) { +		int res = usbmuxd_send((int)(connection->data), data, len, sent_bytes); +		if (res < 0) { +			debug_info("ERROR: usbmuxd_send returned %d (%s)", res, strerror(-res)); +			return IPHONE_E_UNKNOWN_ERROR; +		} +		return IPHONE_E_SUCCESS; +	} else { +		debug_info("Unknown connection type %d", connection->type); +	} +	return IPHONE_E_UNKNOWN_ERROR; + +} + +/**   * Send data to a device via the given connection.   *   * @param connection The connection to send data over. @@ -267,19 +296,41 @@ iphone_error_t iphone_device_disconnect(iphone_connection_t connection)   */  iphone_error_t iphone_device_send(iphone_connection_t connection, const char *data, uint32_t len, uint32_t *sent_bytes)  { -	if (!connection || !data) { +	if (!connection || !data || (connection->ssl_data && !connection->ssl_data->session)) { +		return IPHONE_E_INVALID_ARG; +	} + +	if (connection->ssl_data) { +		ssize_t sent = gnutls_record_send(connection->ssl_data->session, (void*)data, (size_t)len); +		if ((uint32_t)sent == (uint32_t)len) { +			*sent_bytes = sent; +			return IPHONE_E_SUCCESS; +		} +		*sent_bytes = 0; +		return IPHONE_E_SSL_ERROR; +	} +	return internal_connection_send(connection, data, len, sent_bytes); +} + +/** + * Internally used function for receiving raw data over the given connection + * using a timeout. + */ +static iphone_error_t internal_connection_recv_timeout(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout) +{ +	if (!connection) {  		return IPHONE_E_INVALID_ARG;  	}  	if (connection->type == CONNECTION_USBMUXD) { -		int res = usbmuxd_send((int)(connection->data), data, len, sent_bytes); +		int res = usbmuxd_recv_timeout((int)(connection->data), data, len, recv_bytes, timeout);  		if (res < 0) { -			log_debug_msg("%s: ERROR: usbmuxd_send returned %d (%s)\n", __func__, res, strerror(-res)); +			debug_info("ERROR: usbmuxd_recv_timeout returned %d (%s)", res, strerror(-res));  			return IPHONE_E_UNKNOWN_ERROR;  		}  		return IPHONE_E_SUCCESS;  	} else { -		log_debug_msg("%s: Unknown connection type %d\n", __func__, connection->type); +		debug_info("Unknown connection type %d", connection->type);  	}  	return IPHONE_E_UNKNOWN_ERROR;  } @@ -301,19 +352,41 @@ iphone_error_t iphone_device_send(iphone_connection_t connection, const char *da   */  iphone_error_t iphone_device_recv_timeout(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout)  { +	if (!connection || (connection->ssl_data && !connection->ssl_data->session)) { +		return IPHONE_E_INVALID_ARG; +	} + +	if (connection->ssl_data) { +		ssize_t received = gnutls_record_recv(connection->ssl_data->session, (void*)data, (size_t)len); +		if (received > 0) { +			*recv_bytes = received; +			return IPHONE_E_SUCCESS; +		} +		*recv_bytes = 0; +		return IPHONE_E_SSL_ERROR; +	} +	return internal_connection_recv_timeout(connection, data, len, recv_bytes, timeout); +} + +/** + * Internally used function for receiving raw data over the given connection. + */ +static iphone_error_t internal_connection_recv(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes) +{  	if (!connection) {  		return IPHONE_E_INVALID_ARG;  	}  	if (connection->type == CONNECTION_USBMUXD) { -		int res = usbmuxd_recv_timeout((int)(connection->data), data, len, recv_bytes, timeout); +		int res = usbmuxd_recv((int)(connection->data), data, len, recv_bytes);  		if (res < 0) { -			log_debug_msg("%s: ERROR: usbmuxd_recv_timeout returned %d (%s)\n", __func__, res, strerror(-res)); +			debug_info("ERROR: usbmuxd_recv returned %d (%s)", res, strerror(-res));  			return IPHONE_E_UNKNOWN_ERROR;  		} +  		return IPHONE_E_SUCCESS;  	} else { -		log_debug_msg("%s: Unknown connection type %d\n", __func__, connection->type); +		debug_info("Unknown connection type %d", connection->type);  	}  	return IPHONE_E_UNKNOWN_ERROR;  } @@ -333,332 +406,213 @@ iphone_error_t iphone_device_recv_timeout(iphone_connection_t connection, char *   */  iphone_error_t iphone_device_recv(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes)  { -	if (!connection) { -		return -EINVAL; +	if (!connection || (connection->ssl_data && !connection->ssl_data->session)) { +		return IPHONE_E_INVALID_ARG;  	} -	if (connection->type == CONNECTION_USBMUXD) { -		int res = usbmuxd_recv((int)(connection->data), data, len, recv_bytes); -		if (res < 0) { -			log_debug_msg("%s: ERROR: usbmuxd_recv returned %d (%s)\n", __func__, res, strerror(-res)); -			return IPHONE_E_UNKNOWN_ERROR; +	if (connection->ssl_data) { +		ssize_t received = gnutls_record_recv(connection->ssl_data->session, (void*)data, (size_t)len); +		if (received > 0) { +			*recv_bytes = received; +			return IPHONE_E_SUCCESS;  		} +		*recv_bytes = 0; +		return IPHONE_E_SSL_ERROR; +	} +	return internal_connection_recv(connection, data, len, recv_bytes); +} +iphone_error_t iphone_device_get_handle(iphone_device_t device, uint32_t *handle) +{ +	if (!device) +		return IPHONE_E_INVALID_ARG; + +	if (device->conn_type == CONNECTION_USBMUXD) { +		*handle = (uint32_t)device->conn_data;  		return IPHONE_E_SUCCESS;  	} else { -		log_debug_msg("%s: Unknown connection type %d\n", __func__, connection->type); +		debug_info("Unknown connection type %d", device->conn_type);  	}  	return IPHONE_E_UNKNOWN_ERROR;  } +iphone_error_t iphone_device_get_uuid(iphone_device_t device, char **uuid) +{ +	if (!device) +		return IPHONE_E_INVALID_ARG; + +	*uuid = strdup(device->uuid); +	return IPHONE_E_SUCCESS; +} +  /** - * Sends a plist over the given connection. - * Internally used generic plist send function. - * - * @param connection The connection to use for sending. - *        Can be NULL if ssl_session is non-NULL. - * @param plist plist to send - * @param binary 1 = send binary plist, 0 = send xml plist - * @param ssl_session If set to NULL, the communication will be unencrypted. - *        For encrypted communication, pass a valid and properly initialized - *        gnutls_session_t. connection is ignored when ssl_session is non-NULL. - * - * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when one or more - *      parameters are invalid, IPHONE_E_PLIST_ERROR when dict is not a valid - *      plist, or IPHONE_E_UNKNOWN_ERROR when an unspecified error occurs. + * Internally used gnutls callback function for receiving encrypted data.   */ -static iphone_error_t internal_plist_send(iphone_connection_t connection, plist_t plist, int binary, gnutls_session_t ssl_session) +static ssize_t internal_ssl_read(gnutls_transport_ptr_t transport, char *buffer, size_t length)  { -	iphone_error_t res = IPHONE_E_UNKNOWN_ERROR; -	char *content = NULL; -	uint32_t length = 0; -	uint32_t nlen = 0; -	int bytes = 0; +	int bytes = 0, pos_start_fill = 0; +	size_t tbytes = 0; +	int this_len = length; +	iphone_error_t res; +	iphone_connection_t connection = (iphone_connection_t)transport; +	char *recv_buffer; + +	debug_info("pre-read client wants %zi bytes", length); + +	recv_buffer = (char *) malloc(sizeof(char) * this_len); + +	/* repeat until we have the full data or an error occurs */ +	do { +		if ((res = internal_connection_recv(connection, recv_buffer, this_len, (uint32_t*)&bytes)) != IPHONE_E_SUCCESS) { +			debug_info("ERROR: iphone_device_recv returned %d", res); +			return res; +		} +		debug_info("post-read we got %i bytes", bytes); -	if ((!connection && !ssl_session) || !plist) { -		return IPHONE_E_INVALID_ARG; -	} +		// increase read count +		tbytes += bytes; -	if (binary) { -		plist_to_bin(plist, &content, &length); -	} else { -		plist_to_xml(plist, &content, &length); -	} +		// fill the buffer with what we got right now +		memcpy(buffer + pos_start_fill, recv_buffer, bytes); +		pos_start_fill += bytes; -	if (!content || length == 0) { -		return IPHONE_E_PLIST_ERROR; -	} - -	nlen = htonl(length); -	log_debug_msg("%s: sending %d bytes\n", __func__, length); -	if (ssl_session) { -		bytes = gnutls_record_send(ssl_session, (const char*)&nlen, sizeof(nlen)); -	} else { -		iphone_device_send(connection, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes); -	} -	if (bytes == sizeof(nlen)) { -		if (ssl_session) { -			bytes = gnutls_record_send(ssl_session, content, length); -		} else { -			iphone_device_send(connection, content, length, (uint32_t*)&bytes); -		} -		if (bytes > 0) { -			log_debug_msg("%s: sent %d bytes\n", __func__, bytes); -			log_debug_buffer(content, bytes); -			if ((uint32_t)bytes == length) { -				res = IPHONE_E_SUCCESS; -			} else { -				log_debug_msg("%s: ERROR: Could not send all data (%d of %d)!\n", __func__, bytes, length); -			} +		if (tbytes >= length) { +			break;  		} -	} -	if (bytes <= 0) { -		log_debug_msg("%s: ERROR: sending to device failed.\n", __func__); -	} -	free(content); +		this_len = length - tbytes; +		debug_info("re-read trying to read missing %i bytes", this_len); +	} while (tbytes < length); -	return res; +	if (recv_buffer) { +		free(recv_buffer); +	} +	return tbytes;  }  /** - * Sends an XML plist over the given connection. - * - * @param connection The connection to send data over - * @param plist plist to send - * - * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when connection - *      or plist is NULL, IPHONE_E_PLIST_ERROR when dict is not a valid plist, - *      or IPHONE_E_UNKNOWN_ERROR when an unspecified error occurs. + * Internally used gnutls callback function for sending encrypted data.   */ -iphone_error_t iphone_device_send_xml_plist(iphone_connection_t connection, plist_t plist) +static ssize_t internal_ssl_write(gnutls_transport_ptr_t transport, char *buffer, size_t length)  { -	return internal_plist_send(connection, plist, 0, NULL); +	uint32_t bytes = 0; +	iphone_connection_t connection = (iphone_connection_t)transport; +	debug_info("pre-send length = %zi", length); +	internal_connection_send(connection, buffer, length, &bytes); +	debug_info("post-send sent %i bytes", bytes); +	return bytes;  }  /** - * Sends a binary plist over the given connection. - * - * @param connection The connection to send data over - * @param plist plist to send - * - * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when connection - *      or plist is NULL, IPHONE_E_PLIST_ERROR when dict is not a valid plist, - *      or IPHONE_E_UNKNOWN_ERROR when an unspecified error occurs. + * Internally used function for cleaning up SSL stuff.   */ -iphone_error_t iphone_device_send_binary_plist(iphone_connection_t connection, plist_t plist) +static void internal_ssl_cleanup(ssl_data_t ssl_data)  { -	return internal_plist_send(connection, plist, 1, NULL); -} +	if (!ssl_data) +		return; -/** - * Sends an encrypted XML plist. - * - * @param ssl_session Valid and properly initialized gnutls_session_t. - * @param plist plist to send - * - * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when ssl_session - *      or plist is NULL, IPHONE_E_PLIST_ERROR when dict is not a valid plist, - *      or IPHONE_E_UNKNOWN_ERROR when an unspecified error occurs. - */ -iphone_error_t iphone_device_send_encrypted_xml_plist(gnutls_session_t ssl_session, plist_t plist) -{ -	return internal_plist_send(NULL, plist, 0, ssl_session); -} - -/** - * Sends an encrypted binary plist. - * - * @param ssl_session Valid and properly initialized gnutls_session_t. - * @param plist plist to send - * - * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when ssl_session - *      or plist is NULL, IPHONE_E_PLIST_ERROR when dict is not a valid plist, - *      or IPHONE_E_UNKNOWN_ERROR when an unspecified error occurs. - */ -iphone_error_t iphone_device_send_encrypted_binary_plist(gnutls_session_t ssl_session, plist_t plist) -{ -	return internal_plist_send(NULL, plist, 1, ssl_session); +	if (ssl_data->session) { +		gnutls_deinit(ssl_data->session); +	} +	if (ssl_data->certificate) { +		gnutls_certificate_free_credentials(ssl_data->certificate); +	}  }  /** - * Receives a plist over the given connection.  - * Internally used generic plist send function. + * Enables SSL for the given connection.   * - * @param connection The connection to receive data on - * @param plist pointer to a plist_t that will point to the received plist - *              upon successful return - * @param timeout Maximum time in milliseconds to wait for data. - * @param ssl_session If set to NULL, the communication will be unencrypted. - *        For encrypted communication, pass a valid and properly initialized - *        gnutls_session_t. + * @param connection The connection to enable SSL for.   *   * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when connection - *    or *plist is NULL, IPHONE_E_PLIST_ERROR when the received data cannot be - *    converted to a plist, or IPHONE_E_UNKNOWN_ERROR when an unspecified - *    error occurs. + *     is NULL or connection->ssl_data is non-NULL, or IPHONE_E_SSL_ERROR when + *     SSL initialization, setup, or handshake fails.   */ -static iphone_error_t internal_plist_recv_timeout(iphone_connection_t connection, plist_t *plist, unsigned int timeout, gnutls_session_t ssl_session) +iphone_error_t iphone_connection_enable_ssl(iphone_connection_t connection)  { -	iphone_error_t res = IPHONE_E_UNKNOWN_ERROR; -	uint32_t pktlen = 0; -	uint32_t bytes = 0; - -	if ((!connection && !ssl_session) || !plist) { +	if (!connection || connection->ssl_data)  		return IPHONE_E_INVALID_ARG; -	} -	if (ssl_session) { -		bytes = gnutls_record_recv(ssl_session, (char*)&pktlen, sizeof(pktlen)); -	} else { -		iphone_device_recv_timeout(connection, (char*)&pktlen, sizeof(pktlen), &bytes, timeout); +	iphone_error_t ret = IPHONE_E_SSL_ERROR; +	uint32_t return_me = 0; + +	ssl_data_t ssl_data_loc = (ssl_data_t)malloc(sizeof(struct ssl_data_int)); + +	// Set up GnuTLS... +	debug_info("enabling SSL mode"); +	errno = 0; +	gnutls_global_init(); +	gnutls_certificate_allocate_credentials(&ssl_data_loc->certificate); +	gnutls_certificate_set_x509_trust_file(ssl_data_loc->certificate, "hostcert.pem", GNUTLS_X509_FMT_PEM); +	gnutls_init(&ssl_data_loc->session, GNUTLS_CLIENT); +	{ +		int protocol_priority[16] = { GNUTLS_SSL3, 0 }; +		int kx_priority[16] = { GNUTLS_KX_ANON_DH, GNUTLS_KX_RSA, 0 }; +		int cipher_priority[16] = { GNUTLS_CIPHER_AES_128_CBC, GNUTLS_CIPHER_AES_256_CBC, 0 }; +		int mac_priority[16] = { GNUTLS_MAC_SHA1, GNUTLS_MAC_MD5, 0 }; +		int comp_priority[16] = { GNUTLS_COMP_NULL, 0 }; + +		gnutls_cipher_set_priority(ssl_data_loc->session, cipher_priority); +		gnutls_compression_set_priority(ssl_data_loc->session, comp_priority); +		gnutls_kx_set_priority(ssl_data_loc->session, kx_priority); +		gnutls_protocol_set_priority(ssl_data_loc->session, protocol_priority); +		gnutls_mac_set_priority(ssl_data_loc->session, mac_priority);  	} -	log_debug_msg("%s: initial read=%i\n", __func__, bytes); -	if (bytes < 4) { -		log_debug_msg("%s: initial read failed!\n", __func__); -		return IPHONE_E_NOT_ENOUGH_DATA; +	gnutls_credentials_set(ssl_data_loc->session, GNUTLS_CRD_CERTIFICATE, ssl_data_loc->certificate); // this part is killing me. + +	debug_info("GnuTLS step 1..."); +	gnutls_transport_set_ptr(ssl_data_loc->session, (gnutls_transport_ptr_t)connection); +	debug_info("GnuTLS step 2..."); +	gnutls_transport_set_push_function(ssl_data_loc->session, (gnutls_push_func) & internal_ssl_write); +	debug_info("GnuTLS step 3..."); +	gnutls_transport_set_pull_function(ssl_data_loc->session, (gnutls_pull_func) & internal_ssl_read); +	debug_info("GnuTLS step 4 -- now handshaking..."); +	if (errno) +		debug_info("WARN: errno says %s before handshake!", strerror(errno)); +	return_me = gnutls_handshake(ssl_data_loc->session); +	debug_info("GnuTLS handshake done..."); + +	if (return_me != GNUTLS_E_SUCCESS) { +		internal_ssl_cleanup(ssl_data_loc); +		free(ssl_data_loc); +		debug_info("GnuTLS reported something wrong."); +		gnutls_perror(return_me); +		debug_info("oh.. errno says %s", strerror(errno));  	} else { -		if ((char)pktlen == 0) { /* prevent huge buffers */ -			uint32_t curlen = 0; -			char *content = NULL; -			pktlen = ntohl(pktlen); -			log_debug_msg("%s: %d bytes following\n", __func__, pktlen); -			content = (char*)malloc(pktlen); - -			while (curlen < pktlen) { -				if (ssl_session) { -					bytes = gnutls_record_recv(ssl_session, content+curlen, pktlen-curlen); -				} else { -					iphone_device_recv(connection, content+curlen, pktlen-curlen, &bytes); -				} -				if (bytes <= 0) { -					res = IPHONE_E_UNKNOWN_ERROR; -					break; -				} -				log_debug_msg("%s: received %d bytes\n", __func__, bytes); -				curlen += bytes; -			} -			log_debug_buffer(content, pktlen); -			if (!memcmp(content, "bplist00", 8)) { -				plist_from_bin(content, pktlen, plist); -			} else { -				plist_from_xml(content, pktlen, plist); -			} -			if (*plist) { -				res = IPHONE_E_SUCCESS; -			} else { -				res = IPHONE_E_PLIST_ERROR; -			} -			free(content); -			content = NULL; -		} else { -			res = IPHONE_E_UNKNOWN_ERROR; -		} +		connection->ssl_data = ssl_data_loc; +		ret = IPHONE_E_SUCCESS; +		debug_info("SSL mode enabled");  	} -	return res; -} - -/** - * Receives a plist over the given connection with specified timeout. - * Binary or XML plists are automatically handled. - * - * @param connection The connection to receive data on - * @param plist pointer to a plist_t that will point to the received plist - *              upon successful return - * @param timeout Maximum time in milliseconds to wait for data. - * - * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when connection - *    or *plist is NULL, IPHONE_E_PLIST_ERROR when the received data cannot be - *    converted to a plist, or IPHONE_E_UNKNOWN_ERROR when an unspecified - *    error occurs. - */ -iphone_error_t iphone_device_receive_plist_with_timeout(iphone_connection_t connection, plist_t *plist, unsigned int timeout) -{ -	return internal_plist_recv_timeout(connection, plist, timeout, NULL); +	return ret;  }  /** - * Receives a plist over the given connection. - * Binary or XML plists are automatically handled. + * Disable SSL for the given connection.   * - * This function is like iphone_device_receive_plist_with_timeout - *   using a timeout of 10 seconds. - * @see iphone_device_receive_plist_with_timeout - * - * @param connection The connection to receive data on - * @param plist pointer to a plist_t that will point to the received plist - *              upon successful return + * @param connection The connection to disable SSL for.   *   * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when connection - *    or *plist is NULL, IPHONE_E_PLIST_ERROR when the received data cannot be - *    converted to a plist, or IPHONE_E_UNKNOWN_ERROR when an unspecified - *    error occurs. - */ -iphone_error_t iphone_device_receive_plist(iphone_connection_t connection, plist_t *plist) -{ -	return internal_plist_recv_timeout(connection, plist, 10000, NULL); -} - -/** - * Receives an encrypted plist with specified timeout. - * Binary or XML plists are automatically handled. - * - * @param ssl_session Valid and properly initialized gnutls_session_t. - * @param plist pointer to a plist_t that will point to the received plist - *              upon successful return - * @param timeout Maximum time in milliseconds to wait for data. - * - * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when ssl_session - *    or *plist is NULL, IPHONE_E_PLIST_ERROR when the received data cannot be - *    converted to a plist, or IPHONE_E_UNKNOWN_ERROR when an unspecified - *    error occurs. - */ -iphone_error_t iphone_device_receive_encrypted_plist_with_timeout(gnutls_session_t ssl_session, plist_t *plist, unsigned int timeout) -{ -	return internal_plist_recv_timeout(NULL, plist, timeout, ssl_session); -} - -/** - * Receives an encrypted plist. - * Binary or XML plists are automatically handled. - * This function is like iphone_device_receive_encrypted_plist_with_timeout - *   with a timeout value of 10 seconds. - * - * @param ssl_session Valid and properly initialized gnutls_session_t. - * @param connection The connection to receive data on - * @param plist pointer to a plist_t that will point to the received plist - *              upon successful return - * - * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when ssl_session - *    or *plist is NULL, IPHONE_E_PLIST_ERROR when the received data cannot be - *    converted to a plist, or IPHONE_E_UNKNOWN_ERROR when an unspecified - *    error occurs. + *     is NULL. This function also returns IPHONE_E_SUCCESS when SSL is not + *     enabled and does no further error checking on cleanup.   */ -iphone_error_t iphone_device_receive_encrypted_plist(gnutls_session_t ssl_session, plist_t *plist) -{ -	return internal_plist_recv_timeout(NULL, plist, 10000, ssl_session); -} - -iphone_error_t iphone_device_get_handle(iphone_device_t device, uint32_t *handle) +iphone_error_t iphone_connection_disable_ssl(iphone_connection_t connection)  { -	if (!device) +	if (!connection)  		return IPHONE_E_INVALID_ARG; - -	if (device->conn_type == CONNECTION_USBMUXD) { -		*handle = (uint32_t)device->conn_data; +	if (!connection->ssl_data) { +		/* ignore if ssl is not enabled */   		return IPHONE_E_SUCCESS; -	} else { -		log_debug_msg("%s: Unknown connection type %d\n", __func__, device->conn_type);  	} -	return IPHONE_E_UNKNOWN_ERROR; -} -iphone_error_t iphone_device_get_uuid(iphone_device_t device, char **uuid) -{ -	if (!device) -		return IPHONE_E_INVALID_ARG; +	if (connection->ssl_data->session) { +		gnutls_bye(connection->ssl_data->session, GNUTLS_SHUT_RDWR); +	} +	internal_ssl_cleanup(connection->ssl_data); +	free(connection->ssl_data); +	connection->ssl_data = NULL; + +	debug_info("SSL mode disabled"); -	*uuid = strdup(device->uuid);  	return IPHONE_E_SUCCESS;  } 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 {  	CONNECTION_USBMUXD = 1  }; +struct ssl_data_int { +        gnutls_certificate_credentials_t certificate; +	gnutls_session_t session; +}; +typedef struct ssl_data_int *ssl_data_t; +  struct iphone_connection_int {  	enum connection_type type;  	void *data; +	ssl_data_t ssl_data;  };  struct iphone_device_int { @@ -41,14 +48,7 @@ struct iphone_device_int {  	void *conn_data;  }; -iphone_error_t iphone_device_send_xml_plist(iphone_connection_t connection, plist_t plist); -iphone_error_t iphone_device_send_binary_plist(iphone_connection_t connection, plist_t plist); -iphone_error_t iphone_device_send_encrypted_xml_plist(gnutls_session_t ssl_session, plist_t plist); -iphone_error_t iphone_device_send_encrypted_binary_plist(gnutls_session_t ssl_session, plist_t plist); - -iphone_error_t iphone_device_receive_plist_with_timeout(iphone_connection_t connection, plist_t *plist, unsigned int timeout); -iphone_error_t iphone_device_receive_plist(iphone_connection_t connection, plist_t *plist); -iphone_error_t iphone_device_receive_encrypted_plist_with_timeout(gnutls_session_t ssl_session, plist_t *plist, unsigned int timeout); -iphone_error_t iphone_device_receive_encrypted_plist(gnutls_session_t ssl_session, plist_t *plist); +iphone_error_t iphone_connection_enable_ssl(iphone_connection_t connection); +iphone_error_t iphone_connection_disable_ssl(iphone_connection_t connection);  #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 @@  #include <gnutls/x509.h>  #include <plist/plist.h> +#include "property_list_service.h"  #include "lockdown.h"  #include "iphone.h" -#include "utils.h" +#include "debug.h"  #include "userpref.h"  #define RESULT_SUCCESS 0 @@ -98,7 +99,7 @@ static int lockdown_check_result(plist_t dict, const char *query_match)  			} else if (!strcmp(result_value, "Failure")) {  				ret = RESULT_FAILURE;  			} else { -				log_dbg_msg(DBGMASK_LOCKDOWND, "%s: ERROR: unknown result value '%s'\n", __func__, result_value); +				debug_info("ERROR: unknown result value '%s'", result_value);  			}  		}  		if (result_value) @@ -108,30 +109,49 @@ static int lockdown_check_result(plist_t dict, const char *query_match)  }  /** - * Closes the lockdownd communication session, by sending - * the StopSession Request to the device. + * Adds a label key with the passed value to a plist dict node. + * + * @param plist The plist to add the key to + * @param label The value for the label key + * + */ +static void plist_dict_add_label(plist_t plist, const char *label) +{ +	if (plist && label) { +		if (plist_get_node_type(plist) == PLIST_DICT) +			plist_dict_insert_item(plist, "Label", plist_new_string(label)); +	} +} + +/** + * Closes the lockdownd communication session, by sending the StopSession + * Request to the device. + * + * @see lockdownd_start_session   *   * @param control The lockdown client + * @param session_id The id of a running session   *   * @return an error code (LOCKDOWN_E_SUCCESS on success)   */ -lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client) +lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client, const char *session_id)  {  	if (!client)  		return LOCKDOWN_E_INVALID_ARG; -	if (!client->session_id) { -		log_dbg_msg(DBGMASK_LOCKDOWND, "%s: no session_id given, cannot stop session\n", __func__); +	if (!session_id) { +		debug_info("no session_id given, cannot stop session");  		return LOCKDOWN_E_INVALID_ARG;  	}  	lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;  	plist_t dict = plist_new_dict(); +	plist_dict_add_label(dict, client->label);  	plist_dict_insert_item(dict,"Request", plist_new_string("StopSession")); -	plist_dict_insert_item(dict,"SessionID", plist_new_string(client->session_id)); +	plist_dict_insert_item(dict,"SessionID", plist_new_string(session_id)); -	log_dbg_msg(DBGMASK_LOCKDOWND, "%s: stopping session %s\n", __func__, client->session_id); +	debug_info("stopping session %s", session_id);  	ret = lockdownd_send(client, dict); @@ -141,55 +161,20 @@ lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client)  	ret = lockdownd_recv(client, &dict);  	if (!dict) { -		log_dbg_msg(DBGMASK_LOCKDOWND, "%s: LOCKDOWN_E_PLIST_ERROR\n", __func__); +		debug_info("LOCKDOWN_E_PLIST_ERROR");  		return LOCKDOWN_E_PLIST_ERROR;  	}  	ret = LOCKDOWN_E_UNKNOWN_ERROR;  	if (lockdown_check_result(dict, "StopSession") == RESULT_SUCCESS) { -		log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); +		debug_info("success");  		ret = LOCKDOWN_E_SUCCESS;  	}  	plist_free(dict);  	dict = NULL; - -	free(client->session_id); -	client->session_id = NULL; - -	return ret; -} - -/** - * Shuts down the SSL session by first calling iphone_lckd_stop_session - * to cleanly close the lockdownd communication session, and then - * performing a close notify, which is done by "gnutls_bye". - * - * @param client The lockdown client - * - * @return an error code (LOCKDOWN_E_SUCCESS on success) - */ -static lockdownd_error_t lockdownd_stop_ssl_session(lockdownd_client_t client) -{ -	if (!client) { -		log_dbg_msg(DBGMASK_LOCKDOWND, "%s: invalid argument!\n", __func__); -		return LOCKDOWN_E_INVALID_ARG; +	if (client->ssl_enabled) { +		property_list_service_disable_ssl(client->parent);  	} -	lockdownd_error_t ret = LOCKDOWN_E_SUCCESS; - -	if (client->in_SSL) { -		log_dbg_msg(DBGMASK_LOCKDOWND, "%s: stopping SSL session\n", __func__); -		ret = lockdownd_stop_session(client); -		log_dbg_msg(DBGMASK_LOCKDOWND, "%s: sending SSL close notify\n", __func__); -		gnutls_bye(client->ssl_session, GNUTLS_SHUT_RDWR); -	} -	if (client->ssl_session) { -		gnutls_deinit(client->ssl_session); -        } -        if (client->ssl_certificate) { -		gnutls_certificate_free_credentials(client->ssl_certificate); -        } -	client->in_SSL = 0; -  	return ret;  } @@ -205,29 +190,45 @@ lockdownd_error_t lockdownd_client_free(lockdownd_client_t client)  		return LOCKDOWN_E_INVALID_ARG;  	lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; -	lockdownd_stop_ssl_session(client); +	if (client->session_id) +		lockdownd_stop_session(client, client->session_id); -	if (client->connection) { +	if (client->parent) {  		lockdownd_goodbye(client); -		// IMO, read of final "sessionUpcall connection closed" packet -		//  should come here instead of in iphone_free_device -		if ((ret = iphone_device_disconnect(client->connection)) != IPHONE_E_SUCCESS) { -			ret = LOCKDOWN_E_UNKNOWN_ERROR; +		if (property_list_service_client_free(client->parent) == PROPERTY_LIST_SERVICE_E_SUCCESS) { +			ret = LOCKDOWN_E_SUCCESS;  		}  	} -	if (client->session_id) { -		free(client->session_id); -	}  	if (client->uuid) {  		free(client->uuid);  	} +	if (client->label) { +		free(client->label); +	}  	free(client);  	return ret;  } +/** + * Sets the label to send for requests to lockdownd. + * + * @param client The lockdown client + * @param label The label to set or NULL to disable sending a label + * + */ +void lockdownd_client_set_label(lockdownd_client_t client, const char *label) +{ +	if (client) { +		if (client->label) +			free(client->label); + +		client->label = (label != NULL) ? strdup(label): NULL; +	} +} +  /** Polls the iPhone for lockdownd data.   *   * @param control The lockdownd client @@ -240,18 +241,11 @@ lockdownd_error_t lockdownd_recv(lockdownd_client_t client, plist_t *plist)  	if (!client || !plist || (plist && *plist))  		return LOCKDOWN_E_INVALID_ARG;  	lockdownd_error_t ret = LOCKDOWN_E_SUCCESS; -	iphone_error_t err; +	property_list_service_error_t err; -	if (!client->in_SSL) { -		err = iphone_device_receive_plist(client->connection, plist); -		if (err != IPHONE_E_SUCCESS) { -			ret = LOCKDOWN_E_UNKNOWN_ERROR; -		} -	} else { -		err = iphone_device_receive_encrypted_plist(client->ssl_session, plist); -		if (err != IPHONE_E_SUCCESS) { -			return LOCKDOWN_E_SSL_ERROR; -		} +	err = property_list_service_receive_plist(client->parent, plist); +	if (err != PROPERTY_LIST_SERVICE_E_SUCCESS) { +		ret = LOCKDOWN_E_UNKNOWN_ERROR;  	}  	if (!*plist) @@ -278,27 +272,22 @@ lockdownd_error_t lockdownd_send(lockdownd_client_t client, plist_t plist)  	lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;  	iphone_error_t err; -	if (!client->in_SSL) { -		err = iphone_device_send_xml_plist(client->connection, plist); -		if (err != IPHONE_E_SUCCESS) { -			ret = LOCKDOWN_E_UNKNOWN_ERROR; -		} -	} else { -		err = iphone_device_send_encrypted_xml_plist(client->ssl_session, plist); -		if (err != IPHONE_E_SUCCESS) { -			ret = LOCKDOWN_E_SSL_ERROR; -		} +	err = property_list_service_send_xml_plist(client->parent, plist); +	if (err != PROPERTY_LIST_SERVICE_E_SUCCESS) { +		ret = LOCKDOWN_E_UNKNOWN_ERROR;  	}  	return ret;  } -/** Initiates the handshake for the lockdown session. Part of the lockdownd handshake. +/** Query the type of the service daemon. Depending on whether the device is + * queried in normal mode or restore mode, different types will be returned.   *   * @param client The lockdownd client + * @param type The type returned by the service daemon. Can be NULL to ignore.   *   * @return an error code (LOCKDOWN_E_SUCCESS on success)   */ -lockdownd_error_t lockdownd_query_type(lockdownd_client_t client) +lockdownd_error_t lockdownd_query_type(lockdownd_client_t client, char **type)  {  	if (!client)  		return LOCKDOWN_E_INVALID_ARG; @@ -306,9 +295,10 @@ lockdownd_error_t lockdownd_query_type(lockdownd_client_t client)  	lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;  	plist_t dict = plist_new_dict(); +	plist_dict_add_label(dict, client->label);  	plist_dict_insert_item(dict,"Request", plist_new_string("QueryType")); -	log_dbg_msg(DBGMASK_LOCKDOWND, "%s: called\n", __func__); +	debug_info("called");  	ret = lockdownd_send(client, dict);  	plist_free(dict); @@ -321,7 +311,12 @@ lockdownd_error_t lockdownd_query_type(lockdownd_client_t client)  	ret = LOCKDOWN_E_UNKNOWN_ERROR;  	if (lockdown_check_result(dict, "QueryType") == RESULT_SUCCESS) { -		log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); +		/* return the type if requested */ +		if (type != NULL) { +			plist_t type_node = plist_dict_get_item(dict, "Type"); +			plist_get_string_val(type_node, type); +		} +		debug_info("success with type %s", *type);  		ret = LOCKDOWN_E_SUCCESS;  	}  	plist_free(dict); @@ -349,6 +344,7 @@ lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *dom  	/* setup request plist */  	dict = plist_new_dict(); +	plist_dict_add_label(dict, client->label);  	if (domain) {  		plist_dict_insert_item(dict,"Domain", plist_new_string(domain));  	} @@ -372,7 +368,7 @@ lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *dom  		return ret;  	if (lockdown_check_result(dict, "GetValue") == RESULT_SUCCESS) { -		log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); +		debug_info("success");  		ret = LOCKDOWN_E_SUCCESS;  	}  	if (ret != LOCKDOWN_E_SUCCESS) { @@ -383,7 +379,7 @@ lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *dom  	plist_t value_node = plist_dict_get_item(dict, "Value");  	if (value_node) { -		log_dbg_msg(DBGMASK_LOCKDOWND, "%s: has a value\n", __func__); +		debug_info("has a value");  		*value = plist_copy(value_node);  	} @@ -410,6 +406,7 @@ lockdownd_error_t lockdownd_set_value(lockdownd_client_t client, const char *dom  	/* setup request plist */  	dict = plist_new_dict(); +	plist_dict_add_label(dict, client->label);  	if (domain) {  		plist_dict_insert_item(dict,"Domain", plist_new_string(domain));  	} @@ -434,7 +431,7 @@ lockdownd_error_t lockdownd_set_value(lockdownd_client_t client, const char *dom  		return ret;  	if (lockdown_check_result(dict, "SetValue") == RESULT_SUCCESS) { -		log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); +		debug_info("success");  		ret = LOCKDOWN_E_SUCCESS;  	} @@ -467,6 +464,7 @@ lockdownd_error_t lockdownd_remove_value(lockdownd_client_t client, const char *  	/* setup request plist */  	dict = plist_new_dict(); +	plist_dict_add_label(dict, client->label);  	if (domain) {  		plist_dict_insert_item(dict,"Domain", plist_new_string(domain));  	} @@ -490,7 +488,7 @@ lockdownd_error_t lockdownd_remove_value(lockdownd_client_t client, const char *  		return ret;  	if (lockdown_check_result(dict, "RemoveValue") == RESULT_SUCCESS) { -		log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); +		debug_info("success");  		ret = LOCKDOWN_E_SUCCESS;  	} @@ -572,44 +570,85 @@ lockdownd_error_t lockdownd_get_device_name(lockdownd_client_t client, char **de  	return ret;  } -/** Creates a lockdownd client for the give iPhone +/** Creates a lockdownd client for the device.   * - * @param phone The iPhone to create a lockdownd client for + * @param phone The device to create a lockdownd client for   * @param client The pointer to the location of the new lockdownd_client + * @param label The label to use for communication. Usually the program name   *   * @return an error code (LOCKDOWN_E_SUCCESS on success)   */ -lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_t *client) +lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_t *client, const char *label)  {  	if (!client)  		return LOCKDOWN_E_INVALID_ARG; +  	lockdownd_error_t ret = LOCKDOWN_E_SUCCESS; -	char *host_id = NULL; -	iphone_connection_t connection; -	if (iphone_device_connect(device, 0xf27e, &connection) != IPHONE_E_SUCCESS) { -		log_debug_msg("%s: could not connect to lockdownd (device %s)\n", __func__, device->uuid); +	property_list_service_client_t plistclient = NULL; +	if (property_list_service_client_new(device, 0xf27e, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) { +		debug_info("could not connect to lockdownd (device %s)", device->uuid);  		return LOCKDOWN_E_MUX_ERROR;  	}  	lockdownd_client_t client_loc = (lockdownd_client_t) malloc(sizeof(struct lockdownd_client_int)); -	client_loc->connection = connection; -	client_loc->ssl_session = NULL; -	client_loc->ssl_certificate = NULL; -	client_loc->in_SSL = 0; +	client_loc->parent = plistclient; +	client_loc->ssl_enabled = 0;  	client_loc->session_id = NULL;  	client_loc->uuid = NULL; +	client_loc->label = NULL; +	if (label != NULL) +		strdup(label); + +	if (LOCKDOWN_E_SUCCESS == ret) { +		*client = client_loc; +	} else { +		lockdownd_client_free(client_loc); +	} + +	return ret; +} + +/** Creates a lockdownd client for the device and starts initial handshake. + * The handshake consists of query_type, validate_pair, pair and + * start_session calls. + * + * @param phone The device to create a lockdownd client for + * @param client The pointer to the location of the new lockdownd_client + * @param label The label to use for communication. Usually the program name + * + * @return an error code (LOCKDOWN_E_SUCCESS on success) + */ +lockdownd_error_t lockdownd_client_new_with_handshake(iphone_device_t device, lockdownd_client_t *client, const char *label) +{ +	if (!client) +		return LOCKDOWN_E_INVALID_ARG; + +	lockdownd_error_t ret = LOCKDOWN_E_SUCCESS; +	lockdownd_client_t client_loc = NULL; +	char *host_id = NULL; +	char *type = NULL; -	if (LOCKDOWN_E_SUCCESS != lockdownd_query_type(client_loc)) { -		log_debug_msg("%s: QueryType failed in the lockdownd client.\n", __func__); + +	ret = lockdownd_client_new(device, &client_loc, label); + +	/* perform handshake */ +	if (LOCKDOWN_E_SUCCESS != lockdownd_query_type(client_loc, &type)) { +		debug_info("QueryType failed in the lockdownd client.");  		ret = LOCKDOWN_E_NOT_ENOUGH_DATA; +	} else { +		if (strcmp("com.apple.mobile.lockdown", type)) { +			debug_info("Warning QueryType request returned \"%s\".", type); +		} +		if (type) +			free(type);  	}  	ret = iphone_device_get_uuid(device, &client_loc->uuid);  	if (LOCKDOWN_E_SUCCESS != ret) { -		log_debug_msg("%s: failed to get device uuid.\n", __func__); +		debug_info("failed to get device uuid.");  	} -	log_debug_msg("%s: device uuid: %s\n", __func__, client_loc->uuid); +	debug_info("device uuid: %s", client_loc->uuid);  	userpref_get_host_id(&host_id);  	if (LOCKDOWN_E_SUCCESS == ret && !host_id) { @@ -617,77 +656,135 @@ lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_  	}  	if (LOCKDOWN_E_SUCCESS == ret && !userpref_has_device_public_key(client_loc->uuid)) -		ret = lockdownd_pair(client_loc, host_id); +		ret = lockdownd_pair(client_loc, NULL); + +	/* in any case, we need to validate pairing to receive trusted host status */ +	ret = lockdownd_validate_pair(client_loc, NULL);  	if (LOCKDOWN_E_SUCCESS == ret) { -		ret = lockdownd_start_ssl_session(client_loc, host_id); +		ret = lockdownd_start_session(client_loc, host_id, NULL, NULL);  		if (LOCKDOWN_E_SUCCESS != ret) { -			ret = LOCKDOWN_E_SSL_ERROR; -			log_debug_msg("%s: SSL Session opening failed.\n", __func__); +			debug_info("Session opening failed.");  		}  		if (host_id) {  			free(host_id);  			host_id = NULL;  		} +	} +	 +	if (LOCKDOWN_E_SUCCESS == ret) { +		*client = client_loc; +	} else { +		lockdownd_client_free(client_loc); +	} -		if (LOCKDOWN_E_SUCCESS == ret) -			*client = client_loc; +	return ret; +} + +static plist_t lockdownd_pair_record_to_plist(lockdownd_pair_record_t pair_record) +{ +	if (!pair_record) +		return NULL; + +	char *host_id_loc = pair_record->host_id; + +	/* setup request plist */ +	plist_t dict = plist_new_dict(); +	plist_dict_insert_item(dict, "DeviceCertificate", plist_new_data(pair_record->device_certificate, strlen(pair_record->device_certificate))); +	plist_dict_insert_item(dict, "HostCertificate", plist_new_data(pair_record->host_certificate, strlen(pair_record->host_certificate))); +	if (!pair_record->host_id) +		userpref_get_host_id(&host_id_loc); +	plist_dict_insert_item(dict, "HostID", plist_new_string(host_id_loc)); +	plist_dict_insert_item(dict, "RootCertificate", plist_new_data(pair_record->root_certificate, strlen(pair_record->root_certificate))); + +	if (!pair_record->host_id) +		free(host_id_loc); + +	return dict; +} + +static lockdownd_error_t generate_pair_record_plist(gnutls_datum_t public_key, char *host_id, plist_t *pair_record_plist) +{ +	lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; + +	gnutls_datum_t device_cert = { NULL, 0 }; +	gnutls_datum_t host_cert = { NULL, 0 }; +	gnutls_datum_t root_cert = { NULL, 0 }; + +	ret = lockdownd_gen_pair_cert(public_key, &device_cert, &host_cert, &root_cert); +	if (ret != LOCKDOWN_E_SUCCESS) { +		return ret;  	} +	char *host_id_loc = host_id; + +	if (!host_id) +		userpref_get_host_id(&host_id_loc); + +	/* setup request plist */ +	*pair_record_plist = plist_new_dict(); +	plist_dict_insert_item(*pair_record_plist, "DeviceCertificate", plist_new_data((const char*)device_cert.data, device_cert.size)); +	plist_dict_insert_item(*pair_record_plist, "HostCertificate", plist_new_data((const char*)host_cert.data, host_cert.size)); +	plist_dict_insert_item(*pair_record_plist, "HostID", plist_new_string(host_id_loc)); +	plist_dict_insert_item(*pair_record_plist, "RootCertificate", plist_new_data((const char*)root_cert.data, root_cert.size)); + +	if (!host_id) +		free(host_id_loc); +  	return ret;  }  /** Function used internally by lockdownd_pair() and lockdownd_validate_pair()   *   * @param client The lockdown client to pair with. - * @param host_id The HostID to use for pairing. If NULL is passed, then - *    the HostID of the current machine is used. A new HostID will be + * @param pair_record The pair record to use for pairing. If NULL is passed, then + *    the pair records from the current machine are used. New records will be   *    generated automatically when pairing is done for the first time. - * @param verb This is either "Pair" or "ValidatePair". + * @param verb This is either "Pair", "ValidatePair" or "Unpair".   *   * @return an error code (LOCKDOWN_E_SUCCESS on success)   */ -static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, char *host_id, const char *verb) +static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record, const char *verb)  {  	lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;  	plist_t dict = NULL;  	plist_t dict_record = NULL; - -	gnutls_datum_t device_cert = { NULL, 0 }; -	gnutls_datum_t host_cert = { NULL, 0 }; -	gnutls_datum_t root_cert = { NULL, 0 };  	gnutls_datum_t public_key = { NULL, 0 }; +	int pairing_mode = 0; /* 0 = libiphone, 1 = external */ -	char *host_id_loc = host_id; - -	ret = lockdownd_get_device_public_key(client, &public_key); -	if (ret != LOCKDOWN_E_SUCCESS) { -		log_debug_msg("%s: device refused to send public key.\n", __func__); -		return ret; -	} -	log_debug_msg("%s: device public key follows:\n%s\n", __func__, public_key.data); +	if (pair_record && pair_record->host_id) { +		/* valid pair_record passed? */ +		if (!pair_record->device_certificate || !pair_record->host_certificate || !pair_record->root_certificate) { +			return LOCKDOWN_E_PLIST_ERROR; +		} -	ret = lockdownd_gen_pair_cert(public_key, &device_cert, &host_cert, &root_cert); -	if (ret != LOCKDOWN_E_SUCCESS) { -		free(public_key.data); -		return ret; -	} +		/* use passed pair_record */ +		dict_record = lockdownd_pair_record_to_plist(pair_record); -	if (!host_id) { -		userpref_get_host_id(&host_id_loc); +		pairing_mode = 1; +	} else { +		ret = lockdownd_get_device_public_key(client, &public_key); +		if (ret != LOCKDOWN_E_SUCCESS) { +			if (public_key.data) +				free(public_key.data); +			debug_info("device refused to send public key."); +			return ret; +		} +		debug_info("device public key follows:\n%s", public_key.data); +		/* get libiphone pair_record */ +		ret = generate_pair_record_plist(public_key, NULL, &dict_record); +		if (ret != LOCKDOWN_E_SUCCESS) { +			if (dict_record) +				plist_free(dict_record); +			return ret; +		}  	}  	/* Setup Pair request plist */  	dict = plist_new_dict(); -	dict_record = plist_new_dict(); +	plist_dict_add_label(dict, client->label);  	plist_dict_insert_item(dict,"PairRecord", dict_record); - -	plist_dict_insert_item(dict_record, "DeviceCertificate", plist_new_data((const char*)device_cert.data, device_cert.size)); -	plist_dict_insert_item(dict_record, "HostCertificate", plist_new_data((const char*)host_cert.data, host_cert.size)); -	plist_dict_insert_item(dict_record, "HostID", plist_new_string(host_id_loc)); -	plist_dict_insert_item(dict_record, "RootCertificate", plist_new_data((const char*)root_cert.data, root_cert.size)); -  	plist_dict_insert_item(dict, "Request", plist_new_string(verb));  	/* send to iPhone */ @@ -695,10 +792,6 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, char *host  	plist_free(dict);  	dict = NULL; -	if (!host_id) { -		free(host_id_loc); -	} -  	if (ret != LOCKDOWN_E_SUCCESS)  		return ret; @@ -711,17 +804,40 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, char *host  	if (lockdown_check_result(dict, verb) != RESULT_SUCCESS) {  		ret = LOCKDOWN_E_PAIRING_FAILED;  	} -	plist_free(dict); -	dict = NULL; -	/* store public key in config if pairing succeeded */ +	/* if pairing succeeded */  	if (ret == LOCKDOWN_E_SUCCESS) { -		log_dbg_msg(DBGMASK_LOCKDOWND, "%s: %s success\n", __func__, verb); -		userpref_set_device_public_key(client->uuid, public_key); +		debug_info("%s success", verb); +		if (!pairing_mode) { +			if (!strcmp("Unpair", verb)) { +				/* remove public key from config */ +				userpref_remove_device_public_key(client->uuid); +			} else { +				/* store public key in config */ +				userpref_set_device_public_key(client->uuid, public_key); +			} +		}  	} else { -		log_dbg_msg(DBGMASK_LOCKDOWND, "%s: %s failure\n", __func__, verb); +		debug_info("%s failure", verb); +		plist_t error_node = NULL; +		/* verify error condition */ +		error_node = plist_dict_get_item(dict, "Error"); +		if (error_node) { +			char *value = NULL; +			plist_get_string_val(error_node, &value); +			/* the first pairing fails if the device is password protected */ +			if (value && !strcmp(value, "PasswordProtected")) { +				ret = LOCKDOWN_E_PASSWORD_PROTECTED; +				free(value); +			} +			plist_free(error_node); +			error_node = NULL; +		}  	} -	free(public_key.data); +	plist_free(dict); +	dict = NULL; +	if (public_key.data) +		free(public_key.data);  	return ret;  } @@ -730,15 +846,15 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, char *host   * It's part of the lockdownd handshake.   *   * @param client The lockdown client to pair with. - * @param host_id The HostID to use for pairing. If NULL is passed, then - *    the HostID of the current machine is used. A new HostID will be + * @param pair_record The pair record to use for pairing. If NULL is passed, then + *    the pair records from the current machine are used. New records will be   *    generated automatically when pairing is done for the first time.   *   * @return an error code (LOCKDOWN_E_SUCCESS on success)   */ -lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *host_id) +lockdownd_error_t lockdownd_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record)  { -	return lockdownd_do_pair(client, host_id, "Pair"); +	return lockdownd_do_pair(client, pair_record, "Pair");  }  /**  @@ -747,15 +863,31 @@ lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *host_id)   * It's part of the lockdownd handshake.   *   * @param client The lockdown client to pair with. - * @param host_id The HostID to use for pairing. If NULL is passed, then - *    the HostID of the current machine is used. A new HostID will be - *    generated automatically when pairing is done for the first time. + * @param pair_record The pair record to validate pairing with. If NULL is + *    passed, then the pair records from the current machine are used. + *    New records will be generated automatically when pairing is done + *    for the first time.   *   * @return an error code (LOCKDOWN_E_SUCCESS on success)   */ -lockdownd_error_t lockdownd_validate_pair(lockdownd_client_t client, char *host_id) +lockdownd_error_t lockdownd_validate_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record)  { -	return lockdownd_do_pair(client, host_id, "ValidatePair"); +	return lockdownd_do_pair(client, pair_record, "ValidatePair"); +} + +/**  + * Unpairs the device with the given HostID and removes the pairing records + * from the device and host. + * + * @param client The lockdown client to pair with. + * @param pair_record The pair record to use for unpair. If NULL is passed, then + *    the pair records from the current machine are used. + * + * @return an error code (LOCKDOWN_E_SUCCESS on success) + */ +lockdownd_error_t lockdownd_unpair(lockdownd_client_t client, lockdownd_pair_record_t pair_record) +{ +	return lockdownd_do_pair(client, pair_record, "Unpair");  }  /** @@ -773,9 +905,10 @@ lockdownd_error_t lockdownd_enter_recovery(lockdownd_client_t client)  	lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;  	plist_t dict = plist_new_dict(); +	plist_dict_add_label(dict, client->label);  	plist_dict_insert_item(dict,"Request", plist_new_string("EnterRecovery")); -	log_dbg_msg(DBGMASK_LOCKDOWND, "%s: telling device to enter recovery mode\n", __func__); +	debug_info("telling device to enter recovery mode");  	ret = lockdownd_send(client, dict);  	plist_free(dict); @@ -784,7 +917,7 @@ lockdownd_error_t lockdownd_enter_recovery(lockdownd_client_t client)  	ret = lockdownd_recv(client, &dict);  	if (lockdown_check_result(dict, "EnterRecovery") == RESULT_SUCCESS) { -		log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); +		debug_info("success");  		ret = LOCKDOWN_E_SUCCESS;  	}  	plist_free(dict); @@ -808,9 +941,10 @@ lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client)  	lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;  	plist_t dict = plist_new_dict(); +	plist_dict_add_label(dict, client->label);  	plist_dict_insert_item(dict,"Request", plist_new_string("Goodbye")); -	log_dbg_msg(DBGMASK_LOCKDOWND, "%s: called\n", __func__); +	debug_info("called");  	ret = lockdownd_send(client, dict);  	plist_free(dict); @@ -818,12 +952,12 @@ lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client)  	ret = lockdownd_recv(client, &dict);  	if (!dict) { -		log_dbg_msg(DBGMASK_LOCKDOWND, "%s: did not get goodbye response back\n", __func__); +		debug_info("did not get goodbye response back");  		return LOCKDOWN_E_PLIST_ERROR;  	}  	if (lockdown_check_result(dict, "Goodbye") == RESULT_SUCCESS) { -		log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); +		debug_info("success");  		ret = LOCKDOWN_E_SUCCESS;  	}  	plist_free(dict); @@ -879,7 +1013,7 @@ lockdownd_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datu  			asn1_delete_structure(&pkcs1);  	} -	/* now generate certifcates */ +	/* now generate certificates */  	if (LOCKDOWN_E_SUCCESS == ret && 0 != modulus.size && 0 != exponent.size) {  		gnutls_global_init(); @@ -973,24 +1107,29 @@ lockdownd_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datu   *  and if the device requires it, switches to SSL mode.   *   * @param client The lockdownd client - * @param HostID The HostID used with this phone + * @param host_id The HostID of the computer + * @param session_id The session_id of the created session + * @param ssl_enabled Whether SSL communication is used in the session   *   * @return an error code (LOCKDOWN_E_SUCCESS on success)   */ -lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const char *HostID) +lockdownd_error_t lockdownd_start_session(lockdownd_client_t client, const char *host_id, char **session_id, int *ssl_enabled)  { +	lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;  	plist_t dict = NULL; -	uint32_t return_me = 0; -	lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; +	if (!client || !host_id) +		ret = LOCKDOWN_E_INVALID_ARG; + +	/* if we have a running session, stop current one first */  	if (client->session_id) { -		free(client->session_id); -		client->session_id = NULL; +		lockdownd_stop_session(client, client->session_id);  	} -	/* Setup DevicePublicKey request plist */ +	/* setup request plist */  	dict = plist_new_dict(); -	plist_dict_insert_item(dict,"HostID", plist_new_string(HostID)); +	plist_dict_add_label(dict, client->label); +	plist_dict_insert_item(dict,"HostID", plist_new_string(host_id));  	plist_dict_insert_item(dict,"Request", plist_new_string("StartSession"));  	ret = lockdownd_send(client, dict); @@ -1010,183 +1149,54 @@ lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const c  		if (error_node && PLIST_STRING == plist_get_node_type(error_node)) {  			char *error = NULL;  			plist_get_string_val(error_node, &error); -  			if (!strcmp(error, "InvalidHostID")) { -				/* hostid is unknown. Pair and try again */ -				char *host_id = NULL; -				userpref_get_host_id(&host_id); - -				if (LOCKDOWN_E_SUCCESS == lockdownd_pair(client, host_id) ) { -					/* start session again */ -					plist_free(dict); -					dict = plist_new_dict(); -					plist_dict_insert_item(dict,"HostID", plist_new_string(HostID)); -					plist_dict_insert_item(dict,"Request", plist_new_string("StartSession")); - -					ret = lockdownd_send(client, dict); -					plist_free(dict); -					dict = NULL; - -					ret = lockdownd_recv(client, &dict); -				} -				free(host_id); +				ret = LOCKDOWN_E_INVALID_HOST_ID;  			}  			free(error);  		} -	} - -	ret = LOCKDOWN_E_SSL_ERROR; - -	int session_ok = 0;  -	uint8_t UseSSL = 0; +	} else { +		uint8_t use_ssl = 0; -	if (lockdown_check_result(dict, "StartSession") == RESULT_SUCCESS) {  		plist_t enable_ssl = plist_dict_get_item(dict, "EnableSessionSSL");  		if (enable_ssl && (plist_get_node_type(enable_ssl) == PLIST_BOOLEAN)) { -			plist_get_bool_val(enable_ssl, &UseSSL); +			plist_get_bool_val(enable_ssl, &use_ssl);  		} -		log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Session startup OK\n", __func__); -		session_ok = 1; -	} -	if (session_ok && !UseSSL) { -		client->in_SSL = 0; -		ret = LOCKDOWN_E_SUCCESS; -	} else if (session_ok) { -		// Set up GnuTLS... -		log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Switching to SSL mode\n", __func__); -		errno = 0; -		gnutls_global_init(); -		//gnutls_anon_allocate_client_credentials(&anoncred); -		gnutls_certificate_allocate_credentials(&client->ssl_certificate); -		gnutls_certificate_set_x509_trust_file(client->ssl_certificate, "hostcert.pem", GNUTLS_X509_FMT_PEM); -		gnutls_init(&client->ssl_session, GNUTLS_CLIENT); -		{ -			int protocol_priority[16] = { GNUTLS_SSL3, 0 }; -			int kx_priority[16] = { GNUTLS_KX_ANON_DH, GNUTLS_KX_RSA, 0 }; -			int cipher_priority[16] = { GNUTLS_CIPHER_AES_128_CBC, GNUTLS_CIPHER_AES_256_CBC, 0 }; -			int mac_priority[16] = { GNUTLS_MAC_SHA1, GNUTLS_MAC_MD5, 0 }; -			int comp_priority[16] = { GNUTLS_COMP_NULL, 0 }; - -			gnutls_cipher_set_priority(client->ssl_session, cipher_priority); -			gnutls_compression_set_priority(client->ssl_session, comp_priority); -			gnutls_kx_set_priority(client->ssl_session, kx_priority); -			gnutls_protocol_set_priority(client->ssl_session, protocol_priority); -			gnutls_mac_set_priority(client->ssl_session, mac_priority); +		debug_info("Session startup OK"); + +		if (ssl_enabled != NULL) +			*ssl_enabled = use_ssl; + +		/* store session id, we need it for StopSession */ +		plist_t session_node = plist_dict_get_item(dict, "SessionID"); +		if (session_node && (plist_get_node_type(session_node) == PLIST_STRING)) { +			plist_get_string_val(session_node, &client->session_id);  		} -		gnutls_credentials_set(client->ssl_session, GNUTLS_CRD_CERTIFICATE, client->ssl_certificate);	// this part is killing me. - -		log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS step 1...\n", __func__); -		gnutls_transport_set_ptr(client->ssl_session, (gnutls_transport_ptr_t) client); -		log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS step 2...\n", __func__); -		gnutls_transport_set_push_function(client->ssl_session, (gnutls_push_func) & lockdownd_secuwrite); -		log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS step 3...\n", __func__); -		gnutls_transport_set_pull_function(client->ssl_session, (gnutls_pull_func) & lockdownd_securead); -		log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS step 4 -- now handshaking...\n", __func__); -		if (errno) -			log_dbg_msg(DBGMASK_LOCKDOWND, "%s: WARN: errno says %s before handshake!\n", __func__, strerror(errno)); -		return_me = gnutls_handshake(client->ssl_session); -		log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS handshake done...\n", __func__); - -		if (return_me != GNUTLS_E_SUCCESS) { -			log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS reported something wrong.\n", __func__); -			gnutls_perror(return_me); -			log_dbg_msg(DBGMASK_LOCKDOWND, "%s: oh.. errno says %s\n", __func__, strerror(errno)); -			return LOCKDOWN_E_SSL_ERROR; +		if (client->session_id) { +			debug_info("SessionID: %s", client->session_id); +			if (session_id != NULL) +				*session_id = strdup(client->session_id);  		} else { -			client->in_SSL = 1; +			debug_info("Failed to get SessionID!"); +		} +		debug_info("Enable SSL Session: %s", (use_ssl?"true":"false")); +		if (use_ssl) { +			ret = property_list_service_enable_ssl(client->parent); +			if (ret == PROPERTY_LIST_SERVICE_E_SUCCESS) { +				client->ssl_enabled = 1; +			} else { +				ret = LOCKDOWN_E_SSL_ERROR; +				client->ssl_enabled = 0; +			} +		} else { +			client->ssl_enabled = 0;  			ret = LOCKDOWN_E_SUCCESS;  		}  	} -	/* store session id, we need it for StopSession */ -	plist_t session_node = plist_dict_get_item(dict, "SessionID"); -	if (session_node && (plist_get_node_type(session_node) == PLIST_STRING)) { -		plist_get_string_val(session_node, &client->session_id); -	} -	if (client->session_id) { -		log_dbg_msg(DBGMASK_LOCKDOWND, "%s: SessionID: %s\n", __func__, client->session_id); -	} else { -		log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Failed to get SessionID!\n", __func__); -	} +  	plist_free(dict);  	dict = NULL; -	if (ret == LOCKDOWN_E_SUCCESS) -		return ret; - -	log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Apparently failed negotiating with lockdownd.\n", __func__); -	return LOCKDOWN_E_SSL_ERROR; -} - -/** gnutls callback for writing data to the iPhone. - * - * @param transport It's really the lockdownd client, but the method signature has to match - * @param buffer The data to send - * @param length The length of data to send in bytes - * - * @return The number of bytes sent - */ -ssize_t lockdownd_secuwrite(gnutls_transport_ptr_t transport, char *buffer, size_t length) -{ -	uint32_t bytes = 0; -	lockdownd_client_t client; -	client = (lockdownd_client_t) transport; -	log_dbg_msg(DBGMASK_LOCKDOWND, "%s: called\n", __func__); -	log_dbg_msg(DBGMASK_LOCKDOWND, "%s: pre-send length = %zi\n", __func__, length); -	iphone_device_send(client->connection, buffer, length, &bytes); -	log_dbg_msg(DBGMASK_LOCKDOWND, "%s: post-send sent %i bytes\n", __func__, bytes); -	return bytes; -} - -/** gnutls callback for reading data from the iPhone - * - * @param transport It's really the lockdownd client, but the method signature has to match - * @param buffer The buffer to store data in - * @param length The length of data to read in bytes - * - * @return The number of bytes read - */ -ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_t length) -{ -	int bytes = 0, pos_start_fill = 0; -	size_t tbytes = 0; -	int this_len = length; -	iphone_error_t res; -	lockdownd_client_t client; -	client = (lockdownd_client_t) transport; -	char *recv_buffer; - -	log_debug_msg("%s: pre-read client wants %zi bytes\n", __func__, length); - -	recv_buffer = (char *) malloc(sizeof(char) * this_len); - -	// repeat until we have the full data or an error occurs. -	do { -		if ((res = iphone_device_recv(client->connection, recv_buffer, this_len, (uint32_t*)&bytes)) != LOCKDOWN_E_SUCCESS) { -			log_debug_msg("%s: ERROR: usbmux_recv returned %d\n", __func__, res); -			return res; -		} -		log_debug_msg("%s: post-read we got %i bytes\n", __func__, bytes); - -		// increase read count -		tbytes += bytes; - -		// fill the buffer with what we got right now -		memcpy(buffer + pos_start_fill, recv_buffer, bytes); -		pos_start_fill += bytes; - -		if (tbytes >= length) { -			break; -		} - -		this_len = length - tbytes; -		log_debug_msg("%s: re-read trying to read missing %i bytes\n", __func__, this_len); -	} while (tbytes < length); - -	if (recv_buffer) { -		free(recv_buffer); -	} - -	return tbytes; +	return ret;  }  /** Command to start the desired service @@ -1197,7 +1207,7 @@ ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_   * @return an error code (LOCKDOWN_E_SUCCESS on success)   */ -lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char *service, int *port) +lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char *service, uint16_t *port)  {  	if (!client || !service || !port)  		return LOCKDOWN_E_INVALID_ARG; @@ -1206,17 +1216,18 @@ lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char  	userpref_get_host_id(&host_id);  	if (!host_id)  		return LOCKDOWN_E_INVALID_CONF; -	if (!client->in_SSL && !lockdownd_start_ssl_session(client, host_id)) -		return LOCKDOWN_E_SSL_ERROR; +	if (!client->session_id) +		return LOCKDOWN_E_NO_RUNNING_SESSION;  	plist_t dict = NULL; -	uint32_t port_loc = 0; +	uint16_t port_loc = 0;  	lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;  	free(host_id);  	host_id = NULL;  	dict = plist_new_dict(); +	plist_dict_add_label(dict, client->label);  	plist_dict_insert_item(dict,"Request", plist_new_string("StartService"));  	plist_dict_insert_item(dict,"Service", plist_new_string(service)); @@ -1260,3 +1271,97 @@ lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char  	return ret;  } +/** + * Activates the device. Only works within an open session. + * The ActivationRecord plist dictionary must be obtained using the + * activation protocol requesting from Apple's https webservice. + * + * @see http://iphone-docs.org/doku.php?id=docs:protocols:activation + * + * @param control The lockdown client + * @param activation_record The activation record plist dictionary + * + * @return an error code (LOCKDOWN_E_SUCCESS on success) + */ +lockdownd_error_t lockdownd_activate(lockdownd_client_t client, plist_t activation_record)  +{ +	if (!client) +		return LOCKDOWN_E_INVALID_ARG; + +	if (!client->session_id) +		return LOCKDOWN_E_NO_RUNNING_SESSION; + +	if (!activation_record) +		return LOCKDOWN_E_INVALID_ARG; + +	lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; + +	plist_t dict = plist_new_dict(); +	plist_dict_add_label(dict, client->label); +	plist_dict_insert_item(dict,"Request", plist_new_string("Activate")); +	plist_dict_insert_item(dict,"ActivationRecord", activation_record); + +	ret = lockdownd_send(client, dict); +	plist_free(dict); +	dict = NULL; + +	ret = lockdownd_recv(client, &dict); +	if (!dict) { +		debug_info("LOCKDOWN_E_PLIST_ERROR"); +		return LOCKDOWN_E_PLIST_ERROR; +	} + +	ret = LOCKDOWN_E_ACTIVATION_FAILED; +	if (lockdown_check_result(dict, "Activate") == RESULT_SUCCESS) { +		debug_info("success"); +		ret = LOCKDOWN_E_SUCCESS; +	} +	plist_free(dict); +	dict = NULL; + +	return ret; +} + +/** + * Deactivates the device, returning it to the locked + * “Activate with iTunes” screen. + * + * @param control The lockdown client + * + * @return an error code (LOCKDOWN_E_SUCCESS on success) + */ +lockdownd_error_t lockdownd_deactivate(lockdownd_client_t client) +{ +	if (!client) +		return LOCKDOWN_E_INVALID_ARG; + +	if (!client->session_id) +		return LOCKDOWN_E_NO_RUNNING_SESSION; + +	lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; + +	plist_t dict = plist_new_dict(); +	plist_dict_add_label(dict, client->label); +	plist_dict_insert_item(dict,"Request", plist_new_string("Deactivate")); + +	ret = lockdownd_send(client, dict); +	plist_free(dict); +	dict = NULL; + +	ret = lockdownd_recv(client, &dict); +	if (!dict) { +		debug_info("LOCKDOWN_E_PLIST_ERROR"); +		return LOCKDOWN_E_PLIST_ERROR; +	} + +	ret = LOCKDOWN_E_UNKNOWN_ERROR; +	if (lockdown_check_result(dict, "Deactivate") == RESULT_SUCCESS) { +		debug_info("success"); +		ret = LOCKDOWN_E_SUCCESS; +	} +	plist_free(dict); +	dict = NULL; + +	return ret; +} + 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 @@  #include <string.h>  #include "libiphone/lockdown.h" +#include "property_list_service.h"  struct lockdownd_client_int { -	iphone_connection_t connection; -	gnutls_session_t ssl_session; -	gnutls_certificate_credentials_t ssl_certificate; -	int in_SSL; +	property_list_service_client_t parent; +	int ssl_enabled;  	char *session_id;  	char *uuid; +	char *label;  };  lockdownd_error_t lockdownd_get_device_public_key(lockdownd_client_t client, gnutls_datum_t * public_key);  lockdownd_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datum_t * device_cert,  									   gnutls_datum_t * host_cert, gnutls_datum_t * root_cert); -/* SSL functions */ -lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const char *HostID); -ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_t length); -ssize_t lockdownd_secuwrite(gnutls_transport_ptr_t transport, char *buffer, size_t length); - -  #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 @@ +/*  + * property_list_service.c + * PropertyList service implementation. + * + * Copyright (c) 2010 Nikias Bassen. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA  + */ +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <arpa/inet.h> + +#include "property_list_service.h" +#include "iphone.h" +#include "debug.h" + +/** + * Convert an iphone_error_t value to an property_list_service_error_t value. + * Used internally to get correct error codes. + * + * @param err An iphone_error_t error code + * + * @return A matching property_list_service_error_t error code, + *     PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR otherwise. + */ +static property_list_service_error_t iphone_to_property_list_service_error(iphone_error_t err) +{ +	switch (err) { +		case IPHONE_E_SUCCESS: +			return PROPERTY_LIST_SERVICE_E_SUCCESS; +		case IPHONE_E_INVALID_ARG: +			return PROPERTY_LIST_SERVICE_E_INVALID_ARG; +		case IPHONE_E_SSL_ERROR: +			return PROPERTY_LIST_SERVICE_E_SSL_ERROR; +		default: +			break; +	} +	return PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR; +} + +/** + * Creates a new property list service for the specified port. + *  + * @param device The device to connect to. + * @param port The port on the device to connect to, usually opened by a call to + *     lockdownd_start_service. + * @param client Pointer that will be set to a newly allocated + *     property_list_service_client_t upon successful return. + * + * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, + *     PROPERTY_LIST_SERVICE_E_INVALID_ARG when one of the arguments is invalid, + *     or PROPERTY_LIST_SERVICE_E_MUX_ERROR when connecting to the device failed. + */ +property_list_service_error_t property_list_service_client_new(iphone_device_t device, uint16_t port, property_list_service_client_t *client) +{ +	if (!device || port == 0 || !client || *client) +		return PROPERTY_LIST_SERVICE_E_INVALID_ARG; + +	/* Attempt connection */ +	iphone_connection_t connection = NULL; +	if (iphone_device_connect(device, port, &connection) != IPHONE_E_SUCCESS) { +		return PROPERTY_LIST_SERVICE_E_MUX_ERROR; +	} + +	/* create client object */ +	property_list_service_client_t client_loc = (property_list_service_client_t)malloc(sizeof(struct property_list_service_client_int)); +	client_loc->connection = connection; + +	*client = client_loc; + +	return PROPERTY_LIST_SERVICE_E_SUCCESS; +} + +/** + * Frees a PropertyList service. + * + * @param client The property list service to free. + * + * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, + *     PROPERTY_LIST_SERVICE_E_INVALID_ARG when client is invalid, or a + *     PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when another error occured. + */ +property_list_service_error_t property_list_service_client_free(property_list_service_client_t client) +{ +	if (!client) +		return PROPERTY_LIST_SERVICE_E_INVALID_ARG; + +	property_list_service_error_t err = iphone_to_property_list_service_error(iphone_device_disconnect(client->connection)); +	free(client); +	return err; +} + +/** + * Sends a plist using the given property list service client. + * Internally used generic plist send function. + * + * @param client The property list service client to use for sending. + * @param plist plist to send + * @param binary 1 = send binary plist, 0 = send xml plist + * + * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, + *      PROPERTY_LIST_SERVICE_E_INVALID_ARG when one or more parameters are + *      invalid, PROPERTY_LIST_SERVICE_E_PLIST_ERROR when dict is not a valid + *      plist, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when an unspecified + *      error occurs. + */ +static property_list_service_error_t internal_plist_send(property_list_service_client_t client, plist_t plist, int binary) +{ +	property_list_service_error_t res = PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR; +	char *content = NULL; +	uint32_t length = 0; +	uint32_t nlen = 0; +	int bytes = 0; + +	if (!client || (client && !client->connection) || !plist) { +		return PROPERTY_LIST_SERVICE_E_INVALID_ARG; +	} + +	if (binary) { +		plist_to_bin(plist, &content, &length); +	} else { +		plist_to_xml(plist, &content, &length); +	} + +	if (!content || length == 0) { +		return PROPERTY_LIST_SERVICE_E_PLIST_ERROR; +	} + +	nlen = htonl(length); +	debug_info("sending %d bytes", length); +	iphone_device_send(client->connection, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes); +	if (bytes == sizeof(nlen)) { +		iphone_device_send(client->connection, content, length, (uint32_t*)&bytes); +		if (bytes > 0) { +			debug_info("sent %d bytes", bytes); +			debug_plist(plist); +			if ((uint32_t)bytes == length) { +				res = PROPERTY_LIST_SERVICE_E_SUCCESS; +			} else { +				debug_info("ERROR: Could not send all data (%d of %d)!", bytes, length); +			} +		} +	} +	if (bytes <= 0) { +		debug_info("ERROR: sending to device failed."); +	} + +	free(content); + +	return res; +} + +/** + * Sends an XML plist. + * + * @param client The property list service client to use for sending. + * @param plist plist to send + * + * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, + *      PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or plist is NULL, + *      PROPERTY_LIST_SERVICE_E_PLIST_ERROR when dict is not a valid plist, + *      or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when an unspecified error occurs. + */ +property_list_service_error_t property_list_service_send_xml_plist(property_list_service_client_t client, plist_t plist) +{ +	return internal_plist_send(client, plist, 0); +} + +/** + * Sends a binary plist. + * + * @param client The property list service client to use for sending. + * @param plist plist to send + * + * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, + *      PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or plist is NULL, + *      PROPERTY_LIST_SERVICE_E_PLIST_ERROR when dict is not a valid plist, + *      or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when an unspecified error occurs. + */ +property_list_service_error_t property_list_service_send_binary_plist(property_list_service_client_t client, plist_t plist) +{ +	return internal_plist_send(client, plist, 1); +} + +/** + * Receives a plist using the given property list service client. + * Internally used generic plist receive function. + * + * @param client The property list service client to use for receiving + * @param plist pointer to a plist_t that will point to the received plist + *      upon successful return + * @param timeout Maximum time in milliseconds to wait for data. + * + * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, + *      PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or *plist is NULL, + *      PROPERTY_LIST_SERVICE_E_PLIST_ERROR when the received data cannot be + *      converted to a plist, PROPERTY_LIST_SERVICE_E_MUX_ERROR when a + *      communication error occurs, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR + *      when an unspecified error occurs. + */ +static property_list_service_error_t internal_plist_recv_timeout(property_list_service_client_t client, plist_t *plist, unsigned int timeout) +{ +	property_list_service_error_t res = PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR; +	uint32_t pktlen = 0; +	uint32_t bytes = 0; + +	if (!client || (client && !client->connection) || !plist) { +		return PROPERTY_LIST_SERVICE_E_INVALID_ARG; +	} + +	iphone_device_recv_timeout(client->connection, (char*)&pktlen, sizeof(pktlen), &bytes, timeout); +	debug_info("initial read=%i", bytes); +	if (bytes < 4) { +		debug_info("initial read failed!"); +		return PROPERTY_LIST_SERVICE_E_MUX_ERROR; +	} else { +		if ((char)pktlen == 0) { /* prevent huge buffers */ +			uint32_t curlen = 0; +			char *content = NULL; +			pktlen = ntohl(pktlen); +			debug_info("%d bytes following", pktlen); +			content = (char*)malloc(pktlen); + +			while (curlen < pktlen) { +				iphone_device_recv(client->connection, content+curlen, pktlen-curlen, &bytes); +				if (bytes <= 0) { +					res = PROPERTY_LIST_SERVICE_E_MUX_ERROR; +					break; +				} +				debug_info("received %d bytes", bytes); +				curlen += bytes; +			} +			if (!memcmp(content, "bplist00", 8)) { +				plist_from_bin(content, pktlen, plist); +			} else { +				plist_from_xml(content, pktlen, plist); +			} +			if (*plist) { +				debug_plist(*plist); +				res = PROPERTY_LIST_SERVICE_E_SUCCESS; +			} else { +				res = PROPERTY_LIST_SERVICE_E_PLIST_ERROR; +			} +			free(content); +			content = NULL; +		} else { +			res = PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR; +		} +	} +	return res; +} + +/** + * Receives a plist using the given property list service client with specified + * timeout. + * Binary or XML plists are automatically handled. + * + * @param client The property list service client to use for receiving + * @param plist pointer to a plist_t that will point to the received plist + *              upon successful return + * @param timeout Maximum time in milliseconds to wait for data. + * + * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, + *      PROPERTY_LIST_SERVICE_E_INVALID_ARG when connection or *plist is NULL, + *      PROPERTY_LIST_SERVICE_E_PLIST_ERROR when the received data cannot be + *      converted to a plist, PROPERTY_LIST_SERVICE_E_MUX_ERROR when a + *      communication error occurs, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when + *      an unspecified error occurs. + */ +property_list_service_error_t property_list_service_receive_plist_with_timeout(property_list_service_client_t client, plist_t *plist, unsigned int timeout) +{ +	return internal_plist_recv_timeout(client, plist, timeout); +} + +/** + * Receives a plist using the given property list service client. + * Binary or XML plists are automatically handled. + * + * This function is like property_list_service_receive_plist_with_timeout + *   using a timeout of 10 seconds. + * @see property_list_service_receive_plist_with_timeout + * + * @param client The property list service client to use for receiving + * @param plist pointer to a plist_t that will point to the received plist + *      upon successful return + * + * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, + *      PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or *plist is NULL, + *      PROPERTY_LIST_SERVICE_E_PLIST_ERROR when the received data cannot be + *      converted to a plist, PROPERTY_LIST_SERVICE_E_MUX_ERROR when a + *      communication error occurs, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when + *      an unspecified error occurs. + */ +property_list_service_error_t property_list_service_receive_plist(property_list_service_client_t client, plist_t *plist) +{ +	return internal_plist_recv_timeout(client, plist, 10000); +} + +/** + * Enable SSL for the given property list service client. + * + * @param client The connected property list service client for which SSL + *     should be enabled. + * + * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, + *     PROPERTY_LIST_SERVICE_E_INVALID_ARG if client or client->connection is + *     NULL, PROPERTY_LIST_SERVICE_E_SSL_ERROR when SSL could not be enabled, + *     or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR otherwise. + */ +property_list_service_error_t property_list_service_enable_ssl(property_list_service_client_t client) +{ +	if (!client || !client->connection) +		return PROPERTY_LIST_SERVICE_E_INVALID_ARG; +	return iphone_to_property_list_service_error(iphone_connection_enable_ssl(client->connection)); +} + +/** + * Disable SSL for the given property list service client. + * + * @param client The connected property list service client for which SSL + *     should be disabled. + * + * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, + *     PROPERTY_LIST_SERVICE_E_INVALID_ARG if client or client->connection is + *     NULL, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR otherwise. + */ +property_list_service_error_t property_list_service_disable_ssl(property_list_service_client_t client) +{ +	if (!client || !client->connection) +		return PROPERTY_LIST_SERVICE_E_INVALID_ARG; +	return iphone_to_property_list_service_error(iphone_connection_disable_ssl(client->connection)); +} + 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 @@ + /*  + * property_list_service.h + * Definitions for the PropertyList service + *  + * Copyright (c) 2010 Nikias Bassen, All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA  + */ +#ifndef PROPERTY_LIST_SERVICE_H +#define PROPERTY_LIST_SERVICE_H + +#include "iphone.h" + +/* Error Codes */ +#define PROPERTY_LIST_SERVICE_E_SUCCESS                0 +#define PROPERTY_LIST_SERVICE_E_INVALID_ARG           -1 +#define PROPERTY_LIST_SERVICE_E_PLIST_ERROR           -2 +#define PROPERTY_LIST_SERVICE_E_MUX_ERROR             -3 +#define PROPERTY_LIST_SERVICE_E_SSL_ERROR             -4 + +#define PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR       -256 + +struct property_list_service_client_int { +	iphone_connection_t connection; +}; + +typedef struct property_list_service_client_int *property_list_service_client_t; + +typedef int16_t property_list_service_error_t; + +/* creation and destruction */ +property_list_service_error_t property_list_service_client_new(iphone_device_t device, uint16_t port, property_list_service_client_t *client); +property_list_service_error_t property_list_service_client_free(property_list_service_client_t client); + +/* sending */ +property_list_service_error_t property_list_service_send_xml_plist(property_list_service_client_t client, plist_t plist); +property_list_service_error_t property_list_service_send_binary_plist(property_list_service_client_t client, plist_t plist); + +/* receiving */ +property_list_service_error_t property_list_service_receive_plist_with_timeout(property_list_service_client_t client, plist_t *plist, unsigned int timeout); +property_list_service_error_t property_list_service_receive_plist(property_list_service_client_t client, plist_t *plist); + +/* misc */ +property_list_service_error_t property_list_service_enable_ssl(property_list_service_client_t client); +property_list_service_error_t property_list_service_disable_ssl(property_list_service_client_t client); + +#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 @@   */  #include <glib.h> +#include <glib/gstdio.h>  #include <glib/gprintf.h>  #include <stdio.h>  #include <stdint.h> @@ -30,7 +31,7 @@  #include <gcrypt.h>  #include "userpref.h" -#include "utils.h" +#include "debug.h"  #define LIBIPHONE_CONF_DIR  "libiphone"  #define LIBIPHONE_CONF_FILE "libiphonerc" @@ -105,7 +106,7 @@ static int userpref_set_host_id(const char *host_id)  	key_file = g_key_file_new();  	/* Store in config file */ -	log_debug_msg("%s: setting hostID to %s\n", __func__, host_id); +	debug_info("setting hostID to %s", host_id);  	g_key_file_set_value(key_file, "Global", "HostID", host_id);  	/* Write config file on disk */ @@ -154,7 +155,7 @@ void userpref_get_host_id(char **host_id)  		userpref_set_host_id(*host_id);  	} -	log_debug_msg("%s: Using %s as HostID\n", __func__, *host_id); +	debug_info("Using %s as HostID", *host_id);  }  /** 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  	return USERPREF_E_SUCCESS;  } +/** Remove the public key stored for the device with uuid from this host. + * + * @param uuid The uuid of the device + * + * @return USERPREF_E_SUCCESS on success. + */ +userpref_error_t userpref_remove_device_public_key(const char *uuid) +{ +	if (!userpref_has_device_public_key(uuid)) +		return USERPREF_E_SUCCESS; + +	/* build file path */ +	gchar *device_file = g_strconcat(uuid, ".pem", NULL); +	gchar *pem = g_build_path(G_DIR_SEPARATOR_S, g_get_user_config_dir(), LIBIPHONE_CONF_DIR, device_file, NULL); + +	/* remove file */ +	g_remove(pem); + +	g_free(pem); +	g_free(device_file); + +	return USERPREF_E_SUCCESS; +} +  /** Private function which reads the given file into a gnutls structure.   *   * @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  G_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);  G_GNUC_INTERNAL userpref_error_t userpref_get_certs_as_pem(gnutls_datum_t *pem_root_cert, gnutls_datum_t *pem_host_cert);  G_GNUC_INTERNAL userpref_error_t userpref_set_device_public_key(const char *uuid, gnutls_datum_t public_key); +G_GNUC_INTERNAL userpref_error_t userpref_remove_device_public_key(const char *uuid);  G_GNUC_INTERNAL int userpref_has_device_public_key(const char *uuid);  G_GNUC_INTERNAL void userpref_get_host_id(char **host_id); 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 @@ -/* - * utils.h - * contains utilitary methos for logging and debugging - * - * Copyright (c) 2008 Jonathan Beck All Rights Reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA  - */ - -#ifndef UTILS_H -#define UTILS_H - -#include <glib.h> - -G_GNUC_INTERNAL inline void log_debug_msg(const char *format, ...); -G_GNUC_INTERNAL inline void log_dbg_msg(uint16_t id, const char *format, ...); - -G_GNUC_INTERNAL inline void log_debug_buffer(const char *data, const int length); -G_GNUC_INTERNAL inline void dump_debug_buffer(const char *file, const char *data, const int length); - -#endif diff --git a/swig/iphone.i b/swig/iphone.i index a0ee509..f1969ed 100644 --- a/swig/iphone.i +++ b/swig/iphone.i @@ -8,7 +8,7 @@   #include <libiphone/mobilesync.h>   #include <plist/plist.h>   #include <plist/plist++.h> - #include "../src/utils.h" + #include "../src/debug.h"   typedef struct {  	iphone_device_t dev;   } iPhone; @@ -36,11 +36,6 @@ PList::Node* new_node_from_plist(plist_t node);  %include "cstring.i"  %include "plist/swig/plist.i" -#define DBGMASK_ALL        0xFFFF -#define DBGMASK_NONE       0x0000 -#define DBGMASK_LOCKDOWND  (1 << 1) -#define DBGMASK_MOBILESYNC (1 << 2) -  typedef struct {  	iphone_device_t dev;  } iPhone; @@ -71,7 +66,7 @@ Lockdownd* my_new_Lockdownd(iPhone* phone) {  	Lockdownd* client = (Lockdownd*) malloc(sizeof(Lockdownd));  	client->dev = phone;  	client->client = NULL; -	if (LOCKDOWN_E_SUCCESS == lockdownd_client_new(phone->dev , &(client->client))) { +	if (LOCKDOWN_E_SUCCESS == lockdownd_client_new_with_handshake(phone->dev , &(client->client), NULL)) {  		return client;  	}  	else { @@ -90,7 +85,7 @@ void my_delete_Lockdownd(Lockdownd* lckd) {  MobileSync* my_new_MobileSync(Lockdownd* lckd) {  	if (!lckd || !lckd->dev) return NULL;  	MobileSync* client = NULL; -	int port = 0; +	uint16_t port = 0;  	if (LOCKDOWN_E_SUCCESS == lockdownd_start_service(lckd->client, "com.apple.mobilesync", &port)) {  		client = (MobileSync*) malloc(sizeof(MobileSync));  		client->dev = lckd->dev; @@ -149,10 +144,6 @@ PList::Node* new_node_from_plist(plist_t node)  		my_delete_iPhone($self);  	} -	void set_debug_mask(uint16_t mask) { -		iphone_set_debug_mask(mask); -	} -  	void set_debug_level(int level) {  		iphone_set_debug_level(level);  	} diff --git a/tools/iphone_id.c b/tools/iphone_id.c index 80f22e1..4a2c3af 100644 --- a/tools/iphone_id.c +++ b/tools/iphone_id.c @@ -38,7 +38,6 @@ int main(int argc, char **argv)  	/* parse cmdline args */  	for (i = 1; i < argc; i++) {  		if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) { -			iphone_set_debug_mask(DBGMASK_ALL);  			iphone_set_debug_level(1);  			continue;  		} @@ -70,7 +69,7 @@ int main(int argc, char **argv)  			return -2;  		} -		if (LOCKDOWN_E_SUCCESS != lockdownd_client_new(phone, &client)) { +		if (LOCKDOWN_E_SUCCESS != lockdownd_client_new(phone, &client, "iphone_id")) {  			iphone_device_free(phone);  			fprintf(stderr, "ERROR: Connecting to device failed!\n");  			return -2; diff --git a/tools/iphoneinfo.c b/tools/iphoneinfo.c index e0d7693..7c41033 100644 --- a/tools/iphoneinfo.c +++ b/tools/iphoneinfo.c @@ -37,12 +37,18 @@ static const char *domains[] = {  	"com.apple.mobile.debug",. */  	"com.apple.xcode.developerdomain",  	"com.apple.international", +	"com.apple.mobile.data_sync", +	"com.apple.mobile.tethered_sync",  	"com.apple.mobile.mobile_application_usage",  	"com.apple.mobile.backup", +	"com.apple.mobile.nikita", +	"com.apple.mobile.restriction",  	"com.apple.mobile.user_preferences",  	"com.apple.mobile.sync_data_class",  	"com.apple.mobile.software_behavior",  	"com.apple.mobile.iTunes.SQLMusicLibraryPostProcessCommands", +	"com.apple.mobile.iTunes.accessories", +	"com.apple.fairplay",  	"com.apple.iTunes",  	"com.apple.mobile.iTunes.store",  	"com.apple.mobile.iTunes", @@ -72,7 +78,6 @@ int main(int argc, char *argv[])  	/* parse cmdline args */  	for (i = 1; i < argc; i++) {  		if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) { -			iphone_set_debug_mask(DBGMASK_ALL);  			iphone_set_debug_level(1);  			continue;  		} @@ -136,7 +141,7 @@ int main(int argc, char *argv[])  		}  	} -	if (LOCKDOWN_E_SUCCESS != lockdownd_client_new(phone, &client)) { +	if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(phone, &client, "iphoneinfo")) {  		iphone_device_free(phone);  		return -1;  	} @@ -278,13 +283,10 @@ void plist_children_to_string(plist_t node)  	plist_dict_next_item(node, it, &key, &subnode);  	while (subnode)  	{ -		subnode = NULL; -  		printf("%s: ", key);  		free(key);  		key = NULL;  		plist_node_to_string(subnode); -  		plist_dict_next_item(node, it, &key, &subnode);  	}  	free(it); diff --git a/tools/iphonesyslog.c b/tools/iphonesyslog.c index 8fa3b04..017956e 100644 --- a/tools/iphonesyslog.c +++ b/tools/iphonesyslog.c @@ -49,7 +49,7 @@ int main(int argc, char *argv[])  	iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR;  	int i;  	char uuid[41]; -	int port = 0; +	uint16_t port = 0;  	uuid[0] = 0;  	signal(SIGINT, clean_exit); @@ -60,7 +60,6 @@ int main(int argc, char *argv[])  	/* parse cmdline args */  	for (i = 1; i < argc; i++) {  		if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) { -			iphone_set_debug_mask(DBGMASK_ALL);  			iphone_set_debug_level(1);  			continue;  		} @@ -99,7 +98,7 @@ int main(int argc, char *argv[])  		}  	} -	if (LOCKDOWN_E_SUCCESS != lockdownd_client_new(phone, &client)) { +	if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(phone, &client, "iphonesyslog")) {  		iphone_device_free(phone);  		return -1;  	} | 
