diff options
Diffstat (limited to 'src/property_list_service.c')
-rw-r--r-- | src/property_list_service.c | 301 |
1 files changed, 123 insertions, 178 deletions
diff --git a/src/property_list_service.c b/src/property_list_service.c index 8af958e..2fca4e7 100644 --- a/src/property_list_service.c +++ b/src/property_list_service.c @@ -1,4 +1,4 @@ -/* +/* * property_list_service.c * PropertyList service implementation. * @@ -8,97 +8,86 @@ * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif #include <stdlib.h> #include <string.h> -#include <glib.h> #include "property_list_service.h" -#include "idevice.h" -#include "debug.h" +#include "common/debug.h" +#include "endianness.h" /** - * Convert an idevice_error_t value to an property_list_service_error_t value. + * Convert a service_error_t value to a property_list_service_error_t value. * Used internally to get correct error codes. * - * @param err An idevice_error_t error code + * @param err A service_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 idevice_to_property_list_service_error(idevice_error_t err) +static property_list_service_error_t service_to_property_list_service_error(service_error_t err) { switch (err) { - case IDEVICE_E_SUCCESS: + case SERVICE_E_SUCCESS: return PROPERTY_LIST_SERVICE_E_SUCCESS; - case IDEVICE_E_INVALID_ARG: + case SERVICE_E_INVALID_ARG: return PROPERTY_LIST_SERVICE_E_INVALID_ARG; - case IDEVICE_E_SSL_ERROR: + case SERVICE_E_MUX_ERROR: + return PROPERTY_LIST_SERVICE_E_MUX_ERROR; + case SERVICE_E_SSL_ERROR: return PROPERTY_LIST_SERVICE_E_SSL_ERROR; + case SERVICE_E_NOT_ENOUGH_DATA: + return PROPERTY_LIST_SERVICE_E_NOT_ENOUGH_DATA; + case SERVICE_E_TIMEOUT: + return PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT; 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(idevice_t device, uint16_t port, property_list_service_client_t *client) +property_list_service_error_t property_list_service_client_new(idevice_t device, lockdownd_service_descriptor_t service, property_list_service_client_t *client) { - if (!device || port == 0 || !client || *client) + if (!device || !service || service->port == 0 || !client || *client) return PROPERTY_LIST_SERVICE_E_INVALID_ARG; - /* Attempt connection */ - idevice_connection_t connection = NULL; - if (idevice_connect(device, port, &connection) != IDEVICE_E_SUCCESS) { - return PROPERTY_LIST_SERVICE_E_MUX_ERROR; + service_client_t parent = NULL; + service_error_t rerr = service_client_new(device, service, &parent); + if (rerr != SERVICE_E_SUCCESS) { + return service_to_property_list_service_error(rerr); } /* create client object */ property_list_service_client_t client_loc = (property_list_service_client_t)malloc(sizeof(struct property_list_service_client_private)); - client_loc->connection = connection; + client_loc->parent = parent; + /* all done, return success */ *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 = idevice_to_property_list_service_error(idevice_disconnect(client->connection)); + property_list_service_error_t err = service_to_property_list_service_error(service_client_free(client->parent)); + free(client); + client = NULL; + return err; } @@ -113,7 +102,8 @@ property_list_service_error_t property_list_service_client_free(property_list_se * @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 + * 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_send(property_list_service_client_t client, plist_t plist, int binary) @@ -122,9 +112,9 @@ static property_list_service_error_t internal_plist_send(property_list_service_c char *content = NULL; uint32_t length = 0; uint32_t nlen = 0; - int bytes = 0; + uint32_t bytes = 0; - if (!client || (client && !client->connection) || !plist) { + if (!client || (client && !client->parent) || !plist) { return PROPERTY_LIST_SERVICE_E_INVALID_ARG; } @@ -138,15 +128,15 @@ static property_list_service_error_t internal_plist_send(property_list_service_c return PROPERTY_LIST_SERVICE_E_PLIST_ERROR; } - nlen = GUINT32_TO_BE(length); + nlen = htobe32(length); debug_info("sending %d bytes", length); - idevice_connection_send(client->connection, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes); + service_send(client->parent, (const char*)&nlen, sizeof(nlen), &bytes); if (bytes == sizeof(nlen)) { - idevice_connection_send(client->connection, content, length, (uint32_t*)&bytes); + service_send(client->parent, content, length, &bytes); if (bytes > 0) { debug_info("sent %d bytes", bytes); debug_plist(plist); - if ((uint32_t)bytes == length) { + if (bytes == length) { res = PROPERTY_LIST_SERVICE_E_SUCCESS; } else { debug_info("ERROR: Could not send all data (%d of %d)!", bytes, length); @@ -155,40 +145,18 @@ static property_list_service_error_t internal_plist_send(property_list_service_c } if (bytes <= 0) { debug_info("ERROR: sending to device failed."); + res = PROPERTY_LIST_SERVICE_E_MUX_ERROR; } 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); @@ -205,6 +173,8 @@ property_list_service_error_t property_list_service_send_binary_plist(property_l * * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or *plist is NULL, + * PROPERTY_LIST_SERVICE_E_NOT_ENOUGH_DATA when not enough data + * received, PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT when the connection times out, * 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 @@ -216,135 +186,110 @@ static property_list_service_error_t internal_plist_receive_timeout(property_lis uint32_t pktlen = 0; uint32_t bytes = 0; - if (!client || (client && !client->connection) || !plist) { + if (!client || (client && !client->parent) || !plist) { return PROPERTY_LIST_SERVICE_E_INVALID_ARG; } - idevice_connection_receive_timeout(client->connection, (char*)&pktlen, sizeof(pktlen), &bytes, timeout); - debug_info("initial read=%i", bytes); - if (bytes < 4) { + *plist = NULL; + service_error_t serr = service_receive_with_timeout(client->parent, (char*)&pktlen, sizeof(pktlen), &bytes, timeout); + if (serr != SERVICE_E_SUCCESS) { debug_info("initial read failed!"); - return PROPERTY_LIST_SERVICE_E_MUX_ERROR; - } else { - pktlen = GUINT32_FROM_BE(pktlen); - if (pktlen < (1 << 24)) { /* prevent huge buffers */ - uint32_t curlen = 0; - char *content = NULL; - debug_info("%d bytes following", pktlen); - content = (char*)malloc(pktlen); - - while (curlen < pktlen) { - idevice_connection_receive(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 { - /* iOS 4.3 hack: plist data might contain invalid null characters, thus we convert those to spaces */ - for (bytes = 0; bytes < pktlen-1; bytes++) { - if (content[bytes] == 0x0) - content[bytes] = 0x20; - } - 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 service_to_property_list_service_error(serr); + } + + if (bytes == 0) { + /* success but 0 bytes length, assume timeout */ + return PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT; + } + + debug_info("initial read=%i", bytes); + + uint32_t curlen = 0; + char *content = NULL; + + pktlen = be32toh(pktlen); + debug_info("%d bytes following", pktlen); + content = (char*)malloc(pktlen); + if (!content) { + debug_info("out of memory when allocating %d bytes", pktlen); + return PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR; + } + + while (curlen < pktlen) { + serr = service_receive(client->parent, content+curlen, pktlen-curlen, &bytes); + if (serr != SERVICE_E_SUCCESS) { + res = service_to_property_list_service_error(serr); + break; } + debug_info("received %d bytes", bytes); + curlen += bytes; } + + if (curlen < pktlen) { + debug_info("received incomplete packet (%d of %d bytes)", curlen, pktlen); + if (curlen > 0) { + debug_info("incomplete packet following:"); + debug_buffer(content, curlen); + } + free(content); + return res; + } + + if ((pktlen > 8) && !memcmp(content, "bplist00", 8)) { + plist_from_bin(content, pktlen, plist); + } else if ((pktlen > 5) && !memcmp(content, "<?xml", 5)) { + /* iOS 4.3+ hack: plist data might contain invalid characters, thus we convert those to spaces */ + for (bytes = 0; bytes < pktlen-1; bytes++) { + if ((content[bytes] >= 0) && (content[bytes] < 0x20) && (content[bytes] != 0x09) && (content[bytes] != 0x0a) && (content[bytes] != 0x0d)) + content[bytes] = 0x20; + } + plist_from_xml(content, pktlen, plist); + } else { + debug_info("WARNING: received unexpected non-plist content"); + debug_buffer(content, pktlen); + } + + if (*plist) { + debug_plist(*plist); + res = PROPERTY_LIST_SERVICE_E_SUCCESS; + } else { + res = PROPERTY_LIST_SERVICE_E_PLIST_ERROR; + } + + free(content); + content = NULL; + 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_receive_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_receive_timeout(client, plist, 10000); + return internal_plist_receive_timeout(client, plist, 30000); } -/** - * 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) + if (!client || !client->parent) return PROPERTY_LIST_SERVICE_E_INVALID_ARG; - return idevice_to_property_list_service_error(idevice_connection_enable_ssl(client->connection)); + return service_to_property_list_service_error(service_enable_ssl(client->parent)); } -/** - * 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) + if (!client || !client->parent) return PROPERTY_LIST_SERVICE_E_INVALID_ARG; - return idevice_to_property_list_service_error(idevice_connection_disable_ssl(client->connection)); + return service_to_property_list_service_error(service_disable_ssl(client->parent)); } +property_list_service_error_t property_list_service_get_service_client(property_list_service_client_t client, service_client_t *service_client) +{ + if (!client || !client->parent || !service_client) + return PROPERTY_LIST_SERVICE_E_INVALID_ARG; + *service_client = client->parent; + return PROPERTY_LIST_SERVICE_E_SUCCESS; +} |