summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/AFC.c128
-rw-r--r--src/InstallationProxy.c112
-rw-r--r--src/InstallationProxy.h3
-rw-r--r--src/Makefile.am4
-rw-r--r--src/MobileSync.c153
-rw-r--r--src/MobileSync.h3
-rw-r--r--src/NotificationProxy.c98
-rw-r--r--src/NotificationProxy.h17
-rw-r--r--src/SBServices.c139
-rw-r--r--src/SBServices.h3
-rw-r--r--src/debug.c (renamed from src/utils.c)106
-rw-r--r--src/debug.h45
-rw-r--r--src/device_link_service.c299
-rw-r--r--src/device_link_service.h51
-rw-r--r--src/iphone.c528
-rw-r--r--src/iphone.h18
-rw-r--r--src/lockdown.c777
-rw-r--r--src/lockdown.h14
-rw-r--r--src/property_list_service.c346
-rw-r--r--src/property_list_service.h59
-rw-r--r--src/userpref.c31
-rw-r--r--src/userpref.h1
-rw-r--r--src/utils.h33
23 files changed, 1905 insertions, 1063 deletions
diff --git a/src/AFC.c b/src/AFC.c
index 956c8fc..db00735 100644
--- a/src/AFC.c
+++ b/src/AFC.c
@@ -25,7 +25,7 @@
#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, &notification);
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