diff options
-rw-r--r-- | include/libiphone/libiphone.h | 1 | ||||
-rw-r--r-- | src/InstallationProxy.c | 138 | ||||
-rw-r--r-- | src/MobileSync.c | 69 | ||||
-rw-r--r-- | src/NotificationProxy.c | 162 | ||||
-rw-r--r-- | src/SBServices.c | 155 | ||||
-rw-r--r-- | src/iphone.c | 281 | ||||
-rw-r--r-- | src/iphone.h | 13 | ||||
-rw-r--r-- | src/lockdown.c | 98 |
8 files changed, 453 insertions, 464 deletions
diff --git a/include/libiphone/libiphone.h b/include/libiphone/libiphone.h index 923bc58..eb58d5c 100644 --- a/include/libiphone/libiphone.h +++ b/include/libiphone/libiphone.h @@ -39,6 +39,7 @@ extern "C" { #define IPHONE_E_NO_DEVICE -3 #define IPHONE_E_NOT_ENOUGH_DATA -4 #define IPHONE_E_BAD_HEADER -5 +#define IPHONE_E_PLIST_ERROR -6 typedef int16_t iphone_error_t; diff --git a/src/InstallationProxy.c b/src/InstallationProxy.c index 917886d..387f9ca 100644 --- a/src/InstallationProxy.c +++ b/src/InstallationProxy.c @@ -56,112 +56,28 @@ static void instproxy_unlock(instproxy_client_t client) } /** - * Sends an xml plist to the device using the connection specified in client. - * This function is only used internally. + * Convert an iphone_error_t value to an instproxy_error_t value. + * Used internally to get correct error codes when using plist helper + * functions. * - * @param client The installation_proxy to send data to - * @param plist plist to send + * @param err An iphone_error_t error code * - * @return INSTPROXY_E_SUCCESS on success, INSTPROXY_E_INVALID_ARG when client - * or plist are NULL, INSTPROXY_E_PLIST_ERROR when dict is not a valid - * plist, or INSTPROXY_E_UNKNOWN_ERROR when an unspecified error occurs. + * @return A matching instproxy_error_t error code, + * INSTPROXY_E_UNKNOWN_ERROR otherwise. */ -static instproxy_error_t instproxy_plist_send(instproxy_client_t client, plist_t plist) +static instproxy_error_t iphone_to_instproxy_error(iphone_error_t err) { - instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; - char *XML_content = NULL; - uint32_t length = 0; - uint32_t nlen = 0; - int bytes = 0; - - if (!client || !plist) { - return INSTPROXY_E_INVALID_ARG; - } - - plist_to_xml(plist, &XML_content, &length); - - if (!XML_content || length == 0) { - return INSTPROXY_E_PLIST_ERROR; - } - - nlen = htonl(length); - log_debug_msg("%s: sending %d bytes\n", __func__, length); - iphone_device_send(client->connection, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes); - if (bytes == sizeof(nlen)) { - iphone_device_send(client->connection, XML_content, length, (uint32_t*)&bytes); - if (bytes > 0) { - log_debug_msg("%s: received %d bytes\n", __func__, bytes); - log_debug_buffer(XML_content, bytes); - if ((uint32_t)bytes == length) { - res = INSTPROXY_E_SUCCESS; - } else { - log_debug_msg("%s: ERROR: Could not send all data (%d of %d)!\n", __func__, bytes, length); - } - } - } - if (bytes <= 0) { - log_dbg_msg(DBGMASK_INSTPROXY, "%s: ERROR: sending to device failed.\n", __func__); - } - - free(XML_content); - - return res; -} - -/** - * Receives an xml plist from the device using the connection specified in - * client. - * This function is only used internally. - * - * @param client The installation_proxy to receive data from - * @param plist pointer to a plist_t that will point to the received plist - * upon successful return - * - * @return INSTPROXY_E_SUCCESS on success, INSTPROXY_E_INVALID_ARG when client - * or *plist are NULL, INSTPROXY_E_PLIST_ERROR when dict is not a valid - * plist, or INSTPROXY_E_UNKNOWN_ERROR when an unspecified error occurs. - */ -static instproxy_error_t instproxy_plist_recv(instproxy_client_t client, plist_t *plist) -{ - instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; - char *XML_content = NULL; - uint32_t pktlen = 0; - uint32_t bytes = 0; - - if (!client || !plist) { - return INSTPROXY_E_INVALID_ARG; - } - - iphone_device_recv_timeout(client->connection, (char*)&pktlen, sizeof(pktlen), &bytes, 300000); /* 5 minute timeout should be enough */ - log_debug_msg("%s: initial read=%i\n", __func__, bytes); - if (bytes < 4) { - log_dbg_msg(DBGMASK_INSTPROXY, "%s: initial read failed!\n"); - } else { - if ((char)pktlen == 0) { - uint32_t curlen = 0; - pktlen = ntohl(pktlen); - log_debug_msg("%s: %d bytes following\n", __func__, pktlen); - XML_content = (char*)malloc(pktlen); - - while (curlen < pktlen) { - iphone_device_recv(client->connection, XML_content+curlen, pktlen-curlen, &bytes); - if (bytes <= 0) { - res = INSTPROXY_E_UNKNOWN_ERROR; - break; - } - log_debug_msg("%s: received %d bytes\n", __func__, bytes); - curlen += bytes; - } - log_debug_buffer(XML_content, pktlen); - plist_from_xml(XML_content, pktlen, plist); - res = INSTPROXY_E_SUCCESS; - free(XML_content); - XML_content = NULL; - } else { - res = INSTPROXY_E_UNKNOWN_ERROR; - } + switch (err) { + case IPHONE_E_SUCCESS: + return INSTPROXY_E_SUCCESS; + case IPHONE_E_INVALID_ARG: + return INSTPROXY_E_INVALID_ARG; + case IPHONE_E_PLIST_ERROR: + return INSTPROXY_E_PLIST_ERROR; + default: + break; } - return res; + return INSTPROXY_E_UNKNOWN_ERROR; } /** @@ -268,7 +184,7 @@ 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 = instproxy_plist_send(client, dict); + res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); plist_free(dict); if (res != INSTPROXY_E_SUCCESS) { log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not send plist\n", __func__); @@ -280,7 +196,7 @@ instproxy_error_t instproxy_browse(instproxy_client_t client, instproxy_apptype_ do { browsing = 0; dict = NULL; - res = instproxy_plist_recv(client, &dict); + res = iphone_to_instproxy_error(iphone_device_receive_plist(client->connection, &dict)); if (res != INSTPROXY_E_SUCCESS) { break; } @@ -345,7 +261,7 @@ static instproxy_error_t instproxy_perform_operation(instproxy_client_t client, do { instproxy_lock(client); - res = instproxy_plist_recv(client, &dict); + res = iphone_to_instproxy_error(iphone_device_receive_plist_with_timeout(client->connection, &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); @@ -517,7 +433,7 @@ 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 = instproxy_plist_send(client, dict); + res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); instproxy_unlock(client); plist_free(dict); @@ -610,7 +526,7 @@ 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 = instproxy_plist_send(client, dict); + res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); instproxy_unlock(client); plist_free(dict); @@ -647,7 +563,7 @@ instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist_t * instproxy_lock(client); - res = instproxy_plist_send(client, dict); + res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); plist_free(dict); if (res != INSTPROXY_E_SUCCESS) { @@ -655,7 +571,7 @@ instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist_t * goto leave_unlock; } - res = instproxy_plist_recv(client, result); + res = iphone_to_instproxy_error(iphone_device_receive_plist(client->connection, result)); if (res != INSTPROXY_E_SUCCESS) { log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not receive plist, error %d\n", __func__, res); goto leave_unlock; @@ -718,7 +634,7 @@ 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 = instproxy_plist_send(client, dict); + res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); instproxy_unlock(client); plist_free(dict); @@ -764,7 +680,7 @@ 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 = instproxy_plist_send(client, dict); + res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); instproxy_unlock(client); plist_free(dict); @@ -810,7 +726,7 @@ 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 = instproxy_plist_send(client, dict); + res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict)); instproxy_unlock(client); plist_free(dict); diff --git a/src/MobileSync.c b/src/MobileSync.c index 77d2710..76aefa0 100644 --- a/src/MobileSync.c +++ b/src/MobileSync.c @@ -31,6 +31,31 @@ #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. + * + * @param err An iphone_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) +{ + switch (err) { + case IPHONE_E_SUCCESS: + return MOBILESYNC_E_SUCCESS; + case IPHONE_E_INVALID_ARG: + return MOBILESYNC_E_INVALID_ARG; + case IPHONE_E_PLIST_ERROR: + return MOBILESYNC_E_PLIST_ERROR; + default: + break; + } + return MOBILESYNC_E_UNKNOWN_ERROR; +} + mobilesync_error_t mobilesync_client_new(iphone_device_t device, int dst_port, mobilesync_client_t * client) { @@ -160,35 +185,19 @@ mobilesync_error_t mobilesync_recv(mobilesync_client_t client, plist_t * plist) { if (!client || !plist || (plist && *plist)) return MOBILESYNC_E_INVALID_ARG; - mobilesync_error_t ret = MOBILESYNC_E_UNKNOWN_ERROR; - char *receive = NULL; - uint32_t datalen = 0, bytes = 0, received_bytes = 0; - - ret = iphone_device_recv(client->connection, (char *) &datalen, sizeof(datalen), &bytes); - datalen = ntohl(datalen); - - receive = (char *) malloc(sizeof(char) * datalen); - - /* fill buffer and request more packets if needed */ - while ((received_bytes < datalen) && (ret == MOBILESYNC_E_SUCCESS)) { - ret = iphone_device_recv(client->connection, receive + received_bytes, datalen - received_bytes, &bytes); - received_bytes += bytes; - } + mobilesync_error_t ret = iphone_to_mobilesync_error(iphone_device_receive_plist(client->connection, plist)); if (ret != MOBILESYNC_E_SUCCESS) { - free(receive); return MOBILESYNC_E_MUX_ERROR; } - plist_from_bin(receive, received_bytes, plist); - free(receive); - +#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); free(XMLContent); - +#endif return ret; } @@ -207,28 +216,12 @@ mobilesync_error_t mobilesync_send(mobilesync_client_t client, plist_t plist) if (!client || !plist) return MOBILESYNC_E_INVALID_ARG; +#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); free(XMLContent); - - char *content = NULL; - length = 0; - - plist_to_bin(plist, &content, &length); - - char *real_query; - int bytes; - mobilesync_error_t ret = MOBILESYNC_E_UNKNOWN_ERROR; - - real_query = (char *) malloc(sizeof(char) * (length + 4)); - length = htonl(length); - memcpy(real_query, &length, sizeof(length)); - memcpy(real_query + 4, content, ntohl(length)); - - ret = iphone_device_send(client->connection, real_query, ntohl(length) + sizeof(length), (uint32_t*)&bytes); - free(real_query); - return (ret == 0 ? MOBILESYNC_E_SUCCESS: MOBILESYNC_E_MUX_ERROR); +#endif + return (iphone_device_send_binary_plist(client->connection, plist) == IPHONE_E_SUCCESS ? MOBILESYNC_E_SUCCESS : MOBILESYNC_E_MUX_ERROR); } - diff --git a/src/NotificationProxy.c b/src/NotificationProxy.c index cba12b9..b73b521 100644 --- a/src/NotificationProxy.c +++ b/src/NotificationProxy.c @@ -56,53 +56,28 @@ static void np_unlock(np_client_t client) } /** - * Sends an xml plist to the device using the connection specified in client. - * This function is only used internally. + * Convert an iphone_error_t value to an np_error_t value. + * Used internally to get correct error codes when using plist helper + * functions. * - * @param client NP to send data to - * @param dict plist to send + * @param err An iphone_error_t error code * - * @return NP_E_SUCCESS on success, NP_E_INVALID_ARG when client or dict - * are NULL, NP_E_PLIST_ERROR when dict is not a valid plist, - * or NP_E_UNKNOWN_ERROR when an unspecified error occurs. + * @return A matching np_error_t error code, + * NP_E_UNKNOWN_ERROR otherwise. */ -static np_error_t np_plist_send(np_client_t client, plist_t dict) +static np_error_t iphone_to_np_error(iphone_error_t err) { - char *XML_content = NULL; - uint32_t length = 0; - uint32_t nlen = 0; - int bytes = 0; - np_error_t res = NP_E_UNKNOWN_ERROR; - - if (!client || !dict) { - return NP_E_INVALID_ARG; - } - - plist_to_xml(dict, &XML_content, &length); - - if (!XML_content || length == 0) { - return NP_E_PLIST_ERROR; - } - - nlen = htonl(length); - iphone_device_send(client->connection, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes); - if (bytes == sizeof(nlen)) { - iphone_device_send(client->connection, XML_content, length, (uint32_t*)&bytes); - if (bytes > 0) { - if ((uint32_t)bytes == length) { - res = NP_E_SUCCESS; - } else { - log_debug_msg("%s: ERROR: Could not send all data (%d of %d)!\n", __func__, bytes, length); - } - } - } - if (bytes <= 0) { - log_debug_msg("%s: ERROR: sending to device failed.\n", __func__); + switch (err) { + case IPHONE_E_SUCCESS: + return NP_E_SUCCESS; + case IPHONE_E_INVALID_ARG: + return NP_E_INVALID_ARG; + case IPHONE_E_PLIST_ERROR: + return NP_E_PLIST_ERROR; + default: + break; } - - free(XML_content); - - return res; + return NP_E_UNKNOWN_ERROR; } /** Makes a connection to the NP service on the phone. @@ -185,13 +160,13 @@ 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 = np_plist_send(client, dict); + np_error_t res = iphone_to_np_error(iphone_device_send_xml_plist(client->connection, dict)); plist_free(dict); dict = plist_new_dict(); plist_dict_insert_item(dict,"Command", plist_new_string("Shutdown")); - res = np_plist_send(client, dict); + res = iphone_to_np_error(iphone_device_send_xml_plist(client->connection, dict)); plist_free(dict); if (res != NP_E_SUCCESS) { @@ -221,7 +196,7 @@ 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 = np_plist_send(client, dict); + np_error_t res = iphone_to_np_error(iphone_device_send_xml_plist(client->connection, dict)); if (res != NP_E_SUCCESS) { log_debug_msg("%s: Error sending XML plist to device!\n", __func__); } @@ -281,10 +256,7 @@ np_error_t np_observe_notifications(np_client_t client, const char **notificatio */ static int np_get_notification(np_client_t client, char **notification) { - uint32_t bytes = 0; int res = 0; - uint32_t pktlen = 0; - char *XML_content = NULL; plist_t dict = NULL; if (!client || !client->connection || *notification) @@ -292,72 +264,46 @@ static int np_get_notification(np_client_t client, char **notification) np_lock(client); - iphone_device_recv_timeout(client->connection, (char*)&pktlen, sizeof(pktlen), &bytes, 500); - log_debug_msg("NotificationProxy: initial read=%i\n", bytes); - if (bytes < 4) { + iphone_device_receive_plist_with_timeout(client->connection, &dict, 500); + if (!dict) { log_debug_msg("NotificationProxy: no notification received!\n"); res = 0; } else { - if ((char)pktlen == 0) { - pktlen = ntohl(pktlen); - log_debug_msg("NotificationProxy: %d bytes following\n", pktlen); - XML_content = (char*)malloc(pktlen); - log_debug_msg("pointer %p\n", XML_content); - - iphone_device_recv_timeout(client->connection, XML_content, pktlen, &bytes, 1000); - if (bytes <= 0) { - res = -1; - } else { - log_debug_msg("NotificationProxy: received data:\n"); - log_debug_buffer(XML_content, pktlen); - - plist_from_xml(XML_content, bytes, &dict); - if (!dict) { - np_unlock(client); - return -2; - } - - char *cmd_value = NULL; - plist_t cmd_value_node = plist_dict_get_item(dict, "Command"); - - if (plist_get_node_type(cmd_value_node) == PLIST_STRING) { - plist_get_string_val(cmd_value_node, &cmd_value); - } - - if (cmd_value && !strcmp(cmd_value, "RelayNotification")) { - char *name_value = NULL; - plist_t name_value_node = plist_dict_get_item(dict, "Name"); - - if (plist_get_node_type(name_value_node) == PLIST_STRING) { - plist_get_string_val(name_value_node, &name_value); - } - - res = -2; - if (name_value_node && name_value) { - *notification = name_value; - log_debug_msg("%s: 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__); - res = -1; - } else if (cmd_value) { - log_debug_msg("%d: unknown NotificationProxy command '%s' received!\n", __func__); - res = -1; - } else { - res = -2; - } - if (cmd_value) { - free(cmd_value); - } - plist_free(dict); - dict = NULL; - free(XML_content); - XML_content = NULL; + char *cmd_value = NULL; + plist_t cmd_value_node = plist_dict_get_item(dict, "Command"); + + if (plist_get_node_type(cmd_value_node) == PLIST_STRING) { + plist_get_string_val(cmd_value_node, &cmd_value); + } + + if (cmd_value && !strcmp(cmd_value, "RelayNotification")) { + char *name_value = NULL; + plist_t name_value_node = plist_dict_get_item(dict, "Name"); + + if (plist_get_node_type(name_value_node) == PLIST_STRING) { + plist_get_string_val(name_value_node, &name_value); } - } else { + + res = -2; + if (name_value_node && name_value) { + *notification = name_value; + log_debug_msg("%s: 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__); res = -1; + } else if (cmd_value) { + log_debug_msg("%d: unknown NotificationProxy command '%s' received!\n", __func__); + res = -1; + } else { + res = -2; + } + if (cmd_value) { + free(cmd_value); } + plist_free(dict); + dict = NULL; } np_unlock(client); diff --git a/src/SBServices.c b/src/SBServices.c index 9849415..1296245 100644 --- a/src/SBServices.c +++ b/src/SBServices.c @@ -87,112 +87,39 @@ sbservices_error_t sbservices_client_free(sbservices_client_t client) return SBSERVICES_E_SUCCESS; } -/** - * Sends a binary plist to the device using the connection specified in client. - * This function is only used internally. - * - * @param client InstallationProxy to send data to - * @param dict plist to send - * - * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when - * client or dict are NULL, SBSERVICES_E_PLIST_ERROR when dict is not a - * valid plist, or SBSERVICES_E_UNKNOWN_ERROR when an unspecified error - * occurs. - */ -static sbservices_error_t sbservices_plist_send(sbservices_client_t client, plist_t dict) -{ - char *content = NULL; - uint32_t length = 0; - uint32_t nlen = 0; - int bytes = 0; - sbservices_error_t res = SBSERVICES_E_UNKNOWN_ERROR; - - if (!client || !dict) { - return SBSERVICES_E_INVALID_ARG; - } - - plist_to_bin(dict, &content, &length); - - if (!content || length == 0) { - return SBSERVICES_E_PLIST_ERROR; - } - - nlen = htonl(length); - log_debug_msg("%s: sending %d bytes\n", __func__, 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) { - if ((uint32_t)bytes == length) { - res = SBSERVICES_E_SUCCESS; - } else { - log_debug_msg("%s: ERROR: Could not send all data (%d of %d)!\n", __func__, bytes, length); - } - } - } - if (bytes <= 0) { - log_debug_msg("%s: ERROR: sending to device failed.\n", __func__); - } - - free(content); - - return res; -} - sbservices_error_t sbservices_get_icon_state(sbservices_client_t client, plist_t *state) { if (!client || !client->connection || !state) return SBSERVICES_E_INVALID_ARG; sbservices_error_t res = SBSERVICES_E_UNKNOWN_ERROR; - uint32_t pktlen = 0; - uint32_t bytes = 0; plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "command", plist_new_string("getIconState")); sbs_lock(client); - res = sbservices_plist_send(client, dict); - plist_free(dict); - if (res != SBSERVICES_E_SUCCESS) { + 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; } + plist_free(dict); + dict = NULL; - iphone_device_recv(client->connection, (char*)&pktlen, sizeof(pktlen), &bytes); - log_debug_msg("%s: initial read=%i\n", __func__, bytes); - if (bytes < 4) { - log_debug_msg("%s: initial read failed!\n"); - res = 0; + if (iphone_device_receive_plist(client->connection, state) == IPHONE_E_SUCCESS) { + res = SBSERVICES_E_SUCCESS; } else { - if ((char)pktlen == 0) { - char *content = NULL; - uint32_t curlen = 0; - pktlen = ntohl(pktlen); - log_debug_msg("%s: %d bytes following\n", __func__, pktlen); - content = (char*)malloc(pktlen); - log_debug_msg("pointer %p\n", content); - - while (curlen < pktlen) { - iphone_device_recv(client->connection, content+curlen, pktlen-curlen, &bytes); - if (bytes <= 0) { - res = SBSERVICES_E_UNKNOWN_ERROR; - break; - } - log_debug_msg("%s: received %d bytes\n", __func__, bytes); - curlen += bytes; - } - log_debug_buffer(content, pktlen); - plist_from_bin(content, pktlen, state); - res = SBSERVICES_E_SUCCESS; - free(content); - } else { - res = SBSERVICES_E_UNKNOWN_ERROR; + log_debug_msg("%s: could not get icon state!\n", __func__); + if (*state) { + plist_free(*state); + *state = NULL; } } leave_unlock: + if (dict) { + plist_free(dict); + } sbs_unlock(client); return res; } @@ -210,15 +137,16 @@ sbservices_error_t sbservices_set_icon_state(sbservices_client_t client, plist_t sbs_lock(client); - res = sbservices_plist_send(client, dict); - plist_free(dict); - if (res != SBSERVICES_E_SUCCESS) { + 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; } // NO RESPONSE leave_unlock: + if (dict) { + plist_free(dict); + } sbs_unlock(client); return res; } @@ -229,8 +157,6 @@ sbservices_error_t sbservices_get_icon_pngdata(sbservices_client_t client, const return SBSERVICES_E_INVALID_ARG; sbservices_error_t res = SBSERVICES_E_UNKNOWN_ERROR; - uint32_t pktlen = 0; - uint32_t bytes = 0; plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "command", plist_new_string("getIconPNGData")); @@ -238,52 +164,25 @@ sbservices_error_t sbservices_get_icon_pngdata(sbservices_client_t client, const sbs_lock(client); - res = sbservices_plist_send(client, dict); - plist_free(dict); - if (res != SBSERVICES_E_SUCCESS) { + 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; } + plist_free(dict); - iphone_device_recv(client->connection, (char*)&pktlen, sizeof(pktlen), &bytes); - log_debug_msg("%s: initial read=%i\n", __func__, bytes); - if (bytes < 4) { - log_debug_msg("%s: initial read failed!\n"); - res = 0; - } else { - if ((char)pktlen == 0) { - char *content = NULL; - uint32_t curlen = 0; - pktlen = ntohl(pktlen); - log_debug_msg("%s: %d bytes following\n", __func__, pktlen); - content = (char*)malloc(pktlen); - log_debug_msg("pointer %p\n", content); - - while (curlen < pktlen) { - iphone_device_recv(client->connection, content+curlen, pktlen-curlen, &bytes); - if (bytes <= 0) { - res = SBSERVICES_E_UNKNOWN_ERROR; - break; - } - log_debug_msg("%s: received %d bytes\n", __func__, bytes); - curlen += bytes; - } - log_debug_buffer(content, pktlen); - plist_t pngdict = NULL; - plist_from_bin(content, pktlen, &pngdict); - plist_t node = plist_dict_get_item(pngdict, "pngData"); - if (node) { - plist_get_data_val(node, pngdata, pngsize); - } - plist_free(pngdict); - res = SBSERVICES_E_SUCCESS; - free(content); - } else { - res = SBSERVICES_E_UNKNOWN_ERROR; + dict = NULL; + if (iphone_device_receive_plist(client->connection, &dict) == IPHONE_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: + if (dict) { + plist_free(dict); + } sbs_unlock(client); return res; diff --git a/src/iphone.c b/src/iphone.c index 586b3bc..3c13859 100644 --- a/src/iphone.c +++ b/src/iphone.c @@ -23,6 +23,7 @@ #include <stdlib.h> #include <string.h> #include <errno.h> +#include <arpa/inet.h> #include <usbmuxd.h> #include "iphone.h" @@ -350,6 +351,286 @@ iphone_error_t iphone_device_recv(iphone_connection_t connection, char *data, ui return IPHONE_E_UNKNOWN_ERROR; } +/** + * 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. + */ +static iphone_error_t internal_plist_send(iphone_connection_t connection, plist_t plist, int binary, gnutls_session_t ssl_session) +{ + iphone_error_t res = IPHONE_E_UNKNOWN_ERROR; + char *content = NULL; + uint32_t length = 0; + uint32_t nlen = 0; + int bytes = 0; + + if ((!connection && !ssl_session) || !plist) { + return IPHONE_E_INVALID_ARG; + } + + if (binary) { + plist_to_bin(plist, &content, &length); + } else { + plist_to_xml(plist, &content, &length); + } + + 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: received %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 (bytes <= 0) { + log_debug_msg("%s: ERROR: sending to device failed.\n", __func__); + } + + free(content); + + return res; +} + +/** + * 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. + */ +iphone_error_t iphone_device_send_xml_plist(iphone_connection_t connection, plist_t plist) +{ + return internal_plist_send(connection, plist, 0, NULL); +} + +/** + * 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. + */ +iphone_error_t iphone_device_send_binary_plist(iphone_connection_t connection, plist_t plist) +{ + return internal_plist_send(connection, plist, 1, NULL); +} + +/** + * 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); +} + +/** + * Receives a plist over the given connection. + * Internally used generic plist send function. + * + * @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. + * + * @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. + */ +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 res = IPHONE_E_UNKNOWN_ERROR; + uint32_t pktlen = 0; + uint32_t bytes = 0; + + if ((!connection && !ssl_session) || !plist) { + return IPHONE_E_INVALID_ARG; + } + + iphone_device_recv_timeout(connection, (char*)&pktlen, sizeof(pktlen), &bytes, timeout); + 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; + } 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) { + 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; + } + } + 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); +} + +/** + * Receives a plist over the given connection. + * Binary or XML plists are automatically handled. + * + * 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 + * + * @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. + */ +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) { if (!device) diff --git a/src/iphone.h b/src/iphone.h index 98b0ed8..7ffc811 100644 --- a/src/iphone.h +++ b/src/iphone.h @@ -21,6 +21,9 @@ #ifndef IPHONE_H #define IPHONE_H +#include <plist/plist.h> +#include <gnutls/gnutls.h> + #include "libiphone/libiphone.h" enum connection_type { @@ -38,4 +41,14 @@ 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); + #endif diff --git a/src/lockdown.c b/src/lockdown.c index 1b33830..24dd4a1 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -271,61 +271,21 @@ 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_UNKNOWN_ERROR; - char *receive = NULL; - uint32_t datalen = 0, bytes = 0, received_bytes = 0; - - if (!client->in_SSL) - ret = iphone_device_recv(client->connection, (char *) &datalen, sizeof(datalen), &bytes); - else { - ssize_t res = gnutls_record_recv(client->ssl_session, &datalen, sizeof(datalen)); - if (res < 0) { - log_dbg_msg(DBGMASK_LOCKDOWND, "gnutls_record_recv: Error occured: %s\n", gnutls_strerror(res)); - return LOCKDOWN_E_SSL_ERROR; - } else { - bytes = res; - ret = LOCKDOWN_E_SUCCESS; - } - } - datalen = ntohl(datalen); - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: datalen = %d\n", __func__, datalen); - - receive = (char *) malloc(sizeof(char) * datalen); + lockdownd_error_t ret = LOCKDOWN_E_SUCCESS; + iphone_error_t err; - /* fill buffer and request more packets if needed */ if (!client->in_SSL) { - while ((received_bytes < datalen) && (ret == LOCKDOWN_E_SUCCESS)) { - ret = iphone_device_recv(client->connection, receive + received_bytes, datalen - received_bytes, &bytes); - received_bytes += bytes; + err = iphone_device_receive_plist(client->connection, plist); + if (err != IPHONE_E_SUCCESS) { + ret = LOCKDOWN_E_UNKNOWN_ERROR; } } else { - ssize_t res = 0; - while ((received_bytes < datalen) && (ret == LOCKDOWN_E_SUCCESS)) { - res = gnutls_record_recv(client->ssl_session, receive + received_bytes, datalen - received_bytes); - if (res < 0) { - log_dbg_msg(DBGMASK_LOCKDOWND, "gnutls_record_recv: Error occured: %s\n", gnutls_strerror(res)); - ret = LOCKDOWN_E_SSL_ERROR; - } else { - received_bytes += res; - ret = LOCKDOWN_E_SUCCESS; - } + err = iphone_device_receive_encrypted_plist(client->ssl_session, plist); + if (err != IPHONE_E_SUCCESS) { + return LOCKDOWN_E_SSL_ERROR; } } - if (ret != LOCKDOWN_E_SUCCESS) { - free(receive); - return ret; - } - - if ((ssize_t)received_bytes <= 0) { - free(receive); - return LOCKDOWN_E_NOT_ENOUGH_DATA; - } - - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: received msg size: %i, buffer follows:\n%s", __func__, received_bytes, receive); - plist_from_xml(receive, received_bytes, plist); - free(receive); - if (!*plist) ret = LOCKDOWN_E_PLIST_ERROR; @@ -346,41 +306,21 @@ lockdownd_error_t lockdownd_send(lockdownd_client_t client, plist_t plist) { if (!client || !plist) return LOCKDOWN_E_INVALID_ARG; - char *real_query; - int bytes; - char *XMLContent = NULL; - uint32_t length = 0; - lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; - plist_to_xml(plist, &XMLContent, &length); - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: sending msg size %i, buffer follows:\n%s", __func__, length, XMLContent); - - real_query = (char *) malloc(sizeof(char) * (length + 4)); - length = htonl(length); - memcpy(real_query, &length, sizeof(length)); - memcpy(real_query + 4, XMLContent, ntohl(length)); - free(XMLContent); - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: made the query, sending it along\n", __func__); - - if (!client->in_SSL) - ret = iphone_device_send(client->connection, real_query, ntohl(length) + sizeof(length), (uint32_t*)&bytes); - else { - ssize_t res = gnutls_record_send(client->ssl_session, real_query, ntohl(length) + sizeof(length)); - if (res < 0) { - log_dbg_msg(DBGMASK_LOCKDOWND, "gnutls_record_send: Error occured: %s\n", gnutls_strerror(res)); - ret = LOCKDOWN_E_SSL_ERROR; - } else { - bytes = res; - ret = LOCKDOWN_E_SUCCESS; + 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; } - } - if (ret == LOCKDOWN_E_SUCCESS) { - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: sent it!\n", __func__); } else { - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: sending failed!\n", __func__); + err = iphone_device_send_encrypted_xml_plist(client->ssl_session, plist); + if (err != IPHONE_E_SUCCESS) { + ret = LOCKDOWN_E_SSL_ERROR; + } } - free(real_query); - return ret; } |