diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/AFC.c | 128 | ||||
-rw-r--r-- | src/InstallationProxy.c | 112 | ||||
-rw-r--r-- | src/InstallationProxy.h | 3 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/MobileSync.c | 153 | ||||
-rw-r--r-- | src/MobileSync.h | 3 | ||||
-rw-r--r-- | src/NotificationProxy.c | 98 | ||||
-rw-r--r-- | src/NotificationProxy.h | 17 | ||||
-rw-r--r-- | src/SBServices.c | 139 | ||||
-rw-r--r-- | src/SBServices.h | 3 | ||||
-rw-r--r-- | src/debug.c (renamed from src/utils.c) | 106 | ||||
-rw-r--r-- | src/debug.h | 45 | ||||
-rw-r--r-- | src/device_link_service.c | 299 | ||||
-rw-r--r-- | src/device_link_service.h | 51 | ||||
-rw-r--r-- | src/iphone.c | 528 | ||||
-rw-r--r-- | src/iphone.h | 18 | ||||
-rw-r--r-- | src/lockdown.c | 777 | ||||
-rw-r--r-- | src/lockdown.h | 14 | ||||
-rw-r--r-- | src/property_list_service.c | 346 | ||||
-rw-r--r-- | src/property_list_service.h | 59 | ||||
-rw-r--r-- | src/userpref.c | 31 | ||||
-rw-r--r-- | src/userpref.h | 1 | ||||
-rw-r--r-- | src/utils.h | 33 |
23 files changed, 1905 insertions, 1063 deletions
@@ -25,7 +25,7 @@ #include "AFC.h" #include "iphone.h" -#include "utils.h" +#include "debug.h" // This is the maximum size an AFC data packet can be static const int MAXIMUM_PACKET_SIZE = (2 << 15); @@ -36,7 +36,7 @@ static const int MAXIMUM_PACKET_SIZE = (2 << 15); */ static void afc_lock(afc_client_t client) { - log_debug_msg("%s: Locked\n", __func__); + debug_info("Locked"); g_mutex_lock(client->mutex); } @@ -46,30 +46,33 @@ static void afc_lock(afc_client_t client) */ static void afc_unlock(afc_client_t client) { - log_debug_msg("%s: Unlocked\n", __func__); + debug_info("Unlocked"); g_mutex_unlock(client->mutex); } /** Makes a connection to the AFC service on the phone. * - * @param phone The iPhone to connect on. - * @param s_port The source port. - * @param d_port The destination port. + * @param device The device to connect to. + * @param port The destination port. + * @param client Pointer that will be set to a newly allocated afc_client_t + * upon successful return. * - * @return A handle to the newly-connected client or NULL upon error. + * @return AFC_E_SUCCESS on success, AFC_E_INVALID_ARGUMENT when device or port + * is invalid, AFC_E_MUX_ERROR when the connection failed, or AFC_E_NO_MEM + * when there's a memory allocation problem. */ -afc_error_t afc_client_new(iphone_device_t device, int dst_port, afc_client_t * client) +afc_error_t afc_client_new(iphone_device_t device, uint16_t port, afc_client_t * client) { /* makes sure thread environment is available */ if (!g_thread_supported()) g_thread_init(NULL); - if (!device) + if (!device || port==0) return AFC_E_INVALID_ARGUMENT; /* attempt connection */ iphone_connection_t connection = NULL; - if (iphone_device_connect(device, dst_port, &connection) != IPHONE_E_SUCCESS) { + if (iphone_device_connect(device, port, &connection) != IPHONE_E_SUCCESS) { return AFC_E_MUX_ERROR; } @@ -155,12 +158,11 @@ static afc_error_t afc_dispatch_packet(afc_client_t client, const char *data, ui if (client->afc_packet->this_length != client->afc_packet->entire_length) { offset = client->afc_packet->this_length - sizeof(AFCPacket); - log_debug_msg("%s: Offset: %i\n", __func__, offset); + debug_info("Offset: %i", offset); if ((length) < (client->afc_packet->entire_length - client->afc_packet->this_length)) { - log_debug_msg("%s: Length did not resemble what it was supposed", __func__); - log_debug_msg("to based on the packet.\n"); - log_debug_msg("%s: length minus offset: %i\n", __func__, length - offset); - log_debug_msg("%s: rest of packet: %i\n", __func__, client->afc_packet->entire_length - client->afc_packet->this_length); + debug_info("Length did not resemble what it was supposed to based on packet"); + debug_info("length minus offset: %i", length - offset); + debug_info("rest of packet: %i\n", client->afc_packet->entire_length - client->afc_packet->this_length); return AFC_E_INTERNAL_ERROR; } @@ -182,10 +184,10 @@ static afc_error_t afc_dispatch_packet(afc_client_t client, const char *data, ui } *bytes_sent += sent; - log_debug_msg("%s: sent the first now go with the second\n", __func__); - log_debug_msg("%s: Length: %i\n", __func__, length - offset); - log_debug_msg("%s: Buffer: \n", __func__); - log_debug_buffer(data + offset, length - offset); + debug_info("sent the first now go with the second"); + debug_info("Length: %i", length - offset); + debug_info("Buffer: "); + debug_buffer(data + offset, length - offset); sent = 0; iphone_device_send(client->connection, data + offset, length - offset, &sent); @@ -193,11 +195,10 @@ static afc_error_t afc_dispatch_packet(afc_client_t client, const char *data, ui *bytes_sent = sent; return AFC_E_SUCCESS; } else { - log_debug_msg("%s: doin things the old way\n", __func__); - log_debug_msg("%s: packet length = %i\n", __func__, client->afc_packet->this_length); + debug_info("doin things the old way"); + debug_info("packet length = %i", client->afc_packet->this_length); - log_debug_buffer((char*)client->afc_packet, sizeof(AFCPacket)); - log_debug_msg("\n"); + debug_buffer((char*)client->afc_packet, sizeof(AFCPacket)); /* send AFC packet header */ AFCPacket_to_LE(client->afc_packet); @@ -209,10 +210,9 @@ static afc_error_t afc_dispatch_packet(afc_client_t client, const char *data, ui *bytes_sent += sent; /* send AFC packet data (if there's data to send) */ if (length > 0) { - log_debug_msg("%s: packet data follows\n", __func__); + debug_info("packet data follows"); - log_debug_buffer(data, length); - log_debug_msg("\n"); + debug_buffer(data, length); iphone_device_send(client->connection, data, length, &sent); *bytes_sent += sent; } @@ -244,36 +244,36 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint3 iphone_device_recv(client->connection, (char*)&header, sizeof(AFCPacket), bytes_recv); AFCPacket_from_LE(&header); if (*bytes_recv == 0) { - log_debug_msg("%s: Just didn't get enough.\n", __func__); + debug_info("Just didn't get enough."); *dump_here = NULL; return AFC_E_MUX_ERROR; } else if (*bytes_recv < sizeof(AFCPacket)) { - log_debug_msg("%s: Did not even get the AFCPacket header\n", __func__); + debug_info("Did not even get the AFCPacket header"); *dump_here = NULL; return AFC_E_MUX_ERROR; } /* check if it's a valid AFC header */ if (strncmp(header.magic, AFC_MAGIC, AFC_MAGIC_LEN)) { - log_debug_msg("%s: Invalid AFC packet received (magic != " AFC_MAGIC ")!\n", __func__); + debug_info("Invalid AFC packet received (magic != " AFC_MAGIC ")!"); } /* check if it has the correct packet number */ if (header.packet_num != client->afc_packet->packet_num) { /* otherwise print a warning but do not abort */ - log_debug_msg("%s: ERROR: Unexpected packet number (%lld != %lld) aborting.\n", __func__, header.packet_num, client->afc_packet->packet_num); + debug_info("ERROR: Unexpected packet number (%lld != %lld) aborting.", header.packet_num, client->afc_packet->packet_num); *dump_here = NULL; return AFC_E_OP_HEADER_INVALID; } /* then, read the attached packet */ if (header.this_length < sizeof(AFCPacket)) { - log_debug_msg("%s: Invalid AFCPacket header received!\n", __func__); + debug_info("Invalid AFCPacket header received!"); *dump_here = NULL; return AFC_E_OP_HEADER_INVALID; } else if ((header.this_length == header.entire_length) && header.entire_length == sizeof(AFCPacket)) { - log_debug_msg("%s: Empty AFCPacket received!\n", __func__); + debug_info("Empty AFCPacket received!"); *dump_here = NULL; *bytes_recv = 0; if (header.operation == AFC_OP_DATA) { @@ -283,14 +283,14 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint3 } } - log_debug_msg("%s: received AFC packet, full len=%lld, this len=%lld, operation=0x%llx\n", __func__, header.entire_length, header.this_length, header.operation); + debug_info("received AFC packet, full len=%lld, this len=%lld, operation=0x%llx", header.entire_length, header.this_length, header.operation); entire_len = (uint32_t)header.entire_length - sizeof(AFCPacket); this_len = (uint32_t)header.this_length - sizeof(AFCPacket); /* this is here as a check (perhaps a different upper limit is good?) */ if (entire_len > (uint32_t)MAXIMUM_PACKET_SIZE) { - fprintf(stderr, "%s: entire_len is larger than MAXIMUM_PACKET_SIZE, (%d > %d)!\n", __func__, entire_len, MAXIMUM_PACKET_SIZE); + fprintf(stderr, "%s: entire_len is larger than MAXIMUM_PACKET_SIZE, (%d > %d)!", __func__, entire_len, MAXIMUM_PACKET_SIZE); } *dump_here = (char*)malloc(entire_len); @@ -299,12 +299,12 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint3 if (*bytes_recv <= 0) { free(*dump_here); *dump_here = NULL; - log_debug_msg("%s: Did not get packet contents!\n", __func__); + debug_info("Did not get packet contents!"); return AFC_E_NOT_ENOUGH_DATA; } else if (*bytes_recv < this_len) { free(*dump_here); *dump_here = NULL; - log_debug_msg("%s: Could not receive this_len=%d bytes\n", __func__, this_len); + debug_info("Could not receive this_len=%d bytes", this_len); return AFC_E_NOT_ENOUGH_DATA; } } @@ -315,13 +315,13 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint3 while (current_count < entire_len) { iphone_device_recv(client->connection, (*dump_here)+current_count, entire_len - current_count, bytes_recv); if (*bytes_recv <= 0) { - log_debug_msg("%s: Error receiving data (recv returned %d)\n", __func__, *bytes_recv); + debug_info("Error receiving data (recv returned %d)", *bytes_recv); break; } current_count += *bytes_recv; } if (current_count < entire_len) { - log_debug_msg("%s: WARNING: could not receive full packet (read %s, size %d)\n", __func__, current_count, entire_len); + debug_info("WARNING: could not receive full packet (read %s, size %d)", current_count, entire_len); } } @@ -329,14 +329,14 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint3 param1 = *(uint64_t*)(*dump_here); } - log_debug_msg("%s: packet data size = %i\n", __func__, current_count); - log_debug_msg("%s: packet data follows\n", __func__); - log_debug_buffer(*dump_here, current_count); + debug_info("packet data size = %i", current_count); + debug_info("packet data follows"); + debug_buffer(*dump_here, current_count); /* check operation types */ if (header.operation == AFC_OP_STATUS) { /* status response */ - log_debug_msg("%s: got a status response, code=%lld\n", __func__, param1); + debug_info("got a status response, code=%lld", param1); if (param1 != AFC_E_SUCCESS) { /* error status */ @@ -347,21 +347,21 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint3 } } else if (header.operation == AFC_OP_DATA) { /* data response */ - log_debug_msg("%s: got a data response\n", __func__); + debug_info("got a data response"); } else if (header.operation == AFC_OP_FILE_OPEN_RES) { /* file handle response */ - log_debug_msg("%s: got a file handle response, handle=%lld\n", __func__, param1); + debug_info("got a file handle response, handle=%lld", param1); } else if (header.operation == AFC_OP_FILE_TELL_RES) { /* tell response */ - log_debug_msg("%s: got a tell response, position=%lld\n", __func__, param1); + debug_info("got a tell response, position=%lld", param1); } else { /* unknown operation code received */ free(*dump_here); *dump_here = NULL; *bytes_recv = 0; - log_debug_msg("%s: WARNING: Unknown operation code received 0x%llx param1=%lld\n", __func__, header.operation, param1); - fprintf(stderr, "%s: WARNING: Unknown operation code received 0x%llx param1=%lld\n", __func__, (long long)header.operation, (long long)param1); + debug_info("WARNING: Unknown operation code received 0x%llx param1=%lld", header.operation, param1); + fprintf(stderr, "%s: WARNING: Unknown operation code received 0x%llx param1=%lld", __func__, (long long)header.operation, (long long)param1); return AFC_E_OP_NOT_SUPPORTED; } @@ -728,7 +728,7 @@ afc_file_open(afc_client_t client, const char *filename, free(data); if (ret != AFC_E_SUCCESS) { - log_debug_msg("%s: Didn't receive a response to the command\n", __func__); + debug_info("Didn't receive a response to the command"); afc_unlock(client); return AFC_E_NOT_ENOUGH_DATA; } @@ -743,7 +743,7 @@ afc_file_open(afc_client_t client, const char *filename, return ret; } - log_debug_msg("%s: Didn't get any further data\n", __func__); + debug_info("Didn't get any further data"); afc_unlock(client); @@ -770,14 +770,14 @@ afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length, if (!client || !client->afc_packet || !client->connection || handle == 0) return AFC_E_INVALID_ARGUMENT; - log_debug_msg("%s: called for length %i\n", __func__, length); + debug_info("called for length %i", length); afc_lock(client); // Looping here to get around the maximum amount of data that // afc_receive_data can handle while (current_count < length) { - log_debug_msg("%s: current count is %i but length is %i\n", __func__, current_count, length); + debug_info("current count is %i but length is %i", current_count, length); // Send the read command AFCFilePacket *packet = (AFCFilePacket *) malloc(sizeof(AFCFilePacket)); @@ -794,8 +794,8 @@ afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length, } // Receive the data ret = afc_receive_data(client, &input, &bytes_loc); - log_debug_msg("%s: afc_receive_data returned error: %d\n", __func__, ret); - log_debug_msg("%s: bytes returned: %i\n", __func__, bytes_loc); + debug_info("afc_receive_data returned error: %d", ret); + debug_info("bytes returned: %i", bytes_loc); if (ret != AFC_E_SUCCESS) { afc_unlock(client); return ret; @@ -808,7 +808,7 @@ afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length, return ret; } else { if (input) { - log_debug_msg("%s: %d\n", __func__, bytes_loc); + debug_info("%d", bytes_loc); memcpy(data + current_count, input, (bytes_loc > length) ? length : bytes_loc); free(input); input = NULL; @@ -816,7 +816,7 @@ afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length, } } } - log_debug_msg("%s: returning current_count as %i\n", __func__, current_count); + debug_info("returning current_count as %i", current_count); afc_unlock(client); *bytes_read = current_count; @@ -849,7 +849,7 @@ afc_file_write(afc_client_t client, uint64_t handle, const char *data, uint32_t afc_lock(client); - log_debug_msg("%s: Write length: %i\n", __func__, length); + debug_info("Write length: %i", length); // Divide the file into segments. for (i = 0; i < segments; i++) { @@ -909,7 +909,7 @@ afc_file_write(afc_client_t client, uint64_t handle, const char *data, uint32_t ret = afc_receive_data(client, &acknowledgement, &bytes_loc); afc_unlock(client); if (ret != AFC_E_SUCCESS) { - log_debug_msg("%s: uh oh?\n", __func__); + debug_info("uh oh?"); } else { free(acknowledgement); } @@ -933,7 +933,7 @@ afc_error_t afc_file_close(afc_client_t client, uint64_t handle) afc_lock(client); - log_debug_msg("%s: File handle %i\n", __func__, handle); + debug_info("File handle %i", handle); // Send command memcpy(buffer, &handle, sizeof(uint64_t)); @@ -981,7 +981,7 @@ afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t op afc_lock(client); - log_debug_msg("%s: file handle %i\n", __func__, handle); + debug_info("file handle %i", handle); // Send command memcpy(buffer, &handle, sizeof(uint64_t)); @@ -995,13 +995,13 @@ afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t op if (ret != AFC_E_SUCCESS) { afc_unlock(client); - log_debug_msg("%s: could not send lock command\n", __func__); + debug_info("could not send lock command"); return AFC_E_UNKNOWN_ERROR; } // Receive the response ret = afc_receive_data(client, &buffer, &bytes); if (buffer) { - log_debug_buffer(buffer, bytes); + debug_buffer(buffer, bytes); free(buffer); } afc_unlock(client); @@ -1214,9 +1214,9 @@ afc_error_t afc_make_link(afc_client_t client, afc_link_type_t linktype, const c afc_lock(client); - log_debug_msg("%s: link type: %lld\n", __func__, type); - log_debug_msg("%s: target: %s, length:%d\n", __func__, target, strlen(target)); - log_debug_msg("%s: linkname: %s, length:%d\n", __func__, linkname, strlen(linkname)); + debug_info("link type: %lld", type); + debug_info("target: %s, length:%d", target, strlen(target)); + debug_info("linkname: %s, length:%d", linkname, strlen(linkname)); // Send command memcpy(send, &type, 8); diff --git a/src/InstallationProxy.c b/src/InstallationProxy.c index 387f9ca..9ada994 100644 --- a/src/InstallationProxy.c +++ b/src/InstallationProxy.c @@ -26,8 +26,8 @@ #include <plist/plist.h> #include "InstallationProxy.h" -#include "iphone.h" -#include "utils.h" +#include "property_list_service.h" +#include "debug.h" struct instproxy_status_data { instproxy_client_t client; @@ -41,7 +41,7 @@ struct instproxy_status_data { */ static void instproxy_lock(instproxy_client_t client) { - log_debug_msg("InstallationProxy: Locked\n"); + debug_info("InstallationProxy: Locked"); g_mutex_lock(client->mutex); } @@ -51,29 +51,30 @@ static void instproxy_lock(instproxy_client_t client) */ static void instproxy_unlock(instproxy_client_t client) { - log_debug_msg("InstallationProxy: Unlocked\n"); + debug_info("InstallationProxy: Unlocked"); g_mutex_unlock(client->mutex); } /** - * Convert an iphone_error_t value to an instproxy_error_t value. - * Used internally to get correct error codes when using plist helper - * functions. + * Convert a property_list_service_error_t value to an instproxy_error_t value. + * Used internally to get correct error codes. * - * @param err An iphone_error_t error code + * @param err A property_list_service_error_t error code * * @return A matching instproxy_error_t error code, * INSTPROXY_E_UNKNOWN_ERROR otherwise. */ -static instproxy_error_t iphone_to_instproxy_error(iphone_error_t err) +static instproxy_error_t instproxy_error(property_list_service_error_t err) { switch (err) { - case IPHONE_E_SUCCESS: + case PROPERTY_LIST_SERVICE_E_SUCCESS: return INSTPROXY_E_SUCCESS; - case IPHONE_E_INVALID_ARG: + case PROPERTY_LIST_SERVICE_E_INVALID_ARG: return INSTPROXY_E_INVALID_ARG; - case IPHONE_E_PLIST_ERROR: + case PROPERTY_LIST_SERVICE_E_PLIST_ERROR: return INSTPROXY_E_PLIST_ERROR; + case PROPERTY_LIST_SERVICE_E_MUX_ERROR: + return INSTPROXY_E_CONN_FAILED; default: break; } @@ -84,14 +85,14 @@ static instproxy_error_t iphone_to_instproxy_error(iphone_error_t err) * Creates a new installation_proxy client * * @param device The device to connect to - * @param dst_port Destination port (usually given by lockdownd_start_service). + * @param port Destination port (usually given by lockdownd_start_service). * @param client Pointer that will be set to a newly allocated * instproxy_client_t upon successful return. * * @return INSTPROXY_E_SUCCESS on success, or an INSTPROXY_E_* error value * when an error occured. */ -instproxy_error_t instproxy_client_new(iphone_device_t device, int dst_port, instproxy_client_t *client) +instproxy_error_t instproxy_client_new(iphone_device_t device, uint16_t port, instproxy_client_t *client) { /* makes sure thread environment is available */ if (!g_thread_supported()) @@ -100,14 +101,13 @@ instproxy_error_t instproxy_client_new(iphone_device_t device, int dst_port, ins if (!device) return INSTPROXY_E_INVALID_ARG; - /* Attempt connection */ - iphone_connection_t connection = NULL; - if (iphone_device_connect(device, dst_port, &connection) != IPHONE_E_SUCCESS) { + property_list_service_client_t plistclient = NULL; + if (property_list_service_client_new(device, port, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) { return INSTPROXY_E_CONN_FAILED; } instproxy_client_t client_loc = (instproxy_client_t) malloc(sizeof(struct instproxy_client_int)); - client_loc->connection = connection; + client_loc->parent = plistclient; client_loc->mutex = g_mutex_new(); client_loc->status_updater = NULL; @@ -128,10 +128,10 @@ instproxy_error_t instproxy_client_free(instproxy_client_t client) if (!client) return INSTPROXY_E_INVALID_ARG; - iphone_device_disconnect(client->connection); - client->connection = NULL; + property_list_service_client_free(client->parent); + client->parent = NULL; if (client->status_updater) { - log_dbg_msg(DBGMASK_INSTPROXY, "joining status_updater"); + debug_info("joining status_updater"); g_thread_join(client->status_updater); } if (client->mutex) { @@ -155,7 +155,7 @@ instproxy_error_t instproxy_client_free(instproxy_client_t client) */ instproxy_error_t instproxy_browse(instproxy_client_t client, instproxy_apptype_t apptype, plist_t *result) { - if (!client || !client->connection || !result) + if (!client || !client->parent || !result) return INSTPROXY_E_INVALID_ARG; instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; @@ -174,7 +174,7 @@ instproxy_error_t instproxy_browse(instproxy_client_t client, instproxy_apptype_ p_apptype = plist_new_string("User"); break; default: - log_dbg_msg(DBGMASK_INSTPROXY, "%s: unknown apptype %d given, using INSTPROXY_APPTYPE_USER instead\n", __func__, apptype); + debug_info("unknown apptype %d given, using INSTPROXY_APPTYPE_USER instead", apptype); p_apptype = plist_new_string("User"); break; } @@ -184,10 +184,10 @@ instproxy_error_t instproxy_browse(instproxy_client_t client, instproxy_apptype_ plist_dict_insert_item(dict, "Command", plist_new_string("Browse")); instproxy_lock(client); - res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); + res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict)); plist_free(dict); if (res != INSTPROXY_E_SUCCESS) { - log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not send plist\n", __func__); + debug_info("could not send plist"); goto leave_unlock; } @@ -196,7 +196,7 @@ instproxy_error_t instproxy_browse(instproxy_client_t client, instproxy_apptype_ do { browsing = 0; dict = NULL; - res = iphone_to_instproxy_error(iphone_device_receive_plist(client->connection, &dict)); + res = instproxy_error(property_list_service_receive_plist(client->parent, &dict)); if (res != INSTPROXY_E_SUCCESS) { break; } @@ -223,7 +223,7 @@ instproxy_error_t instproxy_browse(instproxy_client_t client, instproxy_apptype_ if (!strcmp(status, "BrowsingApplications")) { browsing = 1; } else if (!strcmp(status, "Complete")) { - log_dbg_msg(DBGMASK_INSTPROXY, "%s: Browsing applications completed\n"); + debug_info("Browsing applications completed"); res = INSTPROXY_E_SUCCESS; } free(status); @@ -261,10 +261,10 @@ static instproxy_error_t instproxy_perform_operation(instproxy_client_t client, do { instproxy_lock(client); - res = iphone_to_instproxy_error(iphone_device_receive_plist_with_timeout(client->connection, &dict, 30000)); + res = instproxy_error(property_list_service_receive_plist_with_timeout(client->parent, &dict, 30000)); instproxy_unlock(client); if (res != INSTPROXY_E_SUCCESS) { - log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not receive plist, error %d\n", __func__, res); + debug_info("could not receive plist, error %d", res); break; } if (dict) { @@ -279,7 +279,7 @@ static instproxy_error_t instproxy_perform_operation(instproxy_client_t client, char *err_msg = NULL; plist_get_string_val(err, &err_msg); if (err_msg) { - log_dbg_msg(DBGMASK_INSTPROXY, "%s(%s): ERROR: %s\n", __func__, operation, err_msg); + debug_info("(%s): ERROR: %s", operation, err_msg); free(err_msg); } #endif @@ -303,9 +303,9 @@ static instproxy_error_t instproxy_perform_operation(instproxy_client_t client, int percent; plist_get_uint_val(npercent, &val); percent = val; - log_dbg_msg(DBGMASK_INSTPROXY, "%s(%s): %s (%d%%)\n", __func__, operation, status_msg, percent); + debug_info("(%s): %s (%d%%)", operation, status_msg, percent); } else { - log_dbg_msg(DBGMASK_INSTPROXY, "%s(%s): %s\n", __func__, operation, status_msg); + debug_info("(%s): %s", operation, status_msg); } #endif free(status_msg); @@ -314,7 +314,7 @@ static instproxy_error_t instproxy_perform_operation(instproxy_client_t client, plist_free(dict); dict = NULL; } - } while (ok && client->connection); + } while (ok && client->parent); return res; } @@ -338,7 +338,7 @@ static gpointer instproxy_status_updater(gpointer arg) /* cleanup */ instproxy_lock(data->client); - log_dbg_msg(DBGMASK_INSTPROXY, "%s: done, cleaning up.\n", __func__); + debug_info("done, cleaning up."); if (data->operation) { free(data->operation); } @@ -404,15 +404,15 @@ static instproxy_error_t instproxy_create_status_updater(instproxy_client_t clie */ static instproxy_error_t instproxy_install_or_upgrade(instproxy_client_t client, const char *pkg_path, plist_t sinf, plist_t metadata, instproxy_status_cb_t status_cb, const char *command) { - if (!client || !client->connection || !pkg_path) { + if (!client || !client->parent || !pkg_path) { return INSTPROXY_E_INVALID_ARG; } if (sinf && (plist_get_node_type(sinf) != PLIST_DATA)) { - log_dbg_msg(DBGMASK_INSTPROXY, "%s(%s): ERROR: sinf data is not a PLIST_DATA node!\n", __func__, command); + debug_info("(%s): ERROR: sinf data is not a PLIST_DATA node!", command); return INSTPROXY_E_INVALID_ARG; } if (metadata && (plist_get_node_type(metadata) != PLIST_DATA)) { - log_dbg_msg(DBGMASK_INSTPROXY, "%s(%s): ERROR: metadata is not a PLIST_DATA node!\n", __func__, command); + debug_info("(%s): ERROR: metadata is not a PLIST_DATA node!", command); return INSTPROXY_E_INVALID_ARG; } @@ -433,13 +433,13 @@ static instproxy_error_t instproxy_install_or_upgrade(instproxy_client_t client, plist_dict_insert_item(dict, "PackagePath", plist_new_string(pkg_path)); instproxy_lock(client); - res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); + res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict)); instproxy_unlock(client); plist_free(dict); if (res != INSTPROXY_E_SUCCESS) { - log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not send plist, error %d\n", __func__, res); + debug_info("could not send plist, error %d", res); return res; } @@ -512,7 +512,7 @@ instproxy_error_t instproxy_upgrade(instproxy_client_t client, const char *pkg_p */ instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *appid, instproxy_status_cb_t status_cb) { - if (!client || !client->connection || !appid) { + if (!client || !client->parent || !appid) { return INSTPROXY_E_INVALID_ARG; } @@ -526,13 +526,13 @@ instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *app plist_dict_insert_item(dict, "Command", plist_new_string("Uninstall")); instproxy_lock(client); - res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); + res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict)); instproxy_unlock(client); plist_free(dict); if (res != INSTPROXY_E_SUCCESS) { - log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not send plist, error %d\n", __func__, res); + debug_info("could not send plist, error %d", res); return res; } @@ -553,7 +553,7 @@ instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *app */ instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist_t *result) { - if (!client || !client->connection || !result) + if (!client || !client->parent || !result) return INSTPROXY_E_INVALID_ARG; instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; @@ -563,17 +563,17 @@ instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist_t * instproxy_lock(client); - res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); + res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict)); plist_free(dict); if (res != INSTPROXY_E_SUCCESS) { - log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not send plist, error %d\n", __func__, res); + debug_info("could not send plist, error %d", res); goto leave_unlock; } - res = iphone_to_instproxy_error(iphone_device_receive_plist(client->connection, result)); + res = instproxy_error(property_list_service_receive_plist(client->parent, result)); if (res != INSTPROXY_E_SUCCESS) { - log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not receive plist, error %d\n", __func__, res); + debug_info("could not receive plist, error %d", res); goto leave_unlock; } @@ -610,7 +610,7 @@ leave_unlock: */ instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid, uint32_t options, instproxy_status_cb_t status_cb) { - if (!client || !client->connection || !appid) + if (!client || !client->parent || !appid) return INSTPROXY_E_INVALID_ARG; if (client->status_updater) { @@ -634,13 +634,13 @@ instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid plist_dict_insert_item(dict, "Command", plist_new_string("Archive")); instproxy_lock(client); - res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); + res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict)); instproxy_unlock(client); plist_free(dict); if (res != INSTPROXY_E_SUCCESS) { - log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not send plist, error %d\n", __func__, res); + debug_info("could not send plist, error %d", res); return res; } return instproxy_create_status_updater(client, status_cb, "Archive"); @@ -666,7 +666,7 @@ instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid */ instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid, instproxy_status_cb_t status_cb) { - if (!client || !client->connection || !appid) + if (!client || !client->parent || !appid) return INSTPROXY_E_INVALID_ARG; if (client->status_updater) { @@ -680,13 +680,13 @@ instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid plist_dict_insert_item(dict, "Command", plist_new_string("Restore")); instproxy_lock(client); - res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); + res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict)); instproxy_unlock(client); plist_free(dict); if (res != INSTPROXY_E_SUCCESS) { - log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not send plist, error %d\n", __func__, res); + debug_info("could not send plist, error %d", res); return res; } return instproxy_create_status_updater(client, status_cb, "Restore"); @@ -712,7 +712,7 @@ instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid */ instproxy_error_t instproxy_remove_archive(instproxy_client_t client, const char *appid, instproxy_status_cb_t status_cb) { - if (!client || !client->connection || !appid) + if (!client || !client->parent || !appid) return INSTPROXY_E_INVALID_ARG; if (client->status_updater) { @@ -726,13 +726,13 @@ instproxy_error_t instproxy_remove_archive(instproxy_client_t client, const char plist_dict_insert_item(dict, "Command", plist_new_string("RemoveArchive")); instproxy_lock(client); - res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); + res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict)); instproxy_unlock(client); plist_free(dict); if (res != INSTPROXY_E_SUCCESS) { - log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not send plist, error %d\n", __func__, res); + debug_info("could not send plist, error %d", res); return res; } return instproxy_create_status_updater(client, status_cb, "RemoveArchive"); diff --git a/src/InstallationProxy.h b/src/InstallationProxy.h index c8c5ef1..f0b5691 100644 --- a/src/InstallationProxy.h +++ b/src/InstallationProxy.h @@ -24,9 +24,10 @@ #include <glib.h> #include "libiphone/installation_proxy.h" +#include "property_list_service.h" struct instproxy_client_int { - iphone_connection_t connection; + property_list_service_client_t parent; GMutex *mutex; GThread *status_updater; }; diff --git a/src/Makefile.am b/src/Makefile.am index 9b42f1c..bb7252e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,11 +5,13 @@ AM_LDFLAGS = $(libglib2_LIBS) $(libgnutls_LIBS) $(libtasn1_LIBS) $(libgthread2_L lib_LTLIBRARIES = libiphone.la libiphone_la_SOURCES = iphone.c iphone.h \ + property_list_service.c property_list_service.h\ + device_link_service.c device_link_service.h\ lockdown.c lockdown.h\ AFC.c AFC.h\ NotificationProxy.c NotificationProxy.h\ InstallationProxy.c InstallationProxy.h\ SBServices.c SBServices.h\ userpref.c userpref.h\ - utils.c utils.h\ + debug.c debug.h\ MobileSync.c MobileSync.h diff --git a/src/MobileSync.c b/src/MobileSync.c index 76aefa0..827ed35 100644 --- a/src/MobileSync.c +++ b/src/MobileSync.c @@ -25,153 +25,76 @@ #include <arpa/inet.h> #include "MobileSync.h" -#include "iphone.h" -#include "utils.h" +#include "device_link_service.h" +#include "debug.h" #define MSYNC_VERSION_INT1 100 #define MSYNC_VERSION_INT2 100 /** - * Convert an iphone_error_t value to an mobilesync_error_t value. - * Used internally to get correct error codes when using plist helper - * functions. + * Convert an device_link_service_error_t value to an mobilesync_error_t value. + * Used internally to get correct error codes when using device_link_service stuff. * - * @param err An iphone_error_t error code + * @param err An device_link_service_error_t error code * * @return A matching mobilesync_error_t error code, * MOBILESYNC_E_UNKNOWN_ERROR otherwise. */ -static mobilesync_error_t iphone_to_mobilesync_error(iphone_error_t err) +static mobilesync_error_t mobilesync_error(device_link_service_error_t err) { switch (err) { - case IPHONE_E_SUCCESS: + case DEVICE_LINK_SERVICE_E_SUCCESS: return MOBILESYNC_E_SUCCESS; - case IPHONE_E_INVALID_ARG: + case DEVICE_LINK_SERVICE_E_INVALID_ARG: return MOBILESYNC_E_INVALID_ARG; - case IPHONE_E_PLIST_ERROR: + case DEVICE_LINK_SERVICE_E_PLIST_ERROR: return MOBILESYNC_E_PLIST_ERROR; + case DEVICE_LINK_SERVICE_E_MUX_ERROR: + return MOBILESYNC_E_MUX_ERROR; + case DEVICE_LINK_SERVICE_E_BAD_VERSION: + return MOBILESYNC_E_BAD_VERSION; default: break; } return MOBILESYNC_E_UNKNOWN_ERROR; } -mobilesync_error_t mobilesync_client_new(iphone_device_t device, int dst_port, +mobilesync_error_t mobilesync_client_new(iphone_device_t device, uint16_t port, mobilesync_client_t * client) { - if (!device || dst_port == 0 || !client || *client) + if (!device || port == 0 || !client || *client) return MOBILESYNC_E_INVALID_ARG; - mobilesync_error_t ret = MOBILESYNC_E_UNKNOWN_ERROR; - - /* Attempt connection */ - iphone_connection_t connection = NULL; - if (iphone_device_connect(device, dst_port, &connection) != IPHONE_E_SUCCESS) { + device_link_service_client_t dlclient = NULL; + mobilesync_error_t ret = mobilesync_error(device_link_service_client_new(device, port, &dlclient)); + if (ret != MOBILESYNC_E_SUCCESS) { return ret; } mobilesync_client_t client_loc = (mobilesync_client_t) malloc(sizeof(struct mobilesync_client_int)); - client_loc->connection = connection; + client_loc->parent = dlclient; /* perform handshake */ - plist_t array = NULL; - - /* first receive version */ - ret = mobilesync_recv(client_loc, &array); - - plist_t msg_node = plist_array_get_item(array, 0); - - char* msg = NULL; - plist_type type = plist_get_node_type(msg_node); - if (PLIST_STRING == type) { - plist_get_string_val(msg_node, &msg); - } - if (PLIST_STRING != type || strcmp(msg, "DLMessageVersionExchange") || plist_array_get_size(array) < 3) { - log_debug_msg("%s: ERROR: MobileSync client expected a version exchange !\n", __func__); - } - free(msg); - msg = NULL; - - plist_t ver_1 = plist_array_get_item(array, 1); - plist_t ver_2 = plist_array_get_item(array, 2); - - plist_type ver_1_type = plist_get_node_type(ver_1); - plist_type ver_2_type = plist_get_node_type(ver_2); - - if (PLIST_UINT == ver_1_type && PLIST_UINT == ver_2_type) { - - uint64_t ver_1_val = 0; - uint64_t ver_2_val = 0; - - plist_get_uint_val(ver_1, &ver_1_val); - plist_get_uint_val(ver_2, &ver_2_val); - - plist_free(array); - array = NULL; - - if (ver_1_type == PLIST_UINT && ver_2_type == PLIST_UINT && ver_1_val == MSYNC_VERSION_INT1 - && ver_2_val == MSYNC_VERSION_INT2) { - - array = plist_new_array(); - plist_array_append_item(array, plist_new_string("DLMessageVersionExchange")); - plist_array_append_item(array, plist_new_string("DLVersionsOk")); - - ret = mobilesync_send(client_loc, array); - - plist_free(array); - array = NULL; - - ret = mobilesync_recv(client_loc, &array); - plist_t rep_node = plist_array_get_item(array, 0); - - type = plist_get_node_type(rep_node); - if (PLIST_STRING == type) { - plist_get_string_val(rep_node, &msg); - } - if (PLIST_STRING != type || strcmp(msg, "DLMessageDeviceReady")) { - log_debug_msg("%s: ERROR: MobileSync client failed to start session !\n", __func__); - ret = MOBILESYNC_E_BAD_VERSION; - } - else - { - ret = MOBILESYNC_E_SUCCESS; - *client = client_loc; - } - free(msg); - msg = NULL; - - plist_free(array); - array = NULL; - } + ret = mobilesync_error(device_link_service_version_exchange(dlclient, MSYNC_VERSION_INT1, MSYNC_VERSION_INT2)); + if (ret != MOBILESYNC_E_SUCCESS) { + debug_info("version exchange failed, error %d", ret); + mobilesync_client_free(client_loc); + return ret; } - if (MOBILESYNC_E_SUCCESS != ret) - mobilesync_client_free(client_loc); + *client = client_loc; return ret; } -static void mobilesync_disconnect(mobilesync_client_t client) -{ - if (!client) - return; - - plist_t array = plist_new_array(); - plist_array_append_item(array, plist_new_string("DLMessageDisconnect")); - plist_array_append_item(array, plist_new_string("All done, thanks for the memories")); - - mobilesync_send(client, array); - plist_free(array); - array = NULL; -} - mobilesync_error_t mobilesync_client_free(mobilesync_client_t client) { if (!client) - return IPHONE_E_INVALID_ARG; - - mobilesync_disconnect(client); - return (iphone_device_disconnect(client->connection) == 0 ? MOBILESYNC_E_SUCCESS: MOBILESYNC_E_MUX_ERROR); + return MOBILESYNC_E_INVALID_ARG; + device_link_service_disconnect(client->parent); + mobilesync_error_t err = mobilesync_error(device_link_service_client_free(client->parent)); + free(client); + return err; } /** Polls the iPhone for MobileSync data. @@ -183,19 +106,17 @@ mobilesync_error_t mobilesync_client_free(mobilesync_client_t client) */ mobilesync_error_t mobilesync_recv(mobilesync_client_t client, plist_t * plist) { - if (!client || !plist || (plist && *plist)) + if (!client) return MOBILESYNC_E_INVALID_ARG; - - mobilesync_error_t ret = iphone_to_mobilesync_error(iphone_device_receive_plist(client->connection, plist)); + mobilesync_error_t ret = mobilesync_error(device_link_service_receive(client->parent, plist)); +#ifndef STRIP_DEBUG_CODE if (ret != MOBILESYNC_E_SUCCESS) { - return MOBILESYNC_E_MUX_ERROR; + return ret; } - -#ifndef STRIP_DEBUG_CODE char *XMLContent = NULL; uint32_t length = 0; plist_to_xml(*plist, &XMLContent, &length); - log_dbg_msg(DBGMASK_MOBILESYNC, "%s: plist size: %i\nbuffer :\n%s\n", __func__, length, XMLContent); + debug_info("plist size: %i\nbuffer :\n%s", length, XMLContent); free(XMLContent); #endif return ret; @@ -220,8 +141,8 @@ mobilesync_error_t mobilesync_send(mobilesync_client_t client, plist_t plist) char *XMLContent = NULL; uint32_t length = 0; plist_to_xml(plist, &XMLContent, &length); - log_dbg_msg(DBGMASK_MOBILESYNC, "%s: plist size: %i\nbuffer :\n%s\n", __func__, length, XMLContent); + debug_info("plist size: %i\nbuffer :\n%s", length, XMLContent); free(XMLContent); #endif - return (iphone_device_send_binary_plist(client->connection, plist) == IPHONE_E_SUCCESS ? MOBILESYNC_E_SUCCESS : MOBILESYNC_E_MUX_ERROR); + return mobilesync_error(device_link_service_send(client->parent, plist)); } diff --git a/src/MobileSync.h b/src/MobileSync.h index 605145f..6538343 100644 --- a/src/MobileSync.h +++ b/src/MobileSync.h @@ -22,9 +22,10 @@ #define MOBILESYNC_H #include "libiphone/mobilesync.h" +#include "device_link_service.h" struct mobilesync_client_int { - iphone_connection_t connection; + device_link_service_client_t parent; }; #endif diff --git a/src/NotificationProxy.c b/src/NotificationProxy.c index e2c1faa..e994c16 100644 --- a/src/NotificationProxy.c +++ b/src/NotificationProxy.c @@ -27,8 +27,8 @@ #include <plist/plist.h> #include "NotificationProxy.h" -#include "iphone.h" -#include "utils.h" +#include "property_list_service.h" +#include "debug.h" struct np_thread { np_client_t client; @@ -41,7 +41,7 @@ struct np_thread { */ static void np_lock(np_client_t client) { - log_debug_msg("NP: Locked\n"); + debug_info("NP: Locked"); g_mutex_lock(client->mutex); } @@ -51,29 +51,30 @@ static void np_lock(np_client_t client) */ static void np_unlock(np_client_t client) { - log_debug_msg("NP: Unlocked\n"); + debug_info("NP: Unlocked"); g_mutex_unlock(client->mutex); } /** - * Convert an iphone_error_t value to an np_error_t value. - * Used internally to get correct error codes when using plist helper - * functions. + * Convert a property_list_service_error_t value to an np_error_t value. + * Used internally to get correct error codes. * - * @param err An iphone_error_t error code + * @param err A property_list_service_error_t error code * * @return A matching np_error_t error code, * NP_E_UNKNOWN_ERROR otherwise. */ -static np_error_t iphone_to_np_error(iphone_error_t err) +static np_error_t np_error(property_list_service_error_t err) { switch (err) { - case IPHONE_E_SUCCESS: + case PROPERTY_LIST_SERVICE_E_SUCCESS: return NP_E_SUCCESS; - case IPHONE_E_INVALID_ARG: + case PROPERTY_LIST_SERVICE_E_INVALID_ARG: return NP_E_INVALID_ARG; - case IPHONE_E_PLIST_ERROR: + case PROPERTY_LIST_SERVICE_E_PLIST_ERROR: return NP_E_PLIST_ERROR; + case PROPERTY_LIST_SERVICE_E_MUX_ERROR: + return NP_E_CONN_FAILED; default: break; } @@ -83,7 +84,7 @@ static np_error_t iphone_to_np_error(iphone_error_t err) /** Makes a connection to the NP service on the phone. * * @param device The device to connect to. - * @param dst_port Destination port (usually given by lockdownd_start_service). + * @param port Destination port (usually given by lockdownd_start_service). * @param client Pointer that will be set to a newly allocated np_client_t * upon successful return. * @@ -91,7 +92,7 @@ static np_error_t iphone_to_np_error(iphone_error_t err) * or NP_E_CONN_FAILED when the connection to the device could not be * established. */ -np_error_t np_client_new(iphone_device_t device, int dst_port, np_client_t *client) +np_error_t np_client_new(iphone_device_t device, uint16_t port, np_client_t *client) { /* makes sure thread environment is available */ if (!g_thread_supported()) @@ -100,14 +101,13 @@ np_error_t np_client_new(iphone_device_t device, int dst_port, np_client_t *clie if (!device) return NP_E_INVALID_ARG; - /* Attempt connection */ - iphone_connection_t connection = NULL; - if (iphone_device_connect(device, dst_port, &connection) != IPHONE_E_SUCCESS) { + property_list_service_client_t plistclient = NULL; + if (property_list_service_client_new(device, port, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) { return NP_E_CONN_FAILED; } np_client_t client_loc = (np_client_t) malloc(sizeof(struct np_client_int)); - client_loc->connection = connection; + client_loc->parent = plistclient; client_loc->mutex = g_mutex_new(); @@ -128,10 +128,10 @@ np_error_t np_client_free(np_client_t client) if (!client) return NP_E_INVALID_ARG; - iphone_device_disconnect(client->connection); - client->connection = NULL; + property_list_service_client_free(client->parent); + client->parent = NULL; if (client->notifier) { - log_debug_msg("joining np callback\n"); + debug_info("joining np callback"); g_thread_join(client->notifier); } if (client->mutex) { @@ -144,10 +144,6 @@ np_error_t np_client_free(np_client_t client) /** Sends a notification to the device's Notification Proxy. * - * notification messages seen so far: - * com.apple.itunes-mobdev.syncWillStart - * com.apple.itunes-mobdev.syncDidStart - * * @param client The client to send to * @param notification The notification message to send * @@ -164,17 +160,17 @@ np_error_t np_post_notification(np_client_t client, const char *notification) plist_dict_insert_item(dict,"Command", plist_new_string("PostNotification")); plist_dict_insert_item(dict,"Name", plist_new_string(notification)); - np_error_t res = iphone_to_np_error(iphone_device_send_xml_plist(client->connection, dict)); + np_error_t res = np_error(property_list_service_send_xml_plist(client->parent, dict)); plist_free(dict); dict = plist_new_dict(); plist_dict_insert_item(dict,"Command", plist_new_string("Shutdown")); - res = iphone_to_np_error(iphone_device_send_xml_plist(client->connection, dict)); + res = np_error(property_list_service_send_xml_plist(client->parent, dict)); plist_free(dict); if (res != NP_E_SUCCESS) { - log_debug_msg("%s: Error sending XML plist to device!\n", __func__); + debug_info("Error sending XML plist to device!"); } np_unlock(client); @@ -200,9 +196,9 @@ np_error_t np_observe_notification( np_client_t client, const char *notification plist_dict_insert_item(dict,"Command", plist_new_string("ObserveNotification")); plist_dict_insert_item(dict,"Name", plist_new_string(notification)); - np_error_t res = iphone_to_np_error(iphone_device_send_xml_plist(client->connection, dict)); + np_error_t res = np_error(property_list_service_send_xml_plist(client->parent, dict)); if (res != NP_E_SUCCESS) { - log_debug_msg("%s: Error sending XML plist to device!\n", __func__); + debug_info("Error sending XML plist to device!"); } plist_free(dict); @@ -212,22 +208,10 @@ np_error_t np_observe_notification( np_client_t client, const char *notification /** Notifies the iphone to send a notification on specified events. * - * observation messages seen so far: - * com.apple.itunes-client.syncCancelRequest - * com.apple.itunes-client.syncSuspendRequest - * com.apple.itunes-client.syncResumeRequest - * com.apple.mobile.lockdown.phone_number_changed - * com.apple.mobile.lockdown.device_name_changed - * com.apple.springboard.attemptactivation - * com.apple.mobile.data_sync.domain_changed - * com.apple.mobile.application_installed - * com.apple.mobile.application_uninstalled - * * @param client The client to send to * @param notification_spec Specification of the notifications that should be * observed. This is expected to be an array of const char* that MUST have a - * terminating NULL entry. However this parameter can be NULL; in this case, - * the default set of notifications will be used. + * terminating NULL entry. * * @return NP_E_SUCCESS on success, NP_E_INVALID_ARG when client is null, * or an error returned by np_observe_notification. @@ -243,7 +227,7 @@ np_error_t np_observe_notifications(np_client_t client, const char **notificatio } if (!notifications) { - notifications = np_default_notifications; + return NP_E_INVALID_ARG; } while (notifications[i]) { @@ -275,14 +259,14 @@ static int np_get_notification(np_client_t client, char **notification) int res = 0; plist_t dict = NULL; - if (!client || !client->connection || *notification) + if (!client || !client->parent || *notification) return -1; np_lock(client); - iphone_device_receive_plist_with_timeout(client->connection, &dict, 500); + property_list_service_receive_plist_with_timeout(client->parent, &dict, 500); if (!dict) { - log_debug_msg("NotificationProxy: no notification received!\n"); + debug_info("NotificationProxy: no notification received!"); res = 0; } else { char *cmd_value = NULL; @@ -303,14 +287,14 @@ static int np_get_notification(np_client_t client, char **notification) res = -2; if (name_value_node && name_value) { *notification = name_value; - log_debug_msg("%s: got notification %s\n", __func__, name_value); + debug_info("got notification %s\n", __func__, name_value); res = 0; } } else if (cmd_value && !strcmp(cmd_value, "ProxyDeath")) { - log_debug_msg("%s: ERROR: NotificationProxy died!\n", __func__); + debug_info("ERROR: NotificationProxy died!"); res = -1; } else if (cmd_value) { - log_debug_msg("%d: unknown NotificationProxy command '%s' received!\n", __func__); + debug_info("unknown NotificationProxy command '%s' received!", cmd_value); res = -1; } else { res = -2; @@ -337,8 +321,8 @@ gpointer np_notifier( gpointer arg ) if (!npt) return NULL; - log_debug_msg("%s: starting callback.\n", __func__); - while (npt->client->connection) { + debug_info("starting callback."); + while (npt->client->parent) { np_get_notification(npt->client, ¬ification); if (notification) { npt->cbfunc(notification); @@ -380,12 +364,12 @@ np_error_t np_set_notify_callback( np_client_t client, np_notify_cb_t notify_cb np_lock(client); if (client->notifier) { - log_debug_msg("%s: callback already set, removing\n"); - iphone_connection_t conn = client->connection; - client->connection = NULL; + debug_info("callback already set, removing\n"); + property_list_service_client_t parent = client->parent; + client->parent = NULL; g_thread_join(client->notifier); client->notifier = NULL; - client->connection = conn; + client->parent = parent; } if (notify_cb) { @@ -400,7 +384,7 @@ np_error_t np_set_notify_callback( np_client_t client, np_notify_cb_t notify_cb } } } else { - log_debug_msg("%s: no callback set\n", __func__); + debug_info("no callback set"); } np_unlock(client); diff --git a/src/NotificationProxy.h b/src/NotificationProxy.h index 84f1f89..a2b3001 100644 --- a/src/NotificationProxy.h +++ b/src/NotificationProxy.h @@ -24,27 +24,14 @@ #include <glib.h> #include "libiphone/notification_proxy.h" +#include "property_list_service.h" struct np_client_int { - iphone_connection_t connection; + property_list_service_client_t parent; GMutex *mutex; GThread *notifier; }; -static const char *np_default_notifications[11] = { - NP_SYNC_SUSPEND_REQUEST, - NP_SYNC_RESUME_REQUEST, - NP_PHONE_NUMBER_CHANGED, - NP_SYNC_CANCEL_REQUEST, - NP_DEVICE_NAME_CHANGED, - NP_ATTEMPTACTIVATION, - NP_DS_DOMAIN_CHANGED, - NP_APP_INSTALLED, - NP_APP_UNINSTALLED, - NP_ITDBPREP_DID_END, - NULL -}; - gpointer np_notifier(gpointer arg); #endif diff --git a/src/SBServices.c b/src/SBServices.c index 1296245..69c7425 100644 --- a/src/SBServices.c +++ b/src/SBServices.c @@ -26,8 +26,8 @@ #include <plist/plist.h> #include "SBServices.h" -#include "iphone.h" -#include "utils.h" +#include "property_list_service.h" +#include "debug.h" /** Locks an sbservices client, done for thread safety stuff. * @@ -35,7 +35,7 @@ */ static void sbs_lock(sbservices_client_t client) { - log_debug_msg("SBServices: Locked\n"); + debug_info("SBServices: Locked"); g_mutex_lock(client->mutex); } @@ -45,11 +45,48 @@ static void sbs_lock(sbservices_client_t client) */ static void sbs_unlock(sbservices_client_t client) { - log_debug_msg("SBServices: Unlocked\n"); + debug_info("SBServices: Unlocked"); g_mutex_unlock(client->mutex); } -sbservices_error_t sbservices_client_new(iphone_device_t device, int dst_port, sbservices_client_t *client) +/** + * Convert a property_list_service_error_t value to a sbservices_error_t value. + * Used internally to get correct error codes. + * + * @param err A property_list_service_error_t error code + * + * @return A matching sbservices_error_t error code, + * SBSERVICES_E_UNKNOWN_ERROR otherwise. + */ +static sbservices_error_t sbservices_error(property_list_service_error_t err) +{ + switch (err) { + case PROPERTY_LIST_SERVICE_E_SUCCESS: + return SBSERVICES_E_SUCCESS; + case PROPERTY_LIST_SERVICE_E_INVALID_ARG: + return SBSERVICES_E_INVALID_ARG; + case PROPERTY_LIST_SERVICE_E_PLIST_ERROR: + return SBSERVICES_E_PLIST_ERROR; + case PROPERTY_LIST_SERVICE_E_MUX_ERROR: + return SBSERVICES_E_CONN_FAILED; + default: + break; + } + return SBSERVICES_E_UNKNOWN_ERROR; +} + +/** + * Creates a new sbservices client. + * + * @param device The device to connect to. + * @param port The port on device to connect to. + * @param client Pointer that will point to a newly allocated + * sbservices_client_t upon successful return. + * + * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when + * client is NULL, or an SBSERVICES_E_* error code otherwise. + */ +sbservices_error_t sbservices_client_new(iphone_device_t device, uint16_t port, sbservices_client_t *client) { /* makes sure thread environment is available */ if (!g_thread_supported()) @@ -58,38 +95,56 @@ sbservices_error_t sbservices_client_new(iphone_device_t device, int dst_port, s if (!device) return SBSERVICES_E_INVALID_ARG; - /* Attempt connection */ - iphone_connection_t connection = NULL; - if (iphone_device_connect(device, dst_port, &connection) != IPHONE_E_SUCCESS) { - return SBSERVICES_E_CONN_FAILED; + property_list_service_client_t plistclient = NULL; + sbservices_error_t err = sbservices_error(property_list_service_client_new(device, port, &plistclient)); + if (err != SBSERVICES_E_SUCCESS) { + return err; } sbservices_client_t client_loc = (sbservices_client_t) malloc(sizeof(struct sbservices_client_int)); - client_loc->connection = connection; + client_loc->parent = plistclient; client_loc->mutex = g_mutex_new(); *client = client_loc; return SBSERVICES_E_SUCCESS; } +/** + * Frees an sbservices client. + * + * @param client The sbservices client to free. + * + * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when + * client is NULL, or an SBSERVICES_E_* error code otherwise. + */ sbservices_error_t sbservices_client_free(sbservices_client_t client) { if (!client) return SBSERVICES_E_INVALID_ARG; - iphone_device_disconnect(client->connection); - client->connection = NULL; + sbservices_error_t err = sbservices_error(property_list_service_client_free(client->parent)); + client->parent = NULL; if (client->mutex) { g_mutex_free(client->mutex); } free(client); - return SBSERVICES_E_SUCCESS; + return err; } +/** + * Gets the icon state of the connected device. + * + * @param client The connected sbservices client to use. + * @param state Pointer that will point to a newly allocated plist containing + * the current icon state. It is up to the caller to free the memory. + * + * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when + * client or state is invalid, or an SBSERVICES_E_* error code otherwise. + */ sbservices_error_t sbservices_get_icon_state(sbservices_client_t client, plist_t *state) { - if (!client || !client->connection || !state) + if (!client || !client->parent || !state) return SBSERVICES_E_INVALID_ARG; sbservices_error_t res = SBSERVICES_E_UNKNOWN_ERROR; @@ -99,17 +154,17 @@ sbservices_error_t sbservices_get_icon_state(sbservices_client_t client, plist_t sbs_lock(client); - if (iphone_device_send_binary_plist(client->connection, dict) != IPHONE_E_SUCCESS) { - log_debug_msg("%s: could not send plist\n", __func__); + res = sbservices_error(property_list_service_send_binary_plist(client->parent, dict)); + if (res != SBSERVICES_E_SUCCESS) { + debug_info("could not send plist, error %d", res); goto leave_unlock; } plist_free(dict); dict = NULL; - if (iphone_device_receive_plist(client->connection, state) == IPHONE_E_SUCCESS) { - res = SBSERVICES_E_SUCCESS; - } else { - log_debug_msg("%s: could not get icon state!\n", __func__); + res = sbservices_error(property_list_service_receive_plist(client->parent, state)); + if (res != SBSERVICES_E_SUCCESS) { + debug_info("could not get icon state, error %d", res); if (*state) { plist_free(*state); *state = NULL; @@ -124,9 +179,18 @@ leave_unlock: return res; } +/** + * Sets the icon state of the connected device. + * + * @param client The connected sbservices client to use. + * @param newstate A plist containing the new iconstate. + * + * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when + * client or newstate is NULL, or an SBSERVICES_E_* error code otherwise. + */ sbservices_error_t sbservices_set_icon_state(sbservices_client_t client, plist_t newstate) { - if (!client || !client->connection || !newstate) + if (!client || !client->parent || !newstate) return SBSERVICES_E_INVALID_ARG; sbservices_error_t res = SBSERVICES_E_UNKNOWN_ERROR; @@ -137,13 +201,12 @@ sbservices_error_t sbservices_set_icon_state(sbservices_client_t client, plist_t sbs_lock(client); - if (iphone_device_send_binary_plist(client->connection, dict) != IPHONE_E_SUCCESS) { - log_debug_msg("%s: could not send plist\n", __func__); - goto leave_unlock; + res = sbservices_error(property_list_service_send_binary_plist(client->parent, dict)); + if (res != SBSERVICES_E_SUCCESS) { + debug_info("could not send plist, error %d", res); } // NO RESPONSE -leave_unlock: if (dict) { plist_free(dict); } @@ -151,9 +214,24 @@ leave_unlock: return res; } +/** + * Get the icon of the specified app as PNG data. + * + * @param client The connected sbservices client to use. + * @param bundleId The bundle identifier of the app to retrieve the icon for. + * @param pngdata Pointer that will point to a newly allocated buffer + * containing the PNG data upon successful return. It is up to the caller + * to free the memory. + * @param pngsize Pointer to a uint64_t that will be set to the size of the + * buffer pngdata points to upon successful return. + * + * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when + * client, bundleId, or pngdata are invalid, or an SBSERVICES_E_* error + * code otherwise. + */ sbservices_error_t sbservices_get_icon_pngdata(sbservices_client_t client, const char *bundleId, char **pngdata, uint64_t *pngsize) { - if (!client || !client->connection || !pngdata) + if (!client || !client->parent || !bundleId || !pngdata) return SBSERVICES_E_INVALID_ARG; sbservices_error_t res = SBSERVICES_E_UNKNOWN_ERROR; @@ -164,19 +242,20 @@ sbservices_error_t sbservices_get_icon_pngdata(sbservices_client_t client, const sbs_lock(client); - if (iphone_device_send_binary_plist(client->connection, dict) != IPHONE_E_SUCCESS) { - log_debug_msg("%s: could not send plist\n", __func__); + res = sbservices_error(property_list_service_send_binary_plist(client->parent, dict)); + if (res != SBSERVICES_E_SUCCESS) { + debug_info("could not send plist, error %d", res); goto leave_unlock; } plist_free(dict); dict = NULL; - if (iphone_device_receive_plist(client->connection, &dict) == IPHONE_E_SUCCESS) { + res = sbservices_error(property_list_service_receive_plist(client->parent, &dict)); + if (res == SBSERVICES_E_SUCCESS) { plist_t node = plist_dict_get_item(dict, "pngData"); if (node) { plist_get_data_val(node, pngdata, pngsize); } - res = SBSERVICES_E_SUCCESS; } leave_unlock: diff --git a/src/SBServices.h b/src/SBServices.h index 8f923b9..d24828a 100644 --- a/src/SBServices.h +++ b/src/SBServices.h @@ -24,9 +24,10 @@ #include <glib.h> #include "libiphone/sbservices.h" +#include "property_list_service.h" struct sbservices_client_int { - iphone_connection_t connection; + property_list_service_client_t parent; GMutex *mutex; }; diff --git a/src/utils.c b/src/debug.c index 3c08351..2cdeebf 100644 --- a/src/utils.c +++ b/src/debug.c @@ -1,6 +1,6 @@ /* - * utils.c - * contains utilitary methos for logging and debugging + * debug.c + * contains utilitary functions for debugging * * Copyright (c) 2008 Jonathan Beck All Rights Reserved. * @@ -18,15 +18,18 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + #include <stdarg.h> +#define _GNU_SOURCE 1 +#define __USE_GNU 1 #include <stdio.h> #include <stdint.h> +#include <stdlib.h> -#include "utils.h" +#include "debug.h" #include "libiphone/libiphone.h" -int toto_debug = 0; -uint16_t dbg_mask = 0; +int debug_level = 0; /** * Sets the level of debugging. Currently the only acceptable values are 0 and @@ -36,59 +39,63 @@ uint16_t dbg_mask = 0; */ void iphone_set_debug_level(int level) { - toto_debug = level; + debug_level = level; } - -/** - * Set debug ids to display. Values can be OR-ed - * - * @param level Set to 0 for no debugging or 1 for debugging. - */ -void iphone_set_debug_mask(uint16_t mask) +static void debug_print_line(const char *func, const char *file, int line, const char *buffer) { - dbg_mask = mask; -} + char *str_time = NULL; + char *header = NULL; + time_t the_time; -void log_debug_msg(const char *format, ...) -{ -#ifndef STRIP_DEBUG_CODE + time(&the_time); + str_time = g_new0 (gchar, 255); + strftime(str_time, 254, "%H:%M:%S", localtime (&the_time)); - va_list args; - /* run the real fprintf */ - va_start(args, format); + /* generate header text */ + (void)asprintf(&header, "%s %s:%d %s()", str_time, file, line, func); + free (str_time); - if (toto_debug) - vfprintf(stderr, format, args); + /* always in light green */ + printf ("%s: ", header); - va_end(args); + /* different colors according to the severity */ + printf ("%s\n", buffer); -#endif + /* flush this output, as we need to debug */ + fflush (stdout); + + free (header); } -void log_dbg_msg(uint16_t id, const char *format, ...) +inline void debug_info_real(const char *func, const char *file, int line, const char *format, ...) { #ifndef STRIP_DEBUG_CODE - if (id & dbg_mask) { - va_list args; - /* run the real fprintf */ - va_start(args, format); + va_list args; + char *buffer = NULL; - vfprintf(stderr, format, args); + if (!debug_level) + return; - va_end(args); - } + /* run the real fprintf */ + va_start(args, format); + (void)vasprintf(&buffer, format, args); + va_end(args); + + debug_print_line(func, file, line, buffer); + + free(buffer); #endif } -inline void log_debug_buffer(const char *data, const int length) +inline void debug_buffer(const char *data, const int length) { #ifndef STRIP_DEBUG_CODE int i; int j; unsigned char c; - if (toto_debug) { + if (debug_level) { for (i = 0; i < length; i += 16) { fprintf(stderr, "%04x: ", i); for (j = 0; j < 16; j++) { @@ -116,16 +123,29 @@ inline void log_debug_buffer(const char *data, const int length) #endif } -inline void dump_debug_buffer(const char *file, const char *data, const int length) +inline void debug_buffer_to_file(const char *file, const char *data, const int length) { #ifndef STRIP_DEBUG_CODE - /* run the real fprintf */ - if (toto_debug) { - FILE *my_ssl_packet = fopen(file, "w+"); - fwrite(data, 1, length, my_ssl_packet); - fflush(my_ssl_packet); - fprintf(stderr, "%s: Wrote SSL packet to drive, too.\n", __func__); - fclose(my_ssl_packet); + if (debug_level) { + FILE *f = fopen(file, "w+"); + fwrite(data, 1, length, f); + fflush(f); + fclose(f); } #endif } + +inline void debug_plist(plist_t plist) +{ +#ifndef STRIP_DEBUG_CODE + if (!plist) + return; + + char *buffer = NULL; + uint32_t length = 0; + plist_to_xml(plist, &buffer, &length); + debug_info("plist size: %i\nbuffer :\n%s", length, buffer); + free(buffer); +#endif +} + diff --git a/src/debug.h b/src/debug.h new file mode 100644 index 0000000..0a29be3 --- /dev/null +++ b/src/debug.h @@ -0,0 +1,45 @@ +/* + * debug.h + * contains utilitary functions for debugging + * + * Copyright (c) 2008 Jonathan Beck All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef DEBUG_H +#define DEBUG_H + +#include <plist/plist.h> +#include <glib.h> + +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && !defined(STRIP_DEBUG_CODE) +#define debug_info(...) debug_info_real (__func__, __FILE__, __LINE__, __VA_ARGS__) +#elif defined(__GNUC__) && __GNUC__ >= 3 && !defined(STRIP_DEBUG_CODE) +#define debug_info(...) debug_info_real (__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__) +#else +#define debug_info(...) +#endif + +G_GNUC_INTERNAL inline void debug_info_real(const char *func, + const char *file, + int line, + const char *format, ...); + +G_GNUC_INTERNAL inline void debug_buffer(const char *data, const int length); +G_GNUC_INTERNAL inline void debug_buffer_to_file(const char *file, const char *data, const int length); +G_GNUC_INTERNAL inline void debug_plist(plist_t plist); + +#endif diff --git a/src/device_link_service.c b/src/device_link_service.c new file mode 100644 index 0000000..e1155a5 --- /dev/null +++ b/src/device_link_service.c @@ -0,0 +1,299 @@ + /* + * device_link_service.c + * DeviceLink service implementation. + * + * Copyright (c) 2010 Nikias Bassen, All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include <string.h> +#include <stdlib.h> +#include "device_link_service.h" +#include "property_list_service.h" +#include "debug.h" + +/** + * Internally used function to extract the message string from a DLMessage* + * plist. + * + * @param dl_msg The DeviceLink property list to parse. + * + * @return An allocated char* with the DLMessage from the given plist, + * or NULL when the plist does not contain any DLMessage. It is up to + * the caller to free the allocated memory. + */ +static char *device_link_service_get_message(plist_t dl_msg) +{ + uint32_t cnt = 0; + plist_t cmd = 0; + char *cmd_str = NULL; + + /* sanity check */ + if ((plist_get_node_type(dl_msg) != PLIST_ARRAY) || ((cnt = plist_array_get_size(dl_msg)) < 1)) { + return NULL; + } + + /* get dl command */ + cmd = plist_array_get_item(dl_msg, 0); + if (!cmd || (plist_get_node_type(cmd) != PLIST_STRING)) { + return NULL; + } + + plist_get_string_val(cmd, &cmd_str); + if (!cmd_str) { + return NULL; + } + + if ((strlen(cmd_str) < (strlen("DLMessage")+1)) + || (strncmp(cmd_str, "DLMessage", strlen("DLMessage")))) { + free(cmd_str); + return NULL; + } + + /* we got a DLMessage* command */ + return cmd_str; +} + +/** + * Creates a new device link service client. + * + * @param device The device to connect to. + * @param port Port on device to connect to. + * @param client Reference that will point to a newly allocated + * device_link_service_client_t upon successful return. + * + * @return DEVICE_LINK_SERVICE_E_SUCCESS on success, + * DEVICE_LINK_SERVICE_E_INVALID_ARG when one of the parameters is invalid, + * or DEVICE_LINK_SERVICE_E_MUX_ERROR when the connection failed. + */ +device_link_service_error_t device_link_service_client_new(iphone_device_t device, uint16_t port, device_link_service_client_t *client) +{ + if (!device || port == 0 || !client || *client) { + return DEVICE_LINK_SERVICE_E_INVALID_ARG; + } + + property_list_service_client_t plistclient = NULL; + if (property_list_service_client_new(device, port, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) { + return DEVICE_LINK_SERVICE_E_MUX_ERROR; + } + + /* create client object */ + device_link_service_client_t client_loc = (device_link_service_client_t) malloc(sizeof(struct device_link_service_client_int)); + client_loc->parent = plistclient; + + /* all done, return success */ + *client = client_loc; + return DEVICE_LINK_SERVICE_E_SUCCESS; +} + +/** + * Frees a device link service client. + * + * @param client The device_link_service_client_t to free. + * + * @return DEVICE_LINK_SERVICE_E_SUCCESS on success, + * DEVICE_LINK_SERVICE_E_INVALID_ARG when one of client or client->parent + * is invalid, or DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR when the was an error + * freeing the parent property_list_service client. + */ +device_link_service_error_t device_link_service_client_free(device_link_service_client_t client) +{ + if (!client) + return DEVICE_LINK_SERVICE_E_INVALID_ARG; + + if (property_list_service_client_free(client->parent) != PROPERTY_LIST_SERVICE_E_SUCCESS) { + return DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR; + } + return DEVICE_LINK_SERVICE_E_SUCCESS; +} + +/** + * Performs the DLMessageVersionExchange with the connected device. + * This should be the first operation to be executed by an implemented + * device link service client. + * + * @param client The device_link_service client to use. + * @param version_major The major version number to check. + * @param version_minor The minor version number to check. + * + * @return DEVICE_LINK_SERVICE_E_SUCCESS on success, + * DEVICE_LINK_SERVICE_E_INVALID_ARG when client is NULL, + * DEVICE_LINK_SERVICE_E_MUX_ERROR when a communication error occurs, + * DEVICE_LINK_SERVICE_E_PLIST_ERROR when the received plist has not the + * expected contents, DEVICE_LINK_SERVICE_E_BAD_VERSION when the version + * given by the device is larger than the given version, + * or DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR otherwise. + */ +device_link_service_error_t device_link_service_version_exchange(device_link_service_client_t client, uint64_t version_major, uint64_t version_minor) +{ + if (!client) + return DEVICE_LINK_SERVICE_E_INVALID_ARG; + + device_link_service_error_t err = DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR; + + /* perform version exchange */ + plist_t array = NULL; + char *msg = NULL; + + /* receive DLMessageVersionExchange from device */ + if (property_list_service_receive_plist(client->parent, &array) != PROPERTY_LIST_SERVICE_E_SUCCESS) { + debug_info("Did not receive initial message from device!"); + err = DEVICE_LINK_SERVICE_E_MUX_ERROR; + goto leave; + } + msg = device_link_service_get_message(array); + if (!msg || strcmp(msg, "DLMessageVersionExchange")) { + debug_info("Did not receive DLMessageVersionExchange from device!"); + err = DEVICE_LINK_SERVICE_E_PLIST_ERROR; + goto leave; + } + free(msg); + msg = NULL; + + /* get major and minor version number */ + if (plist_array_get_size(array) < 3) { + debug_info("DLMessageVersionExchange has unexpected format!"); + err = DEVICE_LINK_SERVICE_E_PLIST_ERROR; + goto leave; + } + plist_t maj = plist_array_get_item(array, 1); + plist_t min = plist_array_get_item(array, 2); + uint64_t vmajor = 0; + uint64_t vminor = 0; + if (maj) { + plist_get_uint_val(maj, &vmajor); + } + if (min) { + plist_get_uint_val(min, &vminor); + } + if (vmajor > version_major) { + debug_info("Version mismatch: device=(%lld,%lld) > expected=(%lld,%lld)", vmajor, vminor, version_major, version_minor); + err = DEVICE_LINK_SERVICE_E_BAD_VERSION; + goto leave; + } else if ((vmajor == version_major) && (vminor > version_minor)) { + debug_info("WARNING: Version mismatch: device=(%lld,%lld) > expected=(%lld,%lld)", vmajor, vminor, version_major, version_minor); + err = DEVICE_LINK_SERVICE_E_BAD_VERSION; + goto leave; + } + plist_free(array); + + /* version is ok, send reply */ + array = plist_new_array(); + plist_array_append_item(array, plist_new_string("DLMessageVersionExchange")); + plist_array_append_item(array, plist_new_string("DLVersionsOk")); + if (property_list_service_send_binary_plist(client->parent, array) != PROPERTY_LIST_SERVICE_E_SUCCESS) { + debug_info("Error when sending DLVersionsOk"); + err = DEVICE_LINK_SERVICE_E_MUX_ERROR; + goto leave; + } + plist_free(array); + + /* receive DeviceReady message */ + array = NULL; + if (property_list_service_receive_plist(client->parent, &array) != PROPERTY_LIST_SERVICE_E_SUCCESS) { + debug_info("Error when receiving DLMessageDeviceReady!"); + err = DEVICE_LINK_SERVICE_E_MUX_ERROR; + goto leave; + } + msg = device_link_service_get_message(array); + if (!msg || strcmp(msg, "DLMessageDeviceReady")) { + debug_info("Did not get DLMessageDeviceReady!"); + err = DEVICE_LINK_SERVICE_E_PLIST_ERROR; + goto leave; + } + err = DEVICE_LINK_SERVICE_E_SUCCESS; + +leave: + if (msg) { + free(msg); + } + if (array) { + plist_free(array); + } + return err; +} + +/** + * Performs a disconnect with the connected device link service client. + * + * @param client The device link service client to disconnect. + * + * @return DEVICE_LINK_SERVICE_E_SUCCESS on success, + * DEVICE_LINK_SERVICE_E_INVALID_ARG if client is NULL, + * or DEVICE_LINK_SERVICE_E_MUX_ERROR when there's an error when sending + * the the disconnect message. + */ +device_link_service_error_t device_link_service_disconnect(device_link_service_client_t client) +{ + if (!client) + return DEVICE_LINK_SERVICE_E_INVALID_ARG; + + plist_t array = plist_new_array(); + plist_array_append_item(array, plist_new_string("DLMessageDisconnect")); + plist_array_append_item(array, plist_new_string("All done, thanks for the memories")); + + device_link_service_error_t err = DEVICE_LINK_SERVICE_E_SUCCESS; + if (property_list_service_send_binary_plist(client->parent, array) != PROPERTY_LIST_SERVICE_E_SUCCESS) { + err = DEVICE_LINK_SERVICE_E_MUX_ERROR; + } + plist_free(array); + return err; +} + +/** + * Generic device link service send function. + * + * @param client The device link service client to use for sending + * @param plist The property list to send + * + * @return DEVICE_LINK_SERVICE_E_SUCCESS on success, + * DEVICE_LINK_SERVICE_E_INVALID_ARG when client or plist is NULL, + * or DEVICE_LINK_SERVICE_E_MUX_ERROR when the given property list could + * not be sent. + */ +device_link_service_error_t device_link_service_send(device_link_service_client_t client, plist_t plist) +{ + if (!client || !plist) { + return DEVICE_LINK_SERVICE_E_INVALID_ARG; + } + if (property_list_service_send_binary_plist(client->parent, plist) != PROPERTY_LIST_SERVICE_E_SUCCESS) { + return DEVICE_LINK_SERVICE_E_MUX_ERROR; + } + return DEVICE_LINK_SERVICE_E_SUCCESS; +} + +/* Generic device link service receive function. + * + * @param client The device link service client to use for sending + * @param plist Pointer that will point to the property list received upon + * successful return. + * + * @return DEVICE_LINK_SERVICE_E_SUCCESS on success, + * DEVICE_LINK_SERVICE_E_INVALID_ARG when client or plist is NULL, + * or DEVICE_LINK_SERVICE_E_MUX_ERROR when no property list could be + * received. + */ +device_link_service_error_t device_link_service_receive(device_link_service_client_t client, plist_t *plist) +{ + if (!client || !plist || (plist && *plist)) { + return DEVICE_LINK_SERVICE_E_INVALID_ARG; + } + + if (property_list_service_receive_plist(client->parent, plist) != PROPERTY_LIST_SERVICE_E_SUCCESS) { + return DEVICE_LINK_SERVICE_E_MUX_ERROR; + } + return DEVICE_LINK_SERVICE_E_SUCCESS; +} + diff --git a/src/device_link_service.h b/src/device_link_service.h new file mode 100644 index 0000000..e14d897 --- /dev/null +++ b/src/device_link_service.h @@ -0,0 +1,51 @@ + /* + * device_link_service.h + * Definitions for the DeviceLink service + * + * Copyright (c) 2010 Nikias Bassen, All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef DEVICE_LINK_SERVICE_H +#define DEVICE_LINK_SERVICE_H + +#include "property_list_service.h" + +/* Error Codes */ +#define DEVICE_LINK_SERVICE_E_SUCCESS 0 +#define DEVICE_LINK_SERVICE_E_INVALID_ARG -1 +#define DEVICE_LINK_SERVICE_E_PLIST_ERROR -2 +#define DEVICE_LINK_SERVICE_E_MUX_ERROR -3 +#define DEVICE_LINK_SERVICE_E_BAD_VERSION -4 + +#define DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR -256 + + +struct device_link_service_client_int { + property_list_service_client_t parent; +}; + +typedef struct device_link_service_client_int *device_link_service_client_t; + +typedef int16_t device_link_service_error_t; + +device_link_service_error_t device_link_service_client_new(iphone_device_t device, uint16_t port, device_link_service_client_t *client); +device_link_service_error_t device_link_service_client_free(device_link_service_client_t client); +device_link_service_error_t device_link_service_version_exchange(device_link_service_client_t client, uint64_t version_major, uint64_t version_minor); +device_link_service_error_t device_link_service_disconnect(device_link_service_client_t client); +device_link_service_error_t device_link_service_send(device_link_service_client_t client, plist_t plist); +device_link_service_error_t device_link_service_receive(device_link_service_client_t client, plist_t *plist); + +#endif diff --git a/src/iphone.c b/src/iphone.c index 4a54848..6d95c45 100644 --- a/src/iphone.c +++ b/src/iphone.c @@ -26,8 +26,9 @@ #include <arpa/inet.h> #include <usbmuxd.h> +#include <gnutls/gnutls.h> #include "iphone.h" -#include "utils.h" +#include "debug.h" static iphone_event_cb_t event_cb = NULL; @@ -60,7 +61,7 @@ iphone_error_t iphone_event_subscribe(iphone_event_cb_t callback, void *user_dat int res = usbmuxd_subscribe(usbmux_event_cb, user_data); if (res != 0) { event_cb = NULL; - log_debug_msg("%s: Error %d when subscribing usbmux event callback!\n", __func__, res); + debug_info("Error %d when subscribing usbmux event callback!", res); return IPHONE_E_UNKNOWN_ERROR; } return IPHONE_E_SUCCESS; @@ -77,7 +78,7 @@ iphone_error_t iphone_event_unsubscribe() event_cb = NULL; int res = usbmuxd_unsubscribe(); if (res != 0) { - log_debug_msg("%s: Error %d when unsubscribing usbmux event callback!\n", __func__, res); + debug_info("Error %d when unsubscribing usbmux event callback!", res); return IPHONE_E_UNKNOWN_ERROR; } return IPHONE_E_SUCCESS; @@ -100,7 +101,7 @@ iphone_error_t iphone_get_device_list(char ***devices, int *count) *count = 0; if (usbmuxd_get_device_list(&dev_list) < 0) { - log_debug_msg("%s: ERROR: usbmuxd is not running!\n", __func__); + debug_info("ERROR: usbmuxd is not running!\n", __func__); return IPHONE_E_NO_DEVICE; } @@ -201,31 +202,32 @@ iphone_error_t iphone_device_free(iphone_device_t device) * Set up a connection to the given device. * * @param device The device to connect to. - * @param dst_port The destination port to connect to. + * @param port The destination port to connect to. * @param connection Pointer to an iphone_connection_t that will be filled * with the necessary data of the connection. * * @return IPHONE_E_SUCCESS if ok, otherwise an error code. */ -iphone_error_t iphone_device_connect(iphone_device_t device, uint16_t dst_port, iphone_connection_t *connection) +iphone_error_t iphone_device_connect(iphone_device_t device, uint16_t port, iphone_connection_t *connection) { if (!device) { return IPHONE_E_INVALID_ARG; } if (device->conn_type == CONNECTION_USBMUXD) { - int sfd = usbmuxd_connect((uint32_t)(device->conn_data), dst_port); + int sfd = usbmuxd_connect((uint32_t)(device->conn_data), port); if (sfd < 0) { - log_debug_msg("%s: ERROR: Connecting to usbmuxd failed: %d (%s)\n", __func__, sfd, strerror(-sfd)); + debug_info("ERROR: Connecting to usbmuxd failed: %d (%s)", sfd, strerror(-sfd)); return IPHONE_E_UNKNOWN_ERROR; } iphone_connection_t new_connection = (iphone_connection_t)malloc(sizeof(struct iphone_connection_int)); new_connection->type = CONNECTION_USBMUXD; new_connection->data = (void*)sfd; + new_connection->ssl_data = NULL; *connection = new_connection; return IPHONE_E_SUCCESS; } else { - log_debug_msg("%s: Unknown connection type %d\n", __func__, device->conn_type); + debug_info("Unknown connection type %d", device->conn_type); } return IPHONE_E_UNKNOWN_ERROR; @@ -243,18 +245,45 @@ iphone_error_t iphone_device_disconnect(iphone_connection_t connection) if (!connection) { return IPHONE_E_INVALID_ARG; } + /* shut down ssl if enabled */ + if (connection->ssl_data) { + iphone_connection_disable_ssl(connection); + } iphone_error_t result = IPHONE_E_UNKNOWN_ERROR; if (connection->type == CONNECTION_USBMUXD) { usbmuxd_disconnect((int)(connection->data)); result = IPHONE_E_SUCCESS; } else { - log_debug_msg("%s: Unknown connection type %d\n", __func__, connection->type); + debug_info("Unknown connection type %d", connection->type); } free(connection); return result; } /** + * Internally used function to send raw data over the given connection. + */ +static iphone_error_t internal_connection_send(iphone_connection_t connection, const char *data, uint32_t len, uint32_t *sent_bytes) +{ + if (!connection || !data) { + return IPHONE_E_INVALID_ARG; + } + + if (connection->type == CONNECTION_USBMUXD) { + int res = usbmuxd_send((int)(connection->data), data, len, sent_bytes); + if (res < 0) { + debug_info("ERROR: usbmuxd_send returned %d (%s)", res, strerror(-res)); + return IPHONE_E_UNKNOWN_ERROR; + } + return IPHONE_E_SUCCESS; + } else { + debug_info("Unknown connection type %d", connection->type); + } + return IPHONE_E_UNKNOWN_ERROR; + +} + +/** * Send data to a device via the given connection. * * @param connection The connection to send data over. @@ -267,19 +296,41 @@ iphone_error_t iphone_device_disconnect(iphone_connection_t connection) */ iphone_error_t iphone_device_send(iphone_connection_t connection, const char *data, uint32_t len, uint32_t *sent_bytes) { - if (!connection || !data) { + if (!connection || !data || (connection->ssl_data && !connection->ssl_data->session)) { + return IPHONE_E_INVALID_ARG; + } + + if (connection->ssl_data) { + ssize_t sent = gnutls_record_send(connection->ssl_data->session, (void*)data, (size_t)len); + if ((uint32_t)sent == (uint32_t)len) { + *sent_bytes = sent; + return IPHONE_E_SUCCESS; + } + *sent_bytes = 0; + return IPHONE_E_SSL_ERROR; + } + return internal_connection_send(connection, data, len, sent_bytes); +} + +/** + * Internally used function for receiving raw data over the given connection + * using a timeout. + */ +static iphone_error_t internal_connection_recv_timeout(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout) +{ + if (!connection) { return IPHONE_E_INVALID_ARG; } if (connection->type == CONNECTION_USBMUXD) { - int res = usbmuxd_send((int)(connection->data), data, len, sent_bytes); + int res = usbmuxd_recv_timeout((int)(connection->data), data, len, recv_bytes, timeout); if (res < 0) { - log_debug_msg("%s: ERROR: usbmuxd_send returned %d (%s)\n", __func__, res, strerror(-res)); + debug_info("ERROR: usbmuxd_recv_timeout returned %d (%s)", res, strerror(-res)); return IPHONE_E_UNKNOWN_ERROR; } return IPHONE_E_SUCCESS; } else { - log_debug_msg("%s: Unknown connection type %d\n", __func__, connection->type); + debug_info("Unknown connection type %d", connection->type); } return IPHONE_E_UNKNOWN_ERROR; } @@ -301,19 +352,41 @@ iphone_error_t iphone_device_send(iphone_connection_t connection, const char *da */ iphone_error_t iphone_device_recv_timeout(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout) { + if (!connection || (connection->ssl_data && !connection->ssl_data->session)) { + return IPHONE_E_INVALID_ARG; + } + + if (connection->ssl_data) { + ssize_t received = gnutls_record_recv(connection->ssl_data->session, (void*)data, (size_t)len); + if (received > 0) { + *recv_bytes = received; + return IPHONE_E_SUCCESS; + } + *recv_bytes = 0; + return IPHONE_E_SSL_ERROR; + } + return internal_connection_recv_timeout(connection, data, len, recv_bytes, timeout); +} + +/** + * Internally used function for receiving raw data over the given connection. + */ +static iphone_error_t internal_connection_recv(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes) +{ if (!connection) { return IPHONE_E_INVALID_ARG; } if (connection->type == CONNECTION_USBMUXD) { - int res = usbmuxd_recv_timeout((int)(connection->data), data, len, recv_bytes, timeout); + int res = usbmuxd_recv((int)(connection->data), data, len, recv_bytes); if (res < 0) { - log_debug_msg("%s: ERROR: usbmuxd_recv_timeout returned %d (%s)\n", __func__, res, strerror(-res)); + debug_info("ERROR: usbmuxd_recv returned %d (%s)", res, strerror(-res)); return IPHONE_E_UNKNOWN_ERROR; } + return IPHONE_E_SUCCESS; } else { - log_debug_msg("%s: Unknown connection type %d\n", __func__, connection->type); + debug_info("Unknown connection type %d", connection->type); } return IPHONE_E_UNKNOWN_ERROR; } @@ -333,332 +406,213 @@ iphone_error_t iphone_device_recv_timeout(iphone_connection_t connection, char * */ iphone_error_t iphone_device_recv(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes) { - if (!connection) { - return -EINVAL; + if (!connection || (connection->ssl_data && !connection->ssl_data->session)) { + return IPHONE_E_INVALID_ARG; } - if (connection->type == CONNECTION_USBMUXD) { - int res = usbmuxd_recv((int)(connection->data), data, len, recv_bytes); - if (res < 0) { - log_debug_msg("%s: ERROR: usbmuxd_recv returned %d (%s)\n", __func__, res, strerror(-res)); - return IPHONE_E_UNKNOWN_ERROR; + if (connection->ssl_data) { + ssize_t received = gnutls_record_recv(connection->ssl_data->session, (void*)data, (size_t)len); + if (received > 0) { + *recv_bytes = received; + return IPHONE_E_SUCCESS; } + *recv_bytes = 0; + return IPHONE_E_SSL_ERROR; + } + return internal_connection_recv(connection, data, len, recv_bytes); +} +iphone_error_t iphone_device_get_handle(iphone_device_t device, uint32_t *handle) +{ + if (!device) + return IPHONE_E_INVALID_ARG; + + if (device->conn_type == CONNECTION_USBMUXD) { + *handle = (uint32_t)device->conn_data; return IPHONE_E_SUCCESS; } else { - log_debug_msg("%s: Unknown connection type %d\n", __func__, connection->type); + debug_info("Unknown connection type %d", device->conn_type); } return IPHONE_E_UNKNOWN_ERROR; } +iphone_error_t iphone_device_get_uuid(iphone_device_t device, char **uuid) +{ + if (!device) + return IPHONE_E_INVALID_ARG; + + *uuid = strdup(device->uuid); + return IPHONE_E_SUCCESS; +} + /** - * Sends a plist over the given connection. - * Internally used generic plist send function. - * - * @param connection The connection to use for sending. - * Can be NULL if ssl_session is non-NULL. - * @param plist plist to send - * @param binary 1 = send binary plist, 0 = send xml plist - * @param ssl_session If set to NULL, the communication will be unencrypted. - * For encrypted communication, pass a valid and properly initialized - * gnutls_session_t. connection is ignored when ssl_session is non-NULL. - * - * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when one or more - * parameters are invalid, IPHONE_E_PLIST_ERROR when dict is not a valid - * plist, or IPHONE_E_UNKNOWN_ERROR when an unspecified error occurs. + * Internally used gnutls callback function for receiving encrypted data. */ -static iphone_error_t internal_plist_send(iphone_connection_t connection, plist_t plist, int binary, gnutls_session_t ssl_session) +static ssize_t internal_ssl_read(gnutls_transport_ptr_t transport, char *buffer, size_t length) { - iphone_error_t res = IPHONE_E_UNKNOWN_ERROR; - char *content = NULL; - uint32_t length = 0; - uint32_t nlen = 0; - int bytes = 0; + int bytes = 0, pos_start_fill = 0; + size_t tbytes = 0; + int this_len = length; + iphone_error_t res; + iphone_connection_t connection = (iphone_connection_t)transport; + char *recv_buffer; + + debug_info("pre-read client wants %zi bytes", length); + + recv_buffer = (char *) malloc(sizeof(char) * this_len); + + /* repeat until we have the full data or an error occurs */ + do { + if ((res = internal_connection_recv(connection, recv_buffer, this_len, (uint32_t*)&bytes)) != IPHONE_E_SUCCESS) { + debug_info("ERROR: iphone_device_recv returned %d", res); + return res; + } + debug_info("post-read we got %i bytes", bytes); - if ((!connection && !ssl_session) || !plist) { - return IPHONE_E_INVALID_ARG; - } + // increase read count + tbytes += bytes; - if (binary) { - plist_to_bin(plist, &content, &length); - } else { - plist_to_xml(plist, &content, &length); - } + // fill the buffer with what we got right now + memcpy(buffer + pos_start_fill, recv_buffer, bytes); + pos_start_fill += bytes; - if (!content || length == 0) { - return IPHONE_E_PLIST_ERROR; - } - - nlen = htonl(length); - log_debug_msg("%s: sending %d bytes\n", __func__, length); - if (ssl_session) { - bytes = gnutls_record_send(ssl_session, (const char*)&nlen, sizeof(nlen)); - } else { - iphone_device_send(connection, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes); - } - if (bytes == sizeof(nlen)) { - if (ssl_session) { - bytes = gnutls_record_send(ssl_session, content, length); - } else { - iphone_device_send(connection, content, length, (uint32_t*)&bytes); - } - if (bytes > 0) { - log_debug_msg("%s: sent %d bytes\n", __func__, bytes); - log_debug_buffer(content, bytes); - if ((uint32_t)bytes == length) { - res = IPHONE_E_SUCCESS; - } else { - log_debug_msg("%s: ERROR: Could not send all data (%d of %d)!\n", __func__, bytes, length); - } + if (tbytes >= length) { + break; } - } - if (bytes <= 0) { - log_debug_msg("%s: ERROR: sending to device failed.\n", __func__); - } - free(content); + this_len = length - tbytes; + debug_info("re-read trying to read missing %i bytes", this_len); + } while (tbytes < length); - return res; + if (recv_buffer) { + free(recv_buffer); + } + return tbytes; } /** - * Sends an XML plist over the given connection. - * - * @param connection The connection to send data over - * @param plist plist to send - * - * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when connection - * or plist is NULL, IPHONE_E_PLIST_ERROR when dict is not a valid plist, - * or IPHONE_E_UNKNOWN_ERROR when an unspecified error occurs. + * Internally used gnutls callback function for sending encrypted data. */ -iphone_error_t iphone_device_send_xml_plist(iphone_connection_t connection, plist_t plist) +static ssize_t internal_ssl_write(gnutls_transport_ptr_t transport, char *buffer, size_t length) { - return internal_plist_send(connection, plist, 0, NULL); + uint32_t bytes = 0; + iphone_connection_t connection = (iphone_connection_t)transport; + debug_info("pre-send length = %zi", length); + internal_connection_send(connection, buffer, length, &bytes); + debug_info("post-send sent %i bytes", bytes); + return bytes; } /** - * Sends a binary plist over the given connection. - * - * @param connection The connection to send data over - * @param plist plist to send - * - * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when connection - * or plist is NULL, IPHONE_E_PLIST_ERROR when dict is not a valid plist, - * or IPHONE_E_UNKNOWN_ERROR when an unspecified error occurs. + * Internally used function for cleaning up SSL stuff. */ -iphone_error_t iphone_device_send_binary_plist(iphone_connection_t connection, plist_t plist) +static void internal_ssl_cleanup(ssl_data_t ssl_data) { - return internal_plist_send(connection, plist, 1, NULL); -} + if (!ssl_data) + return; -/** - * Sends an encrypted XML plist. - * - * @param ssl_session Valid and properly initialized gnutls_session_t. - * @param plist plist to send - * - * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when ssl_session - * or plist is NULL, IPHONE_E_PLIST_ERROR when dict is not a valid plist, - * or IPHONE_E_UNKNOWN_ERROR when an unspecified error occurs. - */ -iphone_error_t iphone_device_send_encrypted_xml_plist(gnutls_session_t ssl_session, plist_t plist) -{ - return internal_plist_send(NULL, plist, 0, ssl_session); -} - -/** - * Sends an encrypted binary plist. - * - * @param ssl_session Valid and properly initialized gnutls_session_t. - * @param plist plist to send - * - * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when ssl_session - * or plist is NULL, IPHONE_E_PLIST_ERROR when dict is not a valid plist, - * or IPHONE_E_UNKNOWN_ERROR when an unspecified error occurs. - */ -iphone_error_t iphone_device_send_encrypted_binary_plist(gnutls_session_t ssl_session, plist_t plist) -{ - return internal_plist_send(NULL, plist, 1, ssl_session); + if (ssl_data->session) { + gnutls_deinit(ssl_data->session); + } + if (ssl_data->certificate) { + gnutls_certificate_free_credentials(ssl_data->certificate); + } } /** - * Receives a plist over the given connection. - * Internally used generic plist send function. + * Enables SSL for the given connection. * - * @param connection The connection to receive data on - * @param plist pointer to a plist_t that will point to the received plist - * upon successful return - * @param timeout Maximum time in milliseconds to wait for data. - * @param ssl_session If set to NULL, the communication will be unencrypted. - * For encrypted communication, pass a valid and properly initialized - * gnutls_session_t. + * @param connection The connection to enable SSL for. * * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when connection - * or *plist is NULL, IPHONE_E_PLIST_ERROR when the received data cannot be - * converted to a plist, or IPHONE_E_UNKNOWN_ERROR when an unspecified - * error occurs. + * is NULL or connection->ssl_data is non-NULL, or IPHONE_E_SSL_ERROR when + * SSL initialization, setup, or handshake fails. */ -static iphone_error_t internal_plist_recv_timeout(iphone_connection_t connection, plist_t *plist, unsigned int timeout, gnutls_session_t ssl_session) +iphone_error_t iphone_connection_enable_ssl(iphone_connection_t connection) { - iphone_error_t res = IPHONE_E_UNKNOWN_ERROR; - uint32_t pktlen = 0; - uint32_t bytes = 0; - - if ((!connection && !ssl_session) || !plist) { + if (!connection || connection->ssl_data) return IPHONE_E_INVALID_ARG; - } - if (ssl_session) { - bytes = gnutls_record_recv(ssl_session, (char*)&pktlen, sizeof(pktlen)); - } else { - iphone_device_recv_timeout(connection, (char*)&pktlen, sizeof(pktlen), &bytes, timeout); + iphone_error_t ret = IPHONE_E_SSL_ERROR; + uint32_t return_me = 0; + + ssl_data_t ssl_data_loc = (ssl_data_t)malloc(sizeof(struct ssl_data_int)); + + // Set up GnuTLS... + debug_info("enabling SSL mode"); + errno = 0; + gnutls_global_init(); + gnutls_certificate_allocate_credentials(&ssl_data_loc->certificate); + gnutls_certificate_set_x509_trust_file(ssl_data_loc->certificate, "hostcert.pem", GNUTLS_X509_FMT_PEM); + gnutls_init(&ssl_data_loc->session, GNUTLS_CLIENT); + { + int protocol_priority[16] = { GNUTLS_SSL3, 0 }; + int kx_priority[16] = { GNUTLS_KX_ANON_DH, GNUTLS_KX_RSA, 0 }; + int cipher_priority[16] = { GNUTLS_CIPHER_AES_128_CBC, GNUTLS_CIPHER_AES_256_CBC, 0 }; + int mac_priority[16] = { GNUTLS_MAC_SHA1, GNUTLS_MAC_MD5, 0 }; + int comp_priority[16] = { GNUTLS_COMP_NULL, 0 }; + + gnutls_cipher_set_priority(ssl_data_loc->session, cipher_priority); + gnutls_compression_set_priority(ssl_data_loc->session, comp_priority); + gnutls_kx_set_priority(ssl_data_loc->session, kx_priority); + gnutls_protocol_set_priority(ssl_data_loc->session, protocol_priority); + gnutls_mac_set_priority(ssl_data_loc->session, mac_priority); } - log_debug_msg("%s: initial read=%i\n", __func__, bytes); - if (bytes < 4) { - log_debug_msg("%s: initial read failed!\n", __func__); - return IPHONE_E_NOT_ENOUGH_DATA; + gnutls_credentials_set(ssl_data_loc->session, GNUTLS_CRD_CERTIFICATE, ssl_data_loc->certificate); // this part is killing me. + + debug_info("GnuTLS step 1..."); + gnutls_transport_set_ptr(ssl_data_loc->session, (gnutls_transport_ptr_t)connection); + debug_info("GnuTLS step 2..."); + gnutls_transport_set_push_function(ssl_data_loc->session, (gnutls_push_func) & internal_ssl_write); + debug_info("GnuTLS step 3..."); + gnutls_transport_set_pull_function(ssl_data_loc->session, (gnutls_pull_func) & internal_ssl_read); + debug_info("GnuTLS step 4 -- now handshaking..."); + if (errno) + debug_info("WARN: errno says %s before handshake!", strerror(errno)); + return_me = gnutls_handshake(ssl_data_loc->session); + debug_info("GnuTLS handshake done..."); + + if (return_me != GNUTLS_E_SUCCESS) { + internal_ssl_cleanup(ssl_data_loc); + free(ssl_data_loc); + debug_info("GnuTLS reported something wrong."); + gnutls_perror(return_me); + debug_info("oh.. errno says %s", strerror(errno)); } else { - if ((char)pktlen == 0) { /* prevent huge buffers */ - uint32_t curlen = 0; - char *content = NULL; - pktlen = ntohl(pktlen); - log_debug_msg("%s: %d bytes following\n", __func__, pktlen); - content = (char*)malloc(pktlen); - - while (curlen < pktlen) { - if (ssl_session) { - bytes = gnutls_record_recv(ssl_session, content+curlen, pktlen-curlen); - } else { - iphone_device_recv(connection, content+curlen, pktlen-curlen, &bytes); - } - if (bytes <= 0) { - res = IPHONE_E_UNKNOWN_ERROR; - break; - } - log_debug_msg("%s: received %d bytes\n", __func__, bytes); - curlen += bytes; - } - log_debug_buffer(content, pktlen); - if (!memcmp(content, "bplist00", 8)) { - plist_from_bin(content, pktlen, plist); - } else { - plist_from_xml(content, pktlen, plist); - } - if (*plist) { - res = IPHONE_E_SUCCESS; - } else { - res = IPHONE_E_PLIST_ERROR; - } - free(content); - content = NULL; - } else { - res = IPHONE_E_UNKNOWN_ERROR; - } + connection->ssl_data = ssl_data_loc; + ret = IPHONE_E_SUCCESS; + debug_info("SSL mode enabled"); } - return res; -} - -/** - * Receives a plist over the given connection with specified timeout. - * Binary or XML plists are automatically handled. - * - * @param connection The connection to receive data on - * @param plist pointer to a plist_t that will point to the received plist - * upon successful return - * @param timeout Maximum time in milliseconds to wait for data. - * - * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when connection - * or *plist is NULL, IPHONE_E_PLIST_ERROR when the received data cannot be - * converted to a plist, or IPHONE_E_UNKNOWN_ERROR when an unspecified - * error occurs. - */ -iphone_error_t iphone_device_receive_plist_with_timeout(iphone_connection_t connection, plist_t *plist, unsigned int timeout) -{ - return internal_plist_recv_timeout(connection, plist, timeout, NULL); + return ret; } /** - * Receives a plist over the given connection. - * Binary or XML plists are automatically handled. + * Disable SSL for the given connection. * - * This function is like iphone_device_receive_plist_with_timeout - * using a timeout of 10 seconds. - * @see iphone_device_receive_plist_with_timeout - * - * @param connection The connection to receive data on - * @param plist pointer to a plist_t that will point to the received plist - * upon successful return + * @param connection The connection to disable SSL for. * * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when connection - * or *plist is NULL, IPHONE_E_PLIST_ERROR when the received data cannot be - * converted to a plist, or IPHONE_E_UNKNOWN_ERROR when an unspecified - * error occurs. - */ -iphone_error_t iphone_device_receive_plist(iphone_connection_t connection, plist_t *plist) -{ - return internal_plist_recv_timeout(connection, plist, 10000, NULL); -} - -/** - * Receives an encrypted plist with specified timeout. - * Binary or XML plists are automatically handled. - * - * @param ssl_session Valid and properly initialized gnutls_session_t. - * @param plist pointer to a plist_t that will point to the received plist - * upon successful return - * @param timeout Maximum time in milliseconds to wait for data. - * - * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when ssl_session - * or *plist is NULL, IPHONE_E_PLIST_ERROR when the received data cannot be - * converted to a plist, or IPHONE_E_UNKNOWN_ERROR when an unspecified - * error occurs. - */ -iphone_error_t iphone_device_receive_encrypted_plist_with_timeout(gnutls_session_t ssl_session, plist_t *plist, unsigned int timeout) -{ - return internal_plist_recv_timeout(NULL, plist, timeout, ssl_session); -} - -/** - * Receives an encrypted plist. - * Binary or XML plists are automatically handled. - * This function is like iphone_device_receive_encrypted_plist_with_timeout - * with a timeout value of 10 seconds. - * - * @param ssl_session Valid and properly initialized gnutls_session_t. - * @param connection The connection to receive data on - * @param plist pointer to a plist_t that will point to the received plist - * upon successful return - * - * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when ssl_session - * or *plist is NULL, IPHONE_E_PLIST_ERROR when the received data cannot be - * converted to a plist, or IPHONE_E_UNKNOWN_ERROR when an unspecified - * error occurs. + * is NULL. This function also returns IPHONE_E_SUCCESS when SSL is not + * enabled and does no further error checking on cleanup. */ -iphone_error_t iphone_device_receive_encrypted_plist(gnutls_session_t ssl_session, plist_t *plist) -{ - return internal_plist_recv_timeout(NULL, plist, 10000, ssl_session); -} - -iphone_error_t iphone_device_get_handle(iphone_device_t device, uint32_t *handle) +iphone_error_t iphone_connection_disable_ssl(iphone_connection_t connection) { - if (!device) + if (!connection) return IPHONE_E_INVALID_ARG; - - if (device->conn_type == CONNECTION_USBMUXD) { - *handle = (uint32_t)device->conn_data; + if (!connection->ssl_data) { + /* ignore if ssl is not enabled */ return IPHONE_E_SUCCESS; - } else { - log_debug_msg("%s: Unknown connection type %d\n", __func__, device->conn_type); } - return IPHONE_E_UNKNOWN_ERROR; -} -iphone_error_t iphone_device_get_uuid(iphone_device_t device, char **uuid) -{ - if (!device) - return IPHONE_E_INVALID_ARG; + if (connection->ssl_data->session) { + gnutls_bye(connection->ssl_data->session, GNUTLS_SHUT_RDWR); + } + internal_ssl_cleanup(connection->ssl_data); + free(connection->ssl_data); + connection->ssl_data = NULL; + + debug_info("SSL mode disabled"); - *uuid = strdup(device->uuid); return IPHONE_E_SUCCESS; } diff --git a/src/iphone.h b/src/iphone.h index 7ffc811..2755349 100644 --- a/src/iphone.h +++ b/src/iphone.h @@ -30,9 +30,16 @@ enum connection_type { CONNECTION_USBMUXD = 1 }; +struct ssl_data_int { + gnutls_certificate_credentials_t certificate; + gnutls_session_t session; +}; +typedef struct ssl_data_int *ssl_data_t; + struct iphone_connection_int { enum connection_type type; void *data; + ssl_data_t ssl_data; }; struct iphone_device_int { @@ -41,14 +48,7 @@ struct iphone_device_int { void *conn_data; }; -iphone_error_t iphone_device_send_xml_plist(iphone_connection_t connection, plist_t plist); -iphone_error_t iphone_device_send_binary_plist(iphone_connection_t connection, plist_t plist); -iphone_error_t iphone_device_send_encrypted_xml_plist(gnutls_session_t ssl_session, plist_t plist); -iphone_error_t iphone_device_send_encrypted_binary_plist(gnutls_session_t ssl_session, plist_t plist); - -iphone_error_t iphone_device_receive_plist_with_timeout(iphone_connection_t connection, plist_t *plist, unsigned int timeout); -iphone_error_t iphone_device_receive_plist(iphone_connection_t connection, plist_t *plist); -iphone_error_t iphone_device_receive_encrypted_plist_with_timeout(gnutls_session_t ssl_session, plist_t *plist, unsigned int timeout); -iphone_error_t iphone_device_receive_encrypted_plist(gnutls_session_t ssl_session, plist_t *plist); +iphone_error_t iphone_connection_enable_ssl(iphone_connection_t connection); +iphone_error_t iphone_connection_disable_ssl(iphone_connection_t connection); #endif diff --git a/src/lockdown.c b/src/lockdown.c index 2532999..1befb72 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -28,9 +28,10 @@ #include <gnutls/x509.h> #include <plist/plist.h> +#include "property_list_service.h" #include "lockdown.h" #include "iphone.h" -#include "utils.h" +#include "debug.h" #include "userpref.h" #define RESULT_SUCCESS 0 @@ -98,7 +99,7 @@ static int lockdown_check_result(plist_t dict, const char *query_match) } else if (!strcmp(result_value, "Failure")) { ret = RESULT_FAILURE; } else { - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: ERROR: unknown result value '%s'\n", __func__, result_value); + debug_info("ERROR: unknown result value '%s'", result_value); } } if (result_value) @@ -108,30 +109,49 @@ static int lockdown_check_result(plist_t dict, const char *query_match) } /** - * Closes the lockdownd communication session, by sending - * the StopSession Request to the device. + * Adds a label key with the passed value to a plist dict node. + * + * @param plist The plist to add the key to + * @param label The value for the label key + * + */ +static void plist_dict_add_label(plist_t plist, const char *label) +{ + if (plist && label) { + if (plist_get_node_type(plist) == PLIST_DICT) + plist_dict_insert_item(plist, "Label", plist_new_string(label)); + } +} + +/** + * Closes the lockdownd communication session, by sending the StopSession + * Request to the device. + * + * @see lockdownd_start_session * * @param control The lockdown client + * @param session_id The id of a running session * * @return an error code (LOCKDOWN_E_SUCCESS on success) */ -lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client) +lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client, const char *session_id) { if (!client) return LOCKDOWN_E_INVALID_ARG; - if (!client->session_id) { - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: no session_id given, cannot stop session\n", __func__); + if (!session_id) { + debug_info("no session_id given, cannot stop session"); return LOCKDOWN_E_INVALID_ARG; } lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); + plist_dict_add_label(dict, client->label); plist_dict_insert_item(dict,"Request", plist_new_string("StopSession")); - plist_dict_insert_item(dict,"SessionID", plist_new_string(client->session_id)); + plist_dict_insert_item(dict,"SessionID", plist_new_string(session_id)); - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: stopping session %s\n", __func__, client->session_id); + debug_info("stopping session %s", session_id); ret = lockdownd_send(client, dict); @@ -141,55 +161,20 @@ lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client) ret = lockdownd_recv(client, &dict); if (!dict) { - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: LOCKDOWN_E_PLIST_ERROR\n", __func__); + debug_info("LOCKDOWN_E_PLIST_ERROR"); return LOCKDOWN_E_PLIST_ERROR; } ret = LOCKDOWN_E_UNKNOWN_ERROR; if (lockdown_check_result(dict, "StopSession") == RESULT_SUCCESS) { - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); + debug_info("success"); ret = LOCKDOWN_E_SUCCESS; } plist_free(dict); dict = NULL; - - free(client->session_id); - client->session_id = NULL; - - return ret; -} - -/** - * Shuts down the SSL session by first calling iphone_lckd_stop_session - * to cleanly close the lockdownd communication session, and then - * performing a close notify, which is done by "gnutls_bye". - * - * @param client The lockdown client - * - * @return an error code (LOCKDOWN_E_SUCCESS on success) - */ -static lockdownd_error_t lockdownd_stop_ssl_session(lockdownd_client_t client) -{ - if (!client) { - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: invalid argument!\n", __func__); - return LOCKDOWN_E_INVALID_ARG; + if (client->ssl_enabled) { + property_list_service_disable_ssl(client->parent); } - lockdownd_error_t ret = LOCKDOWN_E_SUCCESS; - - if (client->in_SSL) { - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: stopping SSL session\n", __func__); - ret = lockdownd_stop_session(client); - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: sending SSL close notify\n", __func__); - gnutls_bye(client->ssl_session, GNUTLS_SHUT_RDWR); - } - if (client->ssl_session) { - gnutls_deinit(client->ssl_session); - } - if (client->ssl_certificate) { - gnutls_certificate_free_credentials(client->ssl_certificate); - } - client->in_SSL = 0; - return ret; } @@ -205,29 +190,45 @@ lockdownd_error_t lockdownd_client_free(lockdownd_client_t client) return LOCKDOWN_E_INVALID_ARG; lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; - lockdownd_stop_ssl_session(client); + if (client->session_id) + lockdownd_stop_session(client, client->session_id); - if (client->connection) { + if (client->parent) { lockdownd_goodbye(client); - // IMO, read of final "sessionUpcall connection closed" packet - // should come here instead of in iphone_free_device - if ((ret = iphone_device_disconnect(client->connection)) != IPHONE_E_SUCCESS) { - ret = LOCKDOWN_E_UNKNOWN_ERROR; + if (property_list_service_client_free(client->parent) == PROPERTY_LIST_SERVICE_E_SUCCESS) { + ret = LOCKDOWN_E_SUCCESS; } } - if (client->session_id) { - free(client->session_id); - } if (client->uuid) { free(client->uuid); } + if (client->label) { + free(client->label); + } free(client); return ret; } +/** + * Sets the label to send for requests to lockdownd. + * + * @param client The lockdown client + * @param label The label to set or NULL to disable sending a label + * + */ +void lockdownd_client_set_label(lockdownd_client_t client, const char *label) +{ + if (client) { + if (client->label) + free(client->label); + + client->label = (label != NULL) ? strdup(label): NULL; + } +} + /** Polls the iPhone for lockdownd data. * * @param control The lockdownd client @@ -240,18 +241,11 @@ lockdownd_error_t lockdownd_recv(lockdownd_client_t client, plist_t *plist) if (!client || !plist || (plist && *plist)) return LOCKDOWN_E_INVALID_ARG; lockdownd_error_t ret = LOCKDOWN_E_SUCCESS; - iphone_error_t err; + property_list_service_error_t err; - if (!client->in_SSL) { - err = iphone_device_receive_plist(client->connection, plist); - if (err != IPHONE_E_SUCCESS) { - ret = LOCKDOWN_E_UNKNOWN_ERROR; - } - } else { - err = iphone_device_receive_encrypted_plist(client->ssl_session, plist); - if (err != IPHONE_E_SUCCESS) { - return LOCKDOWN_E_SSL_ERROR; - } + err = property_list_service_receive_plist(client->parent, plist); + if (err != PROPERTY_LIST_SERVICE_E_SUCCESS) { + ret = LOCKDOWN_E_UNKNOWN_ERROR; } if (!*plist) @@ -278,27 +272,22 @@ lockdownd_error_t lockdownd_send(lockdownd_client_t client, plist_t plist) lockdownd_error_t ret = LOCKDOWN_E_SUCCESS; iphone_error_t err; - if (!client->in_SSL) { - err = iphone_device_send_xml_plist(client->connection, plist); - if (err != IPHONE_E_SUCCESS) { - ret = LOCKDOWN_E_UNKNOWN_ERROR; - } - } else { - err = iphone_device_send_encrypted_xml_plist(client->ssl_session, plist); - if (err != IPHONE_E_SUCCESS) { - ret = LOCKDOWN_E_SSL_ERROR; - } + err = property_list_service_send_xml_plist(client->parent, plist); + if (err != PROPERTY_LIST_SERVICE_E_SUCCESS) { + ret = LOCKDOWN_E_UNKNOWN_ERROR; } return ret; } -/** Initiates the handshake for the lockdown session. Part of the lockdownd handshake. +/** Query the type of the service daemon. Depending on whether the device is + * queried in normal mode or restore mode, different types will be returned. * * @param client The lockdownd client + * @param type The type returned by the service daemon. Can be NULL to ignore. * * @return an error code (LOCKDOWN_E_SUCCESS on success) */ -lockdownd_error_t lockdownd_query_type(lockdownd_client_t client) +lockdownd_error_t lockdownd_query_type(lockdownd_client_t client, char **type) { if (!client) return LOCKDOWN_E_INVALID_ARG; @@ -306,9 +295,10 @@ lockdownd_error_t lockdownd_query_type(lockdownd_client_t client) lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); + plist_dict_add_label(dict, client->label); plist_dict_insert_item(dict,"Request", plist_new_string("QueryType")); - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: called\n", __func__); + debug_info("called"); ret = lockdownd_send(client, dict); plist_free(dict); @@ -321,7 +311,12 @@ lockdownd_error_t lockdownd_query_type(lockdownd_client_t client) ret = LOCKDOWN_E_UNKNOWN_ERROR; if (lockdown_check_result(dict, "QueryType") == RESULT_SUCCESS) { - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); + /* return the type if requested */ + if (type != NULL) { + plist_t type_node = plist_dict_get_item(dict, "Type"); + plist_get_string_val(type_node, type); + } + debug_info("success with type %s", *type); ret = LOCKDOWN_E_SUCCESS; } plist_free(dict); @@ -349,6 +344,7 @@ lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *dom /* setup request plist */ dict = plist_new_dict(); + plist_dict_add_label(dict, client->label); if (domain) { plist_dict_insert_item(dict,"Domain", plist_new_string(domain)); } @@ -372,7 +368,7 @@ lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *dom return ret; if (lockdown_check_result(dict, "GetValue") == RESULT_SUCCESS) { - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); + debug_info("success"); ret = LOCKDOWN_E_SUCCESS; } if (ret != LOCKDOWN_E_SUCCESS) { @@ -383,7 +379,7 @@ lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *dom plist_t value_node = plist_dict_get_item(dict, "Value"); if (value_node) { - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: has a value\n", __func__); + debug_info("has a value"); *value = plist_copy(value_node); } @@ -410,6 +406,7 @@ lockdownd_error_t lockdownd_set_value(lockdownd_client_t client, const char *dom /* setup request plist */ dict = plist_new_dict(); + plist_dict_add_label(dict, client->label); if (domain) { plist_dict_insert_item(dict,"Domain", plist_new_string(domain)); } @@ -434,7 +431,7 @@ lockdownd_error_t lockdownd_set_value(lockdownd_client_t client, const char *dom return ret; if (lockdown_check_result(dict, "SetValue") == RESULT_SUCCESS) { - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); + debug_info("success"); ret = LOCKDOWN_E_SUCCESS; } @@ -467,6 +464,7 @@ lockdownd_error_t lockdownd_remove_value(lockdownd_client_t client, const char * /* setup request plist */ dict = plist_new_dict(); + plist_dict_add_label(dict, client->label); if (domain) { plist_dict_insert_item(dict,"Domain", plist_new_string(domain)); } @@ -490,7 +488,7 @@ lockdownd_error_t lockdownd_remove_value(lockdownd_client_t client, const char * return ret; if (lockdown_check_result(dict, "RemoveValue") == RESULT_SUCCESS) { - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); + debug_info("success"); ret = LOCKDOWN_E_SUCCESS; } @@ -572,44 +570,85 @@ lockdownd_error_t lockdownd_get_device_name(lockdownd_client_t client, char **de return ret; } -/** Creates a lockdownd client for the give iPhone +/** Creates a lockdownd client for the device. * - * @param phone The iPhone to create a lockdownd client for + * @param phone The device to create a lockdownd client for * @param client The pointer to the location of the new lockdownd_client + * @param label The label to use for communication. Usually the program name * * @return an error code (LOCKDOWN_E_SUCCESS on success) */ -lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_t *client) +lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_t *client, const char *label) { if (!client) return LOCKDOWN_E_INVALID_ARG; + lockdownd_error_t ret = LOCKDOWN_E_SUCCESS; - char *host_id = NULL; - iphone_connection_t connection; - if (iphone_device_connect(device, 0xf27e, &connection) != IPHONE_E_SUCCESS) { - log_debug_msg("%s: could not connect to lockdownd (device %s)\n", __func__, device->uuid); + property_list_service_client_t plistclient = NULL; + if (property_list_service_client_new(device, 0xf27e, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) { + debug_info("could not connect to lockdownd (device %s)", device->uuid); return LOCKDOWN_E_MUX_ERROR; } lockdownd_client_t client_loc = (lockdownd_client_t) malloc(sizeof(struct lockdownd_client_int)); - client_loc->connection = connection; - client_loc->ssl_session = NULL; - client_loc->ssl_certificate = NULL; - client_loc->in_SSL = 0; + client_loc->parent = plistclient; + client_loc->ssl_enabled = 0; client_loc->session_id = NULL; client_loc->uuid = NULL; + client_loc->label = NULL; + if (label != NULL) + strdup(label); + + if (LOCKDOWN_E_SUCCESS == ret) { + *client = client_loc; + } else { + lockdownd_client_free(client_loc); + } + + return ret; +} + +/** Creates a lockdownd client for the device and starts initial handshake. + * The handshake consists of query_type, validate_pair, pair and + * start_session calls. + * + * @param phone The device to create a lockdownd client for + * @param client The pointer to the location of the new lockdownd_client + * @param label The label to use for communication. Usually the program name + * + * @return an error code (LOCKDOWN_E_SUCCESS on success) + */ +lockdownd_error_t lockdownd_client_new_with_handshake(iphone_device_t device, lockdownd_client_t *client, const char *label) +{ + if (!client) + return LOCKDOWN_E_INVALID_ARG; + + lockdownd_error_t ret = LOCKDOWN_E_SUCCESS; + lockdownd_client_t client_loc = NULL; + char *host_id = NULL; + char *type = NULL; - if (LOCKDOWN_E_SUCCESS != lockdownd_query_type(client_loc)) { - log_debug_msg("%s: QueryType failed in the lockdownd client.\n", __func__); + + ret = lockdownd_client_new(device, &client_loc, label); + + /* perform handshake */ + if (LOCKDOWN_E_SUCCESS != lockdownd_query_type(client_loc, &type)) { + debug_info("QueryType failed in the lockdownd client."); ret = LOCKDOWN_E_NOT_ENOUGH_DATA; + } else { + if (strcmp("com.apple.mobile.lockdown", type)) { + debug_info("Warning QueryType request returned \"%s\".", type); + } + if (type) + free(type); } ret = iphone_device_get_uuid(device, &client_loc->uuid); if (LOCKDOWN_E_SUCCESS != ret) { - log_debug_msg("%s: failed to get device uuid.\n", __func__); + debug_info("failed to get device uuid."); } - log_debug_msg("%s: device uuid: %s\n", __func__, client_loc->uuid); + debug_info("device uuid: %s", client_loc->uuid); userpref_get_host_id(&host_id); if (LOCKDOWN_E_SUCCESS == ret && !host_id) { @@ -617,77 +656,135 @@ lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_ } if (LOCKDOWN_E_SUCCESS == ret && !userpref_has_device_public_key(client_loc->uuid)) - ret = lockdownd_pair(client_loc, host_id); + ret = lockdownd_pair(client_loc, NULL); + + /* in any case, we need to validate pairing to receive trusted host status */ + ret = lockdownd_validate_pair(client_loc, NULL); if (LOCKDOWN_E_SUCCESS == ret) { - ret = lockdownd_start_ssl_session(client_loc, host_id); + ret = lockdownd_start_session(client_loc, host_id, NULL, NULL); if (LOCKDOWN_E_SUCCESS != ret) { - ret = LOCKDOWN_E_SSL_ERROR; - log_debug_msg("%s: SSL Session opening failed.\n", __func__); + debug_info("Session opening failed."); } if (host_id) { free(host_id); host_id = NULL; } + } + + if (LOCKDOWN_E_SUCCESS == ret) { + *client = client_loc; + } else { + lockdownd_client_free(client_loc); + } - if (LOCKDOWN_E_SUCCESS == ret) - *client = client_loc; + return ret; +} + +static plist_t lockdownd_pair_record_to_plist(lockdownd_pair_record_t pair_record) +{ + if (!pair_record) + return NULL; + + char *host_id_loc = pair_record->host_id; + + /* setup request plist */ + plist_t dict = plist_new_dict(); + plist_dict_insert_item(dict, "DeviceCertificate", plist_new_data(pair_record->device_certificate, strlen(pair_record->device_certificate))); + plist_dict_insert_item(dict, "HostCertificate", plist_new_data(pair_record->host_certificate, strlen(pair_record->host_certificate))); + if (!pair_record->host_id) + userpref_get_host_id(&host_id_loc); + plist_dict_insert_item(dict, "HostID", plist_new_string(host_id_loc)); + plist_dict_insert_item(dict, "RootCertificate", plist_new_data(pair_record->root_certificate, strlen(pair_record->root_certificate))); + + if (!pair_record->host_id) + free(host_id_loc); + + return dict; +} + +static lockdownd_error_t generate_pair_record_plist(gnutls_datum_t public_key, char *host_id, plist_t *pair_record_plist) +{ + lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; + + gnutls_datum_t device_cert = { NULL, 0 }; + gnutls_datum_t host_cert = { NULL, 0 }; + gnutls_datum_t root_cert = { NULL, 0 }; + + ret = lockdownd_gen_pair_cert(public_key, &device_cert, &host_cert, &root_cert); + if (ret != LOCKDOWN_E_SUCCESS) { + return ret; } + char *host_id_loc = host_id; + + if (!host_id) + userpref_get_host_id(&host_id_loc); + + /* setup request plist */ + *pair_record_plist = plist_new_dict(); + plist_dict_insert_item(*pair_record_plist, "DeviceCertificate", plist_new_data((const char*)device_cert.data, device_cert.size)); + plist_dict_insert_item(*pair_record_plist, "HostCertificate", plist_new_data((const char*)host_cert.data, host_cert.size)); + plist_dict_insert_item(*pair_record_plist, "HostID", plist_new_string(host_id_loc)); + plist_dict_insert_item(*pair_record_plist, "RootCertificate", plist_new_data((const char*)root_cert.data, root_cert.size)); + + if (!host_id) + free(host_id_loc); + return ret; } /** Function used internally by lockdownd_pair() and lockdownd_validate_pair() * * @param client The lockdown client to pair with. - * @param host_id The HostID to use for pairing. If NULL is passed, then - * the HostID of the current machine is used. A new HostID will be + * @param pair_record The pair record to use for pairing. If NULL is passed, then + * the pair records from the current machine are used. New records will be * generated automatically when pairing is done for the first time. - * @param verb This is either "Pair" or "ValidatePair". + * @param verb This is either "Pair", "ValidatePair" or "Unpair". * * @return an error code (LOCKDOWN_E_SUCCESS on success) */ -static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, char *host_id, const char *verb) +static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record, const char *verb) { lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; plist_t dict = NULL; plist_t dict_record = NULL; - - gnutls_datum_t device_cert = { NULL, 0 }; - gnutls_datum_t host_cert = { NULL, 0 }; - gnutls_datum_t root_cert = { NULL, 0 }; gnutls_datum_t public_key = { NULL, 0 }; + int pairing_mode = 0; /* 0 = libiphone, 1 = external */ - char *host_id_loc = host_id; - - ret = lockdownd_get_device_public_key(client, &public_key); - if (ret != LOCKDOWN_E_SUCCESS) { - log_debug_msg("%s: device refused to send public key.\n", __func__); - return ret; - } - log_debug_msg("%s: device public key follows:\n%s\n", __func__, public_key.data); + if (pair_record && pair_record->host_id) { + /* valid pair_record passed? */ + if (!pair_record->device_certificate || !pair_record->host_certificate || !pair_record->root_certificate) { + return LOCKDOWN_E_PLIST_ERROR; + } - ret = lockdownd_gen_pair_cert(public_key, &device_cert, &host_cert, &root_cert); - if (ret != LOCKDOWN_E_SUCCESS) { - free(public_key.data); - return ret; - } + /* use passed pair_record */ + dict_record = lockdownd_pair_record_to_plist(pair_record); - if (!host_id) { - userpref_get_host_id(&host_id_loc); + pairing_mode = 1; + } else { + ret = lockdownd_get_device_public_key(client, &public_key); + if (ret != LOCKDOWN_E_SUCCESS) { + if (public_key.data) + free(public_key.data); + debug_info("device refused to send public key."); + return ret; + } + debug_info("device public key follows:\n%s", public_key.data); + /* get libiphone pair_record */ + ret = generate_pair_record_plist(public_key, NULL, &dict_record); + if (ret != LOCKDOWN_E_SUCCESS) { + if (dict_record) + plist_free(dict_record); + return ret; + } } /* Setup Pair request plist */ dict = plist_new_dict(); - dict_record = plist_new_dict(); + plist_dict_add_label(dict, client->label); plist_dict_insert_item(dict,"PairRecord", dict_record); - - plist_dict_insert_item(dict_record, "DeviceCertificate", plist_new_data((const char*)device_cert.data, device_cert.size)); - plist_dict_insert_item(dict_record, "HostCertificate", plist_new_data((const char*)host_cert.data, host_cert.size)); - plist_dict_insert_item(dict_record, "HostID", plist_new_string(host_id_loc)); - plist_dict_insert_item(dict_record, "RootCertificate", plist_new_data((const char*)root_cert.data, root_cert.size)); - plist_dict_insert_item(dict, "Request", plist_new_string(verb)); /* send to iPhone */ @@ -695,10 +792,6 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, char *host plist_free(dict); dict = NULL; - if (!host_id) { - free(host_id_loc); - } - if (ret != LOCKDOWN_E_SUCCESS) return ret; @@ -711,17 +804,40 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, char *host if (lockdown_check_result(dict, verb) != RESULT_SUCCESS) { ret = LOCKDOWN_E_PAIRING_FAILED; } - plist_free(dict); - dict = NULL; - /* store public key in config if pairing succeeded */ + /* if pairing succeeded */ if (ret == LOCKDOWN_E_SUCCESS) { - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: %s success\n", __func__, verb); - userpref_set_device_public_key(client->uuid, public_key); + debug_info("%s success", verb); + if (!pairing_mode) { + if (!strcmp("Unpair", verb)) { + /* remove public key from config */ + userpref_remove_device_public_key(client->uuid); + } else { + /* store public key in config */ + userpref_set_device_public_key(client->uuid, public_key); + } + } } else { - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: %s failure\n", __func__, verb); + debug_info("%s failure", verb); + plist_t error_node = NULL; + /* verify error condition */ + error_node = plist_dict_get_item(dict, "Error"); + if (error_node) { + char *value = NULL; + plist_get_string_val(error_node, &value); + /* the first pairing fails if the device is password protected */ + if (value && !strcmp(value, "PasswordProtected")) { + ret = LOCKDOWN_E_PASSWORD_PROTECTED; + free(value); + } + plist_free(error_node); + error_node = NULL; + } } - free(public_key.data); + plist_free(dict); + dict = NULL; + if (public_key.data) + free(public_key.data); return ret; } @@ -730,15 +846,15 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, char *host * It's part of the lockdownd handshake. * * @param client The lockdown client to pair with. - * @param host_id The HostID to use for pairing. If NULL is passed, then - * the HostID of the current machine is used. A new HostID will be + * @param pair_record The pair record to use for pairing. If NULL is passed, then + * the pair records from the current machine are used. New records will be * generated automatically when pairing is done for the first time. * * @return an error code (LOCKDOWN_E_SUCCESS on success) */ -lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *host_id) +lockdownd_error_t lockdownd_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record) { - return lockdownd_do_pair(client, host_id, "Pair"); + return lockdownd_do_pair(client, pair_record, "Pair"); } /** @@ -747,15 +863,31 @@ lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *host_id) * It's part of the lockdownd handshake. * * @param client The lockdown client to pair with. - * @param host_id The HostID to use for pairing. If NULL is passed, then - * the HostID of the current machine is used. A new HostID will be - * generated automatically when pairing is done for the first time. + * @param pair_record The pair record to validate pairing with. If NULL is + * passed, then the pair records from the current machine are used. + * New records will be generated automatically when pairing is done + * for the first time. * * @return an error code (LOCKDOWN_E_SUCCESS on success) */ -lockdownd_error_t lockdownd_validate_pair(lockdownd_client_t client, char *host_id) +lockdownd_error_t lockdownd_validate_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record) { - return lockdownd_do_pair(client, host_id, "ValidatePair"); + return lockdownd_do_pair(client, pair_record, "ValidatePair"); +} + +/** + * Unpairs the device with the given HostID and removes the pairing records + * from the device and host. + * + * @param client The lockdown client to pair with. + * @param pair_record The pair record to use for unpair. If NULL is passed, then + * the pair records from the current machine are used. + * + * @return an error code (LOCKDOWN_E_SUCCESS on success) + */ +lockdownd_error_t lockdownd_unpair(lockdownd_client_t client, lockdownd_pair_record_t pair_record) +{ + return lockdownd_do_pair(client, pair_record, "Unpair"); } /** @@ -773,9 +905,10 @@ lockdownd_error_t lockdownd_enter_recovery(lockdownd_client_t client) lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); + plist_dict_add_label(dict, client->label); plist_dict_insert_item(dict,"Request", plist_new_string("EnterRecovery")); - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: telling device to enter recovery mode\n", __func__); + debug_info("telling device to enter recovery mode"); ret = lockdownd_send(client, dict); plist_free(dict); @@ -784,7 +917,7 @@ lockdownd_error_t lockdownd_enter_recovery(lockdownd_client_t client) ret = lockdownd_recv(client, &dict); if (lockdown_check_result(dict, "EnterRecovery") == RESULT_SUCCESS) { - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); + debug_info("success"); ret = LOCKDOWN_E_SUCCESS; } plist_free(dict); @@ -808,9 +941,10 @@ lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client) lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); + plist_dict_add_label(dict, client->label); plist_dict_insert_item(dict,"Request", plist_new_string("Goodbye")); - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: called\n", __func__); + debug_info("called"); ret = lockdownd_send(client, dict); plist_free(dict); @@ -818,12 +952,12 @@ lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client) ret = lockdownd_recv(client, &dict); if (!dict) { - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: did not get goodbye response back\n", __func__); + debug_info("did not get goodbye response back"); return LOCKDOWN_E_PLIST_ERROR; } if (lockdown_check_result(dict, "Goodbye") == RESULT_SUCCESS) { - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); + debug_info("success"); ret = LOCKDOWN_E_SUCCESS; } plist_free(dict); @@ -879,7 +1013,7 @@ lockdownd_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datu asn1_delete_structure(&pkcs1); } - /* now generate certifcates */ + /* now generate certificates */ if (LOCKDOWN_E_SUCCESS == ret && 0 != modulus.size && 0 != exponent.size) { gnutls_global_init(); @@ -973,24 +1107,29 @@ lockdownd_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datu * and if the device requires it, switches to SSL mode. * * @param client The lockdownd client - * @param HostID The HostID used with this phone + * @param host_id The HostID of the computer + * @param session_id The session_id of the created session + * @param ssl_enabled Whether SSL communication is used in the session * * @return an error code (LOCKDOWN_E_SUCCESS on success) */ -lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const char *HostID) +lockdownd_error_t lockdownd_start_session(lockdownd_client_t client, const char *host_id, char **session_id, int *ssl_enabled) { + lockdownd_error_t ret = LOCKDOWN_E_SUCCESS; plist_t dict = NULL; - uint32_t return_me = 0; - lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; + if (!client || !host_id) + ret = LOCKDOWN_E_INVALID_ARG; + + /* if we have a running session, stop current one first */ if (client->session_id) { - free(client->session_id); - client->session_id = NULL; + lockdownd_stop_session(client, client->session_id); } - /* Setup DevicePublicKey request plist */ + /* setup request plist */ dict = plist_new_dict(); - plist_dict_insert_item(dict,"HostID", plist_new_string(HostID)); + plist_dict_add_label(dict, client->label); + plist_dict_insert_item(dict,"HostID", plist_new_string(host_id)); plist_dict_insert_item(dict,"Request", plist_new_string("StartSession")); ret = lockdownd_send(client, dict); @@ -1010,183 +1149,54 @@ lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const c if (error_node && PLIST_STRING == plist_get_node_type(error_node)) { char *error = NULL; plist_get_string_val(error_node, &error); - if (!strcmp(error, "InvalidHostID")) { - /* hostid is unknown. Pair and try again */ - char *host_id = NULL; - userpref_get_host_id(&host_id); - - if (LOCKDOWN_E_SUCCESS == lockdownd_pair(client, host_id) ) { - /* start session again */ - plist_free(dict); - dict = plist_new_dict(); - plist_dict_insert_item(dict,"HostID", plist_new_string(HostID)); - plist_dict_insert_item(dict,"Request", plist_new_string("StartSession")); - - ret = lockdownd_send(client, dict); - plist_free(dict); - dict = NULL; - - ret = lockdownd_recv(client, &dict); - } - free(host_id); + ret = LOCKDOWN_E_INVALID_HOST_ID; } free(error); } - } - - ret = LOCKDOWN_E_SSL_ERROR; - - int session_ok = 0; - uint8_t UseSSL = 0; + } else { + uint8_t use_ssl = 0; - if (lockdown_check_result(dict, "StartSession") == RESULT_SUCCESS) { plist_t enable_ssl = plist_dict_get_item(dict, "EnableSessionSSL"); if (enable_ssl && (plist_get_node_type(enable_ssl) == PLIST_BOOLEAN)) { - plist_get_bool_val(enable_ssl, &UseSSL); + plist_get_bool_val(enable_ssl, &use_ssl); } - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Session startup OK\n", __func__); - session_ok = 1; - } - if (session_ok && !UseSSL) { - client->in_SSL = 0; - ret = LOCKDOWN_E_SUCCESS; - } else if (session_ok) { - // Set up GnuTLS... - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Switching to SSL mode\n", __func__); - errno = 0; - gnutls_global_init(); - //gnutls_anon_allocate_client_credentials(&anoncred); - gnutls_certificate_allocate_credentials(&client->ssl_certificate); - gnutls_certificate_set_x509_trust_file(client->ssl_certificate, "hostcert.pem", GNUTLS_X509_FMT_PEM); - gnutls_init(&client->ssl_session, GNUTLS_CLIENT); - { - int protocol_priority[16] = { GNUTLS_SSL3, 0 }; - int kx_priority[16] = { GNUTLS_KX_ANON_DH, GNUTLS_KX_RSA, 0 }; - int cipher_priority[16] = { GNUTLS_CIPHER_AES_128_CBC, GNUTLS_CIPHER_AES_256_CBC, 0 }; - int mac_priority[16] = { GNUTLS_MAC_SHA1, GNUTLS_MAC_MD5, 0 }; - int comp_priority[16] = { GNUTLS_COMP_NULL, 0 }; - - gnutls_cipher_set_priority(client->ssl_session, cipher_priority); - gnutls_compression_set_priority(client->ssl_session, comp_priority); - gnutls_kx_set_priority(client->ssl_session, kx_priority); - gnutls_protocol_set_priority(client->ssl_session, protocol_priority); - gnutls_mac_set_priority(client->ssl_session, mac_priority); + debug_info("Session startup OK"); + + if (ssl_enabled != NULL) + *ssl_enabled = use_ssl; + + /* store session id, we need it for StopSession */ + plist_t session_node = plist_dict_get_item(dict, "SessionID"); + if (session_node && (plist_get_node_type(session_node) == PLIST_STRING)) { + plist_get_string_val(session_node, &client->session_id); } - gnutls_credentials_set(client->ssl_session, GNUTLS_CRD_CERTIFICATE, client->ssl_certificate); // this part is killing me. - - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS step 1...\n", __func__); - gnutls_transport_set_ptr(client->ssl_session, (gnutls_transport_ptr_t) client); - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS step 2...\n", __func__); - gnutls_transport_set_push_function(client->ssl_session, (gnutls_push_func) & lockdownd_secuwrite); - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS step 3...\n", __func__); - gnutls_transport_set_pull_function(client->ssl_session, (gnutls_pull_func) & lockdownd_securead); - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS step 4 -- now handshaking...\n", __func__); - if (errno) - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: WARN: errno says %s before handshake!\n", __func__, strerror(errno)); - return_me = gnutls_handshake(client->ssl_session); - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS handshake done...\n", __func__); - - if (return_me != GNUTLS_E_SUCCESS) { - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS reported something wrong.\n", __func__); - gnutls_perror(return_me); - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: oh.. errno says %s\n", __func__, strerror(errno)); - return LOCKDOWN_E_SSL_ERROR; + if (client->session_id) { + debug_info("SessionID: %s", client->session_id); + if (session_id != NULL) + *session_id = strdup(client->session_id); } else { - client->in_SSL = 1; + debug_info("Failed to get SessionID!"); + } + debug_info("Enable SSL Session: %s", (use_ssl?"true":"false")); + if (use_ssl) { + ret = property_list_service_enable_ssl(client->parent); + if (ret == PROPERTY_LIST_SERVICE_E_SUCCESS) { + client->ssl_enabled = 1; + } else { + ret = LOCKDOWN_E_SSL_ERROR; + client->ssl_enabled = 0; + } + } else { + client->ssl_enabled = 0; ret = LOCKDOWN_E_SUCCESS; } } - /* store session id, we need it for StopSession */ - plist_t session_node = plist_dict_get_item(dict, "SessionID"); - if (session_node && (plist_get_node_type(session_node) == PLIST_STRING)) { - plist_get_string_val(session_node, &client->session_id); - } - if (client->session_id) { - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: SessionID: %s\n", __func__, client->session_id); - } else { - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Failed to get SessionID!\n", __func__); - } + plist_free(dict); dict = NULL; - if (ret == LOCKDOWN_E_SUCCESS) - return ret; - - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Apparently failed negotiating with lockdownd.\n", __func__); - return LOCKDOWN_E_SSL_ERROR; -} - -/** gnutls callback for writing data to the iPhone. - * - * @param transport It's really the lockdownd client, but the method signature has to match - * @param buffer The data to send - * @param length The length of data to send in bytes - * - * @return The number of bytes sent - */ -ssize_t lockdownd_secuwrite(gnutls_transport_ptr_t transport, char *buffer, size_t length) -{ - uint32_t bytes = 0; - lockdownd_client_t client; - client = (lockdownd_client_t) transport; - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: called\n", __func__); - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: pre-send length = %zi\n", __func__, length); - iphone_device_send(client->connection, buffer, length, &bytes); - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: post-send sent %i bytes\n", __func__, bytes); - return bytes; -} - -/** gnutls callback for reading data from the iPhone - * - * @param transport It's really the lockdownd client, but the method signature has to match - * @param buffer The buffer to store data in - * @param length The length of data to read in bytes - * - * @return The number of bytes read - */ -ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_t length) -{ - int bytes = 0, pos_start_fill = 0; - size_t tbytes = 0; - int this_len = length; - iphone_error_t res; - lockdownd_client_t client; - client = (lockdownd_client_t) transport; - char *recv_buffer; - - log_debug_msg("%s: pre-read client wants %zi bytes\n", __func__, length); - - recv_buffer = (char *) malloc(sizeof(char) * this_len); - - // repeat until we have the full data or an error occurs. - do { - if ((res = iphone_device_recv(client->connection, recv_buffer, this_len, (uint32_t*)&bytes)) != LOCKDOWN_E_SUCCESS) { - log_debug_msg("%s: ERROR: usbmux_recv returned %d\n", __func__, res); - return res; - } - log_debug_msg("%s: post-read we got %i bytes\n", __func__, bytes); - - // increase read count - tbytes += bytes; - - // fill the buffer with what we got right now - memcpy(buffer + pos_start_fill, recv_buffer, bytes); - pos_start_fill += bytes; - - if (tbytes >= length) { - break; - } - - this_len = length - tbytes; - log_debug_msg("%s: re-read trying to read missing %i bytes\n", __func__, this_len); - } while (tbytes < length); - - if (recv_buffer) { - free(recv_buffer); - } - - return tbytes; + return ret; } /** Command to start the desired service @@ -1197,7 +1207,7 @@ ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_ * @return an error code (LOCKDOWN_E_SUCCESS on success) */ -lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char *service, int *port) +lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char *service, uint16_t *port) { if (!client || !service || !port) return LOCKDOWN_E_INVALID_ARG; @@ -1206,17 +1216,18 @@ lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char userpref_get_host_id(&host_id); if (!host_id) return LOCKDOWN_E_INVALID_CONF; - if (!client->in_SSL && !lockdownd_start_ssl_session(client, host_id)) - return LOCKDOWN_E_SSL_ERROR; + if (!client->session_id) + return LOCKDOWN_E_NO_RUNNING_SESSION; plist_t dict = NULL; - uint32_t port_loc = 0; + uint16_t port_loc = 0; lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; free(host_id); host_id = NULL; dict = plist_new_dict(); + plist_dict_add_label(dict, client->label); plist_dict_insert_item(dict,"Request", plist_new_string("StartService")); plist_dict_insert_item(dict,"Service", plist_new_string(service)); @@ -1260,3 +1271,97 @@ lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char return ret; } +/** + * Activates the device. Only works within an open session. + * The ActivationRecord plist dictionary must be obtained using the + * activation protocol requesting from Apple's https webservice. + * + * @see http://iphone-docs.org/doku.php?id=docs:protocols:activation + * + * @param control The lockdown client + * @param activation_record The activation record plist dictionary + * + * @return an error code (LOCKDOWN_E_SUCCESS on success) + */ +lockdownd_error_t lockdownd_activate(lockdownd_client_t client, plist_t activation_record) +{ + if (!client) + return LOCKDOWN_E_INVALID_ARG; + + if (!client->session_id) + return LOCKDOWN_E_NO_RUNNING_SESSION; + + if (!activation_record) + return LOCKDOWN_E_INVALID_ARG; + + lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; + + plist_t dict = plist_new_dict(); + plist_dict_add_label(dict, client->label); + plist_dict_insert_item(dict,"Request", plist_new_string("Activate")); + plist_dict_insert_item(dict,"ActivationRecord", activation_record); + + ret = lockdownd_send(client, dict); + plist_free(dict); + dict = NULL; + + ret = lockdownd_recv(client, &dict); + if (!dict) { + debug_info("LOCKDOWN_E_PLIST_ERROR"); + return LOCKDOWN_E_PLIST_ERROR; + } + + ret = LOCKDOWN_E_ACTIVATION_FAILED; + if (lockdown_check_result(dict, "Activate") == RESULT_SUCCESS) { + debug_info("success"); + ret = LOCKDOWN_E_SUCCESS; + } + plist_free(dict); + dict = NULL; + + return ret; +} + +/** + * Deactivates the device, returning it to the locked + * “Activate with iTunes” screen. + * + * @param control The lockdown client + * + * @return an error code (LOCKDOWN_E_SUCCESS on success) + */ +lockdownd_error_t lockdownd_deactivate(lockdownd_client_t client) +{ + if (!client) + return LOCKDOWN_E_INVALID_ARG; + + if (!client->session_id) + return LOCKDOWN_E_NO_RUNNING_SESSION; + + lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; + + plist_t dict = plist_new_dict(); + plist_dict_add_label(dict, client->label); + plist_dict_insert_item(dict,"Request", plist_new_string("Deactivate")); + + ret = lockdownd_send(client, dict); + plist_free(dict); + dict = NULL; + + ret = lockdownd_recv(client, &dict); + if (!dict) { + debug_info("LOCKDOWN_E_PLIST_ERROR"); + return LOCKDOWN_E_PLIST_ERROR; + } + + ret = LOCKDOWN_E_UNKNOWN_ERROR; + if (lockdown_check_result(dict, "Deactivate") == RESULT_SUCCESS) { + debug_info("success"); + ret = LOCKDOWN_E_SUCCESS; + } + plist_free(dict); + dict = NULL; + + return ret; +} + diff --git a/src/lockdown.h b/src/lockdown.h index 931623a..82ea01f 100644 --- a/src/lockdown.h +++ b/src/lockdown.h @@ -26,24 +26,18 @@ #include <string.h> #include "libiphone/lockdown.h" +#include "property_list_service.h" struct lockdownd_client_int { - iphone_connection_t connection; - gnutls_session_t ssl_session; - gnutls_certificate_credentials_t ssl_certificate; - int in_SSL; + property_list_service_client_t parent; + int ssl_enabled; char *session_id; char *uuid; + char *label; }; lockdownd_error_t lockdownd_get_device_public_key(lockdownd_client_t client, gnutls_datum_t * public_key); lockdownd_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datum_t * device_cert, gnutls_datum_t * host_cert, gnutls_datum_t * root_cert); -/* SSL functions */ -lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const char *HostID); -ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_t length); -ssize_t lockdownd_secuwrite(gnutls_transport_ptr_t transport, char *buffer, size_t length); - - #endif diff --git a/src/property_list_service.c b/src/property_list_service.c new file mode 100644 index 0000000..852ed9c --- /dev/null +++ b/src/property_list_service.c @@ -0,0 +1,346 @@ +/* + * property_list_service.c + * PropertyList service implementation. + * + * Copyright (c) 2010 Nikias Bassen. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <arpa/inet.h> + +#include "property_list_service.h" +#include "iphone.h" +#include "debug.h" + +/** + * Convert an iphone_error_t value to an property_list_service_error_t value. + * Used internally to get correct error codes. + * + * @param err An iphone_error_t error code + * + * @return A matching property_list_service_error_t error code, + * PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR otherwise. + */ +static property_list_service_error_t iphone_to_property_list_service_error(iphone_error_t err) +{ + switch (err) { + case IPHONE_E_SUCCESS: + return PROPERTY_LIST_SERVICE_E_SUCCESS; + case IPHONE_E_INVALID_ARG: + return PROPERTY_LIST_SERVICE_E_INVALID_ARG; + case IPHONE_E_SSL_ERROR: + return PROPERTY_LIST_SERVICE_E_SSL_ERROR; + default: + break; + } + return PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR; +} + +/** + * Creates a new property list service for the specified port. + * + * @param device The device to connect to. + * @param port The port on the device to connect to, usually opened by a call to + * lockdownd_start_service. + * @param client Pointer that will be set to a newly allocated + * property_list_service_client_t upon successful return. + * + * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, + * PROPERTY_LIST_SERVICE_E_INVALID_ARG when one of the arguments is invalid, + * or PROPERTY_LIST_SERVICE_E_MUX_ERROR when connecting to the device failed. + */ +property_list_service_error_t property_list_service_client_new(iphone_device_t device, uint16_t port, property_list_service_client_t *client) +{ + if (!device || port == 0 || !client || *client) + return PROPERTY_LIST_SERVICE_E_INVALID_ARG; + + /* Attempt connection */ + iphone_connection_t connection = NULL; + if (iphone_device_connect(device, port, &connection) != IPHONE_E_SUCCESS) { + return PROPERTY_LIST_SERVICE_E_MUX_ERROR; + } + + /* create client object */ + property_list_service_client_t client_loc = (property_list_service_client_t)malloc(sizeof(struct property_list_service_client_int)); + client_loc->connection = connection; + + *client = client_loc; + + return PROPERTY_LIST_SERVICE_E_SUCCESS; +} + +/** + * Frees a PropertyList service. + * + * @param client The property list service to free. + * + * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, + * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client is invalid, or a + * PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when another error occured. + */ +property_list_service_error_t property_list_service_client_free(property_list_service_client_t client) +{ + if (!client) + return PROPERTY_LIST_SERVICE_E_INVALID_ARG; + + property_list_service_error_t err = iphone_to_property_list_service_error(iphone_device_disconnect(client->connection)); + free(client); + return err; +} + +/** + * Sends a plist using the given property list service client. + * Internally used generic plist send function. + * + * @param client The property list service client to use for sending. + * @param plist plist to send + * @param binary 1 = send binary plist, 0 = send xml plist + * + * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, + * PROPERTY_LIST_SERVICE_E_INVALID_ARG when one or more parameters are + * invalid, PROPERTY_LIST_SERVICE_E_PLIST_ERROR when dict is not a valid + * plist, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when an unspecified + * error occurs. + */ +static property_list_service_error_t internal_plist_send(property_list_service_client_t client, plist_t plist, int binary) +{ + property_list_service_error_t res = PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR; + char *content = NULL; + uint32_t length = 0; + uint32_t nlen = 0; + int bytes = 0; + + if (!client || (client && !client->connection) || !plist) { + return PROPERTY_LIST_SERVICE_E_INVALID_ARG; + } + + if (binary) { + plist_to_bin(plist, &content, &length); + } else { + plist_to_xml(plist, &content, &length); + } + + if (!content || length == 0) { + return PROPERTY_LIST_SERVICE_E_PLIST_ERROR; + } + + nlen = htonl(length); + debug_info("sending %d bytes", length); + iphone_device_send(client->connection, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes); + if (bytes == sizeof(nlen)) { + iphone_device_send(client->connection, content, length, (uint32_t*)&bytes); + if (bytes > 0) { + debug_info("sent %d bytes", bytes); + debug_plist(plist); + if ((uint32_t)bytes == length) { + res = PROPERTY_LIST_SERVICE_E_SUCCESS; + } else { + debug_info("ERROR: Could not send all data (%d of %d)!", bytes, length); + } + } + } + if (bytes <= 0) { + debug_info("ERROR: sending to device failed."); + } + + free(content); + + return res; +} + +/** + * Sends an XML plist. + * + * @param client The property list service client to use for sending. + * @param plist plist to send + * + * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, + * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or plist is NULL, + * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when dict is not a valid plist, + * or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when an unspecified error occurs. + */ +property_list_service_error_t property_list_service_send_xml_plist(property_list_service_client_t client, plist_t plist) +{ + return internal_plist_send(client, plist, 0); +} + +/** + * Sends a binary plist. + * + * @param client The property list service client to use for sending. + * @param plist plist to send + * + * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, + * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or plist is NULL, + * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when dict is not a valid plist, + * or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when an unspecified error occurs. + */ +property_list_service_error_t property_list_service_send_binary_plist(property_list_service_client_t client, plist_t plist) +{ + return internal_plist_send(client, plist, 1); +} + +/** + * Receives a plist using the given property list service client. + * Internally used generic plist receive function. + * + * @param client The property list service client to use for receiving + * @param plist pointer to a plist_t that will point to the received plist + * upon successful return + * @param timeout Maximum time in milliseconds to wait for data. + * + * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, + * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or *plist is NULL, + * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when the received data cannot be + * converted to a plist, PROPERTY_LIST_SERVICE_E_MUX_ERROR when a + * communication error occurs, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR + * when an unspecified error occurs. + */ +static property_list_service_error_t internal_plist_recv_timeout(property_list_service_client_t client, plist_t *plist, unsigned int timeout) +{ + property_list_service_error_t res = PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR; + uint32_t pktlen = 0; + uint32_t bytes = 0; + + if (!client || (client && !client->connection) || !plist) { + return PROPERTY_LIST_SERVICE_E_INVALID_ARG; + } + + iphone_device_recv_timeout(client->connection, (char*)&pktlen, sizeof(pktlen), &bytes, timeout); + debug_info("initial read=%i", bytes); + if (bytes < 4) { + debug_info("initial read failed!"); + return PROPERTY_LIST_SERVICE_E_MUX_ERROR; + } else { + if ((char)pktlen == 0) { /* prevent huge buffers */ + uint32_t curlen = 0; + char *content = NULL; + pktlen = ntohl(pktlen); + debug_info("%d bytes following", pktlen); + content = (char*)malloc(pktlen); + + while (curlen < pktlen) { + iphone_device_recv(client->connection, content+curlen, pktlen-curlen, &bytes); + if (bytes <= 0) { + res = PROPERTY_LIST_SERVICE_E_MUX_ERROR; + break; + } + debug_info("received %d bytes", bytes); + curlen += bytes; + } + if (!memcmp(content, "bplist00", 8)) { + plist_from_bin(content, pktlen, plist); + } else { + plist_from_xml(content, pktlen, plist); + } + if (*plist) { + debug_plist(*plist); + res = PROPERTY_LIST_SERVICE_E_SUCCESS; + } else { + res = PROPERTY_LIST_SERVICE_E_PLIST_ERROR; + } + free(content); + content = NULL; + } else { + res = PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR; + } + } + return res; +} + +/** + * Receives a plist using the given property list service client with specified + * timeout. + * Binary or XML plists are automatically handled. + * + * @param client The property list service client to use for receiving + * @param plist pointer to a plist_t that will point to the received plist + * upon successful return + * @param timeout Maximum time in milliseconds to wait for data. + * + * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, + * PROPERTY_LIST_SERVICE_E_INVALID_ARG when connection or *plist is NULL, + * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when the received data cannot be + * converted to a plist, PROPERTY_LIST_SERVICE_E_MUX_ERROR when a + * communication error occurs, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when + * an unspecified error occurs. + */ +property_list_service_error_t property_list_service_receive_plist_with_timeout(property_list_service_client_t client, plist_t *plist, unsigned int timeout) +{ + return internal_plist_recv_timeout(client, plist, timeout); +} + +/** + * Receives a plist using the given property list service client. + * Binary or XML plists are automatically handled. + * + * This function is like property_list_service_receive_plist_with_timeout + * using a timeout of 10 seconds. + * @see property_list_service_receive_plist_with_timeout + * + * @param client The property list service client to use for receiving + * @param plist pointer to a plist_t that will point to the received plist + * upon successful return + * + * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, + * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or *plist is NULL, + * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when the received data cannot be + * converted to a plist, PROPERTY_LIST_SERVICE_E_MUX_ERROR when a + * communication error occurs, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when + * an unspecified error occurs. + */ +property_list_service_error_t property_list_service_receive_plist(property_list_service_client_t client, plist_t *plist) +{ + return internal_plist_recv_timeout(client, plist, 10000); +} + +/** + * Enable SSL for the given property list service client. + * + * @param client The connected property list service client for which SSL + * should be enabled. + * + * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, + * PROPERTY_LIST_SERVICE_E_INVALID_ARG if client or client->connection is + * NULL, PROPERTY_LIST_SERVICE_E_SSL_ERROR when SSL could not be enabled, + * or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR otherwise. + */ +property_list_service_error_t property_list_service_enable_ssl(property_list_service_client_t client) +{ + if (!client || !client->connection) + return PROPERTY_LIST_SERVICE_E_INVALID_ARG; + return iphone_to_property_list_service_error(iphone_connection_enable_ssl(client->connection)); +} + +/** + * Disable SSL for the given property list service client. + * + * @param client The connected property list service client for which SSL + * should be disabled. + * + * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, + * PROPERTY_LIST_SERVICE_E_INVALID_ARG if client or client->connection is + * NULL, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR otherwise. + */ +property_list_service_error_t property_list_service_disable_ssl(property_list_service_client_t client) +{ + if (!client || !client->connection) + return PROPERTY_LIST_SERVICE_E_INVALID_ARG; + return iphone_to_property_list_service_error(iphone_connection_disable_ssl(client->connection)); +} + diff --git a/src/property_list_service.h b/src/property_list_service.h new file mode 100644 index 0000000..bc3122b --- /dev/null +++ b/src/property_list_service.h @@ -0,0 +1,59 @@ + /* + * property_list_service.h + * Definitions for the PropertyList service + * + * Copyright (c) 2010 Nikias Bassen, All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef PROPERTY_LIST_SERVICE_H +#define PROPERTY_LIST_SERVICE_H + +#include "iphone.h" + +/* Error Codes */ +#define PROPERTY_LIST_SERVICE_E_SUCCESS 0 +#define PROPERTY_LIST_SERVICE_E_INVALID_ARG -1 +#define PROPERTY_LIST_SERVICE_E_PLIST_ERROR -2 +#define PROPERTY_LIST_SERVICE_E_MUX_ERROR -3 +#define PROPERTY_LIST_SERVICE_E_SSL_ERROR -4 + +#define PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR -256 + +struct property_list_service_client_int { + iphone_connection_t connection; +}; + +typedef struct property_list_service_client_int *property_list_service_client_t; + +typedef int16_t property_list_service_error_t; + +/* creation and destruction */ +property_list_service_error_t property_list_service_client_new(iphone_device_t device, uint16_t port, property_list_service_client_t *client); +property_list_service_error_t property_list_service_client_free(property_list_service_client_t client); + +/* sending */ +property_list_service_error_t property_list_service_send_xml_plist(property_list_service_client_t client, plist_t plist); +property_list_service_error_t property_list_service_send_binary_plist(property_list_service_client_t client, plist_t plist); + +/* receiving */ +property_list_service_error_t property_list_service_receive_plist_with_timeout(property_list_service_client_t client, plist_t *plist, unsigned int timeout); +property_list_service_error_t property_list_service_receive_plist(property_list_service_client_t client, plist_t *plist); + +/* misc */ +property_list_service_error_t property_list_service_enable_ssl(property_list_service_client_t client); +property_list_service_error_t property_list_service_disable_ssl(property_list_service_client_t client); + +#endif diff --git a/src/userpref.c b/src/userpref.c index 10c14a0..6eff534 100644 --- a/src/userpref.c +++ b/src/userpref.c @@ -20,6 +20,7 @@ */ #include <glib.h> +#include <glib/gstdio.h> #include <glib/gprintf.h> #include <stdio.h> #include <stdint.h> @@ -30,7 +31,7 @@ #include <gcrypt.h> #include "userpref.h" -#include "utils.h" +#include "debug.h" #define LIBIPHONE_CONF_DIR "libiphone" #define LIBIPHONE_CONF_FILE "libiphonerc" @@ -105,7 +106,7 @@ static int userpref_set_host_id(const char *host_id) key_file = g_key_file_new(); /* Store in config file */ - log_debug_msg("%s: setting hostID to %s\n", __func__, host_id); + debug_info("setting hostID to %s", host_id); g_key_file_set_value(key_file, "Global", "HostID", host_id); /* Write config file on disk */ @@ -154,7 +155,7 @@ void userpref_get_host_id(char **host_id) userpref_set_host_id(*host_id); } - log_debug_msg("%s: Using %s as HostID\n", __func__, *host_id); + debug_info("Using %s as HostID", *host_id); } /** Determines whether this iPhone has been connected to this system before. @@ -212,6 +213,30 @@ userpref_error_t userpref_set_device_public_key(const char *uuid, gnutls_datum_t return USERPREF_E_SUCCESS; } +/** Remove the public key stored for the device with uuid from this host. + * + * @param uuid The uuid of the device + * + * @return USERPREF_E_SUCCESS on success. + */ +userpref_error_t userpref_remove_device_public_key(const char *uuid) +{ + if (!userpref_has_device_public_key(uuid)) + return USERPREF_E_SUCCESS; + + /* build file path */ + gchar *device_file = g_strconcat(uuid, ".pem", NULL); + gchar *pem = g_build_path(G_DIR_SEPARATOR_S, g_get_user_config_dir(), LIBIPHONE_CONF_DIR, device_file, NULL); + + /* remove file */ + g_remove(pem); + + g_free(pem); + g_free(device_file); + + return USERPREF_E_SUCCESS; +} + /** Private function which reads the given file into a gnutls structure. * * @param file The filename of the file to read diff --git a/src/userpref.h b/src/userpref.h index 3540468..48b8969 100644 --- a/src/userpref.h +++ b/src/userpref.h @@ -38,6 +38,7 @@ G_GNUC_INTERNAL userpref_error_t userpref_get_keys_and_certs(gnutls_x509_privkey G_GNUC_INTERNAL userpref_error_t userpref_set_keys_and_certs(gnutls_datum_t * root_key, gnutls_datum_t * root_cert, gnutls_datum_t * host_key, gnutls_datum_t * host_cert); G_GNUC_INTERNAL userpref_error_t userpref_get_certs_as_pem(gnutls_datum_t *pem_root_cert, gnutls_datum_t *pem_host_cert); G_GNUC_INTERNAL userpref_error_t userpref_set_device_public_key(const char *uuid, gnutls_datum_t public_key); +G_GNUC_INTERNAL userpref_error_t userpref_remove_device_public_key(const char *uuid); G_GNUC_INTERNAL int userpref_has_device_public_key(const char *uuid); G_GNUC_INTERNAL void userpref_get_host_id(char **host_id); diff --git a/src/utils.h b/src/utils.h deleted file mode 100644 index c99730a..0000000 --- a/src/utils.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * utils.h - * contains utilitary methos for logging and debugging - * - * Copyright (c) 2008 Jonathan Beck All Rights Reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef UTILS_H -#define UTILS_H - -#include <glib.h> - -G_GNUC_INTERNAL inline void log_debug_msg(const char *format, ...); -G_GNUC_INTERNAL inline void log_dbg_msg(uint16_t id, const char *format, ...); - -G_GNUC_INTERNAL inline void log_debug_buffer(const char *data, const int length); -G_GNUC_INTERNAL inline void dump_debug_buffer(const char *file, const char *data, const int length); - -#endif |