diff options
Diffstat (limited to 'src')
57 files changed, 3264 insertions, 633 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 183a745..58cf07c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,32 +1,41 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/include \ + -I$(top_srcdir)/3rd_party/libsrp6a-sha512 \ + -I$(top_srcdir)/3rd_party/ed25519 \ -I$(top_srcdir) AM_CFLAGS = \ $(GLOBAL_CFLAGS) \ - $(libusbmuxd_CFLAGS) \ - $(libplist_CFLAGS) \ - $(limd_glue_CFLAGS) \ $(ssl_lib_CFLAGS) \ $(LFS_CFLAGS) \ - $(PTHREAD_CFLAGS) + $(PTHREAD_CFLAGS) \ + $(libusbmuxd_CFLAGS) \ + $(libplist_CFLAGS) \ + $(limd_glue_CFLAGS) AM_LDFLAGS = \ + $(ssl_lib_LIBS) \ + $(PTHREAD_LIBS) \ $(libusbmuxd_LIBS) \ $(libplist_LIBS) \ - $(limd_glue_LIBS) \ - $(ssl_lib_LIBS) \ - $(PTHREAD_LIBS) + $(limd_glue_LIBS) lib_LTLIBRARIES = libimobiledevice-1.0.la libimobiledevice_1_0_la_LIBADD = $(top_builddir)/common/libinternalcommon.la +if HAVE_WIRELESS_PAIRING +libimobiledevice_1_0_la_LIBADD += $(top_builddir)/3rd_party/ed25519/libed25519.la $(top_builddir)/3rd_party/libsrp6a-sha512/libsrp6a-sha512.la +endif libimobiledevice_1_0_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(LIBIMOBILEDEVICE_SO_VERSION) -no-undefined +if DARWIN +libimobiledevice_1_0_la_LDFLAGS += -framework CoreFoundation -framework SystemConfiguration +endif libimobiledevice_1_0_la_SOURCES = \ idevice.c idevice.h \ service.c service.h \ property_list_service.c property_list_service.h \ device_link_service.c device_link_service.h \ lockdown.c lockdown.h \ + lockdown-cu.c \ afc.c afc.h \ file_relay.c file_relay.h \ notification_proxy.c notification_proxy.h \ @@ -47,7 +56,9 @@ libimobiledevice_1_0_la_SOURCES = \ mobileactivation.c mobileactivation.h \ preboard.c preboard.h \ companion_proxy.c companion_proxy.h \ - syslog_relay.c syslog_relay.h + reverse_proxy.c reverse_proxy.h \ + syslog_relay.c syslog_relay.h \ + bt_packet_logger.c bt_packet_logger.h if WIN32 libimobiledevice_1_0_la_LDFLAGS += -avoid-version -static-libgcc @@ -29,8 +29,8 @@ #include <unistd.h> #include <string.h> -#include "afc.h" #include "idevice.h" +#include "afc.h" #include "common/debug.h" #include "endianness.h" @@ -68,7 +68,7 @@ static void afc_unlock(afc_client_t client) * invalid, or AFC_E_NO_MEM if there is a memory allocation problem. */ -LIBIMOBILEDEVICE_API afc_error_t afc_client_new_with_service_client(service_client_t service_client, afc_client_t *client) +afc_error_t afc_client_new_with_service_client(service_client_t service_client, afc_client_t *client) { if (!service_client) return AFC_E_INVALID_ARG; @@ -94,7 +94,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_client_new_with_service_client(service_clie return AFC_E_SUCCESS; } -LIBIMOBILEDEVICE_API afc_error_t afc_client_new(idevice_t device, lockdownd_service_descriptor_t service, afc_client_t * client) +afc_error_t afc_client_new(idevice_t device, lockdownd_service_descriptor_t service, afc_client_t * client) { if (!device || !service || service->port == 0) return AFC_E_INVALID_ARG; @@ -113,14 +113,14 @@ LIBIMOBILEDEVICE_API afc_error_t afc_client_new(idevice_t device, lockdownd_serv return err; } -LIBIMOBILEDEVICE_API afc_error_t afc_client_start_service(idevice_t device, afc_client_t * client, const char* label) +afc_error_t afc_client_start_service(idevice_t device, afc_client_t * client, const char* label) { afc_error_t err = AFC_E_UNKNOWN_ERROR; service_client_factory_start_service(device, AFC_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(afc_client_new), &err); return err; } -LIBIMOBILEDEVICE_API afc_error_t afc_client_free(afc_client_t client) +afc_error_t afc_client_free(afc_client_t client) { if (!client || !client->afc_packet) return AFC_E_INVALID_ARG; @@ -213,7 +213,8 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t uint32_t this_len = 0; uint32_t current_count = 0; uint64_t param1 = -1; - char* dump_here = NULL; + char *buf = NULL; + uint32_t recv_len = 0; if (bytes_recv) { *bytes_recv = 0; @@ -223,18 +224,20 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t } /* first, read the AFC header */ - service_receive(client->parent, (char*)&header, sizeof(AFCPacket), bytes_recv); + service_receive(client->parent, (char*)&header, sizeof(AFCPacket), &recv_len); AFCPacket_from_LE(&header); - if (*bytes_recv == 0) { + if (recv_len == 0) { debug_info("Just didn't get enough."); return AFC_E_MUX_ERROR; - } else if (*bytes_recv < sizeof(AFCPacket)) { + } + + if (recv_len < sizeof(AFCPacket)) { debug_info("Did not even get the AFCPacket header"); return AFC_E_MUX_ERROR; } /* check if it's a valid AFC header */ - if (strncmp(header.magic, AFC_MAGIC, AFC_MAGIC_LEN)) { + if (strncmp(header.magic, AFC_MAGIC, AFC_MAGIC_LEN) != 0) { debug_info("Invalid AFC packet received (magic != " AFC_MAGIC ")!"); } @@ -249,15 +252,14 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t if (header.this_length < sizeof(AFCPacket)) { debug_info("Invalid AFCPacket header received!"); return AFC_E_OP_HEADER_INVALID; - } else if ((header.this_length == header.entire_length) - && header.entire_length == sizeof(AFCPacket)) { + } + if ((header.this_length == header.entire_length) + && header.entire_length == sizeof(AFCPacket)) { debug_info("Empty AFCPacket received!"); - *bytes_recv = 0; if (header.operation == AFC_OP_DATA) { return AFC_E_SUCCESS; - } else { - return AFC_E_IO_ERROR; } + return AFC_E_IO_ERROR; } debug_info("received AFC packet, full len=%lld, this len=%lld, operation=0x%llx", header.entire_length, header.this_length, header.operation); @@ -265,15 +267,17 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t entire_len = (uint32_t)header.entire_length - sizeof(AFCPacket); this_len = (uint32_t)header.this_length - sizeof(AFCPacket); - dump_here = (char*)malloc(entire_len); + buf = (char*)malloc(entire_len); if (this_len > 0) { - service_receive(client->parent, dump_here, this_len, bytes_recv); - if (*bytes_recv <= 0) { - free(dump_here); + recv_len = 0; + service_receive(client->parent, buf, this_len, &recv_len); + if (recv_len <= 0) { + free(buf); debug_info("Did not get packet contents!"); return AFC_E_NOT_ENOUGH_DATA; - } else if (*bytes_recv < this_len) { - free(dump_here); + } + if (recv_len < this_len) { + free(buf); debug_info("Could not receive this_len=%d bytes", this_len); return AFC_E_NOT_ENOUGH_DATA; } @@ -283,12 +287,13 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t if (entire_len > this_len) { while (current_count < entire_len) { - service_receive(client->parent, dump_here+current_count, entire_len - current_count, bytes_recv); - if (*bytes_recv <= 0) { - debug_info("Error receiving data (recv returned %d)", *bytes_recv); + recv_len = 0; + service_receive(client->parent, buf+current_count, entire_len - current_count, &recv_len); + if (recv_len <= 0) { + debug_info("Error receiving data (recv returned %d)", recv_len); break; } - current_count += *bytes_recv; + current_count += recv_len; } if (current_count < entire_len) { debug_info("WARNING: could not receive full packet (read %s, size %d)", current_count, entire_len); @@ -296,16 +301,16 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t } if (current_count >= sizeof(uint64_t)) { - param1 = le64toh(*(uint64_t*)(dump_here)); + param1 = le64toh(*(uint64_t*)(buf)); } debug_info("packet data size = %i", current_count); if (current_count > 256) { debug_info("packet data follows (256/%u)", current_count); - debug_buffer(dump_here, 256); + debug_buffer(buf, 256); } else { debug_info("packet data follows"); - debug_buffer(dump_here, current_count); + debug_buffer(buf, current_count); } /* check operation types */ @@ -316,7 +321,7 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t if (param1 != AFC_E_SUCCESS) { /* error status */ /* free buffer */ - free(dump_here); + free(buf); return (afc_error_t)param1; } } else if (header.operation == AFC_OP_DATA) { @@ -330,8 +335,7 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t debug_info("got a tell response, position=%lld", param1); } else { /* unknown operation code received */ - free(dump_here); - *bytes_recv = 0; + free(buf); debug_info("WARNING: Unknown operation code received 0x%llx param1=%lld", header.operation, param1); #ifndef WIN32 @@ -342,9 +346,9 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t } if (bytes) { - *bytes = dump_here; + *bytes = buf; } else { - free(dump_here); + free(buf); } *bytes_recv = current_count; @@ -354,7 +358,7 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t /** * Returns counts of null characters within a string. */ -static uint32_t count_nullspaces(char *string, uint32_t number) +static uint32_t count_nullspaces(const char *string, uint32_t number) { uint32_t i = 0, nulls = 0; @@ -410,7 +414,7 @@ static int _afc_check_packet_buffer(afc_client_t client, uint32_t data_len) #define AFC_PACKET_DATA_PTR ((char*)client->afc_packet + sizeof(AFCPacket)) -LIBIMOBILEDEVICE_API afc_error_t afc_read_directory(afc_client_t client, const char *path, char ***directory_information) +afc_error_t afc_read_directory(afc_client_t client, const char *path, char ***directory_information) { uint32_t bytes = 0; char *data = NULL, **list_loc = NULL; @@ -454,7 +458,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_read_directory(afc_client_t client, const c return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_get_device_info(afc_client_t client, char ***device_information) +afc_error_t afc_get_device_info(afc_client_t client, char ***device_information) { uint32_t bytes = 0; char *data = NULL, **list = NULL; @@ -491,7 +495,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_get_device_info(afc_client_t client, char * return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_get_device_info_key(afc_client_t client, const char *key, char **value) +afc_error_t afc_get_device_info_key(afc_client_t client, const char *key, char **value) { afc_error_t ret = AFC_E_INTERNAL_ERROR; char **kvps, **ptr; @@ -518,7 +522,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_get_device_info_key(afc_client_t client, co return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_remove_path(afc_client_t client, const char *path) +afc_error_t afc_remove_path(afc_client_t client, const char *path) { uint32_t bytes = 0; afc_error_t ret = AFC_E_UNKNOWN_ERROR; @@ -554,7 +558,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_remove_path(afc_client_t client, const char return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_rename_path(afc_client_t client, const char *from, const char *to) +afc_error_t afc_rename_path(afc_client_t client, const char *from, const char *to) { if (!client || !from || !to || !client->afc_packet || !client->parent) return AFC_E_INVALID_ARG; @@ -590,7 +594,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_rename_path(afc_client_t client, const char return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_make_directory(afc_client_t client, const char *path) +afc_error_t afc_make_directory(afc_client_t client, const char *path) { uint32_t bytes = 0; afc_error_t ret = AFC_E_UNKNOWN_ERROR; @@ -622,7 +626,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_make_directory(afc_client_t client, const c return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***file_information) +afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***file_information) { char *received = NULL; uint32_t bytes = 0; @@ -662,7 +666,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_get_file_info(afc_client_t client, const ch return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_file_open(afc_client_t client, const char *filename, afc_file_mode_t file_mode, uint64_t *handle) +afc_error_t afc_file_open(afc_client_t client, const char *filename, afc_file_mode_t file_mode, uint64_t *handle) { if (!client || !client->parent || !client->afc_packet) return AFC_E_INVALID_ARG; @@ -714,7 +718,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_open(afc_client_t client, const char * return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length, uint32_t *bytes_read) +afc_error_t afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length, uint32_t *bytes_read) { char *input = NULL; uint32_t current_count = 0, bytes_loc = 0; @@ -748,28 +752,29 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_read(afc_client_t client, uint64_t han if (ret != AFC_E_SUCCESS) { afc_unlock(client); return ret; - } else if (bytes_loc == 0) { + } + if (bytes_loc == 0) { if (input) free(input); afc_unlock(client); *bytes_read = current_count; /* FIXME: check that's actually a success */ return ret; - } else { - if (input) { - debug_info("%d", bytes_loc); - memcpy(data + current_count, input, (bytes_loc > length) ? length : bytes_loc); - free(input); - input = NULL; - current_count += (bytes_loc > length) ? length : bytes_loc; - } } + if (input) { + debug_info("%d", bytes_loc); + memcpy(data + current_count, input, (bytes_loc > length) ? length : bytes_loc); + free(input); + input = NULL; + current_count += (bytes_loc > length) ? length : bytes_loc; + } + afc_unlock(client); *bytes_read = current_count; return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_file_write(afc_client_t client, uint64_t handle, const char *data, uint32_t length, uint32_t *bytes_written) +afc_error_t afc_file_write(afc_client_t client, uint64_t handle, const char *data, uint32_t length, uint32_t *bytes_written) { uint32_t current_count = 0; uint32_t bytes_loc = 0; @@ -798,13 +803,13 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_write(afc_client_t client, uint64_t ha ret = afc_receive_data(client, NULL, &bytes_loc); afc_unlock(client); if (ret != AFC_E_SUCCESS) { - debug_info("uh oh?"); + debug_info("Failed to receive reply (%d)", ret); } *bytes_written = current_count; return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_file_close(afc_client_t client, uint64_t handle) +afc_error_t afc_file_close(afc_client_t client, uint64_t handle) { uint32_t bytes = 0; afc_error_t ret = AFC_E_UNKNOWN_ERROR; @@ -835,7 +840,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_close(afc_client_t client, uint64_t ha return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t operation) +afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t operation) { uint32_t bytes = 0; struct lockinfo { @@ -869,7 +874,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_lock(afc_client_t client, uint64_t han return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_file_seek(afc_client_t client, uint64_t handle, int64_t offset, int whence) +afc_error_t afc_file_seek(afc_client_t client, uint64_t handle, int64_t offset, int whence) { uint32_t bytes = 0; struct seekinfo { @@ -903,7 +908,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_seek(afc_client_t client, uint64_t han return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_file_tell(afc_client_t client, uint64_t handle, uint64_t *position) +afc_error_t afc_file_tell(afc_client_t client, uint64_t handle, uint64_t *position) { char *buffer = NULL; uint32_t bytes = 0; @@ -938,7 +943,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_tell(afc_client_t client, uint64_t han return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_file_truncate(afc_client_t client, uint64_t handle, uint64_t newsize) +afc_error_t afc_file_truncate(afc_client_t client, uint64_t handle, uint64_t newsize) { uint32_t bytes = 0; struct truncinfo { @@ -970,7 +975,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_truncate(afc_client_t client, uint64_t return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_truncate(afc_client_t client, const char *path, uint64_t newsize) +afc_error_t afc_truncate(afc_client_t client, const char *path, uint64_t newsize) { if (!client || !path || !client->afc_packet || !client->parent) return AFC_E_INVALID_ARG; @@ -1003,7 +1008,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_truncate(afc_client_t client, const char *p return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_make_link(afc_client_t client, afc_link_type_t linktype, const char *target, const char *linkname) +afc_error_t afc_make_link(afc_client_t client, afc_link_type_t linktype, const char *target, const char *linkname) { if (!client || !target || !linkname || !client->afc_packet || !client->parent) return AFC_E_INVALID_ARG; @@ -1044,7 +1049,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_make_link(afc_client_t client, afc_link_typ return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_set_file_time(afc_client_t client, const char *path, uint64_t mtime) +afc_error_t afc_set_file_time(afc_client_t client, const char *path, uint64_t mtime) { if (!client || !path || !client->afc_packet || !client->parent) return AFC_E_INVALID_ARG; @@ -1077,7 +1082,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_set_file_time(afc_client_t client, const ch return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_remove_path_and_contents(afc_client_t client, const char *path) +afc_error_t afc_remove_path_and_contents(afc_client_t client, const char *path) { uint32_t bytes = 0; afc_error_t ret = AFC_E_UNKNOWN_ERROR; @@ -1109,7 +1114,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_remove_path_and_contents(afc_client_t clien return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_dictionary_free(char **dictionary) +afc_error_t afc_dictionary_free(char **dictionary) { int i = 0; @@ -1123,3 +1128,70 @@ LIBIMOBILEDEVICE_API afc_error_t afc_dictionary_free(char **dictionary) return AFC_E_SUCCESS; } + +const char* afc_strerror(afc_error_t err) +{ + switch (err) { + case AFC_E_SUCCESS: + return "Success"; + case AFC_E_UNKNOWN_ERROR: + return "Unknown Error"; + case AFC_E_OP_HEADER_INVALID: + return "Operation header invalid"; + case AFC_E_NO_RESOURCES: + return "No resources"; + case AFC_E_READ_ERROR: + return "Read error"; + case AFC_E_WRITE_ERROR: + return "Write error"; + case AFC_E_UNKNOWN_PACKET_TYPE: + return "Unknown packet type"; + case AFC_E_INVALID_ARG: + return "Invalid argument"; + case AFC_E_OBJECT_NOT_FOUND: + return "Not found"; + case AFC_E_OBJECT_IS_DIR: + return "Object is a directory"; + case AFC_E_PERM_DENIED: + return "Permission denied"; + case AFC_E_SERVICE_NOT_CONNECTED: + return "Service not connected"; + case AFC_E_OP_TIMEOUT: + return "Timeout"; + case AFC_E_TOO_MUCH_DATA: + return "Too much data"; + case AFC_E_END_OF_DATA: + return "End of data"; + case AFC_E_OP_NOT_SUPPORTED: + return "Operation not supported"; + case AFC_E_OBJECT_EXISTS: + return "Object exists"; + case AFC_E_OBJECT_BUSY: + return "Object busy"; + case AFC_E_NO_SPACE_LEFT: + return "No space left on device"; + case AFC_E_OP_WOULD_BLOCK: + return "Operation would block"; + case AFC_E_IO_ERROR: + return "I/O error"; + case AFC_E_OP_INTERRUPTED: + return "Operation interrupted"; + case AFC_E_OP_IN_PROGRESS: + return "Operation on progress"; + case AFC_E_INTERNAL_ERROR: + return "Internal error"; + case AFC_E_MUX_ERROR: + return "MUX error"; + case AFC_E_NO_MEM: + return "Out of memory"; + case AFC_E_NOT_ENOUGH_DATA: + return "Not enough data"; + case AFC_E_DIR_NOT_EMPTY: + return "Directory not empty"; + case AFC_E_FORCE_SIGNED_TYPE: + return "Force signed type"; + default: + break; + } + return "Unknown Error"; +} diff --git a/src/bt_packet_logger.c b/src/bt_packet_logger.c new file mode 100644 index 0000000..937747c --- /dev/null +++ b/src/bt_packet_logger.c @@ -0,0 +1,231 @@ +/* + * bt_packet_logger.c + * com.apple.bluetooth.BTPacketLogger service implementation. + * + * Copyright (c) 2021 Geoffrey Kruse, 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 + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <string.h> +#include <stdlib.h> + +#include "bt_packet_logger.h" +#include "lockdown.h" +#include "common/debug.h" + +struct bt_packet_logger_worker_thread { + bt_packet_logger_client_t client; + bt_packet_logger_receive_cb_t cbfunc; + void *user_data; + uint8_t rxbuff[BT_MAX_PACKET_SIZE]; +}; + +#define SZ_READ_TIMEOUT 100 +#define PAYLOAD_READ_TIMEOUT 500 + +/** + * Convert a service_error_t value to a bt_packet_logger_error_t value. + * Used internally to get correct error codes. + * + * @param err An service_error_t error code + * + * @return A matching bt_packet_logger_error_t error code, + * BT_PACKET_LOGGER_E_UNKNOWN_ERROR otherwise. + */ +static bt_packet_logger_error_t bt_packet_logger_error(service_error_t err) +{ + switch (err) { + case SERVICE_E_SUCCESS: + return BT_PACKET_LOGGER_E_SUCCESS; + case SERVICE_E_INVALID_ARG: + return BT_PACKET_LOGGER_E_INVALID_ARG; + case SERVICE_E_MUX_ERROR: + return BT_PACKET_LOGGER_E_MUX_ERROR; + case SERVICE_E_SSL_ERROR: + return BT_PACKET_LOGGER_E_SSL_ERROR; + case SERVICE_E_NOT_ENOUGH_DATA: + return BT_PACKET_LOGGER_E_NOT_ENOUGH_DATA; + case SERVICE_E_TIMEOUT: + return BT_PACKET_LOGGER_E_TIMEOUT; + default: + break; + } + return BT_PACKET_LOGGER_E_UNKNOWN_ERROR; +} + +bt_packet_logger_error_t bt_packet_logger_client_new(idevice_t device, lockdownd_service_descriptor_t service, bt_packet_logger_client_t * client) +{ + if (!device || !service || service->port == 0 || !client || *client) { + debug_info("Incorrect parameter passed to bt_packet_logger_client_new."); + return BT_PACKET_LOGGER_E_INVALID_ARG; + } + + debug_info("Creating bt_packet_logger_client, port = %d.", service->port); + + service_client_t parent = NULL; + bt_packet_logger_error_t ret = bt_packet_logger_error(service_client_new(device, service, &parent)); + if (ret != BT_PACKET_LOGGER_E_SUCCESS) { + debug_info("Creating base service client failed. Error: %i", ret); + return ret; + } + + bt_packet_logger_client_t client_loc = (bt_packet_logger_client_t) malloc(sizeof(struct bt_packet_logger_client_private)); + client_loc->parent = parent; + client_loc->worker = THREAD_T_NULL; + + *client = client_loc; + + debug_info("bt_packet_logger_client successfully created."); + return 0; +} + +bt_packet_logger_error_t bt_packet_logger_client_start_service(idevice_t device, bt_packet_logger_client_t * client, const char* label) +{ + bt_packet_logger_error_t err = BT_PACKET_LOGGER_E_UNKNOWN_ERROR; + service_client_factory_start_service(device, BT_PACKETLOGGER_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(bt_packet_logger_client_new), &err); + return err; +} + +bt_packet_logger_error_t bt_packet_logger_client_free(bt_packet_logger_client_t client) +{ + if (!client) + return BT_PACKET_LOGGER_E_INVALID_ARG; + bt_packet_logger_stop_capture(client); + bt_packet_logger_error_t err = bt_packet_logger_error(service_client_free(client->parent)); + free(client); + + return err; +} + +bt_packet_logger_error_t bt_packet_logger_receive_with_timeout(bt_packet_logger_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout) +{ + bt_packet_logger_error_t res = BT_PACKET_LOGGER_E_UNKNOWN_ERROR; + int bytes = 0; + + if (!client || !data || (size == 0)) { + return BT_PACKET_LOGGER_E_INVALID_ARG; + } + + res = bt_packet_logger_error(service_receive_with_timeout(client->parent, data, size, (uint32_t*)&bytes, timeout)); + if (res != BT_PACKET_LOGGER_E_SUCCESS && res != BT_PACKET_LOGGER_E_TIMEOUT && res != BT_PACKET_LOGGER_E_NOT_ENOUGH_DATA) { + debug_info("Could not read data, error %d", res); + } + if (received) { + *received = (uint32_t)bytes; + } + + return res; +} + +void *bt_packet_logger_worker(void *arg) +{ + bt_packet_logger_error_t ret = BT_PACKET_LOGGER_E_UNKNOWN_ERROR; + struct bt_packet_logger_worker_thread *btwt = (struct bt_packet_logger_worker_thread*)arg; + + if (!btwt) { + return NULL; + } + + debug_info("Running"); + + while (btwt->client->parent) { + uint32_t bytes = 0; + uint16_t len; + + ret = bt_packet_logger_receive_with_timeout(btwt->client, (char*)&len, 2, &bytes, SZ_READ_TIMEOUT); + + if (ret == BT_PACKET_LOGGER_E_TIMEOUT || ret == BT_PACKET_LOGGER_E_NOT_ENOUGH_DATA || ((bytes == 0) && (ret == BT_PACKET_LOGGER_E_SUCCESS))) { + continue; + } else if (ret < 0) { + debug_info("Connection to bt packet logger interrupted"); + break; + } + + // sanity check received length + if(bytes > 0 && len > sizeof(bt_packet_logger_header_t)) { + debug_info("Reading %u bytes\n", len); + ret = bt_packet_logger_receive_with_timeout(btwt->client, (char *)btwt->rxbuff, len, &bytes, PAYLOAD_READ_TIMEOUT); + + if(len != bytes) { + debug_info("Failed Read Expected %u, Received %u\n", len, bytes); + continue; + } + + if (ret == BT_PACKET_LOGGER_E_TIMEOUT || ret == BT_PACKET_LOGGER_E_NOT_ENOUGH_DATA || ((bytes == 0) && (ret == BT_PACKET_LOGGER_E_SUCCESS))) { + continue; + } else if (ret < 0) { + debug_info("Connection to bt packet logger interrupted"); + break; + } + + btwt->cbfunc(btwt->rxbuff, len, btwt->user_data); + } + } + + // null check performed above + free(btwt); + + debug_info("Exiting"); + + return NULL; +} + +bt_packet_logger_error_t bt_packet_logger_start_capture(bt_packet_logger_client_t client, bt_packet_logger_receive_cb_t callback, void* user_data) +{ + if (!client || !callback) + return BT_PACKET_LOGGER_E_INVALID_ARG; + + bt_packet_logger_error_t res = BT_PACKET_LOGGER_E_UNKNOWN_ERROR; + + if (client->worker) { + debug_info("Another syslog capture thread appears to be running already."); + return res; + } + + /* start worker thread */ + struct bt_packet_logger_worker_thread *btwt = (struct bt_packet_logger_worker_thread*)malloc(sizeof(struct bt_packet_logger_worker_thread)); + if (btwt) { + btwt->client = client; + btwt->cbfunc = callback; + btwt->user_data = user_data; + + if (thread_new(&client->worker, bt_packet_logger_worker, btwt) == 0) { + res = BT_PACKET_LOGGER_E_SUCCESS; + } + } + + return res; +} + + +bt_packet_logger_error_t bt_packet_logger_stop_capture(bt_packet_logger_client_t client) +{ + if (client->worker) { + /* notify thread to finish */ + service_client_t parent = client->parent; + client->parent = NULL; + /* join thread to make it exit */ + thread_join(client->worker); + thread_free(client->worker); + client->worker = THREAD_T_NULL; + client->parent = parent; + } + + return BT_PACKET_LOGGER_E_SUCCESS; +} diff --git a/src/bt_packet_logger.h b/src/bt_packet_logger.h new file mode 100644 index 0000000..620555e --- /dev/null +++ b/src/bt_packet_logger.h @@ -0,0 +1,37 @@ +/* + * bt_packet_logger.h + * com.apple.bluetooth.BTPacketLogger service header file. + * + * Copyright (c) 2021 Geoffrey Kruse, 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 _BR_PACKET_LOGGER_H +#define _BR_PACKET_LOGGER_H + +#include "idevice.h" +#include "libimobiledevice/bt_packet_logger.h" +#include "service.h" +#include <libimobiledevice-glue/thread.h> + +struct bt_packet_logger_client_private { + service_client_t parent; + THREAD_T worker; +}; + +void *bt_packet_logger_worker(void *arg); + +#endif diff --git a/src/companion_proxy.c b/src/companion_proxy.c index 92bc7f1..421fa9a 100644 --- a/src/companion_proxy.c +++ b/src/companion_proxy.c @@ -62,7 +62,7 @@ static companion_proxy_error_t companion_proxy_error(property_list_service_error return COMPANION_PROXY_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_client_new(idevice_t device, lockdownd_service_descriptor_t service, companion_proxy_client_t * client) +companion_proxy_error_t companion_proxy_client_new(idevice_t device, lockdownd_service_descriptor_t service, companion_proxy_client_t * client) { *client = NULL; @@ -90,14 +90,14 @@ LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_client_new(idevice_ return COMPANION_PROXY_E_SUCCESS; } -LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_client_start_service(idevice_t device, companion_proxy_client_t * client, const char* label) +companion_proxy_error_t companion_proxy_client_start_service(idevice_t device, companion_proxy_client_t * client, const char* label) { companion_proxy_error_t err = COMPANION_PROXY_E_UNKNOWN_ERROR; service_client_factory_start_service(device, COMPANION_PROXY_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(companion_proxy_client_new), &err); return err; } -LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_client_free(companion_proxy_client_t client) +companion_proxy_error_t companion_proxy_client_free(companion_proxy_client_t client) { if (!client) return COMPANION_PROXY_E_INVALID_ARG; @@ -116,7 +116,7 @@ LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_client_free(compani return err; } -LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_send(companion_proxy_client_t client, plist_t plist) +companion_proxy_error_t companion_proxy_send(companion_proxy_client_t client, plist_t plist) { companion_proxy_error_t res = COMPANION_PROXY_E_UNKNOWN_ERROR; @@ -129,7 +129,7 @@ LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_send(companion_prox return res; } -LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_receive(companion_proxy_client_t client, plist_t * plist) +companion_proxy_error_t companion_proxy_receive(companion_proxy_client_t client, plist_t * plist) { companion_proxy_error_t res = COMPANION_PROXY_E_UNKNOWN_ERROR; plist_t outplist = NULL; @@ -143,7 +143,7 @@ LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_receive(companion_p return res; } -LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_get_device_registry(companion_proxy_client_t client, plist_t* paired_devices) +companion_proxy_error_t companion_proxy_get_device_registry(companion_proxy_client_t client, plist_t* paired_devices) { if (!client || !paired_devices) { return COMPANION_PROXY_E_INVALID_ARG; @@ -226,7 +226,7 @@ static void* companion_proxy_event_thread(void* arg) return NULL; } -LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_start_listening_for_devices(companion_proxy_client_t client, companion_proxy_device_event_cb_t callback, void* userdata) +companion_proxy_error_t companion_proxy_start_listening_for_devices(companion_proxy_client_t client, companion_proxy_device_event_cb_t callback, void* userdata) { if (!client || !client->parent || !callback) { return COMPANION_PROXY_E_INVALID_ARG; @@ -252,7 +252,7 @@ LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_start_listening_for return res; } -LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_stop_listening_for_devices(companion_proxy_client_t client) +companion_proxy_error_t companion_proxy_stop_listening_for_devices(companion_proxy_client_t client) { property_list_service_client_t parent = client->parent; client->parent = NULL; @@ -266,7 +266,7 @@ LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_stop_listening_for_ return COMPANION_PROXY_E_SUCCESS; } -LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_get_value_from_registry(companion_proxy_client_t client, const char* companion_udid, const char* key, plist_t* value) +companion_proxy_error_t companion_proxy_get_value_from_registry(companion_proxy_client_t client, const char* companion_udid, const char* key, plist_t* value) { if (!client || !companion_udid || !key || !value) { return COMPANION_PROXY_E_INVALID_ARG; @@ -310,7 +310,7 @@ LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_get_value_from_regi return res; } -LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_start_forwarding_service_port(companion_proxy_client_t client, uint16_t remote_port, const char* service_name, uint16_t* forward_port, plist_t options) +companion_proxy_error_t companion_proxy_start_forwarding_service_port(companion_proxy_client_t client, uint16_t remote_port, const char* service_name, uint16_t* forward_port, plist_t options) { if (!client) { return COMPANION_PROXY_E_INVALID_ARG; @@ -325,7 +325,7 @@ LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_start_forwarding_se plist_dict_set_item(dict, "IsServiceLowPriority", plist_new_bool(0)); plist_dict_set_item(dict, "PreferWifi", plist_new_bool(0)); if (options) { - plist_dict_merge(dict, options); + plist_dict_merge(&dict, options); } companion_proxy_error_t res = companion_proxy_send(client, dict); @@ -353,7 +353,7 @@ LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_start_forwarding_se return res; } -LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_stop_forwarding_service_port(companion_proxy_client_t client, uint16_t remote_port) +companion_proxy_error_t companion_proxy_stop_forwarding_service_port(companion_proxy_client_t client, uint16_t remote_port) { if (!client) { return COMPANION_PROXY_E_INVALID_ARG; diff --git a/src/companion_proxy.h b/src/companion_proxy.h index 0226640..e36932a 100644 --- a/src/companion_proxy.h +++ b/src/companion_proxy.h @@ -22,6 +22,7 @@ #ifndef __COMPANION_PROXY_H #define __COMPANION_PROXY_H +#include "idevice.h" #include "libimobiledevice/companion_proxy.h" #include "property_list_service.h" #include <libimobiledevice-glue/thread.h> diff --git a/src/debugserver.c b/src/debugserver.c index b6a8b62..74ade8a 100644 --- a/src/debugserver.c +++ b/src/debugserver.c @@ -64,7 +64,7 @@ static debugserver_error_t debugserver_error(service_error_t err) return DEBUGSERVER_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_new(idevice_t device, lockdownd_service_descriptor_t service, debugserver_client_t* client) +debugserver_error_t debugserver_client_new(idevice_t device, lockdownd_service_descriptor_t service, debugserver_client_t* client) { *client = NULL; @@ -89,6 +89,8 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_new(idevice_t device debugserver_client_t client_loc = (debugserver_client_t) malloc(sizeof(struct debugserver_client_private)); client_loc->parent = parent; client_loc->noack_mode = 0; + client_loc->cancel_receive = NULL; + client_loc->receive_loop_timeout = 1000; *client = client_loc; @@ -96,7 +98,7 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_new(idevice_t device return DEBUGSERVER_E_SUCCESS; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_start_service(idevice_t device, debugserver_client_t * client, const char* label) +debugserver_error_t debugserver_client_start_service(idevice_t device, debugserver_client_t * client, const char* label) { debugserver_error_t err = DEBUGSERVER_E_UNKNOWN_ERROR; service_client_factory_start_service(device, DEBUGSERVER_SECURE_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(debugserver_client_new), &err); @@ -107,7 +109,7 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_start_service(idevic return err; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_free(debugserver_client_t client) +debugserver_error_t debugserver_client_free(debugserver_client_t client) { if (!client) return DEBUGSERVER_E_INVALID_ARG; @@ -119,7 +121,7 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_free(debugserver_cli return err; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_send(debugserver_client_t client, const char* data, uint32_t size, uint32_t *sent) +debugserver_error_t debugserver_client_send(debugserver_client_t client, const char* data, uint32_t size, uint32_t *sent) { debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR; int bytes = 0; @@ -140,7 +142,7 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_send(debugserver_cli return res; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive_with_timeout(debugserver_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout) +debugserver_error_t debugserver_client_receive_with_timeout(debugserver_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout) { debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR; int bytes = 0; @@ -150,7 +152,7 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive_with_timeout } res = debugserver_error(service_receive_with_timeout(client->parent, data, size, (uint32_t*)&bytes, timeout)); - if (bytes <= 0) { + if (bytes <= 0 && res != DEBUGSERVER_E_TIMEOUT) { debug_info("Could not read data, error %d", res); } if (received) { @@ -160,12 +162,17 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive_with_timeout return (bytes > 0) ? DEBUGSERVER_E_SUCCESS : res; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive(debugserver_client_t client, char* data, uint32_t size, uint32_t *received) +debugserver_error_t debugserver_client_receive(debugserver_client_t client, char* data, uint32_t size, uint32_t *received) { - return debugserver_client_receive_with_timeout(client, data, size, received, 1000); + debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR; + do { + /* Is this allowed to return DEBUGSERVER_E_TIMEOUT and also set data and received? */ + res = debugserver_client_receive_with_timeout(client, data, size, received, client->receive_loop_timeout); + } while (res == DEBUGSERVER_E_TIMEOUT && client->cancel_receive != NULL && !client->cancel_receive()); + return res; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_command_new(const char* name, int argc, char* argv[], debugserver_command_t* command) +debugserver_error_t debugserver_command_new(const char* name, int argc, char* argv[], debugserver_command_t* command) { int i; debugserver_command_t tmp = (debugserver_command_t) malloc(sizeof(struct debugserver_command_private)); @@ -190,7 +197,7 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_command_new(const char* nam return DEBUGSERVER_E_SUCCESS; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_command_free(debugserver_command_t command) +debugserver_error_t debugserver_command_free(debugserver_command_t command) { int i; debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR; @@ -232,10 +239,10 @@ static char debugserver_int2hex(int x) return hexchars[x]; } -#define DEBUGSERVER_HEX_ENCODE_FIRST_BYTE(byte) debugserver_int2hex((byte >> 0x4) & 0xf) -#define DEBUGSERVER_HEX_ENCODE_SECOND_BYTE(byte) debugserver_int2hex(byte & 0xf) -#define DEBUGSERVER_HEX_DECODE_FIRST_BYTE(byte) ((byte >> 0x4) & 0xf) -#define DEBUGSERVER_HEX_DECODE_SECOND_BYTE(byte) (byte & 0xf) +#define DEBUGSERVER_HEX_ENCODE_FIRST_BYTE(byte) debugserver_int2hex(((byte) >> 0x4) & 0xf) +#define DEBUGSERVER_HEX_ENCODE_SECOND_BYTE(byte) debugserver_int2hex((byte) & 0xf) +#define DEBUGSERVER_HEX_DECODE_FIRST_BYTE(byte) (((byte) >> 0x4) & 0xf) +#define DEBUGSERVER_HEX_DECODE_SECOND_BYTE(byte) ((byte) & 0xf) static uint32_t debugserver_get_checksum_for_buffer(const char* buffer, uint32_t size) { @@ -268,7 +275,7 @@ static int debugserver_response_is_checksum_valid(const char* response, uint32_t return 1; } -LIBIMOBILEDEVICE_API void debugserver_encode_string(const char* buffer, char** encoded_buffer, uint32_t* encoded_length) +void debugserver_encode_string(const char* buffer, char** encoded_buffer, uint32_t* encoded_length) { uint32_t position; uint32_t index; @@ -284,7 +291,7 @@ LIBIMOBILEDEVICE_API void debugserver_encode_string(const char* buffer, char** e } } -LIBIMOBILEDEVICE_API void debugserver_decode_string(const char *encoded_buffer, size_t encoded_length, char** buffer) +void debugserver_decode_string(const char *encoded_buffer, size_t encoded_length, char** buffer) { *buffer = malloc(sizeof(char) * ((encoded_length / 2)+1)); char* t = *buffer; @@ -343,7 +350,7 @@ static debugserver_error_t debugserver_client_send_noack(debugserver_client_t cl return debugserver_client_send(client, "-", sizeof(char), NULL); } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_ack_mode(debugserver_client_t client, int enabled) +debugserver_error_t debugserver_client_set_ack_mode(debugserver_client_t client, int enabled) { if (!client) return DEBUGSERVER_E_INVALID_ARG; @@ -355,130 +362,137 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_ack_mode(debugse return DEBUGSERVER_E_SUCCESS; } -static int debugserver_client_receive_internal_check(debugserver_client_t client, char* received_char) +debugserver_error_t debugserver_client_set_receive_params(debugserver_client_t client, int (*cancel_receive)(), int receive_loop_timeout) +{ + if (!client) + return DEBUGSERVER_E_INVALID_ARG; + + client->cancel_receive = cancel_receive; + client->receive_loop_timeout = receive_loop_timeout; + + debug_info("receive params: cancel_receive %s, receive_loop_timeout %dms", (client->cancel_receive == NULL ? "unset": "set"), client->receive_loop_timeout); + + return DEBUGSERVER_E_SUCCESS; +} + +static debugserver_error_t debugserver_client_receive_internal_char(debugserver_client_t client, char* received_char) { debugserver_error_t res = DEBUGSERVER_E_SUCCESS; - int did_receive_char = 0; - char buffer = 0; uint32_t bytes = 0; /* we loop here as we expect an answer */ - res = debugserver_client_receive_with_timeout(client, &buffer, sizeof(char), &bytes, 1000); - if (res == DEBUGSERVER_E_SUCCESS && received_char[0] != 0) { - if (memcmp(&buffer, received_char, sizeof(char)) == 0) { - did_receive_char = 1; - } - } else { - did_receive_char = 0; + res = debugserver_client_receive(client, received_char, sizeof(char), &bytes); + if (res != DEBUGSERVER_E_SUCCESS) { + return res; } - - if (!did_receive_char) { - memcpy(received_char, &buffer, sizeof(char)); + if (bytes != 1) { + debug_info("received %d bytes when asking for %d!", bytes, sizeof(char)); + return DEBUGSERVER_E_UNKNOWN_ERROR; } - - return did_receive_char; + return res; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive_response(debugserver_client_t client, char** response, size_t* response_size) +debugserver_error_t debugserver_client_receive_response(debugserver_client_t client, char** response, size_t* response_size) { debugserver_error_t res = DEBUGSERVER_E_SUCCESS; - int should_receive = 1; + char data = '\0'; int skip_prefix = 0; - char* command_prefix = strdup("$"); - char* buffer = NULL; + char* buffer = malloc(1024); uint32_t buffer_size = 0; - uint32_t buffer_capacity = 0; + uint32_t buffer_capacity = 1024; if (response) *response = NULL; if (!client->noack_mode) { - char ack[2] = {'+', '\0'}; - debug_info("attempting to receive ACK %c", *ack); - should_receive = debugserver_client_receive_internal_check(client, ack); - debug_info("received char: %c", *ack); - if (strncmp(ack, command_prefix, sizeof(char)) == 0) { - should_receive = 1; + debug_info("attempting to receive ACK (+)"); + res = debugserver_client_receive_internal_char(client, &data); + if (res != DEBUGSERVER_E_SUCCESS) { + goto cleanup; + } + if (data == '+') { + debug_info("received ACK (+)"); + } else if (data == '$') { + debug_info("received prefix ($)"); + buffer[0] = '$'; + buffer_size = 1; skip_prefix = 1; - buffer = malloc(1024); - buffer_capacity = 1024; - strcpy(buffer, command_prefix); - buffer_size += sizeof(char); - debug_info("received ACK"); + } else { + debug_info("unrecognized response when looking for ACK: %c", data); + goto cleanup; } } - debug_info("should_receive: %d, skip_prefix: %d", should_receive, skip_prefix); - - if (should_receive && !skip_prefix) { - debug_info("attempting to receive prefix"); - should_receive = debugserver_client_receive_internal_check(client, command_prefix); - debug_info("received command_prefix: %c", *command_prefix); - if (should_receive) { - if (buffer) { - strcpy(buffer, command_prefix); - } else { - buffer = malloc(1024); - buffer_capacity = 1024; - strcpy(buffer, command_prefix); - buffer_size += sizeof(char); - } + debug_info("skip_prefix: %d", skip_prefix); + + if (!skip_prefix) { + debug_info("attempting to receive prefix ($)"); + res = debugserver_client_receive_internal_char(client, &data); + if (res != DEBUGSERVER_E_SUCCESS) { + goto cleanup; + } + if (data == '$') { + debug_info("received prefix ($)"); + buffer[0] = '$'; + buffer_size = 1; + } else { + debug_info("unrecognized response when looking for prefix: %c", data); + goto cleanup; } } - debug_info("buffer: %*s, should_receive: %d, skip_prefix: %d", buffer_size, buffer, should_receive, skip_prefix); + uint32_t checksum_length = DEBUGSERVER_CHECKSUM_HASH_LENGTH; + int receiving_checksum_response = 0; + debug_info("attempting to read up response until checksum"); - if (should_receive) { - uint32_t checksum_length = DEBUGSERVER_CHECKSUM_HASH_LENGTH; - int receiving_checksum_response = 0; - debug_info("attempting to read up response until checksum"); - - while ((checksum_length > 0)) { - char data[2] = {'#', '\0'}; - if (debugserver_client_receive_internal_check(client, data)) { - receiving_checksum_response = 1; - } - if (receiving_checksum_response) { - checksum_length--; - } - if (buffer_size + 1 >= buffer_capacity) { - char* newbuffer = realloc(buffer, buffer_capacity+1024); - if (!newbuffer) { - return DEBUGSERVER_E_UNKNOWN_ERROR; - } - buffer = newbuffer; - buffer[buffer_capacity] = '\0'; - buffer_capacity += 1024; - } - strcat(buffer, data); - buffer_size += sizeof(char); + while ((checksum_length > 0)) { + res = debugserver_client_receive_internal_char(client, &data); + if (res != DEBUGSERVER_E_SUCCESS) { + goto cleanup; } - debug_info("validating response checksum..."); - if (client->noack_mode || debugserver_response_is_checksum_valid(buffer, buffer_size)) { - if (response) { - /* assemble response string */ - uint32_t resp_size = sizeof(char) * (buffer_size - DEBUGSERVER_CHECKSUM_HASH_LENGTH - 1); - *response = (char*)malloc(resp_size + 1); - memcpy(*response, buffer + 1, resp_size); - (*response)[resp_size] = '\0'; - if (response_size) *response_size = resp_size; - } - if (!client->noack_mode) { - /* confirm valid command */ - debugserver_client_send_ack(client); - } - } else { - /* response was invalid */ - res = DEBUGSERVER_E_RESPONSE_ERROR; - if (!client->noack_mode) { - /* report invalid command */ - debugserver_client_send_noack(client); + if (data == '#') { + receiving_checksum_response = 1; + } + if (receiving_checksum_response) { + checksum_length--; + } + if (buffer_size + 1 >= buffer_capacity) { + char* newbuffer = realloc(buffer, buffer_capacity+1024); + if (!newbuffer) { + return DEBUGSERVER_E_UNKNOWN_ERROR; } + buffer = newbuffer; + buffer_capacity += 1024; + } + buffer[buffer_size] = data; + buffer_size += sizeof(char); + } + debug_info("validating response checksum..."); + if (client->noack_mode || debugserver_response_is_checksum_valid(buffer, buffer_size)) { + if (response) { + /* assemble response string */ + uint32_t resp_size = sizeof(char) * (buffer_size - DEBUGSERVER_CHECKSUM_HASH_LENGTH - 1); + *response = (char*)malloc(resp_size + 1); + memcpy(*response, buffer + 1, resp_size); + (*response)[resp_size] = '\0'; + if (response_size) *response_size = resp_size; + } + if (!client->noack_mode) { + /* confirm valid command */ + debugserver_client_send_ack(client); + } + } else { + /* response was invalid */ + res = DEBUGSERVER_E_RESPONSE_ERROR; + if (!client->noack_mode) { + /* report invalid command */ + debugserver_client_send_noack(client); } } +cleanup: if (response) { debug_info("response: %s", *response); } @@ -486,13 +500,10 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive_response(deb if (buffer) free(buffer); - if (command_prefix) - free(command_prefix); - return res; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_send_command(debugserver_client_t client, debugserver_command_t command, char** response, size_t* response_size) +debugserver_error_t debugserver_client_send_command(debugserver_client_t client, debugserver_command_t command, char** response, size_t* response_size) { debugserver_error_t res = DEBUGSERVER_E_SUCCESS; int i; @@ -548,7 +559,7 @@ cleanup: return res; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_environment_hex_encoded(debugserver_client_t client, const char* env, char** response) +debugserver_error_t debugserver_client_set_environment_hex_encoded(debugserver_client_t client, const char* env, char** response) { if (!client || !env) return DEBUGSERVER_E_INVALID_ARG; @@ -567,21 +578,25 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_environment_hex_ return result; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_argv(debugserver_client_t client, int argc, char* argv[], char** response) +debugserver_error_t debugserver_client_set_argv(debugserver_client_t client, int argc, char* argv[], char** response) { if (!client || !argc) return DEBUGSERVER_E_INVALID_ARG; debugserver_error_t result = DEBUGSERVER_E_UNKNOWN_ERROR; char *pkt = NULL; - int pkt_len = 0; + size_t pkt_len = 0; int i = 0; /* calculate total length */ while (i < argc && argv && argv[i]) { char *prefix = NULL; - asprintf(&prefix, ",%d,%d,", (int)strlen(argv[i]) * 2, i); - pkt_len += (int)strlen(prefix) + (int)strlen(argv[i]) * 2; + int ret = asprintf(&prefix, ",%zu,%d,", strlen(argv[i]) * 2, i); + if (ret < 0 || prefix == NULL) { + debug_info("asprintf failed, out of memory?"); + return DEBUGSERVER_E_UNKNOWN_ERROR; + } + pkt_len += strlen(prefix) + strlen(argv[i]) * 2; free(prefix); i++; } @@ -598,10 +613,14 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_argv(debugserver char *prefix = NULL; char *m = NULL; - int arg_len = strlen(argv[i]); - int arg_hexlen = arg_len * 2; + size_t arg_len = strlen(argv[i]); + size_t arg_hexlen = arg_len * 2; - asprintf(&prefix, ",%d,%d,", arg_hexlen, i); + int ret = asprintf(&prefix, ",%zu,%d,", arg_hexlen, i); + if (ret < 0 || prefix == NULL) { + debug_info("asprintf failed, out of memory?"); + return DEBUGSERVER_E_UNKNOWN_ERROR; + } m = (char *) malloc(arg_hexlen); char *p = m; diff --git a/src/debugserver.h b/src/debugserver.h index 05cd97b..ce9c255 100644 --- a/src/debugserver.h +++ b/src/debugserver.h @@ -22,6 +22,7 @@ #ifndef _DEBUGSERVER_H #define _DEBUGSERVER_H +#include "idevice.h" #include "libimobiledevice/debugserver.h" #include "service.h" @@ -30,6 +31,8 @@ struct debugserver_client_private { service_client_t parent; int noack_mode; + int (*cancel_receive)(); + int receive_loop_timeout; }; struct debugserver_command_private { diff --git a/src/device_link_service.c b/src/device_link_service.c index 6daf84d..66c2461 100644 --- a/src/device_link_service.c +++ b/src/device_link_service.c @@ -83,7 +83,7 @@ static int device_link_service_get_message(plist_t dl_msg, char **message) return 0; } - if ((strlen(cmd_str) < 9) || (strncmp(cmd_str, "DL", 2))) { + if ((strlen(cmd_str) < 9) || (strncmp(cmd_str, "DL", 2) != 0)) { free(cmd_str); return 0; } @@ -184,7 +184,7 @@ device_link_service_error_t device_link_service_version_exchange(device_link_ser goto leave; } device_link_service_get_message(array, &msg); - if (!msg || strcmp(msg, "DLMessageVersionExchange")) { + if (!msg || strcmp(msg, "DLMessageVersionExchange") != 0) { debug_info("Did not receive DLMessageVersionExchange from device!"); err = DEVICE_LINK_SERVICE_E_PLIST_ERROR; goto leave; @@ -239,7 +239,7 @@ device_link_service_error_t device_link_service_version_exchange(device_link_ser goto leave; } device_link_service_get_message(array, &msg); - if (!msg || strcmp(msg, "DLMessageDeviceReady")) { + if (!msg || strcmp(msg, "DLMessageDeviceReady") != 0) { debug_info("Did not get DLMessageDeviceReady!"); err = DEVICE_LINK_SERVICE_E_PLIST_ERROR; goto leave; @@ -403,7 +403,7 @@ device_link_service_error_t device_link_service_receive_process_message(device_l char *msg = NULL; device_link_service_get_message(pmsg, &msg); - if (!msg || strcmp(msg, "DLMessageProcessMessage")) { + if (!msg || strcmp(msg, "DLMessageProcessMessage") != 0) { debug_info("Did not receive DLMessageProcessMessage as expected!"); err = DEVICE_LINK_SERVICE_E_PLIST_ERROR; goto leave; diff --git a/src/device_link_service.h b/src/device_link_service.h index eae912a..0255b21 100644 --- a/src/device_link_service.h +++ b/src/device_link_service.h @@ -22,6 +22,7 @@ #ifndef __DEVICE_LINK_SERVICE_H #define __DEVICE_LINK_SERVICE_H +#include "idevice.h" #include "property_list_service.h" /* Error Codes */ diff --git a/src/diagnostics_relay.c b/src/diagnostics_relay.c index b6cf4d9..6ee3150 100644 --- a/src/diagnostics_relay.c +++ b/src/diagnostics_relay.c @@ -73,7 +73,7 @@ static int diagnostics_relay_check_result(plist_t dict) return ret; } -LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, diagnostics_relay_client_t *client) +diagnostics_relay_error_t diagnostics_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, diagnostics_relay_client_t *client) { if (!device || !service || service->port == 0 || !client || *client) { return DIAGNOSTICS_RELAY_E_INVALID_ARG; @@ -93,14 +93,14 @@ LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_client_new(idev return DIAGNOSTICS_RELAY_E_SUCCESS; } -LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_client_start_service(idevice_t device, diagnostics_relay_client_t * client, const char* label) +diagnostics_relay_error_t diagnostics_relay_client_start_service(idevice_t device, diagnostics_relay_client_t * client, const char* label) { diagnostics_relay_error_t err = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR; service_client_factory_start_service(device, DIAGNOSTICS_RELAY_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(diagnostics_relay_client_new), &err); return err; } -LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_client_free(diagnostics_relay_client_t client) +diagnostics_relay_error_t diagnostics_relay_client_free(diagnostics_relay_client_t client) { if (!client) return DIAGNOSTICS_RELAY_E_INVALID_ARG; @@ -167,7 +167,7 @@ static diagnostics_relay_error_t diagnostics_relay_send(diagnostics_relay_client return ret; } -LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_goodbye(diagnostics_relay_client_t client) +diagnostics_relay_error_t diagnostics_relay_goodbye(diagnostics_relay_client_t client) { if (!client) return DIAGNOSTICS_RELAY_E_INVALID_ARG; @@ -201,7 +201,7 @@ LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_goodbye(diagnos return ret; } -LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_sleep(diagnostics_relay_client_t client) +diagnostics_relay_error_t diagnostics_relay_sleep(diagnostics_relay_client_t client) { if (!client) return DIAGNOSTICS_RELAY_E_INVALID_ARG; @@ -277,17 +277,17 @@ static diagnostics_relay_error_t internal_diagnostics_relay_action(diagnostics_r return ret; } -LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_restart(diagnostics_relay_client_t client, diagnostics_relay_action_t flags) +diagnostics_relay_error_t diagnostics_relay_restart(diagnostics_relay_client_t client, diagnostics_relay_action_t flags) { return internal_diagnostics_relay_action(client, "Restart", flags); } -LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_shutdown(diagnostics_relay_client_t client, diagnostics_relay_action_t flags) +diagnostics_relay_error_t diagnostics_relay_shutdown(diagnostics_relay_client_t client, diagnostics_relay_action_t flags) { return internal_diagnostics_relay_action(client, "Shutdown", flags); } -LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_request_diagnostics(diagnostics_relay_client_t client, const char* type, plist_t* diagnostics) +diagnostics_relay_error_t diagnostics_relay_request_diagnostics(diagnostics_relay_client_t client, const char* type, plist_t* diagnostics) { if (!client || diagnostics == NULL) return DIAGNOSTICS_RELAY_E_INVALID_ARG; @@ -299,6 +299,9 @@ LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_request_diagnos ret = diagnostics_relay_send(client, dict); plist_free(dict); dict = NULL; + if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) { + return ret; + } ret = diagnostics_relay_receive(client, &dict); if (!dict) { @@ -328,7 +331,7 @@ LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_request_diagnos return ret; } -LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_query_mobilegestalt(diagnostics_relay_client_t client, plist_t keys, plist_t* result) +diagnostics_relay_error_t diagnostics_relay_query_mobilegestalt(diagnostics_relay_client_t client, plist_t keys, plist_t* result) { if (!client || plist_get_node_type(keys) != PLIST_ARRAY || result == NULL) return DIAGNOSTICS_RELAY_E_INVALID_ARG; @@ -341,6 +344,9 @@ LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_query_mobileges ret = diagnostics_relay_send(client, dict); plist_free(dict); dict = NULL; + if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) { + return ret; + } ret = diagnostics_relay_receive(client, &dict); if (!dict) { @@ -370,7 +376,7 @@ LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_query_mobileges return ret; } -LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_query_ioregistry_entry(diagnostics_relay_client_t client, const char* entry_name, const char* entry_class, plist_t* result) +diagnostics_relay_error_t diagnostics_relay_query_ioregistry_entry(diagnostics_relay_client_t client, const char* entry_name, const char* entry_class, plist_t* result) { if (!client || (entry_name == NULL && entry_class == NULL) || result == NULL) return DIAGNOSTICS_RELAY_E_INVALID_ARG; @@ -386,6 +392,9 @@ LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_query_ioregistr ret = diagnostics_relay_send(client, dict); plist_free(dict); dict = NULL; + if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) { + return ret; + } ret = diagnostics_relay_receive(client, &dict); if (!dict) { @@ -415,7 +424,7 @@ LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_query_ioregistr return ret; } -LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_query_ioregistry_plane(diagnostics_relay_client_t client, const char* plane, plist_t* result) +diagnostics_relay_error_t diagnostics_relay_query_ioregistry_plane(diagnostics_relay_client_t client, const char* plane, plist_t* result) { if (!client || plane == NULL || result == NULL) return DIAGNOSTICS_RELAY_E_INVALID_ARG; diff --git a/src/diagnostics_relay.h b/src/diagnostics_relay.h index 6d11ea1..3bb543a 100644 --- a/src/diagnostics_relay.h +++ b/src/diagnostics_relay.h @@ -22,6 +22,7 @@ #ifndef __DIAGNOSTICS_RELAY_H #define __DIAGNOSTICS_RELAY_H +#include "idevice.h" #include "libimobiledevice/diagnostics_relay.h" #include "property_list_service.h" diff --git a/src/file_relay.c b/src/file_relay.c index e304d31..fbe7cbf 100644 --- a/src/file_relay.c +++ b/src/file_relay.c @@ -28,7 +28,7 @@ #include "property_list_service.h" #include "common/debug.h" -LIBIMOBILEDEVICE_API file_relay_error_t file_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, file_relay_client_t *client) +file_relay_error_t file_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, file_relay_client_t *client) { if (!device || !service || service->port == 0 || !client || *client) { return FILE_RELAY_E_INVALID_ARG; @@ -48,14 +48,14 @@ LIBIMOBILEDEVICE_API file_relay_error_t file_relay_client_new(idevice_t device, return FILE_RELAY_E_SUCCESS; } -LIBIMOBILEDEVICE_API file_relay_error_t file_relay_client_start_service(idevice_t device, file_relay_client_t * client, const char* label) +file_relay_error_t file_relay_client_start_service(idevice_t device, file_relay_client_t * client, const char* label) { file_relay_error_t err = FILE_RELAY_E_UNKNOWN_ERROR; service_client_factory_start_service(device, FILE_RELAY_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(file_relay_client_new), &err); return err; } -LIBIMOBILEDEVICE_API file_relay_error_t file_relay_client_free(file_relay_client_t client) +file_relay_error_t file_relay_client_free(file_relay_client_t client) { if (!client) return FILE_RELAY_E_INVALID_ARG; @@ -67,7 +67,7 @@ LIBIMOBILEDEVICE_API file_relay_error_t file_relay_client_free(file_relay_client return FILE_RELAY_E_SUCCESS; } -LIBIMOBILEDEVICE_API file_relay_error_t file_relay_request_sources_timeout(file_relay_client_t client, const char **sources, idevice_connection_t *connection, unsigned int timeout) +file_relay_error_t file_relay_request_sources_timeout(file_relay_client_t client, const char **sources, idevice_connection_t *connection, unsigned int timeout) { if (!client || !client->parent || !sources || !sources[0]) { return FILE_RELAY_E_INVALID_ARG; @@ -143,7 +143,7 @@ LIBIMOBILEDEVICE_API file_relay_error_t file_relay_request_sources_timeout(file_ goto leave; } - if (strcmp(ack, "Acknowledged")) { + if (strcmp(ack, "Acknowledged") != 0) { debug_info("ERROR: Did not receive 'Acknowledged' but '%s'", ack); goto leave; } @@ -159,7 +159,7 @@ leave: return err; } -LIBIMOBILEDEVICE_API file_relay_error_t file_relay_request_sources(file_relay_client_t client, const char **sources, idevice_connection_t *connection) +file_relay_error_t file_relay_request_sources(file_relay_client_t client, const char **sources, idevice_connection_t *connection) { return file_relay_request_sources_timeout(client, sources, connection, 60000); } diff --git a/src/file_relay.h b/src/file_relay.h index 626fab8..65bf460 100644 --- a/src/file_relay.h +++ b/src/file_relay.h @@ -22,6 +22,7 @@ #ifndef __FILE_RELAY_H #define __FILE_RELAY_H +#include "idevice.h" #include "libimobiledevice/file_relay.h" #include "property_list_service.h" diff --git a/src/heartbeat.c b/src/heartbeat.c index 9a527cc..3945d73 100644 --- a/src/heartbeat.c +++ b/src/heartbeat.c @@ -62,7 +62,7 @@ static heartbeat_error_t heartbeat_error(property_list_service_error_t err) return HEARTBEAT_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_client_new(idevice_t device, lockdownd_service_descriptor_t service, heartbeat_client_t * client) +heartbeat_error_t heartbeat_client_new(idevice_t device, lockdownd_service_descriptor_t service, heartbeat_client_t * client) { *client = NULL; @@ -89,14 +89,14 @@ LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_client_new(idevice_t device, lo return 0; } -LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_client_start_service(idevice_t device, heartbeat_client_t * client, const char* label) +heartbeat_error_t heartbeat_client_start_service(idevice_t device, heartbeat_client_t * client, const char* label) { heartbeat_error_t err = HEARTBEAT_E_UNKNOWN_ERROR; service_client_factory_start_service(device, HEARTBEAT_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(heartbeat_client_new), &err); return err; } -LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_client_free(heartbeat_client_t client) +heartbeat_error_t heartbeat_client_free(heartbeat_client_t client) { if (!client) return HEARTBEAT_E_INVALID_ARG; @@ -107,7 +107,7 @@ LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_client_free(heartbeat_client_t return err; } -LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_send(heartbeat_client_t client, plist_t plist) +heartbeat_error_t heartbeat_send(heartbeat_client_t client, plist_t plist) { heartbeat_error_t res = HEARTBEAT_E_UNKNOWN_ERROR; @@ -122,12 +122,12 @@ LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_send(heartbeat_client_t client, return res; } -LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_receive(heartbeat_client_t client, plist_t * plist) +heartbeat_error_t heartbeat_receive(heartbeat_client_t client, plist_t * plist) { return heartbeat_receive_with_timeout(client, plist, 1000); } -LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_receive_with_timeout(heartbeat_client_t client, plist_t * plist, uint32_t timeout_ms) +heartbeat_error_t heartbeat_receive_with_timeout(heartbeat_client_t client, plist_t * plist, uint32_t timeout_ms) { heartbeat_error_t res = HEARTBEAT_E_UNKNOWN_ERROR; plist_t outplist = NULL; diff --git a/src/heartbeat.h b/src/heartbeat.h index f648681..379ecc1 100644 --- a/src/heartbeat.h +++ b/src/heartbeat.h @@ -22,6 +22,7 @@ #ifndef __HEARTBEAT_H #define __HEARTBEAT_H +#include "idevice.h" #include "libimobiledevice/heartbeat.h" #include "property_list_service.h" diff --git a/src/house_arrest.c b/src/house_arrest.c index ac92130..caad731 100644 --- a/src/house_arrest.c +++ b/src/house_arrest.c @@ -58,7 +58,7 @@ static house_arrest_error_t house_arrest_error(property_list_service_error_t err return HOUSE_ARREST_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_client_new(idevice_t device, lockdownd_service_descriptor_t service, house_arrest_client_t *client) +house_arrest_error_t house_arrest_client_new(idevice_t device, lockdownd_service_descriptor_t service, house_arrest_client_t *client) { property_list_service_client_t plistclient = NULL; house_arrest_error_t err = house_arrest_error(property_list_service_client_new(device, service, &plistclient)); @@ -74,14 +74,14 @@ LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_client_new(idevice_t devi return HOUSE_ARREST_E_SUCCESS; } -LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_client_start_service(idevice_t device, house_arrest_client_t * client, const char* label) +house_arrest_error_t house_arrest_client_start_service(idevice_t device, house_arrest_client_t * client, const char* label) { house_arrest_error_t err = HOUSE_ARREST_E_UNKNOWN_ERROR; service_client_factory_start_service(device, HOUSE_ARREST_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(house_arrest_client_new), &err); return err; } -LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_client_free(house_arrest_client_t client) +house_arrest_error_t house_arrest_client_free(house_arrest_client_t client) { if (!client) return HOUSE_ARREST_E_INVALID_ARG; @@ -96,7 +96,7 @@ LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_client_free(house_arrest_ return err; } -LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_send_request(house_arrest_client_t client, plist_t dict) +house_arrest_error_t house_arrest_send_request(house_arrest_client_t client, plist_t dict) { if (!client || !client->parent || !dict) return HOUSE_ARREST_E_INVALID_ARG; @@ -112,7 +112,7 @@ LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_send_request(house_arrest return res; } -LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_send_command(house_arrest_client_t client, const char *command, const char *appid) +house_arrest_error_t house_arrest_send_command(house_arrest_client_t client, const char *command, const char *appid) { if (!client || !client->parent || !command || !appid) return HOUSE_ARREST_E_INVALID_ARG; @@ -132,7 +132,7 @@ LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_send_command(house_arrest return res; } -LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_get_result(house_arrest_client_t client, plist_t *dict) +house_arrest_error_t house_arrest_get_result(house_arrest_client_t client, plist_t *dict) { if (!client || !client->parent) return HOUSE_ARREST_E_INVALID_ARG; @@ -150,7 +150,7 @@ LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_get_result(house_arrest_c return res; } -LIBIMOBILEDEVICE_API afc_error_t afc_client_new_from_house_arrest_client(house_arrest_client_t client, afc_client_t *afc_client) +afc_error_t afc_client_new_from_house_arrest_client(house_arrest_client_t client, afc_client_t *afc_client) { if (!client || !client->parent || (client->mode == HOUSE_ARREST_CLIENT_MODE_AFC)) { return AFC_E_INVALID_ARG; diff --git a/src/house_arrest.h b/src/house_arrest.h index 387594f..5612a29 100644 --- a/src/house_arrest.h +++ b/src/house_arrest.h @@ -22,6 +22,7 @@ #ifndef __HOUSE_ARREST_H #define __HOUSE_ARREST_H +#include "idevice.h" #include "libimobiledevice/house_arrest.h" #include "property_list_service.h" diff --git a/src/idevice.c b/src/idevice.c index 04189d6..b9bbb1f 100644 --- a/src/idevice.c +++ b/src/idevice.c @@ -30,6 +30,15 @@ #include <errno.h> #include <time.h> +#ifdef WIN32 +#include <winsock2.h> +#include <ws2tcpip.h> +#include <windows.h> +#else +#include <sys/socket.h> +#include <netinet/in.h> +#endif + #include <usbmuxd.h> #if defined(HAVE_OPENSSL) @@ -52,17 +61,18 @@ #include <libimobiledevice-glue/thread.h> #include "idevice.h" +#include "lockdown.h" #include "common/userpref.h" #include "common/debug.h" -#ifdef WIN32 -#include <windows.h> +#ifndef ECONNREFUSED +#define ECONNREFUSED 107 #endif - #ifndef ETIMEDOUT #define ETIMEDOUT 138 #endif + #ifdef HAVE_OPENSSL #if OPENSSL_VERSION_NUMBER < 0x10100000L || \ @@ -209,10 +219,25 @@ BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved) #warning No compiler support for constructor/destructor attributes, some features might not be available. #endif -static idevice_event_cb_t event_cb = NULL; +const char* libimobiledevice_version() +{ +#ifndef PACKAGE_VERSION +#error PACKAGE_VERSION is not defined! +#endif + return PACKAGE_VERSION; +} + +struct idevice_subscription_context { + idevice_event_cb_t callback; + void *user_data; + usbmuxd_subscription_context_t ctx; +}; + +static idevice_subscription_context_t event_ctx = NULL; static void usbmux_event_cb(const usbmuxd_event_t *event, void *user_data) { + idevice_subscription_context_t context = (idevice_subscription_context_t)user_data; idevice_event_t ev; ev.event = event->event; @@ -226,35 +251,68 @@ static void usbmux_event_cb(const usbmuxd_event_t *event, void *user_data) debug_info("Unknown connection type %d", event->device.conn_type); } - if (event_cb) { - event_cb(&ev, user_data); + if (context->callback) { + context->callback(&ev, context->user_data); } } -LIBIMOBILEDEVICE_API idevice_error_t idevice_event_subscribe(idevice_event_cb_t callback, void *user_data) +idevice_error_t idevice_events_subscribe(idevice_subscription_context_t *context, idevice_event_cb_t callback, void *user_data) { - event_cb = callback; - int res = usbmuxd_subscribe(usbmux_event_cb, user_data); + if (!context || !callback) { + return IDEVICE_E_INVALID_ARG; + } + *context = malloc(sizeof(struct idevice_subscription_context)); + if (!*context) { + debug_info("ERROR: %s: Failed to allocate subscription context\n", __func__); + return IDEVICE_E_UNKNOWN_ERROR; + } + (*context)->callback = callback; + (*context)->user_data = user_data; + int res = usbmuxd_events_subscribe(&(*context)->ctx, usbmux_event_cb, *context); if (res != 0) { - event_cb = NULL; + free(*context); + *context = NULL; debug_info("ERROR: usbmuxd_subscribe() returned %d!", res); return IDEVICE_E_UNKNOWN_ERROR; } return IDEVICE_E_SUCCESS; } -LIBIMOBILEDEVICE_API idevice_error_t idevice_event_unsubscribe(void) +idevice_error_t idevice_events_unsubscribe(idevice_subscription_context_t context) { - event_cb = NULL; - int res = usbmuxd_unsubscribe(); + if (!context) { + return IDEVICE_E_INVALID_ARG; + } + int res = usbmuxd_events_unsubscribe(context->ctx); if (res != 0) { debug_info("ERROR: usbmuxd_unsubscribe() returned %d!", res); return IDEVICE_E_UNKNOWN_ERROR; } + if (context == event_ctx) { + event_ctx = NULL; + } + free(context); return IDEVICE_E_SUCCESS; } -LIBIMOBILEDEVICE_API idevice_error_t idevice_get_device_list_extended(idevice_info_t **devices, int *count) +idevice_error_t idevice_event_subscribe(idevice_event_cb_t callback, void *user_data) +{ + if (event_ctx) { + idevice_events_unsubscribe(event_ctx); + } + return idevice_events_subscribe(&event_ctx, callback, user_data); +} + +idevice_error_t idevice_event_unsubscribe(void) +{ + if (!event_ctx) { + return IDEVICE_E_SUCCESS; + } + event_ctx->callback = NULL; + return idevice_events_unsubscribe(event_ctx); +} + +idevice_error_t idevice_get_device_list_extended(idevice_info_t **devices, int *count) { usbmuxd_device_info_t *dev_list; @@ -278,7 +336,21 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_get_device_list_extended(idevice_in newlist[newcount]->conn_data = NULL; } else if (dev_list[i].conn_type == CONNECTION_TYPE_NETWORK) { newlist[newcount]->conn_type = CONNECTION_NETWORK; - size_t addrlen = dev_list[i].conn_data[0]; + struct sockaddr* saddr = (struct sockaddr*)(dev_list[i].conn_data); + size_t addrlen = 0; + switch (saddr->sa_family) { + case AF_INET: + addrlen = sizeof(struct sockaddr_in); + break; +#ifdef AF_INET6 + case AF_INET6: + addrlen = sizeof(struct sockaddr_in6); + break; +#endif + default: + debug_info("Unsupported address family 0x%02x\n", saddr->sa_family); + continue; + } newlist[newcount]->conn_data = malloc(addrlen); memcpy(newlist[newcount]->conn_data, dev_list[i].conn_data, addrlen); } @@ -295,7 +367,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_get_device_list_extended(idevice_in return IDEVICE_E_SUCCESS; } -LIBIMOBILEDEVICE_API idevice_error_t idevice_device_list_extended_free(idevice_info_t *devices) +idevice_error_t idevice_device_list_extended_free(idevice_info_t *devices) { if (devices) { int i = 0; @@ -310,7 +382,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_device_list_extended_free(idevice_i return IDEVICE_E_SUCCESS; } -LIBIMOBILEDEVICE_API idevice_error_t idevice_get_device_list(char ***devices, int *count) +idevice_error_t idevice_get_device_list(char ***devices, int *count) { usbmuxd_device_info_t *dev_list; @@ -342,7 +414,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_get_device_list(char ***devices, in return IDEVICE_E_SUCCESS; } -LIBIMOBILEDEVICE_API idevice_error_t idevice_device_list_free(char **devices) +idevice_error_t idevice_device_list_free(char **devices) { if (devices) { int i = 0; @@ -355,7 +427,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_device_list_free(char **devices) return IDEVICE_E_SUCCESS; } -LIBIMOBILEDEVICE_API void idevice_set_debug_level(int level) +void idevice_set_debug_level(int level) { internal_set_debug_level(level); } @@ -380,9 +452,25 @@ static idevice_t idevice_from_mux_device(usbmuxd_device_info_t *muxdev) break; case CONNECTION_TYPE_NETWORK: device->conn_type = CONNECTION_NETWORK; - size_t len = ((uint8_t*)muxdev->conn_data)[0]; - device->conn_data = malloc(len); - memcpy(device->conn_data, muxdev->conn_data, len); + struct sockaddr* saddr = (struct sockaddr*)(muxdev->conn_data); + size_t addrlen = 0; + switch (saddr->sa_family) { + case AF_INET: + addrlen = sizeof(struct sockaddr_in); + break; +#ifdef AF_INET6 + case AF_INET6: + addrlen = sizeof(struct sockaddr_in6); + break; +#endif + default: + debug_info("Unsupported address family 0x%02x\n", saddr->sa_family); + free(device->udid); + free(device); + return NULL; + } + device->conn_data = malloc(addrlen); + memcpy(device->conn_data, muxdev->conn_data, addrlen); break; default: device->conn_type = 0; @@ -392,7 +480,7 @@ static idevice_t idevice_from_mux_device(usbmuxd_device_info_t *muxdev) return device; } -LIBIMOBILEDEVICE_API idevice_error_t idevice_new_with_options(idevice_t * device, const char *udid, enum idevice_options options) +idevice_error_t idevice_new_with_options(idevice_t * device, const char *udid, enum idevice_options options) { usbmuxd_device_info_t muxdev; int usbmux_options = 0; @@ -416,12 +504,12 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_new_with_options(idevice_t * device return IDEVICE_E_NO_DEVICE; } -LIBIMOBILEDEVICE_API idevice_error_t idevice_new(idevice_t * device, const char *udid) +idevice_error_t idevice_new(idevice_t * device, const char *udid) { return idevice_new_with_options(device, udid, 0); } -LIBIMOBILEDEVICE_API idevice_error_t idevice_free(idevice_t device) +idevice_error_t idevice_free(idevice_t device) { if (!device) return IDEVICE_E_INVALID_ARG; @@ -438,7 +526,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_free(idevice_t device) return ret; } -LIBIMOBILEDEVICE_API idevice_error_t idevice_connect(idevice_t device, uint16_t port, idevice_connection_t *connection) +idevice_error_t idevice_connect(idevice_t device, uint16_t port, idevice_connection_t *connection) { if (!device) { return IDEVICE_E_INVALID_ARG; @@ -467,28 +555,18 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connect(idevice_t device, uint16_t new_connection->status = IDEVICE_E_SUCCESS; *connection = new_connection; return IDEVICE_E_SUCCESS; - } else if (device->conn_type == CONNECTION_NETWORK) { - struct sockaddr_storage saddr_storage; - struct sockaddr* saddr = (struct sockaddr*)&saddr_storage; - - /* FIXME: Improve handling of this platform/host dependent connection data */ - if (((char*)device->conn_data)[1] == 0x02) { // AF_INET - saddr->sa_family = AF_INET; - memcpy(&saddr->sa_data[0], (char*)device->conn_data + 2, 14); - } - else if (((char*)device->conn_data)[1] == 0x1E) { // AF_INET6 (bsd) + } + if (device->conn_type == CONNECTION_NETWORK) { + struct sockaddr* saddr = (struct sockaddr*)(device->conn_data); + switch (saddr->sa_family) { + case AF_INET: #ifdef AF_INET6 - saddr->sa_family = AF_INET6; - /* copy the address and the host dependent scope id */ - memcpy(&saddr->sa_data[0], (char*)device->conn_data + 2, 26); -#else - debug_info("ERROR: Got an IPv6 address but this system doesn't support IPv6"); - return IDEVICE_E_UNKNOWN_ERROR; + case AF_INET6: #endif - } - else { - debug_info("Unsupported address family 0x%02x", ((char*)device->conn_data)[1]); - return IDEVICE_E_UNKNOWN_ERROR; + break; + default: + debug_info("Unsupported address family 0x%02x", saddr->sa_family); + return IDEVICE_E_UNKNOWN_ERROR; } char addrtxt[48]; @@ -523,14 +601,13 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connect(idevice_t device, uint16_t *connection = new_connection; return IDEVICE_E_SUCCESS; - } else { - debug_info("Unknown connection type %d", device->conn_type); } + debug_info("Unknown connection type %d", device->conn_type); return IDEVICE_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API idevice_error_t idevice_disconnect(idevice_connection_t connection) +idevice_error_t idevice_disconnect(idevice_connection_t connection) { if (!connection) { return IDEVICE_E_INVALID_ARG; @@ -577,7 +654,8 @@ static idevice_error_t internal_connection_send(idevice_connection_t connection, return IDEVICE_E_UNKNOWN_ERROR; } return IDEVICE_E_SUCCESS; - } else if (connection->type == CONNECTION_NETWORK) { + } + if (connection->type == CONNECTION_NETWORK) { int s = socket_send((int)(long)connection->data, (void*)data, len); if (s < 0) { *sent_bytes = 0; @@ -585,14 +663,14 @@ static idevice_error_t internal_connection_send(idevice_connection_t connection, } *sent_bytes = s; return IDEVICE_E_SUCCESS; - } else { - debug_info("Unknown connection type %d", connection->type); } + + debug_info("Unknown connection type %d", connection->type); return IDEVICE_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_send(idevice_connection_t connection, const char *data, uint32_t len, uint32_t *sent_bytes) +idevice_error_t idevice_connection_send(idevice_connection_t connection, const char *data, uint32_t len, uint32_t *sent_bytes) { if (!connection || !data #if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS) @@ -632,24 +710,26 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_send(idevice_connection_ } *sent_bytes = sent; return IDEVICE_E_SUCCESS; - } else { - uint32_t sent = 0; - while (sent < len) { - uint32_t bytes = 0; - int s = internal_connection_send(connection, data+sent, len-sent, &bytes); - if (s < 0) { - break; - } - sent += bytes; - } - debug_info("internal_connection_send %d, sent %d", len, sent); - if (sent < len) { - *sent_bytes = 0; - return IDEVICE_E_NOT_ENOUGH_DATA; + } + uint32_t sent = 0; + while (sent < len) { + uint32_t bytes = 0; + int s = internal_connection_send(connection, data+sent, len-sent, &bytes); + if (s < 0) { + break; } + sent += bytes; + } + debug_info("internal_connection_send %d, sent %d", len, sent); + if (sent < len) { *sent_bytes = sent; - return IDEVICE_E_SUCCESS; + if (sent == 0) { + return IDEVICE_E_UNKNOWN_ERROR; + } + return IDEVICE_E_NOT_ENOUGH_DATA; } + *sent_bytes = sent; + return IDEVICE_E_SUCCESS; } static inline idevice_error_t socket_recv_to_idevice_error(int conn_error, uint32_t len, uint32_t received) @@ -689,7 +769,8 @@ static idevice_error_t internal_connection_receive_timeout(idevice_connection_t debug_info("ERROR: usbmuxd_recv_timeout returned %d (%s)", conn_error, strerror(-conn_error)); } return error; - } else if (connection->type == CONNECTION_NETWORK) { + } + if (connection->type == CONNECTION_NETWORK) { int res = socket_receive_timeout((int)(long)connection->data, data, len, 0, timeout); idevice_error_t error = socket_recv_to_idevice_error(res, 0, 0); if (error == IDEVICE_E_SUCCESS) { @@ -698,13 +779,13 @@ static idevice_error_t internal_connection_receive_timeout(idevice_connection_t debug_info("ERROR: socket_receive_timeout returned %d (%s)", res, strerror(-res)); } return error; - } else { - debug_info("Unknown connection type %d", connection->type); } + + debug_info("Unknown connection type %d", connection->type); return IDEVICE_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive_timeout(idevice_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout) +idevice_error_t idevice_connection_receive_timeout(idevice_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout) { if (!connection #if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS) @@ -735,6 +816,10 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive_timeout(idevice_ int sslerr = SSL_get_error(connection->ssl_data->session, r); if (sslerr == SSL_ERROR_WANT_READ) { continue; + } else if (sslerr == SSL_ERROR_ZERO_RETURN) { + if (connection->status == IDEVICE_E_TIMEOUT) { + SSL_set_shutdown(connection->ssl_data->session, 0); + } } break; } @@ -784,7 +869,8 @@ static idevice_error_t internal_connection_receive(idevice_connection_t connecti return IDEVICE_E_UNKNOWN_ERROR; } return IDEVICE_E_SUCCESS; - } else if (connection->type == CONNECTION_NETWORK) { + } + if (connection->type == CONNECTION_NETWORK) { int res = socket_receive((int)(long)connection->data, data, len); if (res < 0) { debug_info("ERROR: socket_receive returned %d (%s)", res, strerror(-res)); @@ -792,13 +878,13 @@ static idevice_error_t internal_connection_receive(idevice_connection_t connecti } *recv_bytes = (uint32_t)res; return IDEVICE_E_SUCCESS; - } else { - debug_info("Unknown connection type %d", connection->type); } + + debug_info("Unknown connection type %d", connection->type); return IDEVICE_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive(idevice_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes) +idevice_error_t idevice_connection_receive(idevice_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes) { if (!connection #if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS) @@ -831,26 +917,26 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive(idevice_connecti return internal_connection_receive(connection, data, len, recv_bytes); } -LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_get_fd(idevice_connection_t connection, int *fd) +idevice_error_t idevice_connection_get_fd(idevice_connection_t connection, int *fd) { if (!connection || !fd) { return IDEVICE_E_INVALID_ARG; } - idevice_error_t result = IDEVICE_E_UNKNOWN_ERROR; if (connection->type == CONNECTION_USBMUXD) { *fd = (int)(long)connection->data; - result = IDEVICE_E_SUCCESS; - } else if (connection->type == CONNECTION_NETWORK) { + return IDEVICE_E_SUCCESS; + } + if (connection->type == CONNECTION_NETWORK) { *fd = (int)(long)connection->data; - result = IDEVICE_E_SUCCESS; - } else { - debug_info("Unknown connection type %d", connection->type); + return IDEVICE_E_SUCCESS; } - return result; + + debug_info("Unknown connection type %d", connection->type); + return IDEVICE_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API idevice_error_t idevice_get_handle(idevice_t device, uint32_t *handle) +idevice_error_t idevice_get_handle(idevice_t device, uint32_t *handle) { if (!device || !handle) return IDEVICE_E_INVALID_ARG; @@ -859,12 +945,14 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_get_handle(idevice_t device, uint32 return IDEVICE_E_SUCCESS; } -LIBIMOBILEDEVICE_API idevice_error_t idevice_get_udid(idevice_t device, char **udid) +idevice_error_t idevice_get_udid(idevice_t device, char **udid) { if (!device || !udid) return IDEVICE_E_INVALID_ARG; - *udid = strdup(device->udid); + if (device->udid) { + *udid = strdup(device->udid); + } return IDEVICE_E_SUCCESS; } @@ -977,18 +1065,33 @@ static void internal_ssl_cleanup(ssl_data_t ssl_data) } #ifdef HAVE_OPENSSL +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +static long ssl_idevice_bio_callback(BIO *b, int oper, const char *argp, size_t len, int argi, long argl, int retvalue, size_t *processed) +#else static long ssl_idevice_bio_callback(BIO *b, int oper, const char *argp, int argi, long argl, long retvalue) +#endif { + ssize_t bytes = 0; idevice_connection_t conn = (idevice_connection_t)BIO_get_callback_arg(b); +#if OPENSSL_VERSION_NUMBER < 0x30000000L size_t len = (size_t)argi; + size_t *processed = (size_t*)&bytes; +#endif switch (oper) { case (BIO_CB_READ|BIO_CB_RETURN): - return argp ? (long)internal_ssl_read(conn, (char *)argp, len) : 0; + if (argp) { + bytes = internal_ssl_read(conn, (char *)argp, len); + *processed = bytes; + return (long)bytes; + } + return 0; case (BIO_CB_PUTS|BIO_CB_RETURN): len = strlen(argp); // fallthrough case (BIO_CB_WRITE|BIO_CB_RETURN): - return (long)internal_ssl_write(conn, argp, len); + bytes = internal_ssl_write(conn, argp, len); + *processed = bytes; + return (long)bytes; default: return retvalue; } @@ -999,7 +1102,11 @@ static BIO *ssl_idevice_bio_new(idevice_connection_t conn) BIO *b = BIO_new(BIO_s_null()); if (!b) return NULL; BIO_set_callback_arg(b, (char *)conn); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + BIO_set_callback_ex(b, ssl_idevice_bio_callback); +#else BIO_set_callback(b, ssl_idevice_bio_callback); +#endif return b; } @@ -1087,7 +1194,7 @@ static int _mbedtls_f_rng(void* p_rng, unsigned char* buf, size_t len) } #endif -LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection) +idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection) { if (!connection || connection->ssl_data) return IDEVICE_E_INVALID_ARG; @@ -1124,7 +1231,8 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_conne return ret; } -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) || \ + (defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER >= 0x3060000fL)) SSL_CTX_set_security_level(ssl_ctx, 0); #endif @@ -1133,23 +1241,52 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_conne /* force use of TLSv1 for older devices */ if (connection->device->version < DEVICE_VERSION(10,0,0)) { #ifdef SSL_OP_NO_TLSv1_1 - long opts = SSL_CTX_get_options(ssl_ctx); - opts |= SSL_OP_NO_TLSv1_1; + SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_1); +#endif #ifdef SSL_OP_NO_TLSv1_2 - opts |= SSL_OP_NO_TLSv1_2; + SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_2); #endif #ifdef SSL_OP_NO_TLSv1_3 - opts |= SSL_OP_NO_TLSv1_3; -#endif - SSL_CTX_set_options(ssl_ctx, opts); + SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_3); #endif } #else SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_VERSION); if (connection->device->version < DEVICE_VERSION(10,0,0)) { SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_VERSION); + if (connection->device->version == 0) { + /* + iOS 1 doesn't understand TLS1_VERSION, it can only speak SSL3_VERSION. + However, modern OpenSSL is usually compiled without SSLv3 support. + So if we set min_proto_version to SSL3_VERSION on an OpenSSL instance which doesn't support it, + it will just ignore min_proto_version altogether and fall back to an even higher version. + To avoid accidentally breaking iOS 2.0+, we set min version to 0 instead. + Here is what documentation says: + Setting the minimum or maximum version to 0, + will enable protocol versions down to the lowest version, + or up to the highest version supported by the library, respectively. + */ + SSL_CTX_set_min_proto_version(ssl_ctx, 0); + } } #endif +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#if defined(SSL_OP_IGNORE_UNEXPECTED_EOF) + /* + * For OpenSSL 3 and later, mark close_notify alerts as optional. + * For prior versions of OpenSSL we check for SSL_ERROR_SYSCALL when + * reading instead (this error changes to SSL_ERROR_SSL in OpenSSL 3). + */ + SSL_CTX_set_options(ssl_ctx, SSL_OP_IGNORE_UNEXPECTED_EOF); +#endif +#if defined(SSL_OP_LEGACY_SERVER_CONNECT) + /* + * Without setting SSL_OP_LEGACY_SERVER_CONNECT, OpenSSL 3 fails with + * error "unsafe legacy renegotiation disabled" when talking to iOS 5 + */ + SSL_CTX_set_options(ssl_ctx, SSL_OP_LEGACY_SERVER_CONNECT); +#endif +#endif BIO* membp; X509* rootCert = NULL; @@ -1162,6 +1299,16 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_conne X509_free(rootCert); free(root_cert.data); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY* rootPrivKey = NULL; + membp = BIO_new_mem_buf(root_privkey.data, root_privkey.size); + PEM_read_bio_PrivateKey(membp, &rootPrivKey, NULL, NULL); + BIO_free(membp); + if (SSL_CTX_use_PrivateKey(ssl_ctx, rootPrivKey) != 1) { + debug_info("WARNING: Could not load RootPrivateKey"); + } + EVP_PKEY_free(rootPrivKey); +#else RSA* rootPrivKey = NULL; membp = BIO_new_mem_buf(root_privkey.data, root_privkey.size); PEM_read_bio_RSAPrivateKey(membp, &rootPrivKey, NULL, NULL); @@ -1170,6 +1317,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_conne debug_info("WARNING: Could not load RootPrivateKey"); } RSA_free(rootPrivKey); +#endif free(root_privkey.data); SSL *ssl = SSL_new(ssl_ctx); @@ -1349,12 +1497,12 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_conne return ret; } -LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_disable_ssl(idevice_connection_t connection) +idevice_error_t idevice_connection_disable_ssl(idevice_connection_t connection) { return idevice_connection_disable_bypass_ssl(connection, 0); } -LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_disable_bypass_ssl(idevice_connection_t connection, uint8_t sslBypass) +idevice_error_t idevice_connection_disable_bypass_ssl(idevice_connection_t connection, uint8_t sslBypass) { if (!connection) return IDEVICE_E_INVALID_ARG; diff --git a/src/idevice.h b/src/idevice.h index 2509e48..dd72f9d 100644 --- a/src/idevice.h +++ b/src/idevice.h @@ -37,14 +37,16 @@ #include <mbedtls/ctr_drbg.h> #endif -#ifdef WIN32 -#define LIBIMOBILEDEVICE_API __declspec( dllexport ) +#ifdef LIBIMOBILEDEVICE_STATIC + #define LIBIMOBILEDEVICE_API +#elif defined(_WIN32) + #define LIBIMOBILEDEVICE_API __declspec( dllexport ) #else -#ifdef HAVE_FVISIBILITY -#define LIBIMOBILEDEVICE_API __attribute__((visibility("default"))) -#else -#define LIBIMOBILEDEVICE_API -#endif + #if __GNUC__ >= 4 + #define LIBIMOBILEDEVICE_API __attribute__((visibility("default"))) + #else + #define LIBIMOBILEDEVICE_API + #endif #endif #include "common/userpref.h" diff --git a/src/installation_proxy.c b/src/installation_proxy.c index ebf2d03..ec19da0 100644 --- a/src/installation_proxy.c +++ b/src/installation_proxy.c @@ -232,7 +232,7 @@ static instproxy_error_t instproxy_error(property_list_service_error_t err) return INSTPROXY_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_client_new(idevice_t device, lockdownd_service_descriptor_t service, instproxy_client_t *client) +instproxy_error_t instproxy_client_new(idevice_t device, lockdownd_service_descriptor_t service, instproxy_client_t *client) { property_list_service_client_t plistclient = NULL; instproxy_error_t err = instproxy_error(property_list_service_client_new(device, service, &plistclient)); @@ -249,14 +249,14 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_client_new(idevice_t device, lo return INSTPROXY_E_SUCCESS; } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_client_start_service(idevice_t device, instproxy_client_t * client, const char* label) +instproxy_error_t instproxy_client_start_service(idevice_t device, instproxy_client_t * client, const char* label) { instproxy_error_t err = INSTPROXY_E_UNKNOWN_ERROR; service_client_factory_start_service(device, INSTPROXY_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(instproxy_client_new), &err); return err; } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_client_free(instproxy_client_t client) +instproxy_error_t instproxy_client_free(instproxy_client_t client) { if (!client) return INSTPROXY_E_INVALID_ARG; @@ -282,9 +282,6 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_client_free(instproxy_client_t * * @param client The connected installation_proxy client. * @param command The command to execute. Required. - * @param client_options The client options to use, as PLIST_DICT, or NULL. - * @param appid The ApplicationIdentifier to add or NULL if not required. - * @param package_path The installation package path or NULL if not required. * * @return INSTPROXY_E_SUCCESS on success or an INSTPROXY_E_* error value if * an error occurred. @@ -528,7 +525,7 @@ static instproxy_error_t instproxy_perform_command(instproxy_client_t client, pl return res; } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_browse_with_callback(instproxy_client_t client, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) +instproxy_error_t instproxy_browse_with_callback(instproxy_client_t client, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) { if (!client || !client->parent || !status_cb) return INSTPROXY_E_INVALID_ARG; @@ -569,7 +566,7 @@ static void instproxy_append_current_list_to_result_cb(plist_t command, plist_t plist_free(current_list); } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_browse(instproxy_client_t client, plist_t client_options, plist_t *result) +instproxy_error_t instproxy_browse(instproxy_client_t client, plist_t client_options, plist_t *result) { if (!client || !client->parent || !result) return INSTPROXY_E_INVALID_ARG; @@ -606,7 +603,7 @@ static void instproxy_copy_lookup_result_cb(plist_t command, plist_t status, voi } } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_lookup(instproxy_client_t client, const char** appids, plist_t client_options, plist_t *result) +instproxy_error_t instproxy_lookup(instproxy_client_t client, const char** appids, plist_t client_options, plist_t *result) { instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; int i = 0; @@ -653,7 +650,7 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_lookup(instproxy_client_t clien return res; } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_install(instproxy_client_t client, const char *pkg_path, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) +instproxy_error_t instproxy_install(instproxy_client_t client, const char *pkg_path, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) { instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; @@ -663,14 +660,14 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_install(instproxy_client_t clie plist_dict_set_item(command, "ClientOptions", plist_copy(client_options)); plist_dict_set_item(command, "PackagePath", plist_new_string(pkg_path)); - res = instproxy_perform_command(client, command, INSTPROXY_COMMAND_TYPE_ASYNC, status_cb, user_data); + res = instproxy_perform_command(client, command, status_cb == NULL ? INSTPROXY_COMMAND_TYPE_SYNC : INSTPROXY_COMMAND_TYPE_ASYNC, status_cb, user_data); plist_free(command); return res; } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_upgrade(instproxy_client_t client, const char *pkg_path, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) +instproxy_error_t instproxy_upgrade(instproxy_client_t client, const char *pkg_path, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) { instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; @@ -680,14 +677,14 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_upgrade(instproxy_client_t clie plist_dict_set_item(command, "ClientOptions", plist_copy(client_options)); plist_dict_set_item(command, "PackagePath", plist_new_string(pkg_path)); - res = instproxy_perform_command(client, command, INSTPROXY_COMMAND_TYPE_ASYNC, status_cb, user_data); + res = instproxy_perform_command(client, command, status_cb == NULL ? INSTPROXY_COMMAND_TYPE_SYNC : INSTPROXY_COMMAND_TYPE_ASYNC, status_cb, user_data); plist_free(command); return res; } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) +instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) { instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; @@ -697,14 +694,14 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_uninstall(instproxy_client_t cl plist_dict_set_item(command, "ClientOptions", plist_copy(client_options)); plist_dict_set_item(command, "ApplicationIdentifier", plist_new_string(appid)); - res = instproxy_perform_command(client, command, INSTPROXY_COMMAND_TYPE_ASYNC, status_cb, user_data); + res = instproxy_perform_command(client, command, status_cb == NULL ? INSTPROXY_COMMAND_TYPE_SYNC : INSTPROXY_COMMAND_TYPE_ASYNC, status_cb, user_data); plist_free(command); return res; } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist_t client_options, plist_t *result) +instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist_t client_options, plist_t *result) { instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; @@ -720,7 +717,7 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_lookup_archives(instproxy_clien return res; } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) +instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) { instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; @@ -730,14 +727,14 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_archive(instproxy_client_t clie plist_dict_set_item(command, "ClientOptions", plist_copy(client_options)); plist_dict_set_item(command, "ApplicationIdentifier", plist_new_string(appid)); - res = instproxy_perform_command(client, command, INSTPROXY_COMMAND_TYPE_ASYNC, status_cb, user_data); + res = instproxy_perform_command(client, command, status_cb == NULL ? INSTPROXY_COMMAND_TYPE_SYNC : INSTPROXY_COMMAND_TYPE_ASYNC, status_cb, user_data); plist_free(command); return res; } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) +instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) { instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; @@ -747,14 +744,14 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_restore(instproxy_client_t clie plist_dict_set_item(command, "ClientOptions", plist_copy(client_options)); plist_dict_set_item(command, "ApplicationIdentifier", plist_new_string(appid)); - res = instproxy_perform_command(client, command, INSTPROXY_COMMAND_TYPE_ASYNC, status_cb, user_data); + res = instproxy_perform_command(client, command, status_cb == NULL ? INSTPROXY_COMMAND_TYPE_SYNC : INSTPROXY_COMMAND_TYPE_ASYNC, status_cb, user_data); plist_free(command); return res; } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_remove_archive(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) +instproxy_error_t instproxy_remove_archive(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) { instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; @@ -764,14 +761,14 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_remove_archive(instproxy_client plist_dict_set_item(command, "ClientOptions", plist_copy(client_options)); plist_dict_set_item(command, "ApplicationIdentifier", plist_new_string(appid)); - res = instproxy_perform_command(client, command, INSTPROXY_COMMAND_TYPE_ASYNC, status_cb, user_data); + res = instproxy_perform_command(client, command, status_cb == NULL ? INSTPROXY_COMMAND_TYPE_SYNC : INSTPROXY_COMMAND_TYPE_ASYNC, status_cb, user_data); plist_free(command); return res; } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_check_capabilities_match(instproxy_client_t client, const char** capabilities, plist_t client_options, plist_t *result) +instproxy_error_t instproxy_check_capabilities_match(instproxy_client_t client, const char** capabilities, plist_t client_options, plist_t *result) { if (!client || !capabilities || !result) return INSTPROXY_E_INVALID_ARG; @@ -808,7 +805,7 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_check_capabilities_match(instpr return res; } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_status_get_error(plist_t status, char **name, char** description, uint64_t* code) +instproxy_error_t instproxy_status_get_error(plist_t status, char **name, char** description, uint64_t* code) { instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; @@ -846,7 +843,7 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_status_get_error(plist_t status return res; } -LIBIMOBILEDEVICE_API void instproxy_status_get_name(plist_t status, char **name) +void instproxy_status_get_name(plist_t status, char **name) { if (name) { plist_t node = plist_dict_get_item(status, "Status"); @@ -858,7 +855,7 @@ LIBIMOBILEDEVICE_API void instproxy_status_get_name(plist_t status, char **name) } } -LIBIMOBILEDEVICE_API void instproxy_status_get_percent_complete(plist_t status, int *percent) +void instproxy_status_get_percent_complete(plist_t status, int *percent) { uint64_t val = 0; if (percent) { @@ -870,7 +867,7 @@ LIBIMOBILEDEVICE_API void instproxy_status_get_percent_complete(plist_t status, } } -LIBIMOBILEDEVICE_API void instproxy_status_get_current_list(plist_t status, uint64_t* total, uint64_t* current_index, uint64_t* current_amount, plist_t* list) +void instproxy_status_get_current_list(plist_t status, uint64_t* total, uint64_t* current_index, uint64_t* current_amount, plist_t* list) { plist_t node = NULL; @@ -907,7 +904,7 @@ LIBIMOBILEDEVICE_API void instproxy_status_get_current_list(plist_t status, uint } } -LIBIMOBILEDEVICE_API void instproxy_command_get_name(plist_t command, char** name) +void instproxy_command_get_name(plist_t command, char** name) { if (name) { plist_t node = plist_dict_get_item(command, "Command"); @@ -919,12 +916,12 @@ LIBIMOBILEDEVICE_API void instproxy_command_get_name(plist_t command, char** nam } } -LIBIMOBILEDEVICE_API plist_t instproxy_client_options_new(void) +plist_t instproxy_client_options_new(void) { return plist_new_dict(); } -LIBIMOBILEDEVICE_API void instproxy_client_options_add(plist_t client_options, ...) +void instproxy_client_options_add(plist_t client_options, ...) { if (!client_options) return; @@ -937,7 +934,7 @@ LIBIMOBILEDEVICE_API void instproxy_client_options_add(plist_t client_options, . if (!strcmp(key, "SkipUninstall")) { int intval = va_arg(args, int); plist_dict_set_item(client_options, key, plist_new_bool(intval)); - } else if (!strcmp(key, "ApplicationSINF") || !strcmp(key, "iTunesMetadata") || !strcmp(key, "ReturnAttributes")) { + } else if (!strcmp(key, "ApplicationSINF") || !strcmp(key, "iTunesMetadata") || !strcmp(key, "ReturnAttributes") || !strcmp(key, "BundleIDs")) { plist_t plistval = va_arg(args, plist_t); if (!plistval) { free(key); @@ -958,7 +955,7 @@ LIBIMOBILEDEVICE_API void instproxy_client_options_add(plist_t client_options, . va_end(args); } -LIBIMOBILEDEVICE_API void instproxy_client_options_set_return_attributes(plist_t client_options, ...) +void instproxy_client_options_set_return_attributes(plist_t client_options, ...) { if (!client_options) return; @@ -979,16 +976,16 @@ LIBIMOBILEDEVICE_API void instproxy_client_options_set_return_attributes(plist_t plist_dict_set_item(client_options, "ReturnAttributes", return_attributes); } -LIBIMOBILEDEVICE_API void instproxy_client_options_free(plist_t client_options) +void instproxy_client_options_free(plist_t client_options) { if (client_options) { plist_free(client_options); } } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_client_get_path_for_bundle_identifier(instproxy_client_t client, const char* appid, char** path) +instproxy_error_t instproxy_client_get_path_for_bundle_identifier(instproxy_client_t client, const char* bundle_id, char** path) { - if (!client || !client->parent || !appid) + if (!client || !client->parent || !bundle_id) return INSTPROXY_E_INVALID_ARG; plist_t apps = NULL; @@ -1001,7 +998,7 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_client_get_path_for_bundle_iden instproxy_client_options_set_return_attributes(client_opts, "CFBundleIdentifier", "CFBundleExecutable", "Path", NULL); // only query for specific appid - const char* appids[] = {appid, NULL}; + const char* appids[] = {bundle_id, NULL}; // query device for list of apps instproxy_error_t ierr = instproxy_lookup(client, appids, client_opts, &apps); @@ -1012,7 +1009,7 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_client_get_path_for_bundle_iden return ierr; } - plist_t app_found = plist_access_path(apps, 1, appid); + plist_t app_found = plist_access_path(apps, 1, bundle_id); if (!app_found) { if (apps) plist_free(apps); diff --git a/src/installation_proxy.h b/src/installation_proxy.h index 033bdef..5bdbb71 100644 --- a/src/installation_proxy.h +++ b/src/installation_proxy.h @@ -23,6 +23,7 @@ #ifndef __INSTALLATION_PROXY_H #define __INSTALLATION_PROXY_H +#include "idevice.h" #include "libimobiledevice/installation_proxy.h" #include "property_list_service.h" #include <libimobiledevice-glue/thread.h> diff --git a/src/lockdown-cu.c b/src/lockdown-cu.c new file mode 100644 index 0000000..1afc2c5 --- /dev/null +++ b/src/lockdown-cu.c @@ -0,0 +1,1193 @@ +/* + * lockdown-cu.c + * com.apple.mobile.lockdownd service CU additions + * + * Copyright (c) 2021 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 + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include <stdlib.h> +#define _GNU_SOURCE 1 +#define __USE_GNU 1 +#include <stdio.h> +#include <ctype.h> +#include <unistd.h> +#include <plist/plist.h> + +#include "idevice.h" +#include "lockdown.h" +#include "common/debug.h" + +#ifdef HAVE_WIRELESS_PAIRING + +#include <libimobiledevice-glue/utils.h> +#include <libimobiledevice-glue/socket.h> +#include <libimobiledevice-glue/opack.h> +#include <libimobiledevice-glue/tlv.h> + +#if defined(HAVE_OPENSSL) +#include <openssl/hmac.h> +#include <openssl/evp.h> +#include <openssl/rand.h> +#if defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x2030200fL) +#include <openssl/chacha.h> +#include <openssl/poly1305.h> +#endif +#elif defined(HAVE_GCRYPT) +#include <gcrypt.h> +#elif defined(HAVE_MBEDTLS) +#include <mbedtls/md.h> +#include <mbedtls/chachapoly.h> +#endif + +#ifdef __APPLE__ +#include <sys/sysctl.h> +#include <SystemConfiguration/SystemConfiguration.h> +#include <CoreFoundation/CoreFoundation.h> +#include <TargetConditionals.h> +#endif + +#include "property_list_service.h" +#include "common/userpref.h" + +#include "endianness.h" + +#include "srp.h" +#include "ed25519.h" + +/* {{{ SRP6a parameters */ +static const unsigned char kSRPModulus3072[384] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34, + 0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74, + 0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd, + 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14, 0x37, + 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, + 0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x37, 0xed, 0x6b, 0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed, + 0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5, 0xae, 0x9f, 0x24, 0x11, 0x7c, 0x4b, 0x1f, 0xe6, + 0x49, 0x28, 0x66, 0x51, 0xec, 0xe4, 0x5b, 0x3d, 0xc2, 0x00, 0x7c, 0xb8, 0xa1, 0x63, 0xbf, 0x05, + 0x98, 0xda, 0x48, 0x36, 0x1c, 0x55, 0xd3, 0x9a, 0x69, 0x16, 0x3f, 0xa8, 0xfd, 0x24, 0xcf, 0x5f, + 0x83, 0x65, 0x5d, 0x23, 0xdc, 0xa3, 0xad, 0x96, 0x1c, 0x62, 0xf3, 0x56, 0x20, 0x85, 0x52, 0xbb, + 0x9e, 0xd5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6d, 0x67, 0x0c, 0x35, 0x4e, 0x4a, 0xbc, 0x98, 0x04, + 0xf1, 0x74, 0x6c, 0x08, 0xca, 0x18, 0x21, 0x7c, 0x32, 0x90, 0x5e, 0x46, 0x2e, 0x36, 0xce, 0x3b, + 0xe3, 0x9e, 0x77, 0x2c, 0x18, 0x0e, 0x86, 0x03, 0x9b, 0x27, 0x83, 0xa2, 0xec, 0x07, 0xa2, 0x8f, + 0xb5, 0xc5, 0x5d, 0xf0, 0x6f, 0x4c, 0x52, 0xc9, 0xde, 0x2b, 0xcb, 0xf6, 0x95, 0x58, 0x17, 0x18, + 0x39, 0x95, 0x49, 0x7c, 0xea, 0x95, 0x6a, 0xe5, 0x15, 0xd2, 0x26, 0x18, 0x98, 0xfa, 0x05, 0x10, + 0x15, 0x72, 0x8e, 0x5a, 0x8a, 0xaa, 0xc4, 0x2d, 0xad, 0x33, 0x17, 0x0d, 0x04, 0x50, 0x7a, 0x33, + 0xa8, 0x55, 0x21, 0xab, 0xdf, 0x1c, 0xba, 0x64, 0xec, 0xfb, 0x85, 0x04, 0x58, 0xdb, 0xef, 0x0a, + 0x8a, 0xea, 0x71, 0x57, 0x5d, 0x06, 0x0c, 0x7d, 0xb3, 0x97, 0x0f, 0x85, 0xa6, 0xe1, 0xe4, 0xc7, + 0xab, 0xf5, 0xae, 0x8c, 0xdb, 0x09, 0x33, 0xd7, 0x1e, 0x8c, 0x94, 0xe0, 0x4a, 0x25, 0x61, 0x9d, + 0xce, 0xe3, 0xd2, 0x26, 0x1a, 0xd2, 0xee, 0x6b, 0xf1, 0x2f, 0xfa, 0x06, 0xd9, 0x8a, 0x08, 0x64, + 0xd8, 0x76, 0x02, 0x73, 0x3e, 0xc8, 0x6a, 0x64, 0x52, 0x1f, 0x2b, 0x18, 0x17, 0x7b, 0x20, 0x0c, + 0xbb, 0xe1, 0x17, 0x57, 0x7a, 0x61, 0x5d, 0x6c, 0x77, 0x09, 0x88, 0xc0, 0xba, 0xd9, 0x46, 0xe2, + 0x08, 0xe2, 0x4f, 0xa0, 0x74, 0xe5, 0xab, 0x31, 0x43, 0xdb, 0x5b, 0xfc, 0xe0, 0xfd, 0x10, 0x8e, + 0x4b, 0x82, 0xd1, 0x20, 0xa9, 0x3a, 0xd2, 0xca, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + +static const unsigned char kSRPGenerator5 = 5; +/* }}} */ + +/* {{{ HKDF */ +#if defined(HAVE_OPENSSL) +#define MD_ALGO_SHA512 EVP_sha512() +typedef const EVP_MD* MD_ALGO_TYPE_T; +#define MD_ALGO_DIGEST_SIZE EVP_MD_size +#define MD_MAX_DIGEST_SIZE EVP_MAX_MD_SIZE + +#elif defined(HAVE_GCRYPT) +#define MD_ALGO_SHA512 GCRY_MD_SHA512 +typedef int MD_ALGO_TYPE_T; +#define MD_ALGO_DIGEST_SIZE gcry_md_get_algo_dlen +#define MD_MAX_DIGEST_SIZE 64 + +static void HMAC(MD_ALGO_TYPE_T md, unsigned char* key, unsigned int key_len, unsigned char* data, unsigned int data_len, unsigned char* out, unsigned int* out_len) +{ + gcry_md_hd_t hd; + if (gcry_md_open(&hd, md, GCRY_MD_FLAG_HMAC)) { + debug_info("gcry_md_open() failed"); + return; + } + if (gcry_md_setkey(hd, key, key_len)) { + gcry_md_close (hd); + debug_info("gcry_md_setkey() failed"); + return; + } + gcry_md_write(hd, data, data_len); + + unsigned char* digest = gcry_md_read(hd, md); + if (!digest) { + gcry_md_close(hd); + debug_info("gcry_md_read() failed"); + return; + } + + *out_len = gcry_md_get_algo_dlen(md); + memcpy(out, digest, *out_len); + gcry_md_close(hd); +} +#elif defined(HAVE_MBEDTLS) +#define MD_ALGO_SHA512 MBEDTLS_MD_SHA512 +typedef mbedtls_md_type_t MD_ALGO_TYPE_T; +#define MD_ALGO_DIGEST_SIZE(x) mbedtls_md_get_size(mbedtls_md_info_from_type(x)) +#define MD_MAX_DIGEST_SIZE MBEDTLS_MD_MAX_SIZE + +static void HMAC(MD_ALGO_TYPE_T md, unsigned char* key, unsigned int key_len, unsigned char* data, unsigned int data_len, unsigned char* out, unsigned int* out_len) +{ + mbedtls_md_context_t mdctx; + mbedtls_md_init(&mdctx); + int mr = mbedtls_md_setup(&mdctx, mbedtls_md_info_from_type(md), 1); + if (mr != 0) { + debug_info("mbedtls_md_setup() failed: %d", mr); + return; + } + + mr = mbedtls_md_hmac_starts(&mdctx, key, key_len); + if (mr != 0) { + mbedtls_md_free(&mdctx); + debug_info("mbedtls_md_hmac_starts() failed: %d", mr); + return; + } + + mbedtls_md_hmac_update(&mdctx, data, data_len); + + mr = mbedtls_md_hmac_finish(&mdctx, out); + if (mr == 0) { + *out_len = mbedtls_md_get_size(mbedtls_md_info_from_type(md)); + } else { + debug_info("mbedtls_md_hmac_finish() failed: %d", mr); + } + mbedtls_md_free(&mdctx); +} +#endif + +static void hkdf_md_extract(MD_ALGO_TYPE_T md, unsigned char* salt, unsigned int salt_len, unsigned char* input_key_material, unsigned int input_key_material_len, unsigned char* out, unsigned int* out_len) +{ + unsigned char empty_salt[MD_MAX_DIGEST_SIZE]; + if (!md || !out || !out_len || !*out_len) return; + if (salt_len == 0) { + salt_len = MD_ALGO_DIGEST_SIZE(md); + salt = (unsigned char*)empty_salt; + } + HMAC(md, salt, salt_len, input_key_material, input_key_material_len, out, out_len); +} + +static void hkdf_md_expand(MD_ALGO_TYPE_T md, unsigned char* prk, unsigned int prk_len, unsigned char* info, unsigned int info_len, unsigned char* out, unsigned int* out_len) +{ + if (!md || !out || !out_len || !*out_len) return; + unsigned int md_size = MD_ALGO_DIGEST_SIZE(md); + if (*out_len > 255 * md_size) { + *out_len = 0; + return; + } + int blocks_needed = (*out_len) / md_size; + if (((*out_len) % md_size) != 0) blocks_needed++; + unsigned int okm_len = 0; + unsigned char okm_block[MD_MAX_DIGEST_SIZE]; + unsigned int okm_block_len = 0; + int i; + for (i = 0; i < blocks_needed; i++) { + unsigned int output_block_len = okm_block_len + info_len + 1; + unsigned char* output_block = malloc(output_block_len); + if (okm_block_len > 0) { + memcpy(output_block, okm_block, okm_block_len); + } + memcpy(output_block + okm_block_len, info, info_len); + output_block[okm_block_len + info_len] = (uint8_t)(i+1); + + HMAC(md, prk, prk_len, output_block, output_block_len, okm_block, &okm_block_len); + if (okm_len < *out_len) { + memcpy(out + okm_len, okm_block, (okm_len + okm_block_len > *out_len) ? *out_len - okm_len : okm_block_len); + } + okm_len += okm_block_len; + free(output_block); + } +} + +static void hkdf_md(MD_ALGO_TYPE_T md, unsigned char* salt, unsigned int salt_len, unsigned char* info, unsigned int info_len, unsigned char* initial_key_material, unsigned int initial_key_material_size, unsigned char* out, unsigned int *out_len) +{ + if (!md || !initial_key_material || !out || !out_len || !*out_len) return; + + unsigned char prk[MD_MAX_DIGEST_SIZE]; + unsigned int prk_len = MD_ALGO_DIGEST_SIZE(md); + + hkdf_md_extract(md, salt, salt_len, initial_key_material, initial_key_material_size, prk, &prk_len); + if (prk_len > 0) { + hkdf_md_expand(md, prk, prk_len, info, info_len, out, out_len); + } else { + *out_len = 0; + } +} +/* }}} */ + +/* {{{ chacha20 poly1305 encryption/decryption */ +#if defined(HAVE_OPENSSL) && defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x2030200fL) +/* {{{ From: OpenBSD's e_chacha20poly1305.c */ +/* + * Copyright (c) 2015 Reyk Floter <reyk@openbsd.org> + * Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +static void +poly1305_update_with_length(poly1305_state *poly1305, + const unsigned char *data, size_t data_len) +{ + size_t j = data_len; + unsigned char length_bytes[8]; + unsigned i; + + for (i = 0; i < sizeof(length_bytes); i++) { + length_bytes[i] = j; + j >>= 8; + } + + if (data != NULL) + CRYPTO_poly1305_update(poly1305, data, data_len); + CRYPTO_poly1305_update(poly1305, length_bytes, sizeof(length_bytes)); +} + +static void +poly1305_update_with_pad16(poly1305_state *poly1305, + const unsigned char *data, size_t data_len) +{ + static const unsigned char zero_pad16[16]; + size_t pad_len; + + CRYPTO_poly1305_update(poly1305, data, data_len); + + /* pad16() is defined in RFC 7539 2.8.1. */ + if ((pad_len = data_len % 16) == 0) + return; + + CRYPTO_poly1305_update(poly1305, zero_pad16, 16 - pad_len); +} +/* }}} */ +#endif + +static void chacha20_poly1305_encrypt_96(unsigned char* key, unsigned char* nonce, unsigned char* ad, size_t ad_len, unsigned char* in, size_t in_len, unsigned char* out, size_t* out_len) +{ +#if defined(HAVE_OPENSSL) +#if defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x3050000fL) +#if (LIBRESSL_VERSION_NUMBER >= 0x2040000fL) + const EVP_AEAD *aead = EVP_aead_chacha20_poly1305(); + EVP_AEAD_CTX ctx; + EVP_AEAD_CTX_init(&ctx, aead, key, EVP_AEAD_key_length(aead), EVP_AEAD_DEFAULT_TAG_LENGTH, NULL); + EVP_AEAD_CTX_seal(&ctx, out, out_len, *out_len, nonce, 12, in, in_len, ad, ad_len); +#else + unsigned char poly1305_key[32]; + poly1305_state poly1305; + uint64_t ctr = (uint64_t)(nonce[0] | nonce[1] << 8 | nonce[2] << 16 | nonce[3] << 24) << 32; + const unsigned char* iv = nonce + 4; + + memset(poly1305_key, 0, sizeof(poly1305_key)); + CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key), key, iv, ctr); + + CRYPTO_poly1305_init(&poly1305, poly1305_key); + poly1305_update_with_pad16(&poly1305, ad, ad_len); + CRYPTO_chacha_20(out, in, in_len, key, iv, ctr + 1); + poly1305_update_with_pad16(&poly1305, out, in_len); + poly1305_update_with_length(&poly1305, NULL, ad_len); + poly1305_update_with_length(&poly1305, NULL, in_len); + + CRYPTO_poly1305_finish(&poly1305, out + in_len); + + *out_len = in_len + 16; +#endif +#elif defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x10100000L) + int outl = 0; + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), NULL, key, nonce); + EVP_EncryptUpdate(ctx, out, &outl, in, in_len); + *out_len = outl; + outl = 0; + EVP_EncryptFinal_ex(ctx, out + *out_len, &outl); + *out_len += outl; + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, out + *out_len); + EVP_CIPHER_CTX_free(ctx); + *out_len += 16; +#else +#error Please use a newer version of OpenSSL (>= 1.1.0) +#endif +#elif defined(HAVE_GCRYPT) +#if defined(GCRYPT_VERSION_NUMBER) && (GCRYPT_VERSION_NUMBER >= 0x010700) + gcry_cipher_hd_t hd; + if (gcry_cipher_open(&hd, GCRY_CIPHER_CHACHA20, GCRY_CIPHER_MODE_POLY1305, 0)) { + debug_info("gcry_cipher_open() failed"); + return; + } + gcry_cipher_setkey(hd, key, 32); + gcry_cipher_setiv(hd, nonce, 12); + gcry_cipher_authenticate(hd, ad, ad_len); + *out_len = in_len + 16; + if (gcry_cipher_encrypt(hd, out, *out_len, in, in_len)) { + *out_len = 0; + } + gcry_cipher_gettag(hd, out+in_len, 16); + gcry_cipher_close(hd); +#else +#error Please use a newer version of libgcrypt (>= 1.7.0) +#endif +#elif defined (HAVE_MBEDTLS) + mbedtls_chachapoly_context ctx; + mbedtls_chachapoly_init(&ctx); + mbedtls_chachapoly_setkey(&ctx, key); + if (mbedtls_chachapoly_encrypt_and_tag(&ctx, in_len, nonce, ad, ad_len, in, out, out+in_len) != 0) { + *out_len = 0; + } + mbedtls_chachapoly_free(&ctx); +#else +#error chacha20_poly1305_encrypt_96 is not implemented +#endif +} + +static void chacha20_poly1305_encrypt_64(unsigned char* key, unsigned char* nonce, unsigned char* ad, size_t ad_len, unsigned char* in, size_t in_len, unsigned char* out, size_t* out_len) +{ + unsigned char _nonce[12]; + *(uint32_t*)(&_nonce[0]) = 0; + memcpy(&_nonce[4], nonce, 8); + chacha20_poly1305_encrypt_96(key, _nonce, ad, ad_len, in, in_len, out, out_len); +} + +static void chacha20_poly1305_decrypt_96(unsigned char* key, unsigned char* nonce, unsigned char* ad, size_t ad_len, unsigned char* in, size_t in_len, unsigned char* out, size_t* out_len) +{ +#if defined(HAVE_OPENSSL) +#if defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x3050000fL) +#if (LIBRESSL_VERSION_NUMBER >= 0x2040000fL) + const EVP_AEAD *aead = EVP_aead_chacha20_poly1305(); + EVP_AEAD_CTX ctx; + EVP_AEAD_CTX_init(&ctx, aead, key, EVP_AEAD_key_length(aead), EVP_AEAD_DEFAULT_TAG_LENGTH, NULL); + EVP_AEAD_CTX_open(&ctx, out, out_len, *out_len, nonce, 12, in, in_len, ad, ad_len); +#else + unsigned char mac[16]; + unsigned char poly1305_key[32]; + poly1305_state poly1305; + size_t plaintext_len = in_len - 16; + uint64_t ctr = (uint64_t)(nonce[0] | nonce[1] << 8 | nonce[2] << 16 | nonce[3] << 24) << 32; + const unsigned char *iv = nonce + 4; + + memset(poly1305_key, 0, sizeof(poly1305_key)); + CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key), key, iv, ctr); + + CRYPTO_poly1305_init(&poly1305, poly1305_key); + poly1305_update_with_pad16(&poly1305, ad, ad_len); + poly1305_update_with_pad16(&poly1305, in, plaintext_len); + poly1305_update_with_length(&poly1305, NULL, ad_len); + poly1305_update_with_length(&poly1305, NULL, plaintext_len); + + CRYPTO_poly1305_finish(&poly1305, mac); + + if (memcmp(mac, in + plaintext_len, 16) != 0) { + *out_len = 0; + return; + } + + CRYPTO_chacha_20(out, in, plaintext_len, key, iv, ctr + 1); + *out_len = plaintext_len; +#endif +#elif defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x10100000L) + int outl = 0; + size_t plaintext_len = in_len - 16; + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + EVP_DecryptInit_ex(ctx, EVP_chacha20_poly1305(), NULL, key, nonce); + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, in + plaintext_len); + EVP_DecryptUpdate(ctx, out, &outl, in, plaintext_len); + *out_len = outl; + outl = 0; + if (EVP_DecryptFinal_ex(ctx, out + *out_len, &outl) == 1) { + *out_len += outl; + } else { + *out_len = 0; + } + EVP_CIPHER_CTX_free(ctx); +#else +#error Please use a newer version of OpenSSL (>= 1.1.0) +#endif +#elif defined(HAVE_GCRYPT) +#if defined(GCRYPT_VERSION_NUMBER) && (GCRYPT_VERSION_NUMBER >= 0x010700) + gcry_cipher_hd_t hd; + if (gcry_cipher_open(&hd, GCRY_CIPHER_CHACHA20, GCRY_CIPHER_MODE_POLY1305, 0)) { + debug_info("gcry_cipher_open() failed"); + return; + } + gcry_cipher_setkey(hd, key, 32); + gcry_cipher_setiv(hd, nonce, 12); + gcry_cipher_authenticate(hd, ad, ad_len); + unsigned int plaintext_len = in_len - 16; + gcry_cipher_decrypt(hd, out, *out_len, in, plaintext_len); + if (gcry_cipher_checktag(hd, in + plaintext_len, 16) == 0) { + *out_len = plaintext_len; + } else { + *out_len = 0; + } + gcry_cipher_close(hd); +#else +#error Please use a newer version of libgcrypt (>= 1.7.0) +#endif +#elif defined(HAVE_MBEDTLS) + mbedtls_chachapoly_context ctx; + mbedtls_chachapoly_init(&ctx); + mbedtls_chachapoly_setkey(&ctx, key); + unsigned int plaintext_len = in_len - 16; + if (mbedtls_chachapoly_auth_decrypt(&ctx, plaintext_len, nonce, ad, ad_len, in + plaintext_len, in, out) == 0) { + *out_len = plaintext_len; + } else { + *out_len = 0; + } + mbedtls_chachapoly_free(&ctx); +#else +#error chacha20_poly1305_decrypt_96 is not implemented +#endif +} + +static void chacha20_poly1305_decrypt_64(unsigned char* key, unsigned char* nonce, unsigned char* ad, size_t ad_len, unsigned char* in, size_t in_len, unsigned char* out, size_t* out_len) +{ + unsigned char _nonce[12]; + *(uint32_t*)(&_nonce[0]) = 0; + memcpy(&_nonce[4], nonce, 8); + chacha20_poly1305_decrypt_96(key, _nonce, ad, ad_len, in, in_len, out, out_len); +} +/* }}} */ + +#define PAIRING_ERROR(x) \ + debug_info(x); \ + if (pairing_callback) { \ + pairing_callback(LOCKDOWN_CU_PAIRING_ERROR, cb_user_data, (char*)x, NULL); \ + } + +#define PAIRING_ERROR_FMT(...) \ + sprintf(tmp, __VA_ARGS__); \ + debug_info(tmp); \ + if (pairing_callback) { \ + pairing_callback(LOCKDOWN_CU_PAIRING_ERROR, cb_user_data, tmp, NULL); \ + } + +#endif /* HAVE_WIRELESS_PAIRING */ + +lockdownd_error_t lockdownd_cu_pairing_create(lockdownd_client_t client, lockdownd_cu_pairing_cb_t pairing_callback, void* cb_user_data, plist_t host_info, plist_t acl) +{ +#ifdef HAVE_WIRELESS_PAIRING + if (!client || !pairing_callback || (host_info && plist_get_node_type(host_info) != PLIST_DICT) || (acl && plist_get_node_type(acl) != PLIST_DICT)) + return LOCKDOWN_E_INVALID_ARG; + + lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; + + if (client->device && client->device->version == 0) { + plist_t p_version = NULL; + if (lockdownd_get_value(client, NULL, "ProductVersion", &p_version) == LOCKDOWN_E_SUCCESS) { + int vers[3] = {0, 0, 0}; + char *s_version = NULL; + plist_get_string_val(p_version, &s_version); + if (s_version && sscanf(s_version, "%d.%d.%d", &vers[0], &vers[1], &vers[2]) >= 2) { + client->device->version = DEVICE_VERSION(vers[0], vers[1], vers[2]); + } + free(s_version); + } + plist_free(p_version); + } + + char* pairing_uuid = NULL; + if (host_info) { + plist_t accountid = plist_dict_get_item(host_info, "accountID"); + if (accountid && plist_get_node_type(accountid) == PLIST_STRING) { + plist_get_string_val(accountid, &pairing_uuid); + } + } + if (!pairing_uuid) { + userpref_read_system_buid(&pairing_uuid); + } + if (!pairing_uuid) { + pairing_uuid = generate_uuid(); + } + unsigned int pairing_uuid_len = strlen(pairing_uuid); + + SRP_initialize_library(); + + SRP* srp = SRP_new(SRP6a_sha512_client_method()); + if (!srp) { + PAIRING_ERROR("Failed to initialize SRP") + return LOCKDOWN_E_UNKNOWN_ERROR; + } + + char tmp[256]; + plist_t dict = NULL; + uint8_t current_state = 0; + uint8_t final_state = 6; + + unsigned char* salt = NULL; + unsigned int salt_size = 0; + unsigned char* pubkey = NULL; + unsigned int pubkey_size = 0; + + unsigned char setup_encryption_key[32]; + + cstr *thekey = NULL; + + do { + current_state++; + + dict = plist_new_dict(); + plist_dict_set_item(dict, "Request", plist_new_string("CUPairingCreate")); + if (current_state == 1) { + plist_dict_set_item(dict, "Flags", plist_new_uint(1)); + } else { + plist_dict_set_item(dict, "Flags", plist_new_uint(0)); + } + + tlv_buf_t tlv = tlv_buf_new(); + + if (current_state == 1) { + /* send method */ + tlv_buf_append(tlv, 0x00, 1, (void*)"\x00"); // 0x00 (Method), 1 bytes, 00 + } else if (current_state == 3) { + /* generate public key */ + cstr* own_pub = NULL; + SRP_gen_pub(srp, &own_pub); + + if (!own_pub) { + PAIRING_ERROR("[SRP] Failed to generate public key") + ret = LOCKDOWN_E_PAIRING_FAILED; + break; + } + + /* compute key from remote's public key */ + if (SRP_compute_key(srp, &thekey, pubkey, pubkey_size) != 0) { + cstr_free(own_pub); + PAIRING_ERROR("[SRP] Failed to compute key") + ret = LOCKDOWN_E_PAIRING_FAILED; + break; + } + + /* compute response */ + cstr *response = NULL; + SRP_respond(srp, &response); + + /* send our public key + response */ + tlv_buf_append(tlv, 0x03, own_pub->length, own_pub->data); + tlv_buf_append(tlv, 0x04, response->length, response->data); + cstr_free(response); + cstr_free(own_pub); + } else if (current_state == 5) { + /* send encrypted info */ + + static const char PAIR_SETUP_ENCRYPT_SALT[] = "Pair-Setup-Encrypt-Salt"; + static const char PAIR_SETUP_ENCRYPT_INFO[] = "Pair-Setup-Encrypt-Info"; + static const char PAIR_SETUP_CONTROLLER_SIGN_SALT[] = "Pair-Setup-Controller-Sign-Salt"; + static const char PAIR_SETUP_CONTROLLER_SIGN_INFO[] = "Pair-Setup-Controller-Sign-Info"; + + // HKDF with above computed key (SRP_compute_key) + Pair-Setup-Encrypt-Salt + Pair-Setup-Encrypt-Info + // result used as key for chacha20-poly1305 + unsigned int setup_encryption_key_len = sizeof(setup_encryption_key); + hkdf_md(MD_ALGO_SHA512, (unsigned char*)PAIR_SETUP_ENCRYPT_SALT, sizeof(PAIR_SETUP_ENCRYPT_SALT)-1, (unsigned char*)PAIR_SETUP_ENCRYPT_INFO, sizeof(PAIR_SETUP_ENCRYPT_INFO)-1, (unsigned char*)thekey->data, thekey->length, setup_encryption_key, &setup_encryption_key_len); + + unsigned char ed25519_pubkey[32]; + unsigned char ed25519_privkey[64]; + unsigned char ed25519seed[32]; + ed25519_create_seed(ed25519seed); + + ed25519_create_keypair(ed25519_pubkey, ed25519_privkey, ed25519seed); + + unsigned int signbuf_len = pairing_uuid_len + 64; + unsigned char* signbuf = malloc(signbuf_len); + unsigned int hkdf_len = 32; + // HKDF with above computed key (SRP_compute_key) + Pair-Setup-Controller-Sign-Salt + Pair-Setup-Controller-Sign-Info + hkdf_md(MD_ALGO_SHA512, (unsigned char*)PAIR_SETUP_CONTROLLER_SIGN_SALT, sizeof(PAIR_SETUP_CONTROLLER_SIGN_SALT)-1, (unsigned char*)PAIR_SETUP_CONTROLLER_SIGN_INFO, sizeof(PAIR_SETUP_CONTROLLER_SIGN_INFO)-1, (unsigned char*)thekey->data, thekey->length, signbuf, &hkdf_len); + + memcpy(signbuf + 32, pairing_uuid, pairing_uuid_len); + memcpy(signbuf + 32 + pairing_uuid_len, ed25519_pubkey, 32); + + unsigned char ed_sig[64]; + ed25519_sign(ed_sig, signbuf, 0x64, ed25519_pubkey, ed25519_privkey); + + tlv_buf_t tlvbuf = tlv_buf_new(); + tlv_buf_append(tlvbuf, 0x01, pairing_uuid_len, (void*)pairing_uuid); + tlv_buf_append(tlvbuf, 0x03, sizeof(ed25519_pubkey), ed25519_pubkey); + tlv_buf_append(tlvbuf, 0x0a, sizeof(ed_sig), ed_sig); + + /* ACL */ + unsigned char* odata = NULL; + unsigned int olen = 0; + if (acl) { + opack_encode_from_plist(acl, &odata, &olen); + } else { + /* defaut ACL */ + plist_t acl_plist = plist_new_dict(); + plist_dict_set_item(acl_plist, "com.apple.ScreenCapture", plist_new_bool(1)); + plist_dict_set_item(acl_plist, "com.apple.developer", plist_new_bool(1)); + opack_encode_from_plist(acl_plist, &odata, &olen); + plist_free(acl_plist); + } + tlv_buf_append(tlvbuf, 0x12, olen, odata); + free(odata); + + /* HOST INFORMATION */ + char hostname[256]; +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) + CFStringRef cname = SCDynamicStoreCopyComputerName(NULL, NULL); + CFStringGetCString(cname, hostname, sizeof(hostname), kCFStringEncodingUTF8); + CFRelease(cname); +#else +#ifdef WIN32 + DWORD hostname_len = sizeof(hostname); + GetComputerName(hostname, &hostname_len); +#else + gethostname(hostname, sizeof(hostname)); +#endif +#endif + + char modelname[256]; + modelname[0] = '\0'; +#ifdef __APPLE__ + size_t len = sizeof(modelname); + sysctlbyname("hw.model", &modelname, &len, NULL, 0); +#endif + if (strlen(modelname) == 0) { + strcpy(modelname, "HackbookPro13,37"); + } + + unsigned char primary_mac_addr[6] = { 0, 0, 0, 0, 0, 0 }; + if (get_primary_mac_address(primary_mac_addr) != 0) { + debug_info("Failed to get primary mac address"); + } + debug_info("Primary mac address: %02x:%02x:%02x:%02x:%02x:%02x\n", primary_mac_addr[0], primary_mac_addr[1], primary_mac_addr[2], primary_mac_addr[3], primary_mac_addr[4], primary_mac_addr[5]); + + // "OPACK" encoded device info + plist_t info_plist = plist_new_dict(); + //plist_dict_set_item(info_plist, "altIRK", plist_new_data((char*)altIRK, 16)); + plist_dict_set_item(info_plist, "accountID", plist_new_string(pairing_uuid)); + plist_dict_set_item(info_plist, "model", plist_new_string(modelname)); + plist_dict_set_item(info_plist, "name", plist_new_string(hostname)); + plist_dict_set_item(info_plist, "mac", plist_new_data((char*)primary_mac_addr, 6)); + if (host_info) { + plist_dict_merge(&info_plist, host_info); + } + opack_encode_from_plist(info_plist, &odata, &olen); + plist_free(info_plist); + tlv_buf_append(tlvbuf, 0x11, olen, odata); + free(odata); + + size_t encrypted_len = tlvbuf->length + 16; + unsigned char* encrypted_buf = (unsigned char*)malloc(encrypted_len); + + chacha20_poly1305_encrypt_64(setup_encryption_key, (unsigned char*)"PS-Msg05", NULL, 0, tlvbuf->data, tlvbuf->length, encrypted_buf, &encrypted_len); + + tlv_buf_free(tlvbuf); + + tlv_buf_append(tlv, 0x05, encrypted_len, encrypted_buf); + free(encrypted_buf); + } else { + tlv_buf_free(tlv); + PAIRING_ERROR("[SRP] Invalid state"); + ret = LOCKDOWN_E_PAIRING_FAILED; + break; + } + tlv_buf_append(tlv, 0x06, 1, ¤t_state); + plist_dict_set_item(dict, "Payload", plist_new_data((char*)tlv->data, tlv->length)); + tlv_buf_free(tlv); + + plist_dict_set_item(dict, "Label", plist_new_string(client->label)); + plist_dict_set_item(dict, "ProtocolVersion", plist_new_uint(2)); + + ret = lockdownd_send(client, dict); + plist_free(dict); + dict = NULL; + + if (ret != LOCKDOWN_E_SUCCESS) { + break; + } + + current_state++; + + ret = lockdownd_receive(client, &dict); + if (ret != LOCKDOWN_E_SUCCESS) { + break; + } + ret = lockdown_check_result(dict, "CUPairingCreate"); + if (ret != LOCKDOWN_E_SUCCESS) { + break; + } + + plist_t extresp = plist_dict_get_item(dict, "ExtendedResponse"); + if (!extresp) { + ret = LOCKDOWN_E_PLIST_ERROR; + break; + } + plist_t blob = plist_dict_get_item(extresp, "Payload"); + if (!blob) { + ret = LOCKDOWN_E_PLIST_ERROR; + break; + } + uint64_t data_len = 0; + const char* data = plist_get_data_ptr(blob, &data_len); + + uint8_t state = 0; + if (!tlv_data_get_uint8(data, data_len, 0x06, &state)) { + PAIRING_ERROR("[SRP] ERROR: Could not find state in response"); + ret = LOCKDOWN_E_PAIRING_FAILED; + break; + } + if (state != current_state) { + PAIRING_ERROR_FMT("[SRP] ERROR: Unexpected state %d, expected %d", state, current_state); + ret = LOCKDOWN_E_PAIRING_FAILED; + break; + } + + unsigned int errval = 0; + uint64_t u64val = 0; + tlv_data_get_uint(data, data_len, 0x07, &u64val); +debug_buffer(data, data_len); + errval = (unsigned int)u64val; + if (errval > 0) { + if (errval == 3) { + u64val = 0; + tlv_data_get_uint(data, data_len, 0x08, &u64val); + if (u64val > 0) { + uint32_t retry_delay = (uint32_t)u64val; + PAIRING_ERROR_FMT("[SRP] Pairing is blocked for another %u seconds", retry_delay) + ret = LOCKDOWN_E_PAIRING_FAILED; + break; + } + } else if (errval == 2 && state == 4) { + PAIRING_ERROR_FMT("[SRP] Invalid PIN") + ret = LOCKDOWN_E_PAIRING_FAILED; + break; + } else { + PAIRING_ERROR_FMT("[SRP] Received error %u in state %d.", errval, state); + ret = LOCKDOWN_E_PAIRING_FAILED; + break; + } + } + + if (state == 2) { + /* receive salt and public key */ + if (!tlv_data_copy_data(data, data_len, 0x02, (void**)&salt, &salt_size)) { + PAIRING_ERROR("[SRP] ERROR: Could not find salt in response"); + ret = LOCKDOWN_E_PAIRING_FAILED; + break; + } + if (!tlv_data_copy_data(data, data_len, 0x03, (void**)&pubkey, &pubkey_size)) { + PAIRING_ERROR("[SRP] ERROR: Could not find public key in response"); + + ret = LOCKDOWN_E_PAIRING_FAILED; + break; + } + + const char PAIR_SETUP[] = "Pair-Setup"; + if (SRP_set_user_raw(srp, (const unsigned char*)PAIR_SETUP, sizeof(PAIR_SETUP)-1) != 0) { + PAIRING_ERROR("[SRP] Failed to set SRP user"); + ret = LOCKDOWN_E_PAIRING_FAILED; + break; + } + + /* kSRPParameters_3072_SHA512 */ + if (SRP_set_params(srp, kSRPModulus3072, sizeof(kSRPModulus3072), &kSRPGenerator5, 1, salt, salt_size) != 0) { + PAIRING_ERROR("[SRP] Failed to set SRP parameters"); + ret = LOCKDOWN_E_PAIRING_FAILED; + break; + + } + + if (pairing_callback) { + char pin[64]; + unsigned int pin_len = sizeof(pin); + pairing_callback(LOCKDOWN_CU_PAIRING_PIN_REQUESTED, cb_user_data, pin, &pin_len); + + SRP_set_auth_password_raw(srp, (const unsigned char*)pin, pin_len); + } + } else if (state == 4) { + /* receive proof */ + unsigned char* proof = NULL; + unsigned int proof_len = 0; + + if (!tlv_data_copy_data(data, data_len, 0x04, (void**)&proof, &proof_len)) { + PAIRING_ERROR("[SRP] ERROR: Could not find proof data in response"); + ret = LOCKDOWN_E_PAIRING_FAILED; + break; + } + + /* verify */ + int vrfy_result = SRP_verify(srp, proof, proof_len); + free(proof); + + if (vrfy_result == 0) { + debug_info("[SRP] PIN verified successfully"); + } else { + PAIRING_ERROR("[SRP] PIN verification failure"); + ret = LOCKDOWN_E_PAIRING_FAILED; + break; + } + + } else if (state == 6) { + int srp_pair_success = 0; + plist_t node = plist_dict_get_item(extresp, "doSRPPair"); + if (node) { + const char* strv = plist_get_string_ptr(node, NULL); + if (strcmp(strv, "succeed") == 0) { + srp_pair_success = 1; + } + } + if (!srp_pair_success) { + PAIRING_ERROR("SRP Pairing failed"); + ret = LOCKDOWN_E_PAIRING_FAILED; + break; + } + + /* receive encrypted info */ + unsigned char* encrypted_buf = NULL; + unsigned int enc_len = 0; + if (!tlv_data_copy_data(data, data_len, 0x05, (void**)&encrypted_buf, &enc_len)) { + PAIRING_ERROR("[SRP] ERROR: Could not find encrypted data in response"); + ret = LOCKDOWN_E_PAIRING_FAILED; + break; + } + size_t plain_len = enc_len-16; + unsigned char* plain_buf = malloc(plain_len); + chacha20_poly1305_decrypt_64(setup_encryption_key, (unsigned char*)"PS-Msg06", NULL, 0, encrypted_buf, enc_len, plain_buf, &plain_len); + free(encrypted_buf); + + unsigned char* dev_info = NULL; + unsigned int dev_info_len = 0; + int res = tlv_data_copy_data(plain_buf, plain_len, 0x11, (void**)&dev_info, &dev_info_len); + free(plain_buf); + if (!res) { + PAIRING_ERROR("[SRP] ERROR: Failed to locate device info in response"); + ret = LOCKDOWN_E_PAIRING_FAILED; + break; + } + plist_t device_info = NULL; + opack_decode_to_plist(dev_info, dev_info_len, &device_info); + free(dev_info); + + if (!device_info) { + PAIRING_ERROR("[SRP] ERROR: Failed to parse device info"); + ret = LOCKDOWN_E_PAIRING_FAILED; + break; + } + + if (pairing_callback) { + pairing_callback(LOCKDOWN_CU_PAIRING_DEVICE_INFO, cb_user_data, device_info, NULL); + } + plist_free(device_info); + } else { + PAIRING_ERROR("[SRP] ERROR: Invalid state"); + ret = LOCKDOWN_E_PAIRING_FAILED; + break; + } + plist_free(dict); + dict = NULL; + + } while (current_state != final_state); + + plist_free(dict); + + free(salt); + free(pubkey); + + SRP_free(srp); + srp = NULL; + + if (ret != LOCKDOWN_E_SUCCESS) { + if (thekey) { + cstr_free(thekey); + } + return ret; + } + + free(client->cu_key); + client->cu_key = malloc(thekey->length); + memcpy(client->cu_key, thekey->data, thekey->length); + client->cu_key_len = thekey->length; + cstr_free(thekey); + + return LOCKDOWN_E_SUCCESS; +#else + debug_info("not supported"); + return LOCKDOWN_E_UNKNOWN_ERROR; +#endif +} + +lockdownd_error_t lockdownd_cu_send_request_and_get_reply(lockdownd_client_t client, const char* request, plist_t request_payload, plist_t* reply) +{ +#ifdef HAVE_WIRELESS_PAIRING + if (!client || !request) + return LOCKDOWN_E_INVALID_ARG; + + if (!client->cu_key) + return LOCKDOWN_E_NO_RUNNING_SESSION; + + lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; + + /* derive keys */ + unsigned char cu_write_key[32]; + unsigned int cu_write_key_len = sizeof(cu_write_key); + static const char WRITE_KEY_SALT_MDLD[] = "WriteKeySaltMDLD"; + static const char WRITE_KEY_INFO_MDLD[] = "WriteKeyInfoMDLD"; + hkdf_md(MD_ALGO_SHA512, (unsigned char*)WRITE_KEY_SALT_MDLD, sizeof(WRITE_KEY_SALT_MDLD)-1, (unsigned char*)WRITE_KEY_INFO_MDLD, sizeof(WRITE_KEY_INFO_MDLD)-1, client->cu_key, client->cu_key_len, cu_write_key, &cu_write_key_len); + + unsigned char cu_read_key[32]; + unsigned int cu_read_key_len = sizeof(cu_write_key); + static const char READ_KEY_SALT_MDLD[] = "ReadKeySaltMDLD"; + static const char READ_KEY_INFO_MDLD[] = "ReadKeyInfoMDLD"; + hkdf_md(MD_ALGO_SHA512, (unsigned char*)READ_KEY_SALT_MDLD, sizeof(READ_KEY_SALT_MDLD)-1, (unsigned char*)READ_KEY_INFO_MDLD, sizeof(READ_KEY_INFO_MDLD)-1, client->cu_key, client->cu_key_len, cu_read_key, &cu_read_key_len); + + // Starting with iOS/tvOS 11.2 and WatchOS 4.2, this nonce is random and sent along with the request. Before, the request doesn't have a nonce and it uses hardcoded nonce "sendone01234". + unsigned char cu_nonce[12] = "sendone01234"; // guaranteed to be random by fair dice troll + if (client->device->version >= DEVICE_VERSION(11,2,0)) { +#if defined(HAVE_OPENSSL) + RAND_bytes(cu_nonce, sizeof(cu_nonce)); +#elif defined(HAVE_GCRYPT) + gcry_create_nonce(cu_nonce, sizeof(cu_nonce)); +#endif + } + + debug_plist(request_payload); + + /* convert request payload to binary */ + uint32_t bin_len = 0; + char* bin = NULL; + plist_to_bin(request_payload, &bin, &bin_len); + + /* encrypt request */ + size_t encrypted_len = bin_len + 16; + unsigned char* encrypted_buf = malloc(encrypted_len); + chacha20_poly1305_encrypt_96(cu_write_key, cu_nonce, NULL, 0, (unsigned char*)bin, bin_len, encrypted_buf, &encrypted_len); + free(bin); + bin = NULL; + + plist_t dict = plist_new_dict(); + plist_dict_set_item(dict,"Request", plist_new_string(request)); + plist_dict_set_item(dict, "Payload", plist_new_data((char*)encrypted_buf, encrypted_len)); + free(encrypted_buf); + plist_dict_set_item(dict, "Nonce", plist_new_data((char*)cu_nonce, sizeof(cu_nonce))); + plist_dict_set_item(dict, "Label", plist_new_string(client->label)); + plist_dict_set_item(dict, "ProtocolVersion", plist_new_uint(2)); + + /* send to device */ + ret = lockdownd_send(client, dict); + plist_free(dict); + dict = NULL; + + if (ret != LOCKDOWN_E_SUCCESS) + return ret; + + /* Now get device's answer */ + ret = lockdownd_receive(client, &dict); + if (ret != LOCKDOWN_E_SUCCESS) + return ret; + + ret = lockdown_check_result(dict, request); + if (ret != LOCKDOWN_E_SUCCESS) { + plist_free(dict); + return ret; + } + + /* get payload */ + plist_t blob = plist_dict_get_item(dict, "Payload"); + if (!blob) { + plist_free(dict); + return LOCKDOWN_E_DICT_ERROR; + } + + uint64_t dl = 0; + const char* dt = plist_get_data_ptr(blob, &dl); + + /* see if we have a nonce */ + blob = plist_dict_get_item(dict, "Nonce"); + const unsigned char* rnonce = (unsigned char*)"receiveone01"; + if (blob) { + uint64_t rl = 0; + rnonce = (const unsigned char*)plist_get_data_ptr(blob, &rl); + } + + /* decrypt payload */ + size_t decrypted_len = dl-16; + unsigned char* decrypted = malloc(decrypted_len); + chacha20_poly1305_decrypt_96(cu_read_key, (unsigned char*)rnonce, NULL, 0, (unsigned char*)dt, dl, decrypted, &decrypted_len); + plist_free(dict); + dict = NULL; + + plist_from_memory((const char*)decrypted, decrypted_len, &dict, NULL); + if (!dict) { + ret = LOCKDOWN_E_PLIST_ERROR; + debug_info("Failed to parse PLIST from decrypted payload:"); + debug_buffer((const char*)decrypted, decrypted_len); + free(decrypted); + return ret; + } + free(decrypted); + + debug_plist(dict); + + if (reply) { + *reply = dict; + } else { + plist_free(dict); + } + + return LOCKDOWN_E_SUCCESS; +#else + debug_info("not supported"); + return LOCKDOWN_E_UNKNOWN_ERROR; +#endif +} + +lockdownd_error_t lockdownd_get_value_cu(lockdownd_client_t client, const char* domain, const char* key, plist_t* value) +{ +#ifdef HAVE_WIRELESS_PAIRING + if (!client) + return LOCKDOWN_E_INVALID_ARG; + + if (!client->cu_key) + return LOCKDOWN_E_NO_RUNNING_SESSION; + + lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; + + plist_t request = plist_new_dict(); + if (domain) { + plist_dict_set_item(request, "Domain", plist_new_string(domain)); + } + if (key) { + plist_dict_set_item(request, "Key", plist_new_string(key)); + } + + plist_t reply = NULL; + ret = lockdownd_cu_send_request_and_get_reply(client, "GetValueCU", request, &reply); + plist_free(request); + if (ret != LOCKDOWN_E_SUCCESS) { + return ret; + } + + plist_t value_node = plist_dict_get_item(reply, "Value"); + if (value_node) { + debug_info("has a value"); + *value = plist_copy(value_node); + } + plist_free(reply); + + return ret; +#else + debug_info("not supported"); + return LOCKDOWN_E_UNKNOWN_ERROR; +#endif +} + +lockdownd_error_t lockdownd_pair_cu(lockdownd_client_t client) +{ +#ifdef HAVE_WIRELESS_PAIRING + if (!client) + return LOCKDOWN_E_INVALID_ARG; + + if (!client->cu_key) + return LOCKDOWN_E_NO_RUNNING_SESSION; + + lockdownd_error_t ret; + + plist_t wifi_mac = NULL; + ret = lockdownd_get_value_cu(client, NULL, "WiFiAddress", &wifi_mac); + if (ret != LOCKDOWN_E_SUCCESS) { + return ret; + } + + plist_t pubkey = NULL; + ret = lockdownd_get_value_cu(client, NULL, "DevicePublicKey", &pubkey); + if (ret != LOCKDOWN_E_SUCCESS) { + plist_free(wifi_mac); + return ret; + } + + key_data_t public_key = { NULL, 0 }; + uint64_t data_len = 0; + plist_get_data_val(pubkey, (char**)&public_key.data, &data_len); + public_key.size = (unsigned int)data_len; + plist_free(pubkey); + + plist_t pair_record_plist = plist_new_dict(); + pair_record_generate_keys_and_certs(pair_record_plist, public_key); + + char* host_id = NULL; + char* system_buid = NULL; + + /* set SystemBUID */ + userpref_read_system_buid(&system_buid); + if (system_buid) { + plist_dict_set_item(pair_record_plist, USERPREF_SYSTEM_BUID_KEY, plist_new_string(system_buid)); + free(system_buid); + } + + /* set HostID */ + host_id = generate_uuid(); + pair_record_set_host_id(pair_record_plist, host_id); + free(host_id); + + plist_t request_pair_record = plist_copy(pair_record_plist); + /* remove stuff that is private */ + plist_dict_remove_item(request_pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY); + plist_dict_remove_item(request_pair_record, USERPREF_HOST_PRIVATE_KEY_KEY); + + plist_t request = plist_new_dict(); + plist_dict_set_item(request, "PairRecord", request_pair_record); + plist_t pairing_opts = plist_new_dict(); + plist_dict_set_item(pairing_opts, "ExtendedPairingErrors", plist_new_bool(1)); + plist_dict_set_item(request, "PairingOptions", pairing_opts); + + plist_t reply = NULL; + ret = lockdownd_cu_send_request_and_get_reply(client, "PairCU", request, &reply); + plist_free(request); + if (ret != LOCKDOWN_E_SUCCESS) { + plist_free(wifi_mac); + return ret; + } + + char *s_udid = NULL; + plist_t p_udid = plist_dict_get_item(reply, "UDID"); + if (p_udid) { + plist_get_string_val(p_udid, &s_udid); + } + plist_t ebag = plist_dict_get_item(reply, "EscrowBag"); + if (ebag) { + plist_dict_set_item(pair_record_plist, USERPREF_ESCROW_BAG_KEY, plist_copy(ebag)); + } + plist_dict_set_item(pair_record_plist, USERPREF_WIFI_MAC_ADDRESS_KEY, wifi_mac); + plist_free(reply); + + if (userpref_save_pair_record(s_udid, 0, pair_record_plist) != 0) { + printf("Failed to save pair record for UDID %s\n", s_udid); + } + free(s_udid); + s_udid = NULL; + plist_free(pair_record_plist); + + ret = LOCKDOWN_E_SUCCESS; + + return ret; +#else + debug_info("not supported"); + return LOCKDOWN_E_UNKNOWN_ERROR; +#endif +} diff --git a/src/lockdown.c b/src/lockdown.c index 70db834..256bff0 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -152,7 +152,7 @@ static lockdownd_error_t lockdownd_error(property_list_service_error_t err) * LOCKDOWN_E_UNKNOWN_ERROR when the result is 'Failure', * or a specific error code if derieved from the result. */ -static lockdownd_error_t lockdown_check_result(plist_t dict, const char *query_match) +lockdownd_error_t lockdown_check_result(plist_t dict, const char *query_match) { lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; @@ -163,53 +163,40 @@ static lockdownd_error_t lockdown_check_result(plist_t dict, const char *query_m if (plist_get_node_type(query_node) != PLIST_STRING) { return ret; - } else { - char *query_value = NULL; - - plist_get_string_val(query_node, &query_value); - if (!query_value) { - return ret; - } + } - if (query_match && (strcmp(query_value, query_match) != 0)) { - free(query_value); - return ret; - } + const char *query_value = plist_get_string_ptr(query_node, NULL); + if (!query_value) { + return ret; + } - free(query_value); + if (query_match && (strcmp(query_value, query_match) != 0)) { + return ret; } - plist_t result_node = plist_dict_get_item(dict, "Result"); - if (!result_node) { - /* iOS 5: the 'Result' key is not present anymore. - But we need to check for the 'Error' key. */ - plist_t err_node = plist_dict_get_item(dict, "Error"); - if (err_node) { - if (plist_get_node_type(err_node) == PLIST_STRING) { - char *err_value = NULL; - - plist_get_string_val(err_node, &err_value); - if (err_value) { - debug_info("ERROR: %s", err_value); - ret = lockdownd_strtoerr(err_value); - free(err_value); - } else { - debug_info("ERROR: unknown error occurred"); - } + /* Check for 'Error' in reply */ + plist_t err_node = plist_dict_get_item(dict, "Error"); + if (err_node) { + if (plist_get_node_type(err_node) == PLIST_STRING) { + const char *err_value = plist_get_string_ptr(err_node, NULL); + if (err_value) { + debug_info("ERROR: %s", err_value); + ret = lockdownd_strtoerr(err_value); + } else { + debug_info("ERROR: unknown error occurred"); } - return ret; } - - ret = LOCKDOWN_E_SUCCESS; - return ret; } - plist_type result_type = plist_get_node_type(result_node); - if (result_type == PLIST_STRING) { - char *result_value = NULL; - - plist_get_string_val(result_node, &result_value); + plist_t result_node = plist_dict_get_item(dict, "Result"); + if (!result_node) { + /* With iOS 5+ 'Result' is not present anymore. + If there is no 'Error', we can just assume success. */ + return LOCKDOWN_E_SUCCESS; + } + if (plist_get_node_type(result_node) == PLIST_STRING) { + const char *result_value = plist_get_string_ptr(result_node, NULL); if (result_value) { if (!strcmp(result_value, "Success")) { ret = LOCKDOWN_E_SUCCESS; @@ -219,9 +206,6 @@ static lockdownd_error_t lockdown_check_result(plist_t dict, const char *query_m debug_info("ERROR: unknown result value '%s'", result_value); } } - - if (result_value) - free(result_value); } return ret; @@ -242,7 +226,7 @@ static void plist_dict_add_label(plist_t plist, const char *label) } } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client, const char *session_id) +lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client, const char *session_id) { if (!client) return LOCKDOWN_E_INVALID_ARG; @@ -314,6 +298,10 @@ static lockdownd_error_t lockdownd_client_free_simple(lockdownd_client_t client) if (client->label) { free(client->label); } + if (client->cu_key) { + free(client->cu_key); + client->cu_key = NULL; + } free(client); client = NULL; @@ -321,7 +309,7 @@ static lockdownd_error_t lockdownd_client_free_simple(lockdownd_client_t client) return ret; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_free(lockdownd_client_t client) +lockdownd_error_t lockdownd_client_free(lockdownd_client_t client) { if (!client) return LOCKDOWN_E_INVALID_ARG; @@ -337,7 +325,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_free(lockdownd_client_t return ret; } -LIBIMOBILEDEVICE_API void lockdownd_client_set_label(lockdownd_client_t client, const char *label) +void lockdownd_client_set_label(lockdownd_client_t client, const char *label) { if (client) { if (client->label) @@ -347,7 +335,7 @@ LIBIMOBILEDEVICE_API void lockdownd_client_set_label(lockdownd_client_t client, } } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_receive(lockdownd_client_t client, plist_t *plist) +lockdownd_error_t lockdownd_receive(lockdownd_client_t client, plist_t *plist) { if (!client || !plist || (plist && *plist)) return LOCKDOWN_E_INVALID_ARG; @@ -355,7 +343,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_receive(lockdownd_client_t clie return lockdownd_error(property_list_service_receive_plist(client->parent, plist)); } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_send(lockdownd_client_t client, plist_t plist) +lockdownd_error_t lockdownd_send(lockdownd_client_t client, plist_t plist) { if (!client || !plist) return LOCKDOWN_E_INVALID_ARG; @@ -363,7 +351,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_send(lockdownd_client_t client, return lockdownd_error(property_list_service_send_xml_plist(client->parent, plist)); } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_query_type(lockdownd_client_t client, char **type) +lockdownd_error_t lockdownd_query_type(lockdownd_client_t client, char **type) { if (!client) return LOCKDOWN_E_INVALID_ARG; @@ -408,7 +396,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_query_type(lockdownd_client_t c return ret; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *domain, const char *key, plist_t *value) +lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *domain, const char *key, plist_t *value) { if (!client) return LOCKDOWN_E_INVALID_ARG; @@ -462,7 +450,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_value(lockdownd_client_t cl return ret; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_set_value(lockdownd_client_t client, const char *domain, const char *key, plist_t value) +lockdownd_error_t lockdownd_set_value(lockdownd_client_t client, const char *domain, const char *key, plist_t value) { if (!client || !value) return LOCKDOWN_E_INVALID_ARG; @@ -510,7 +498,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_set_value(lockdownd_client_t cl return ret; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_remove_value(lockdownd_client_t client, const char *domain, const char *key) +lockdownd_error_t lockdownd_remove_value(lockdownd_client_t client, const char *domain, const char *key) { if (!client) return LOCKDOWN_E_INVALID_ARG; @@ -557,7 +545,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_remove_value(lockdownd_client_t return ret; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_device_udid(lockdownd_client_t client, char **udid) +lockdownd_error_t lockdownd_get_device_udid(lockdownd_client_t client, char **udid) { lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; plist_t value = NULL; @@ -603,7 +591,7 @@ static lockdownd_error_t lockdownd_get_device_public_key_as_key_data(lockdownd_c return ret; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_device_name(lockdownd_client_t client, char **device_name) +lockdownd_error_t lockdownd_get_device_name(lockdownd_client_t client, char **device_name) { lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; plist_t value = NULL; @@ -620,7 +608,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_device_name(lockdownd_clien return ret; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_new(idevice_t device, lockdownd_client_t *client, const char *label) +lockdownd_error_t lockdownd_client_new(idevice_t device, lockdownd_client_t *client, const char *label) { if (!device || !client) return LOCKDOWN_E_INVALID_ARG; @@ -641,8 +629,12 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_new(idevice_t device, lo client_loc->ssl_enabled = 0; client_loc->session_id = NULL; client_loc->device = device; + client_loc->cu_key = NULL; + client_loc->cu_key_len = 0; - debug_info("device udid: %s", device->udid); + if (device->udid) { + debug_info("device udid: %s", device->udid); + } client_loc->label = label ? strdup(label) : NULL; @@ -651,7 +643,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_new(idevice_t device, lo return LOCKDOWN_E_SUCCESS; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_new_with_handshake(idevice_t device, lockdownd_client_t *client, const char *label) +lockdownd_error_t lockdownd_client_new_with_handshake(idevice_t device, lockdownd_client_t *client, const char *label) { if (!client) return LOCKDOWN_E_INVALID_ARG; @@ -672,7 +664,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_new_with_handshake(idevi ret = lockdownd_query_type(client_loc, &type); if (LOCKDOWN_E_SUCCESS != ret) { debug_info("QueryType failed in the lockdownd client."); - } else if (strcmp("com.apple.mobile.lockdown", type)) { + } else if (strcmp("com.apple.mobile.lockdown", type) != 0) { debug_info("Warning QueryType request returned \"%s\".", type); } free(type); @@ -758,12 +750,15 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_new_with_handshake(idevi uerr = userpref_read_pair_record(client_loc->device->udid, &pair_record); if (uerr == USERPREF_E_READ_ERROR) { debug_info("ERROR: Failed to retrieve pair record for %s", client_loc->device->udid); + lockdownd_client_free(client_loc); return LOCKDOWN_E_RECEIVE_TIMEOUT; } else if (uerr == USERPREF_E_NOENT) { debug_info("ERROR: No pair record for %s", client_loc->device->udid); + lockdownd_client_free(client_loc); return LOCKDOWN_E_INVALID_CONF; } else if (uerr != USERPREF_E_SUCCESS) { debug_info("ERROR: Failed to retrieve or parse pair record for %s", client_loc->device->udid); + lockdownd_client_free(client_loc); return LOCKDOWN_E_INVALID_CONF; } if (pair_record) { @@ -1061,7 +1056,7 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_ return ret; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record) +lockdownd_error_t lockdownd_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record) { plist_t options = plist_new_dict(); @@ -1074,22 +1069,22 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_pair(lockdownd_client_t client, return ret; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_pair_with_options(lockdownd_client_t client, lockdownd_pair_record_t pair_record, plist_t options, plist_t *response) +lockdownd_error_t lockdownd_pair_with_options(lockdownd_client_t client, lockdownd_pair_record_t pair_record, plist_t options, plist_t *response) { return lockdownd_do_pair(client, pair_record, "Pair", options, response); } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_validate_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record) +lockdownd_error_t lockdownd_validate_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record) { return lockdownd_do_pair(client, pair_record, "ValidatePair", NULL, NULL); } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_unpair(lockdownd_client_t client, lockdownd_pair_record_t pair_record) +lockdownd_error_t lockdownd_unpair(lockdownd_client_t client, lockdownd_pair_record_t pair_record) { return lockdownd_do_pair(client, pair_record, "Unpair", NULL, NULL); } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_enter_recovery(lockdownd_client_t client) +lockdownd_error_t lockdownd_enter_recovery(lockdownd_client_t client) { if (!client) return LOCKDOWN_E_INVALID_ARG; @@ -1119,7 +1114,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_enter_recovery(lockdownd_client return ret; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client) +lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client) { if (!client) return LOCKDOWN_E_INVALID_ARG; @@ -1153,7 +1148,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_goodbye(lockdownd_client_t clie return ret; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_start_session(lockdownd_client_t client, const char *host_id, char **session_id, int *ssl_enabled) +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; @@ -1397,17 +1392,17 @@ static lockdownd_error_t lockdownd_do_start_service(lockdownd_client_t client, c return ret; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char *identifier, lockdownd_service_descriptor_t *service) +lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char *identifier, lockdownd_service_descriptor_t *service) { return lockdownd_do_start_service(client, identifier, 0, service); } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_start_service_with_escrow_bag(lockdownd_client_t client, const char *identifier, lockdownd_service_descriptor_t *service) +lockdownd_error_t lockdownd_start_service_with_escrow_bag(lockdownd_client_t client, const char *identifier, lockdownd_service_descriptor_t *service) { return lockdownd_do_start_service(client, identifier, 1, service); } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_activate(lockdownd_client_t client, plist_t activation_record) +lockdownd_error_t lockdownd_activate(lockdownd_client_t client, plist_t activation_record) { if (!client) return LOCKDOWN_E_INVALID_ARG; @@ -1446,7 +1441,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_activate(lockdownd_client_t cli return ret; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_deactivate(lockdownd_client_t client) +lockdownd_error_t lockdownd_deactivate(lockdownd_client_t client) { if (!client) return LOCKDOWN_E_INVALID_ARG; @@ -1493,7 +1488,7 @@ static void str_remove_spaces(char *source) *dest = 0; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_sync_data_classes(lockdownd_client_t client, char ***classes, int *count) +lockdownd_error_t lockdownd_get_sync_data_classes(lockdownd_client_t client, char ***classes, int *count) { if (!client) return LOCKDOWN_E_INVALID_ARG; @@ -1548,7 +1543,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_sync_data_classes(lockdownd return LOCKDOWN_E_SUCCESS; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_data_classes_free(char **classes) +lockdownd_error_t lockdownd_data_classes_free(char **classes) { if (classes) { int i = 0; @@ -1560,7 +1555,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_data_classes_free(char **classe return LOCKDOWN_E_SUCCESS; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_service_descriptor_free(lockdownd_service_descriptor_t service) +lockdownd_error_t lockdownd_service_descriptor_free(lockdownd_service_descriptor_t service) { if (service) { free(service->identifier); @@ -1570,7 +1565,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_service_descriptor_free(lockdow return LOCKDOWN_E_SUCCESS; } -LIBIMOBILEDEVICE_API const char* lockdownd_strerror(lockdownd_error_t err) +const char* lockdownd_strerror(lockdownd_error_t err) { switch (err) { case LOCKDOWN_E_SUCCESS: diff --git a/src/lockdown.h b/src/lockdown.h index 0091f1d..ba291ec 100644 --- a/src/lockdown.h +++ b/src/lockdown.h @@ -23,6 +23,7 @@ #ifndef __LOCKDOWND_H #define __LOCKDOWND_H +#include "idevice.h" #include "libimobiledevice/lockdown.h" #include "property_list_service.h" @@ -34,6 +35,10 @@ struct lockdownd_client_private { char *session_id; char *label; idevice_t device; + unsigned char* cu_key; + unsigned int cu_key_len; }; +lockdownd_error_t lockdown_check_result(plist_t dict, const char *query_match); + #endif diff --git a/src/misagent.c b/src/misagent.c index d790a05..e3da997 100644 --- a/src/misagent.c +++ b/src/misagent.c @@ -85,12 +85,11 @@ static misagent_error_t misagent_check_result(plist_t response, int* status_code *status_code = (int)(val & 0xFFFFFFFF); if (*status_code == 0) { return MISAGENT_E_SUCCESS; - } else { - return MISAGENT_E_REQUEST_FAILED; } + return MISAGENT_E_REQUEST_FAILED; } -LIBIMOBILEDEVICE_API misagent_error_t misagent_client_new(idevice_t device, lockdownd_service_descriptor_t service, misagent_client_t *client) +misagent_error_t misagent_client_new(idevice_t device, lockdownd_service_descriptor_t service, misagent_client_t *client) { property_list_service_client_t plistclient = NULL; misagent_error_t err = misagent_error(property_list_service_client_new(device, service, &plistclient)); @@ -106,14 +105,14 @@ LIBIMOBILEDEVICE_API misagent_error_t misagent_client_new(idevice_t device, lock return MISAGENT_E_SUCCESS; } -LIBIMOBILEDEVICE_API misagent_error_t misagent_client_start_service(idevice_t device, misagent_client_t * client, const char* label) +misagent_error_t misagent_client_start_service(idevice_t device, misagent_client_t * client, const char* label) { misagent_error_t err = MISAGENT_E_UNKNOWN_ERROR; service_client_factory_start_service(device, MISAGENT_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(misagent_client_new), &err); return err; } -LIBIMOBILEDEVICE_API misagent_error_t misagent_client_free(misagent_client_t client) +misagent_error_t misagent_client_free(misagent_client_t client) { if (!client) return MISAGENT_E_INVALID_ARG; @@ -128,7 +127,7 @@ LIBIMOBILEDEVICE_API misagent_error_t misagent_client_free(misagent_client_t cli return err; } -LIBIMOBILEDEVICE_API misagent_error_t misagent_install(misagent_client_t client, plist_t profile) +misagent_error_t misagent_install(misagent_client_t client, plist_t profile) { if (!client || !client->parent || !profile || (plist_get_node_type(profile) != PLIST_DATA)) return MISAGENT_E_INVALID_ARG; @@ -165,7 +164,7 @@ LIBIMOBILEDEVICE_API misagent_error_t misagent_install(misagent_client_t client, return res; } -LIBIMOBILEDEVICE_API misagent_error_t misagent_copy(misagent_client_t client, plist_t* profiles) +misagent_error_t misagent_copy(misagent_client_t client, plist_t* profiles) { if (!client || !client->parent || !profiles) return MISAGENT_E_INVALID_ARG; @@ -205,7 +204,7 @@ LIBIMOBILEDEVICE_API misagent_error_t misagent_copy(misagent_client_t client, pl } -LIBIMOBILEDEVICE_API misagent_error_t misagent_copy_all(misagent_client_t client, plist_t* profiles) +misagent_error_t misagent_copy_all(misagent_client_t client, plist_t* profiles) { if (!client || !client->parent || !profiles) return MISAGENT_E_INVALID_ARG; @@ -245,7 +244,7 @@ LIBIMOBILEDEVICE_API misagent_error_t misagent_copy_all(misagent_client_t client } -LIBIMOBILEDEVICE_API misagent_error_t misagent_remove(misagent_client_t client, const char* profileID) +misagent_error_t misagent_remove(misagent_client_t client, const char* profileID) { if (!client || !client->parent || !profileID) return MISAGENT_E_INVALID_ARG; @@ -282,7 +281,7 @@ LIBIMOBILEDEVICE_API misagent_error_t misagent_remove(misagent_client_t client, return res; } -LIBIMOBILEDEVICE_API int misagent_get_status_code(misagent_client_t client) +int misagent_get_status_code(misagent_client_t client) { if (!client) { return -1; diff --git a/src/misagent.h b/src/misagent.h index 08ad063..e394087 100644 --- a/src/misagent.h +++ b/src/misagent.h @@ -22,6 +22,7 @@ #ifndef __MISAGENT_H #define __MISAGENT_H +#include "idevice.h" #include "libimobiledevice/misagent.h" #include "property_list_service.h" diff --git a/src/mobile_image_mounter.c b/src/mobile_image_mounter.c index 9ccfd85..5df8e86 100644 --- a/src/mobile_image_mounter.c +++ b/src/mobile_image_mounter.c @@ -78,7 +78,7 @@ static mobile_image_mounter_error_t mobile_image_mounter_error(property_list_ser return MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_new(idevice_t device, lockdownd_service_descriptor_t service, mobile_image_mounter_client_t *client) +mobile_image_mounter_error_t mobile_image_mounter_new(idevice_t device, lockdownd_service_descriptor_t service, mobile_image_mounter_client_t *client) { property_list_service_client_t plistclient = NULL; mobile_image_mounter_error_t err = mobile_image_mounter_error(property_list_service_client_new(device, service, &plistclient)); @@ -95,14 +95,14 @@ LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_new(idevi return MOBILE_IMAGE_MOUNTER_E_SUCCESS; } -LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_start_service(idevice_t device, mobile_image_mounter_client_t * client, const char* label) +mobile_image_mounter_error_t mobile_image_mounter_start_service(idevice_t device, mobile_image_mounter_client_t * client, const char* label) { mobile_image_mounter_error_t err = MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR; service_client_factory_start_service(device, MOBILE_IMAGE_MOUNTER_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(mobile_image_mounter_new), &err); return err; } -LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_free(mobile_image_mounter_client_t client) +mobile_image_mounter_error_t mobile_image_mounter_free(mobile_image_mounter_client_t client) { if (!client) return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; @@ -115,7 +115,7 @@ LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_free(mobi return MOBILE_IMAGE_MOUNTER_E_SUCCESS; } -LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_lookup_image(mobile_image_mounter_client_t client, const char *image_type, plist_t *result) +mobile_image_mounter_error_t mobile_image_mounter_lookup_image(mobile_image_mounter_client_t client, const char *image_type, plist_t *result) { if (!client || !image_type || !result) { return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; @@ -181,7 +181,7 @@ static mobile_image_mounter_error_t process_result(plist_t result, const char *e return res; } -LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_upload_image(mobile_image_mounter_client_t client, const char *image_type, size_t image_size, const char *signature, uint16_t signature_size, mobile_image_mounter_upload_cb_t upload_cb, void* userdata) +mobile_image_mounter_error_t mobile_image_mounter_upload_image(mobile_image_mounter_client_t client, const char *image_type, size_t image_size, const char *signature, uint16_t signature_size, mobile_image_mounter_upload_cb_t upload_cb, void* userdata) { if (!client || !image_type || (image_size == 0) || !upload_cb) { return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; @@ -260,7 +260,7 @@ leave_unlock: } -LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_mount_image(mobile_image_mounter_client_t client, const char *image_path, const char *signature, uint16_t signature_size, const char *image_type, plist_t *result) +mobile_image_mounter_error_t mobile_image_mounter_mount_image(mobile_image_mounter_client_t client, const char *image_path, const char *signature, uint16_t signature_size, const char *image_type, plist_t *result) { if (!client || !image_path || !image_type || !result) { return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; @@ -292,7 +292,7 @@ leave_unlock: return res; } -LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_hangup(mobile_image_mounter_client_t client) +mobile_image_mounter_error_t mobile_image_mounter_hangup(mobile_image_mounter_client_t client) { if (!client) { return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; diff --git a/src/mobile_image_mounter.h b/src/mobile_image_mounter.h index 55c9cf2..9a8fcdd 100644 --- a/src/mobile_image_mounter.h +++ b/src/mobile_image_mounter.h @@ -22,6 +22,7 @@ #ifndef __MOBILE_IMAGE_MOUNTER_H #define __MOBILE_IMAGE_MOUNTER_H +#include "idevice.h" #include "libimobiledevice/mobile_image_mounter.h" #include "property_list_service.h" #include <libimobiledevice-glue/thread.h> diff --git a/src/mobileactivation.c b/src/mobileactivation.c index 2de4333..fce5f16 100644 --- a/src/mobileactivation.c +++ b/src/mobileactivation.c @@ -54,7 +54,7 @@ static mobileactivation_error_t mobileactivation_error(property_list_service_err return MOBILEACTIVATION_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobileactivation_client_t *client) +mobileactivation_error_t mobileactivation_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobileactivation_client_t *client) { if (!device || !service || service->port == 0 || !client || *client) { return MOBILEACTIVATION_E_INVALID_ARG; @@ -74,14 +74,14 @@ LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_client_new(idevic return MOBILEACTIVATION_E_SUCCESS; } -LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_client_start_service(idevice_t device, mobileactivation_client_t * client, const char* label) +mobileactivation_error_t mobileactivation_client_start_service(idevice_t device, mobileactivation_client_t * client, const char* label) { mobileactivation_error_t err = MOBILEACTIVATION_E_UNKNOWN_ERROR; service_client_factory_start_service(device, MOBILEACTIVATION_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(mobileactivation_client_new), &err); return err; } -LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_client_free(mobileactivation_client_t client) +mobileactivation_error_t mobileactivation_client_free(mobileactivation_client_t client) { if (!client) return MOBILEACTIVATION_E_INVALID_ARG; @@ -109,8 +109,6 @@ static plist_t plist_data_from_plist(plist_t plist) static mobileactivation_error_t mobileactivation_check_result(plist_t dict, const char *command) { - mobileactivation_error_t ret = MOBILEACTIVATION_E_UNKNOWN_ERROR; - if (!dict || plist_get_node_type(dict) != PLIST_DICT) { return MOBILEACTIVATION_E_PLIST_ERROR; } @@ -118,14 +116,13 @@ static mobileactivation_error_t mobileactivation_check_result(plist_t dict, cons plist_t err_node = plist_dict_get_item(dict, "Error"); if (!err_node) { return MOBILEACTIVATION_E_SUCCESS; - } else { - char *errmsg = NULL; - plist_get_string_val(err_node, &errmsg); - debug_info("ERROR: %s: %s", command, errmsg); - ret = MOBILEACTIVATION_E_REQUEST_FAILED; - free(errmsg); } - return ret; + + char *errmsg = NULL; + plist_get_string_val(err_node, &errmsg); + debug_info("ERROR: %s: %s", command, errmsg); + free(errmsg); + return MOBILEACTIVATION_E_REQUEST_FAILED; } static mobileactivation_error_t mobileactivation_send_command_plist(mobileactivation_client_t client, plist_t command, plist_t *result) @@ -179,7 +176,7 @@ static mobileactivation_error_t mobileactivation_send_command(mobileactivation_c return ret; } -LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_get_activation_state(mobileactivation_client_t client, plist_t *state) +mobileactivation_error_t mobileactivation_get_activation_state(mobileactivation_client_t client, plist_t *state) { if (!client || !state) return MOBILEACTIVATION_E_INVALID_ARG; @@ -201,7 +198,7 @@ LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_get_activation_st return ret; } -LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_create_activation_session_info(mobileactivation_client_t client, plist_t *blob) +mobileactivation_error_t mobileactivation_create_activation_session_info(mobileactivation_client_t client, plist_t *blob) { if (!client || !blob) return MOBILEACTIVATION_E_INVALID_ARG; @@ -221,7 +218,7 @@ LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_create_activation return ret; } -LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_create_activation_info(mobileactivation_client_t client, plist_t *info) +mobileactivation_error_t mobileactivation_create_activation_info(mobileactivation_client_t client, plist_t *info) { if (!client || !info) return MOBILEACTIVATION_E_INVALID_ARG; @@ -243,7 +240,7 @@ LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_create_activation return ret; } -LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_create_activation_info_with_session(mobileactivation_client_t client, plist_t handshake_response, plist_t *info) +mobileactivation_error_t mobileactivation_create_activation_info_with_session(mobileactivation_client_t client, plist_t handshake_response, plist_t *info) { if (!client || !info) return MOBILEACTIVATION_E_INVALID_ARG; @@ -267,7 +264,7 @@ LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_create_activation return ret; } -LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_activate(mobileactivation_client_t client, plist_t activation_record) +mobileactivation_error_t mobileactivation_activate(mobileactivation_client_t client, plist_t activation_record) { if (!client || !activation_record) return MOBILEACTIVATION_E_INVALID_ARG; @@ -280,7 +277,7 @@ LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_activate(mobileac return ret; } -LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_activate_with_session(mobileactivation_client_t client, plist_t activation_record, plist_t headers) +mobileactivation_error_t mobileactivation_activate_with_session(mobileactivation_client_t client, plist_t activation_record, plist_t headers) { if (!client || !activation_record) return MOBILEACTIVATION_E_INVALID_ARG; @@ -303,7 +300,7 @@ LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_activate_with_ses } -LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_deactivate(mobileactivation_client_t client) +mobileactivation_error_t mobileactivation_deactivate(mobileactivation_client_t client) { if (!client) return MOBILEACTIVATION_E_INVALID_ARG; diff --git a/src/mobileactivation.h b/src/mobileactivation.h index 49b9ebc..a8dff5d 100644 --- a/src/mobileactivation.h +++ b/src/mobileactivation.h @@ -22,6 +22,7 @@ #ifndef __MOBILEACTIVATION_H #define __MOBILEACTIVATION_H +#include "idevice.h" #include "libimobiledevice/mobileactivation.h" #include "property_list_service.h" diff --git a/src/mobilebackup.c b/src/mobilebackup.c index cde96b5..36986a4 100644 --- a/src/mobilebackup.c +++ b/src/mobilebackup.c @@ -26,6 +26,7 @@ #include <plist/plist.h> #include <string.h> #include <stdlib.h> +#include <stdio.h> #include "mobilebackup.h" #include "device_link_service.h" @@ -34,7 +35,7 @@ #define MBACKUP_VERSION_INT1 100 #define MBACKUP_VERSION_INT2 0 -#define IS_FLAG_SET(x, y) ((x & y) == y) +#define IS_FLAG_SET(x, y) (((x) & (y)) == (y)) /** * Convert an device_link_service_error_t value to an mobilebackup_error_t value. @@ -68,7 +69,7 @@ static mobilebackup_error_t mobilebackup_error(device_link_service_error_t err) return MOBILEBACKUP_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobilebackup_client_t * client) +mobilebackup_error_t mobilebackup_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobilebackup_client_t * client) { if (!device || !service || service->port == 0 || !client || *client) return MOBILEBACKUP_E_INVALID_ARG; @@ -95,14 +96,14 @@ LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_client_new(idevice_t devi return ret; } -LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_client_start_service(idevice_t device, mobilebackup_client_t * client, const char* label) +mobilebackup_error_t mobilebackup_client_start_service(idevice_t device, mobilebackup_client_t * client, const char* label) { mobilebackup_error_t err = MOBILEBACKUP_E_UNKNOWN_ERROR; service_client_factory_start_service(device, MOBILEBACKUP_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(mobilebackup_client_new), &err); return err; } -LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_client_free(mobilebackup_client_t client) +mobilebackup_error_t mobilebackup_client_free(mobilebackup_client_t client) { if (!client) return MOBILEBACKUP_E_INVALID_ARG; @@ -115,7 +116,7 @@ LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_client_free(mobilebackup_ return err; } -LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_receive(mobilebackup_client_t client, plist_t * plist) +mobilebackup_error_t mobilebackup_receive(mobilebackup_client_t client, plist_t * plist) { if (!client) return MOBILEBACKUP_E_INVALID_ARG; @@ -123,7 +124,7 @@ LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_receive(mobilebackup_clie return ret; } -LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_send(mobilebackup_client_t client, plist_t plist) +mobilebackup_error_t mobilebackup_send(mobilebackup_client_t client, plist_t plist) { if (!client || !plist) return MOBILEBACKUP_E_INVALID_ARG; @@ -240,7 +241,7 @@ leave: return err; } -LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_request_backup(mobilebackup_client_t client, plist_t backup_manifest, const char *base_path, const char *proto_version) +mobilebackup_error_t mobilebackup_request_backup(mobilebackup_client_t client, plist_t backup_manifest, const char *base_path, const char *proto_version) { if (!client || !client->parent || !base_path || !proto_version) return MOBILEBACKUP_E_INVALID_ARG; @@ -279,7 +280,15 @@ LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_request_backup(mobileback char *str = NULL; plist_get_string_val(node, &str); if (str) { - if (strcmp(str, proto_version) != 0) { + int maj = 0; + int min = 0; + sscanf(str, "%u.%u", &maj, &min); + uint32_t this_ver = ((maj & 0xFF) << 8) | (min & 0xFF); + maj = 0; + min = 0; + sscanf(proto_version, "%u.%u", &maj, &min); + uint32_t proto_ver = ((maj & 0xFF) << 8) | (min & 0xFF); + if (this_ver > proto_ver) { err = MOBILEBACKUP_E_BAD_VERSION; } free(str); @@ -300,12 +309,12 @@ leave: return err; } -LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_send_backup_file_received(mobilebackup_client_t client) +mobilebackup_error_t mobilebackup_send_backup_file_received(mobilebackup_client_t client) { return mobilebackup_send_message(client, "kBackupMessageBackupFileReceived", NULL); } -LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_request_restore(mobilebackup_client_t client, plist_t backup_manifest, mobilebackup_flags_t flags, const char *proto_version) +mobilebackup_error_t mobilebackup_request_restore(mobilebackup_client_t client, plist_t backup_manifest, mobilebackup_flags_t flags, const char *proto_version) { if (!client || !client->parent || !backup_manifest || !proto_version) return MOBILEBACKUP_E_INVALID_ARG; @@ -346,7 +355,15 @@ LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_request_restore(mobilebac char *str = NULL; plist_get_string_val(node, &str); if (str) { - if (strcmp(str, proto_version) != 0) { + int maj = 0; + int min = 0; + sscanf(str, "%u.%u", &maj, &min); + uint32_t this_ver = ((maj & 0xFF) << 8) | (min & 0xFF); + maj = 0; + min = 0; + sscanf(proto_version, "%u.%u", &maj, &min); + uint32_t proto_ver = ((maj & 0xFF) << 8) | (min & 0xFF); + if (this_ver > proto_ver) { err = MOBILEBACKUP_E_BAD_VERSION; } free(str); @@ -359,17 +376,17 @@ leave: return err; } -LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_receive_restore_file_received(mobilebackup_client_t client, plist_t *result) +mobilebackup_error_t mobilebackup_receive_restore_file_received(mobilebackup_client_t client, plist_t *result) { return mobilebackup_receive_message(client, "BackupMessageRestoreFileReceived", result); } -LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_receive_restore_application_received(mobilebackup_client_t client, plist_t *result) +mobilebackup_error_t mobilebackup_receive_restore_application_received(mobilebackup_client_t client, plist_t *result) { return mobilebackup_receive_message(client, "BackupMessageRestoreApplicationReceived", result); } -LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_send_restore_complete(mobilebackup_client_t client) +mobilebackup_error_t mobilebackup_send_restore_complete(mobilebackup_client_t client) { mobilebackup_error_t err = mobilebackup_send_message(client, "BackupMessageRestoreComplete", NULL); if (err != MOBILEBACKUP_E_SUCCESS) { @@ -414,7 +431,7 @@ LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_send_restore_complete(mob return err; } -LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_send_error(mobilebackup_client_t client, const char *reason) +mobilebackup_error_t mobilebackup_send_error(mobilebackup_client_t client, const char *reason) { if (!client || !client->parent || !reason) return MOBILEBACKUP_E_INVALID_ARG; diff --git a/src/mobilebackup.h b/src/mobilebackup.h index edda70f..04ec479 100644 --- a/src/mobilebackup.h +++ b/src/mobilebackup.h @@ -23,6 +23,7 @@ #ifndef __MOBILEBACKUP_H #define __MOBILEBACKUP_H +#include "idevice.h" #include "libimobiledevice/mobilebackup.h" #include "device_link_service.h" diff --git a/src/mobilebackup2.c b/src/mobilebackup2.c index 6c6556d..a8d673f 100644 --- a/src/mobilebackup2.c +++ b/src/mobilebackup2.c @@ -33,7 +33,7 @@ #define MBACKUP2_VERSION_INT1 400 #define MBACKUP2_VERSION_INT2 0 -#define IS_FLAG_SET(x, y) ((x & y) == y) +#define IS_FLAG_SET(x, y) (((x) & (y)) == (y)) /** * Convert an device_link_service_error_t value to an mobilebackup2_error_t value. @@ -68,7 +68,7 @@ static mobilebackup2_error_t mobilebackup2_error(device_link_service_error_t err return MOBILEBACKUP2_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_client_new(idevice_t device, lockdownd_service_descriptor_t service, +mobilebackup2_error_t mobilebackup2_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobilebackup2_client_t * client) { if (!device || !service || service->port == 0 || !client || *client) @@ -96,14 +96,14 @@ LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_client_new(idevice_t de return ret; } -LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_client_start_service(idevice_t device, mobilebackup2_client_t * client, const char* label) +mobilebackup2_error_t mobilebackup2_client_start_service(idevice_t device, mobilebackup2_client_t * client, const char* label) { mobilebackup2_error_t err = MOBILEBACKUP2_E_UNKNOWN_ERROR; service_client_factory_start_service(device, MOBILEBACKUP2_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(mobilebackup2_client_new), &err); return err; } -LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_client_free(mobilebackup2_client_t client) +mobilebackup2_error_t mobilebackup2_client_free(mobilebackup2_client_t client) { if (!client) return MOBILEBACKUP2_E_INVALID_ARG; @@ -116,7 +116,7 @@ LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_client_free(mobilebacku return err; } -LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_send_message(mobilebackup2_client_t client, const char *message, plist_t options) +mobilebackup2_error_t mobilebackup2_send_message(mobilebackup2_client_t client, const char *message, plist_t options) { if (!client || !client->parent || (!message && !options)) return MOBILEBACKUP2_E_INVALID_ARG; @@ -214,12 +214,12 @@ leave: return err; } -LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_receive_message(mobilebackup2_client_t client, plist_t *msg_plist, char **dlmessage) +mobilebackup2_error_t mobilebackup2_receive_message(mobilebackup2_client_t client, plist_t *msg_plist, char **dlmessage) { return mobilebackup2_error(device_link_service_receive_message(client->parent, msg_plist, dlmessage)); } -LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_send_raw(mobilebackup2_client_t client, const char *data, uint32_t length, uint32_t *bytes) +mobilebackup2_error_t mobilebackup2_send_raw(mobilebackup2_client_t client, const char *data, uint32_t length, uint32_t *bytes) { if (!client || !client->parent || !data || (length == 0) || !bytes) return MOBILEBACKUP2_E_INVALID_ARG; @@ -240,12 +240,11 @@ LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_send_raw(mobilebackup2_ if (sent > 0) { *bytes = sent; return MOBILEBACKUP2_E_SUCCESS; - } else { - return MOBILEBACKUP2_E_MUX_ERROR; } + return MOBILEBACKUP2_E_MUX_ERROR; } -LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_receive_raw(mobilebackup2_client_t client, char *data, uint32_t length, uint32_t *bytes) +mobilebackup2_error_t mobilebackup2_receive_raw(mobilebackup2_client_t client, char *data, uint32_t length, uint32_t *bytes) { if (!client || !client->parent || !data || (length == 0) || !bytes) return MOBILEBACKUP2_E_INVALID_ARG; @@ -265,14 +264,14 @@ LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_receive_raw(mobilebacku if (received > 0) { *bytes = received; return MOBILEBACKUP2_E_SUCCESS; - } else if (received == 0) { + } + if (received == 0) { return MOBILEBACKUP2_E_SUCCESS; - } else { - return MOBILEBACKUP2_E_MUX_ERROR; } + return MOBILEBACKUP2_E_MUX_ERROR; } -LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_version_exchange(mobilebackup2_client_t client, double local_versions[], char count, double *remote_version) +mobilebackup2_error_t mobilebackup2_version_exchange(mobilebackup2_client_t client, double local_versions[], char count, double *remote_version) { int i; @@ -330,7 +329,7 @@ leave: return err; } -LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_send_request(mobilebackup2_client_t client, const char *request, const char *target_identifier, const char *source_identifier, plist_t options) +mobilebackup2_error_t mobilebackup2_send_request(mobilebackup2_client_t client, const char *request, const char *target_identifier, const char *source_identifier, plist_t options) { if (!client || !client->parent || !request || !target_identifier) return MOBILEBACKUP2_E_INVALID_ARG; @@ -361,7 +360,7 @@ LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_send_request(mobileback return err; } -LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_send_status_response(mobilebackup2_client_t client, int status_code, const char *status1, plist_t status2) +mobilebackup2_error_t mobilebackup2_send_status_response(mobilebackup2_client_t client, int status_code, const char *status1, plist_t status2) { if (!client || !client->parent) return MOBILEBACKUP2_E_INVALID_ARG; diff --git a/src/mobilebackup2.h b/src/mobilebackup2.h index 025b6bf..e232b97 100644 --- a/src/mobilebackup2.h +++ b/src/mobilebackup2.h @@ -22,6 +22,7 @@ #ifndef __MOBILEBACKUP2_H #define __MOBILEBACKUP2_H +#include "idevice.h" #include "libimobiledevice/mobilebackup2.h" #include "device_link_service.h" diff --git a/src/mobilesync.c b/src/mobilesync.c index 8881e75..9b81a49 100644 --- a/src/mobilesync.c +++ b/src/mobilesync.c @@ -71,7 +71,7 @@ static mobilesync_error_t mobilesync_error(device_link_service_error_t err) return MOBILESYNC_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_client_new(idevice_t device, lockdownd_service_descriptor_t service, +mobilesync_error_t mobilesync_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobilesync_client_t * client) { if (!device || !service || service->port == 0 || !client || *client) @@ -101,14 +101,14 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_client_new(idevice_t device, return ret; } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_client_start_service(idevice_t device, mobilesync_client_t * client, const char* label) +mobilesync_error_t mobilesync_client_start_service(idevice_t device, mobilesync_client_t * client, const char* label) { mobilesync_error_t err = MOBILESYNC_E_UNKNOWN_ERROR; service_client_factory_start_service(device, MOBILESYNC_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(mobilesync_client_new), &err); return err; } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_client_free(mobilesync_client_t client) +mobilesync_error_t mobilesync_client_free(mobilesync_client_t client) { if (!client) return MOBILESYNC_E_INVALID_ARG; @@ -118,7 +118,7 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_client_free(mobilesync_client return err; } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_receive(mobilesync_client_t client, plist_t * plist) +mobilesync_error_t mobilesync_receive(mobilesync_client_t client, plist_t * plist) { if (!client) return MOBILESYNC_E_INVALID_ARG; @@ -126,14 +126,14 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_receive(mobilesync_client_t c return ret; } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_send(mobilesync_client_t client, plist_t plist) +mobilesync_error_t mobilesync_send(mobilesync_client_t client, plist_t plist) { if (!client || !plist) return MOBILESYNC_E_INVALID_ARG; return mobilesync_error(device_link_service_send(client->parent, plist)); } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_start(mobilesync_client_t client, const char *data_class, mobilesync_anchors_t anchors, uint64_t computer_data_class_version, mobilesync_sync_type_t *sync_type, uint64_t *device_data_class_version, char** error_description) +mobilesync_error_t mobilesync_start(mobilesync_client_t client, const char *data_class, mobilesync_anchors_t anchors, uint64_t computer_data_class_version, mobilesync_sync_type_t *sync_type, uint64_t *device_data_class_version, char** error_description) { if (!client || client->data_class || !data_class || !anchors || !anchors->computer_anchor) { @@ -259,7 +259,7 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_start(mobilesync_client_t cli return err; } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_finish(mobilesync_client_t client) +mobilesync_error_t mobilesync_finish(mobilesync_client_t client) { if (!client || !client->data_class) { return MOBILESYNC_E_INVALID_ARG; @@ -344,17 +344,17 @@ static mobilesync_error_t mobilesync_get_records(mobilesync_client_t client, con return err; } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_get_all_records_from_device(mobilesync_client_t client) +mobilesync_error_t mobilesync_get_all_records_from_device(mobilesync_client_t client) { return mobilesync_get_records(client, "SDMessageGetAllRecordsFromDevice"); } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_get_changes_from_device(mobilesync_client_t client) +mobilesync_error_t mobilesync_get_changes_from_device(mobilesync_client_t client) { return mobilesync_get_records(client, "SDMessageGetChangesFromDevice"); } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_receive_changes(mobilesync_client_t client, plist_t *entities, uint8_t *is_last_record, plist_t *actions) +mobilesync_error_t mobilesync_receive_changes(mobilesync_client_t client, plist_t *entities, uint8_t *is_last_record, plist_t *actions) { if (!client || !client->data_class) { return MOBILESYNC_E_INVALID_ARG; @@ -421,7 +421,7 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_receive_changes(mobilesync_cl return err; } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_clear_all_records_on_device(mobilesync_client_t client) +mobilesync_error_t mobilesync_clear_all_records_on_device(mobilesync_client_t client) { if (!client || !client->data_class) { return MOBILESYNC_E_INVALID_ARG; @@ -473,7 +473,7 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_clear_all_records_on_device(m goto out; } - if (strcmp(response_type, "SDMessageDeviceWillClearAllRecords")) { + if (strcmp(response_type, "SDMessageDeviceWillClearAllRecords") != 0) { err = MOBILESYNC_E_PLIST_ERROR; } @@ -490,7 +490,7 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_clear_all_records_on_device(m return err; } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_acknowledge_changes_from_device(mobilesync_client_t client) +mobilesync_error_t mobilesync_acknowledge_changes_from_device(mobilesync_client_t client) { if (!client || !client->data_class) { return MOBILESYNC_E_INVALID_ARG; @@ -524,7 +524,7 @@ static plist_t create_process_changes_message(const char *data_class, plist_t en return msg; } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_ready_to_send_changes_from_computer(mobilesync_client_t client) +mobilesync_error_t mobilesync_ready_to_send_changes_from_computer(mobilesync_client_t client) { if (!client || !client->data_class) { return MOBILESYNC_E_INVALID_ARG; @@ -591,7 +591,7 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_ready_to_send_changes_from_co return err; } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_send_changes(mobilesync_client_t client, plist_t entities, uint8_t is_last_record, plist_t actions) +mobilesync_error_t mobilesync_send_changes(mobilesync_client_t client, plist_t entities, uint8_t is_last_record, plist_t actions) { if (!client || !client->data_class || !entities) { return MOBILESYNC_E_INVALID_ARG; @@ -619,7 +619,7 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_send_changes(mobilesync_clien return err; } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_remap_identifiers(mobilesync_client_t client, plist_t *mapping) +mobilesync_error_t mobilesync_remap_identifiers(mobilesync_client_t client, plist_t *mapping) { if (!client || !client->data_class) { return MOBILESYNC_E_INVALID_ARG; @@ -688,7 +688,7 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_remap_identifiers(mobilesync_ return err; } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_cancel(mobilesync_client_t client, const char* reason) +mobilesync_error_t mobilesync_cancel(mobilesync_client_t client, const char* reason) { if (!client || !client->data_class || !reason) { return MOBILESYNC_E_INVALID_ARG; @@ -714,7 +714,7 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_cancel(mobilesync_client_t cl return err; } -LIBIMOBILEDEVICE_API mobilesync_anchors_t mobilesync_anchors_new(const char *device_anchor, const char *computer_anchor) +mobilesync_anchors_t mobilesync_anchors_new(const char *device_anchor, const char *computer_anchor) { mobilesync_anchors_t anchors = (mobilesync_anchors_t) malloc(sizeof(mobilesync_anchors)); if (device_anchor != NULL) { @@ -731,7 +731,7 @@ LIBIMOBILEDEVICE_API mobilesync_anchors_t mobilesync_anchors_new(const char *dev return anchors; } -LIBIMOBILEDEVICE_API void mobilesync_anchors_free(mobilesync_anchors_t anchors) +void mobilesync_anchors_free(mobilesync_anchors_t anchors) { if (anchors->device_anchor != NULL) { free(anchors->device_anchor); @@ -745,12 +745,12 @@ LIBIMOBILEDEVICE_API void mobilesync_anchors_free(mobilesync_anchors_t anchors) anchors = NULL; } -LIBIMOBILEDEVICE_API plist_t mobilesync_actions_new(void) +plist_t mobilesync_actions_new(void) { return plist_new_dict(); } -LIBIMOBILEDEVICE_API void mobilesync_actions_add(plist_t actions, ...) +void mobilesync_actions_add(plist_t actions, ...) { if (!actions) return; @@ -782,7 +782,7 @@ LIBIMOBILEDEVICE_API void mobilesync_actions_add(plist_t actions, ...) va_end(args); } -LIBIMOBILEDEVICE_API void mobilesync_actions_free(plist_t actions) +void mobilesync_actions_free(plist_t actions) { if (actions) { plist_free(actions); diff --git a/src/mobilesync.h b/src/mobilesync.h index f672252..3b5ece9 100644 --- a/src/mobilesync.h +++ b/src/mobilesync.h @@ -23,6 +23,7 @@ #ifndef __MOBILESYNC_H #define __MOBILESYNC_H +#include "idevice.h" #include "libimobiledevice/mobilesync.h" #include "device_link_service.h" diff --git a/src/notification_proxy.c b/src/notification_proxy.c index e17e2fe..60b2e03 100644 --- a/src/notification_proxy.c +++ b/src/notification_proxy.c @@ -89,7 +89,7 @@ static np_error_t np_error(property_list_service_error_t err) return NP_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API np_error_t np_client_new(idevice_t device, lockdownd_service_descriptor_t service, np_client_t *client) +np_error_t np_client_new(idevice_t device, lockdownd_service_descriptor_t service, np_client_t *client) { property_list_service_client_t plistclient = NULL; np_error_t err = np_error(property_list_service_client_new(device, service, &plistclient)); @@ -107,14 +107,14 @@ LIBIMOBILEDEVICE_API np_error_t np_client_new(idevice_t device, lockdownd_servic return NP_E_SUCCESS; } -LIBIMOBILEDEVICE_API np_error_t np_client_start_service(idevice_t device, np_client_t* client, const char* label) +np_error_t np_client_start_service(idevice_t device, np_client_t* client, const char* label) { np_error_t err = NP_E_UNKNOWN_ERROR; service_client_factory_start_service(device, NP_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(np_client_new), &err); return err; } -LIBIMOBILEDEVICE_API np_error_t np_client_free(np_client_t client) +np_error_t np_client_free(np_client_t client) { plist_t dict; property_list_service_client_t parent; @@ -168,7 +168,7 @@ LIBIMOBILEDEVICE_API np_error_t np_client_free(np_client_t client) return NP_E_SUCCESS; } -LIBIMOBILEDEVICE_API np_error_t np_post_notification(np_client_t client, const char *notification) +np_error_t np_post_notification(np_client_t client, const char *notification) { if (!client || !notification) { return NP_E_INVALID_ARG; @@ -204,7 +204,7 @@ static np_error_t internal_np_observe_notification(np_client_t client, const cha return res; } -LIBIMOBILEDEVICE_API np_error_t np_observe_notification( np_client_t client, const char *notification ) +np_error_t np_observe_notification( np_client_t client, const char *notification ) { if (!client || !notification) { return NP_E_INVALID_ARG; @@ -215,7 +215,7 @@ LIBIMOBILEDEVICE_API np_error_t np_observe_notification( np_client_t client, con return res; } -LIBIMOBILEDEVICE_API np_error_t np_observe_notifications(np_client_t client, const char **notification_spec) +np_error_t np_observe_notifications(np_client_t client, const char **notification_spec) { int i = 0; np_error_t res = NP_E_UNKNOWN_ERROR; @@ -346,7 +346,7 @@ void* np_notifier( void* arg ) return NULL; } -LIBIMOBILEDEVICE_API np_error_t np_set_notify_callback( np_client_t client, np_notify_cb_t notify_cb, void *user_data ) +np_error_t np_set_notify_callback( np_client_t client, np_notify_cb_t notify_cb, void *user_data ) { if (!client) return NP_E_INVALID_ARG; diff --git a/src/notification_proxy.h b/src/notification_proxy.h index ea85149..595cb01 100644 --- a/src/notification_proxy.h +++ b/src/notification_proxy.h @@ -22,6 +22,7 @@ #ifndef __NOTIFICATION_PROXY_H #define __NOTIFICATION_PROXY_H +#include "idevice.h" #include "libimobiledevice/notification_proxy.h" #include "property_list_service.h" #include <libimobiledevice-glue/thread.h> diff --git a/src/preboard.c b/src/preboard.c index b975f0e..c3eff02 100644 --- a/src/preboard.c +++ b/src/preboard.c @@ -62,7 +62,7 @@ static preboard_error_t preboard_error(property_list_service_error_t err) return PREBOARD_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API preboard_error_t preboard_client_new(idevice_t device, lockdownd_service_descriptor_t service, preboard_client_t * client) +preboard_error_t preboard_client_new(idevice_t device, lockdownd_service_descriptor_t service, preboard_client_t * client) { *client = NULL; @@ -90,14 +90,14 @@ LIBIMOBILEDEVICE_API preboard_error_t preboard_client_new(idevice_t device, lock return 0; } -LIBIMOBILEDEVICE_API preboard_error_t preboard_client_start_service(idevice_t device, preboard_client_t * client, const char* label) +preboard_error_t preboard_client_start_service(idevice_t device, preboard_client_t * client, const char* label) { preboard_error_t err = PREBOARD_E_UNKNOWN_ERROR; service_client_factory_start_service(device, PREBOARD_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(preboard_client_new), &err); return err; } -LIBIMOBILEDEVICE_API preboard_error_t preboard_client_free(preboard_client_t client) +preboard_error_t preboard_client_free(preboard_client_t client) { if (!client) return PREBOARD_E_INVALID_ARG; @@ -116,7 +116,7 @@ LIBIMOBILEDEVICE_API preboard_error_t preboard_client_free(preboard_client_t cli return err; } -LIBIMOBILEDEVICE_API preboard_error_t preboard_send(preboard_client_t client, plist_t plist) +preboard_error_t preboard_send(preboard_client_t client, plist_t plist) { preboard_error_t res = PREBOARD_E_UNKNOWN_ERROR; res = preboard_error(property_list_service_send_binary_plist(client->parent, plist)); @@ -127,7 +127,7 @@ LIBIMOBILEDEVICE_API preboard_error_t preboard_send(preboard_client_t client, pl return res; } -LIBIMOBILEDEVICE_API preboard_error_t preboard_receive_with_timeout(preboard_client_t client, plist_t * plist, uint32_t timeout_ms) +preboard_error_t preboard_receive_with_timeout(preboard_client_t client, plist_t * plist, uint32_t timeout_ms) { preboard_error_t res = PREBOARD_E_UNKNOWN_ERROR; plist_t outplist = NULL; @@ -141,7 +141,7 @@ LIBIMOBILEDEVICE_API preboard_error_t preboard_receive_with_timeout(preboard_cli return res; } -LIBIMOBILEDEVICE_API preboard_error_t preboard_receive(preboard_client_t client, plist_t * plist) +preboard_error_t preboard_receive(preboard_client_t client, plist_t * plist) { return preboard_receive_with_timeout(client, plist, 5000); } @@ -162,7 +162,8 @@ static void* preboard_receive_status_loop_thread(void* arg) preboard_error_t perr = preboard_receive_with_timeout(data->client, &pl, 1000); if (perr == PREBOARD_E_TIMEOUT) { continue; - } else if (perr == PREBOARD_E_SUCCESS) { + } + if (perr == PREBOARD_E_SUCCESS) { data->cbfunc(pl, data->user_data); } plist_free(pl); @@ -208,7 +209,7 @@ static preboard_error_t preboard_receive_status_loop_with_callback(preboard_clie return res; } -LIBIMOBILEDEVICE_API preboard_error_t preboard_create_stashbag(preboard_client_t client, plist_t manifest, preboard_status_cb_t status_cb, void *user_data) +preboard_error_t preboard_create_stashbag(preboard_client_t client, plist_t manifest, preboard_status_cb_t status_cb, void *user_data) { if (!client) { return PREBOARD_E_INVALID_ARG; @@ -231,7 +232,7 @@ LIBIMOBILEDEVICE_API preboard_error_t preboard_create_stashbag(preboard_client_t return preboard_receive_status_loop_with_callback(client, status_cb, user_data); } -LIBIMOBILEDEVICE_API preboard_error_t preboard_commit_stashbag(preboard_client_t client, plist_t manifest, preboard_status_cb_t status_cb, void *user_data) +preboard_error_t preboard_commit_stashbag(preboard_client_t client, plist_t manifest, preboard_status_cb_t status_cb, void *user_data) { if (!client) { return PREBOARD_E_INVALID_ARG; diff --git a/src/preboard.h b/src/preboard.h index 61263fc..f8164eb 100644 --- a/src/preboard.h +++ b/src/preboard.h @@ -22,6 +22,7 @@ #ifndef __PREBOARD_H #define __PREBOARD_H +#include "idevice.h" #include "libimobiledevice/preboard.h" #include "property_list_service.h" #include <libimobiledevice-glue/thread.h> diff --git a/src/property_list_service.c b/src/property_list_service.c index 7b5c738..2fca4e7 100644 --- a/src/property_list_service.c +++ b/src/property_list_service.c @@ -58,7 +58,7 @@ static property_list_service_error_t service_to_property_list_service_error(serv return PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_client_new(idevice_t device, lockdownd_service_descriptor_t service, 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 || !service || service->port == 0 || !client || *client) return PROPERTY_LIST_SERVICE_E_INVALID_ARG; @@ -78,7 +78,7 @@ LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_client_ return PROPERTY_LIST_SERVICE_E_SUCCESS; } -LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_client_free(property_list_service_client_t client) +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; @@ -152,12 +152,12 @@ static property_list_service_error_t internal_plist_send(property_list_service_c return res; } -LIBIMOBILEDEVICE_API 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_xml_plist(property_list_service_client_t client, plist_t plist) { return internal_plist_send(client, plist, 0); } -LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_send_binary_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) { return internal_plist_send(client, plist, 1); } @@ -262,27 +262,34 @@ static property_list_service_error_t internal_plist_receive_timeout(property_lis return res; } -LIBIMOBILEDEVICE_API 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_with_timeout(property_list_service_client_t client, plist_t *plist, unsigned int timeout) { return internal_plist_receive_timeout(client, plist, timeout); } -LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_receive_plist(property_list_service_client_t client, plist_t *plist) +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, 30000); } -LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_enable_ssl(property_list_service_client_t client) +property_list_service_error_t property_list_service_enable_ssl(property_list_service_client_t client) { if (!client || !client->parent) return PROPERTY_LIST_SERVICE_E_INVALID_ARG; return service_to_property_list_service_error(service_enable_ssl(client->parent)); } -LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_disable_ssl(property_list_service_client_t client) +property_list_service_error_t property_list_service_disable_ssl(property_list_service_client_t client) { if (!client || !client->parent) return PROPERTY_LIST_SERVICE_E_INVALID_ARG; 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; +} diff --git a/src/property_list_service.h b/src/property_list_service.h index 3c9e14d..0e9e948 100644 --- a/src/property_list_service.h +++ b/src/property_list_service.h @@ -22,6 +22,7 @@ #ifndef __PROPERTY_LIST_SERVICE_H #define __PROPERTY_LIST_SERVICE_H +#include "idevice.h" #include "libimobiledevice/property_list_service.h" #include "service.h" diff --git a/src/restore.c b/src/restore.c index 4e9d65a..d13a28a 100644 --- a/src/restore.c +++ b/src/restore.c @@ -111,7 +111,7 @@ static restored_error_t restored_error(property_list_service_error_t err) return RESTORE_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API restored_error_t restored_client_free(restored_client_t client) +restored_error_t restored_client_free(restored_client_t client) { if (!client) return RESTORE_E_INVALID_ARG; @@ -139,7 +139,7 @@ LIBIMOBILEDEVICE_API restored_error_t restored_client_free(restored_client_t cli return ret; } -LIBIMOBILEDEVICE_API void restored_client_set_label(restored_client_t client, const char *label) +void restored_client_set_label(restored_client_t client, const char *label) { if (client) { if (client->label) @@ -149,7 +149,7 @@ LIBIMOBILEDEVICE_API void restored_client_set_label(restored_client_t client, co } } -LIBIMOBILEDEVICE_API restored_error_t restored_receive(restored_client_t client, plist_t *plist) +restored_error_t restored_receive(restored_client_t client, plist_t *plist) { if (!client || !plist || (plist && *plist)) return RESTORE_E_INVALID_ARG; @@ -157,7 +157,7 @@ LIBIMOBILEDEVICE_API restored_error_t restored_receive(restored_client_t client, return restored_error(property_list_service_receive_plist(client->parent, plist)); } -LIBIMOBILEDEVICE_API restored_error_t restored_send(restored_client_t client, plist_t plist) +restored_error_t restored_send(restored_client_t client, plist_t plist) { if (!client || !plist) return RESTORE_E_INVALID_ARG; @@ -165,7 +165,7 @@ LIBIMOBILEDEVICE_API restored_error_t restored_send(restored_client_t client, pl return restored_error(property_list_service_send_xml_plist(client->parent, plist)); } -LIBIMOBILEDEVICE_API restored_error_t restored_query_type(restored_client_t client, char **type, uint64_t *version) +restored_error_t restored_query_type(restored_client_t client, char **type, uint64_t *version) { if (!client) return RESTORE_E_INVALID_ARG; @@ -224,7 +224,7 @@ LIBIMOBILEDEVICE_API restored_error_t restored_query_type(restored_client_t clie return ret; } -LIBIMOBILEDEVICE_API restored_error_t restored_query_value(restored_client_t client, const char *key, plist_t *value) +restored_error_t restored_query_value(restored_client_t client, const char *key, plist_t *value) { if (!client || !key) return RESTORE_E_INVALID_ARG; @@ -266,34 +266,32 @@ LIBIMOBILEDEVICE_API restored_error_t restored_query_value(restored_client_t cli return ret; } -LIBIMOBILEDEVICE_API restored_error_t restored_get_value(restored_client_t client, const char *key, plist_t *value) +restored_error_t restored_get_value(restored_client_t client, const char *key, plist_t *value) { + plist_t item; + if (!client || !value || (value && *value)) return RESTORE_E_INVALID_ARG; if (!client->info) return RESTORE_E_NOT_ENOUGH_DATA; - restored_error_t ret = RESTORE_E_SUCCESS; - plist_t item = NULL; - if (!key) { *value = plist_copy(client->info); return RESTORE_E_SUCCESS; - } else { - item = plist_dict_get_item(client->info, key); } - if (item) { - *value = plist_copy(item); - } else { - ret = RESTORE_E_PLIST_ERROR; + item = plist_dict_get_item(client->info, key); + if (!item) { + return RESTORE_E_PLIST_ERROR; } - return ret; + *value = plist_copy(item); + + return RESTORE_E_SUCCESS; } -LIBIMOBILEDEVICE_API restored_error_t restored_client_new(idevice_t device, restored_client_t *client, const char *label) +restored_error_t restored_client_new(idevice_t device, restored_client_t *client, const char *label) { if (!client) return RESTORE_E_INVALID_ARG; @@ -337,7 +335,7 @@ LIBIMOBILEDEVICE_API restored_error_t restored_client_new(idevice_t device, rest return ret; } -LIBIMOBILEDEVICE_API restored_error_t restored_goodbye(restored_client_t client) +restored_error_t restored_goodbye(restored_client_t client) { if (!client) return RESTORE_E_INVALID_ARG; @@ -369,7 +367,7 @@ LIBIMOBILEDEVICE_API restored_error_t restored_goodbye(restored_client_t client) return ret; } -LIBIMOBILEDEVICE_API restored_error_t restored_start_restore(restored_client_t client, plist_t options, uint64_t version) +restored_error_t restored_start_restore(restored_client_t client, plist_t options, uint64_t version) { if (!client) return RESTORE_E_INVALID_ARG; @@ -393,7 +391,7 @@ LIBIMOBILEDEVICE_API restored_error_t restored_start_restore(restored_client_t c return ret; } -LIBIMOBILEDEVICE_API restored_error_t restored_reboot(restored_client_t client) +restored_error_t restored_reboot(restored_client_t client) { if (!client) return RESTORE_E_INVALID_ARG; diff --git a/src/restore.h b/src/restore.h index 646d1d1..ec6fa04 100644 --- a/src/restore.h +++ b/src/restore.h @@ -24,6 +24,7 @@ #include <string.h> +#include "idevice.h" #include "libimobiledevice/restore.h" #include "property_list_service.h" diff --git a/src/reverse_proxy.c b/src/reverse_proxy.c new file mode 100644 index 0000000..2fcfdd1 --- /dev/null +++ b/src/reverse_proxy.c @@ -0,0 +1,810 @@ +/* + * reverse_proxy.c + * com.apple.PurpleReverseProxy service implementation. + * + * Copyright (c) 2021 Nikias Bassen, All Rights Reserved. + * Copyright (c) 2014 BALATON Zoltan. 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 + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <string.h> +#include <stdlib.h> +#define _GNU_SOURCE 1 +#define __USE_GNU 1 +#include <stdio.h> +#include <errno.h> + +#include <plist/plist.h> +#include <libimobiledevice-glue/thread.h> +#include <libimobiledevice-glue/socket.h> + +#include "reverse_proxy.h" +#include "lockdown.h" +#include "common/debug.h" +#include "endianness.h" +#include "asprintf.h" + +#ifndef ECONNRESET +#define ECONNRESET 108 +#endif +#ifndef ETIMEDOUT +#define ETIMEDOUT 138 +#endif + +#define CTRL_PORT 1082 +#define CTRLCMD "BeginCtrl" +#define HELLOCTRLCMD "HelloCtrl" +#define HELLOCMD "HelloConn" + +#define RP_SYNC_MSG 0x1 +#define RP_PROXY_MSG 0x105 +#define RP_PLIST_MSG 0xbbaa + +/** + * Convert a service_error_t value to a reverse_proxy_error_t value. + * Used internally to get correct error codes. + * + * @param err A service_error_t error code + * + * @return A matching reverse_proxy_error_t error code, + * REVERSE_PROXY_E_UNKNOWN_ERROR otherwise. + */ +static reverse_proxy_error_t reverse_proxy_error(service_error_t err) +{ + switch (err) { + case SERVICE_E_SUCCESS: + return REVERSE_PROXY_E_SUCCESS; + case SERVICE_E_INVALID_ARG: + return REVERSE_PROXY_E_INVALID_ARG; + case SERVICE_E_MUX_ERROR: + return REVERSE_PROXY_E_MUX_ERROR; + case SERVICE_E_SSL_ERROR: + return REVERSE_PROXY_E_SSL_ERROR; + case SERVICE_E_NOT_ENOUGH_DATA: + return REVERSE_PROXY_E_NOT_ENOUGH_DATA; + case SERVICE_E_TIMEOUT: + return REVERSE_PROXY_E_TIMEOUT; + default: + break; + } + return REVERSE_PROXY_E_UNKNOWN_ERROR; +} + +static void _reverse_proxy_log(reverse_proxy_client_t client, const char* format, ...) +{ + if (!client || !client->log_cb) { + return; + } + va_list args; + va_start(args, format); + char* buffer = NULL; + if(vasprintf(&buffer, format, args)<0){} + va_end(args); + client->log_cb(client, buffer, client->log_cb_user_data); + free(buffer); +} + +static void _reverse_proxy_data(reverse_proxy_client_t client, int direction, char* buffer, uint32_t length) +{ + if (!client || !client->data_cb) { + return; + } + client->data_cb(client, direction, buffer, length, client->data_cb_user_data); +} + +static void _reverse_proxy_status(reverse_proxy_client_t client, int status, const char* format, ...) +{ + if (!client || !client->status_cb) { + return; + } + va_list args; + va_start(args, format); + char* buffer = NULL; + if(vasprintf(&buffer, format, args)<0){} + va_end(args); + client->status_cb(client, status, buffer, client->status_cb_user_data); + free(buffer); +} + +static int _reverse_proxy_handle_proxy_cmd(reverse_proxy_client_t client) +{ + reverse_proxy_error_t err = REVERSE_PROXY_E_SUCCESS; + char *buf = NULL; + size_t bufsize = 1048576; + uint32_t sent = 0, bytes = 0; + uint32_t sent_total = 0; + uint32_t recv_total = 0; + char *host = NULL; + uint16_t port = 0; + + buf = malloc(bufsize); + if (!buf) { + _reverse_proxy_log(client, "ERROR: Failed to allocate buffer"); + return -1; + } + + err = reverse_proxy_receive(client, buf, bufsize, &bytes); + if (err != REVERSE_PROXY_E_SUCCESS) { + free(buf); + _reverse_proxy_log(client, "ERROR: Unable to read data for proxy command"); + return -1; + } + _reverse_proxy_log(client, "Handling proxy command"); + + /* Just return success here unconditionally because we don't know + * anything else and we will eventually abort on failure anyway */ + uint16_t ack = 5; + err = reverse_proxy_send(client, (char *)&ack, sizeof(ack), &sent); + if (err != REVERSE_PROXY_E_SUCCESS || sent != sizeof(ack)) { + free(buf); + _reverse_proxy_log(client, "ERROR: Unable to send ack. Sent %u of %u bytes.", sent, (uint32_t)sizeof(ack)); + return -1; + } + + if (bytes < 3) { + free(buf); + _reverse_proxy_log(client, "Proxy command data too short, retrying"); + return 0; + } + + /* ack command data too */ + err = reverse_proxy_send(client, buf, bytes, &sent); + if (err != REVERSE_PROXY_E_SUCCESS || sent != bytes) { + free(buf); + _reverse_proxy_log(client, "ERROR: Unable to send data. Sent %u of %u bytes.", sent, bytes); + return -1; + } + + /* Now try to handle actual messages */ + /* Connect: 0 3 hostlen <host> <port> */ + if (buf[0] == 0 && buf[1] == 3) { + uint16_t *p = (uint16_t *)&buf[bytes - 2]; + port = be16toh(*p); + buf[bytes - 2] = '\0'; + host = strdup(&buf[3]); + _reverse_proxy_log(client, "Connect request to %s:%u", host, port); + } + + if (!host || !buf[2]) { + /* missing or zero length host name */ + free(buf); + return 0; + } + + /* else wait for messages and forward them */ + int sockfd = socket_connect(host, port); + if (sockfd < 0) { + free(buf); + _reverse_proxy_log(client, "ERROR: Connection to %s:%u failed: %s", host, port, strerror(errno)); + free(host); + return -1; + } + + _reverse_proxy_status(client, RP_STATUS_CONNECTED, "Connected to %s:%u", host, port); + + int res = 0, bytes_ret; + while (1) { + bytes = 0; + err = reverse_proxy_receive_with_timeout(client, buf, bufsize, &bytes, 100); + if (err == REVERSE_PROXY_E_TIMEOUT || (err == REVERSE_PROXY_E_SUCCESS && !bytes)) { + /* just a timeout condition */ + } + else if (err != REVERSE_PROXY_E_SUCCESS) { + _reverse_proxy_log(client, "Connection closed"); + res = -1; + break; + } + if (bytes) { + _reverse_proxy_log(client, "Proxying %u bytes of data", bytes); + _reverse_proxy_data(client, RP_DATA_DIRECTION_OUT, buf, bytes); + sent = 0; + while (sent < bytes) { + int s = socket_send(sockfd, buf + sent, bytes - sent); + if (s < 0) { + break; + } + sent += s; + } + sent_total += sent; + if (sent != bytes) { + _reverse_proxy_log(client, "ERROR: Sending proxy payload failed: %s. Sent %u of %u bytes.", strerror(errno), sent, bytes); + socket_close(sockfd); + res = -1; + break; + } + } + bytes_ret = socket_receive_timeout(sockfd, buf, bufsize, 0, 100); + if (bytes_ret == -ETIMEDOUT) { + bytes_ret = 0; + } else if (bytes_ret == -ECONNRESET) { + res = 1; + break; + } else if (bytes_ret < 0) { + _reverse_proxy_log(client, "ERROR: Failed to receive from host: %s", strerror(-bytes_ret)); + break; + } + + bytes = bytes_ret; + if (bytes) { + _reverse_proxy_log(client, "Received %u bytes reply data, sending to device\n", bytes); + _reverse_proxy_data(client, RP_DATA_DIRECTION_IN, buf, bytes); + recv_total += bytes; + sent = 0; + while (sent < bytes) { + uint32_t s; + err = reverse_proxy_send(client, buf + sent, bytes - sent, &s); + if (err != REVERSE_PROXY_E_SUCCESS) { + break; + } + sent += s; + } + if (err != REVERSE_PROXY_E_SUCCESS || bytes != sent) { + _reverse_proxy_log(client, "ERROR: Unable to send data (%d). Sent %u of %u bytes.", err, sent, bytes); + res = -1; + break; + } + } + } + socket_close(sockfd); + free(host); + free(buf); + + _reverse_proxy_status(client, RP_STATUS_DISCONNECTED, "Disconnected (out: %u / in: %u)", sent_total, recv_total); + + return res; +} + +static int _reverse_proxy_handle_plist_cmd(reverse_proxy_client_t client) +{ + plist_t dict; + reverse_proxy_error_t err; + + err = reverse_proxy_receive_plist(client, &dict); + if (err != REVERSE_PROXY_E_SUCCESS) { + _reverse_proxy_log(client, "ERROR: Unable to receive plist command, error", err); + return -1; + } + plist_t node = plist_dict_get_item(dict, "Command"); + if (!node || (plist_get_node_type(node) != PLIST_STRING)) { + _reverse_proxy_log(client, "ERROR: No 'Command' in reply", err); + plist_free(dict); + return -1; + } + char *command = NULL; + plist_get_string_val(node, &command); + plist_free(dict); + + if (!command) { + _reverse_proxy_log(client, "ERROR: Empty 'Command' string"); + return -1; + } + + if (!strcmp(command, "Ping")) { + _reverse_proxy_log(client, "Received Ping command, replying with Pong"); + dict = plist_new_dict(); + plist_dict_set_item(dict, "Pong", plist_new_bool(1)); + err = reverse_proxy_send_plist(client, dict); + plist_free(dict); + if (err) { + _reverse_proxy_log(client, "ERROR: Unable to send Ping command reply"); + free(command); + return -1; + } + } else { + _reverse_proxy_log(client, "WARNING: Received unhandled plist command '%s'", command); + free(command); + return -1; + } + + free(command); + /* reverse proxy connection will be terminated remotely. Next receive will get nothing, error and terminate this worker thread. */ + return 0; +} + +static reverse_proxy_error_t reverse_proxy_client_new(idevice_t device, lockdownd_service_descriptor_t service, reverse_proxy_client_t * client) +{ + *client = NULL; + + if (!device || !service || service->port == 0 || !client || *client) { + return REVERSE_PROXY_E_INVALID_ARG; + } + + debug_info("Creating reverse_proxy_client, port = %d.", service->port); + + service_client_t sclient = NULL; + reverse_proxy_error_t ret = reverse_proxy_error(service_client_new(device, service, &sclient)); + if (ret != REVERSE_PROXY_E_SUCCESS) { + debug_info("Creating service client failed. Error: %i", ret); + return ret; + } + + reverse_proxy_client_t client_loc = (reverse_proxy_client_t) calloc(1, sizeof(struct reverse_proxy_client_private)); + client_loc->parent = sclient; + client_loc->th_ctrl = THREAD_T_NULL; + *client = client_loc; + + return 0; +} + +static void* _reverse_proxy_connection_thread(void *cdata) +{ + reverse_proxy_client_t client = (reverse_proxy_client_t)cdata; + uint32_t bytes = 0; + reverse_proxy_client_t conn_client = NULL; + reverse_proxy_error_t err = REVERSE_PROXY_E_UNKNOWN_ERROR; + + if (client->conn_port == 0) { + service_client_factory_start_service(client->parent->connection->device, "com.apple.PurpleReverseProxy.Conn", (void**)&conn_client, client->label, SERVICE_CONSTRUCTOR(reverse_proxy_client_new), &err); + if (!conn_client) { + _reverse_proxy_log(client, "ERROR: Failed to start proxy connection service, error %d", err); + } + } else { + struct lockdownd_service_descriptor svc; + svc.port = client->conn_port; + svc.ssl_enabled = 0; + svc.identifier = NULL; + err = reverse_proxy_client_new(client->parent->connection->device, &svc, &conn_client); + if (!conn_client) { + _reverse_proxy_log(client, "ERROR: Failed to connect to proxy connection port %u, error %d", client->conn_port, err); + } + } + if (!conn_client) { + goto leave; + } + conn_client->type = RP_TYPE_CONN; + conn_client->protoversion = client->protoversion; + conn_client->log_cb = client->log_cb; + conn_client->log_cb_user_data = client->log_cb_user_data; + conn_client->status_cb = client->status_cb; + conn_client->status_cb_user_data = client->status_cb_user_data; + + err = reverse_proxy_send(conn_client, HELLOCMD, sizeof(HELLOCMD), &bytes); + if (err != REVERSE_PROXY_E_SUCCESS || bytes != sizeof(HELLOCMD)) { + _reverse_proxy_log(conn_client, "ERROR: Unable to send " HELLOCMD " (sent %u/%u bytes)", bytes, sizeof(HELLOCMD)); + goto leave; + } + + if (conn_client->protoversion == 2) { + plist_t reply = NULL; + err = reverse_proxy_receive_plist(conn_client, &reply); + if (err != REVERSE_PROXY_E_SUCCESS) { + _reverse_proxy_log(conn_client, "ERROR: Did not receive " HELLOCMD " reply, error %d", err); + goto leave; + } + char* identifier = NULL; + char* cmd = NULL; + plist_t node = NULL; + node = plist_dict_get_item(reply, "Command"); + if (node) { + plist_get_string_val(node, &cmd); + } + node = plist_dict_get_item(reply, "Identifier"); + if (node) { + plist_get_string_val(node, &identifier); + } + plist_free(reply); + + if (!cmd || (strcmp(cmd, HELLOCMD) != 0)) { + free(cmd); + free(identifier); + _reverse_proxy_log(conn_client, "ERROR: Unexpected reply to " HELLOCMD " received"); + goto leave; + } + free(cmd); + + if (identifier) { + _reverse_proxy_log(conn_client, "Got device identifier %s", identifier); + free(identifier); + } + } else { + char buf[16]; + memset(buf, '\0', sizeof(buf)); + bytes = 0; + err = reverse_proxy_receive(conn_client, buf, sizeof(HELLOCMD), &bytes); + if (err != REVERSE_PROXY_E_SUCCESS) { + _reverse_proxy_log(conn_client, "ERROR: Did not receive " HELLOCMD " reply, error %d", err); + goto leave; + } + if (memcmp(buf, HELLOCMD, sizeof(HELLOCMD)) != 0) { + _reverse_proxy_log(conn_client, "ERROR: Did not receive " HELLOCMD " as reply, but %.*s", (int)bytes, buf); + goto leave; + } + } + + _reverse_proxy_status(conn_client, RP_STATUS_READY, "Ready"); + + int running = 1; + while (client->th_ctrl != THREAD_T_NULL && conn_client && running) { + uint16_t cmd = 0; + bytes = 0; + err = reverse_proxy_receive_with_timeout(conn_client, (char*)&cmd, sizeof(cmd), &bytes, 1000); + if (err == REVERSE_PROXY_E_TIMEOUT || (err == REVERSE_PROXY_E_SUCCESS && bytes != sizeof(cmd))) { + continue; + } else if (err != REVERSE_PROXY_E_SUCCESS) { + _reverse_proxy_log(conn_client, "Connection closed"); + break; + } + cmd = le16toh(cmd); + switch (cmd) { + case 0xBBAA: + /* plist command */ + if (_reverse_proxy_handle_plist_cmd(conn_client) < 0) { + running = 0; + } + break; + case 0x105: + /* proxy command */ + if (_reverse_proxy_handle_proxy_cmd(conn_client) < 0) { + running = 0; + } + break; + default: + /* unknown */ + debug_info("ERROR: Unknown request 0x%x", cmd); + _reverse_proxy_log(conn_client, "ERROR: Unknown request 0x%x", cmd); + running = 0; + break; + } + } + +leave: + _reverse_proxy_status(conn_client, RP_STATUS_TERMINATE, "Terminated"); + if (conn_client) { + reverse_proxy_client_free(conn_client); + } + + return NULL; +} + +static void* _reverse_proxy_control_thread(void *cdata) +{ + reverse_proxy_client_t client = (reverse_proxy_client_t)cdata; + THREAD_T th_conn = THREAD_T_NULL; + int running = 1; + _reverse_proxy_status(client, RP_STATUS_READY, "Ready"); + while (client && client->parent && running) { + uint32_t cmd = 0; + uint32_t bytes = 0; + reverse_proxy_error_t err = reverse_proxy_receive_with_timeout(client, (char*)&cmd, sizeof(cmd), &bytes, 1000); + if (err == REVERSE_PROXY_E_TIMEOUT || (err == REVERSE_PROXY_E_SUCCESS && bytes != sizeof(cmd))) { + continue; + } else if (err != REVERSE_PROXY_E_SUCCESS) { + _reverse_proxy_log(client, "Connection closed"); + break; + } + cmd = le32toh(cmd); + switch (cmd) { + case 1: + /* connection request */ + debug_info("ReverseProxy<%p> got connect request", client); + _reverse_proxy_status(client, RP_STATUS_CONNECT_REQ, "Connect Request"); + if (thread_new(&th_conn, _reverse_proxy_connection_thread, client) != 0) { + debug_info("ERROR: Failed to start connection thread"); + th_conn = THREAD_T_NULL; + running = 0; + } + break; + case 2: + /* shutdown request */ + debug_info("ReverseProxy<%p> got shutdown request", client); + _reverse_proxy_status(client, RP_STATUS_SHUTDOWN_REQ, "Shutdown Request"); + running = 0; + break; + default: + /* unknown */ + debug_info("ERROR: Unknown request 0x%x", cmd); + _reverse_proxy_log(client, "ERROR: Unknown request 0x%x", cmd); + running = 0; + break; + } + } + _reverse_proxy_log(client, "Terminating"); + + client->th_ctrl = THREAD_T_NULL; + if (th_conn) { + debug_info("joining connection thread"); + thread_join(th_conn); + thread_free(th_conn); + } + + _reverse_proxy_status(client, RP_STATUS_TERMINATE, "Terminated"); + + return NULL; +} + +reverse_proxy_error_t reverse_proxy_client_start_proxy(reverse_proxy_client_t client, int control_protocol_version) +{ + char buf[16] = {0, }; + uint32_t bytes = 0; + reverse_proxy_error_t err = REVERSE_PROXY_E_UNKNOWN_ERROR; + + if (!client) { + return REVERSE_PROXY_E_INVALID_ARG; + } + if (control_protocol_version < 1 || control_protocol_version > 2) { + debug_info("invalid protocol version %d, must be 1 or 2", control_protocol_version); + return REVERSE_PROXY_E_INVALID_ARG; + } + + if (control_protocol_version == 2) { + err = reverse_proxy_send(client, CTRLCMD, sizeof(CTRLCMD), &bytes); + if (err != REVERSE_PROXY_E_SUCCESS) { + _reverse_proxy_log(client, "ERROR: Failed to send " CTRLCMD " to device, error %d", err); + return err; + } + plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "Command", plist_new_string(CTRLCMD)); + plist_dict_set_item(dict, "CtrlProtoVersion", plist_new_uint(client->protoversion)); + err = reverse_proxy_send_plist(client, dict); + plist_free(dict); + if (err != REVERSE_PROXY_E_SUCCESS) { + _reverse_proxy_log(client, "ERROR: Could not send " CTRLCMD " plist command, error %d", err); + return err; + } + dict = NULL; + err = reverse_proxy_receive_plist(client, &dict); + if (err != REVERSE_PROXY_E_SUCCESS) { + _reverse_proxy_log(client, "ERROR: Could not receive " CTRLCMD " plist reply, error %d", err); + return err; + } + plist_t node = plist_dict_get_item(dict, "ConnPort"); + if (node && plist_get_node_type(node) == PLIST_UINT) { + uint64_t u64val = 0; + plist_get_uint_val(node, &u64val); + client->conn_port = (uint16_t)u64val; + } else { + _reverse_proxy_log(client, "ERROR: Could not get ConnPort value"); + return REVERSE_PROXY_E_UNKNOWN_ERROR; + } + client->protoversion = 2; + } else { + err = reverse_proxy_send(client, HELLOCTRLCMD, sizeof(HELLOCTRLCMD), &bytes); + if (err != REVERSE_PROXY_E_SUCCESS) { + _reverse_proxy_log(client, "ERROR: Failed to send " HELLOCTRLCMD " to device, error %d", err); + return err; + } + + bytes = 0; + err = reverse_proxy_receive(client, buf, sizeof(HELLOCTRLCMD)-1, &bytes); + if (err != REVERSE_PROXY_E_SUCCESS) { + _reverse_proxy_log(client, "ERROR: Could not receive " HELLOCTRLCMD " reply, error %d", err); + return err; + } + + uint16_t cport = 0; + bytes = 0; + err = reverse_proxy_receive(client, (char*)&cport, 2, &bytes); + if (err != REVERSE_PROXY_E_SUCCESS) { + _reverse_proxy_log(client, "ERROR: Failed to receive connection port, error %d", err); + return err; + } + client->conn_port = le16toh(cport); + client->protoversion = 1; + } + + if (thread_new(&(client->th_ctrl), _reverse_proxy_control_thread, client) != 0) { + _reverse_proxy_log(client, "ERROR: Failed to start control thread"); + client->th_ctrl = THREAD_T_NULL; /* undefined after failure */ + err = REVERSE_PROXY_E_UNKNOWN_ERROR; + } + + return err; +} + +reverse_proxy_error_t reverse_proxy_client_create_with_service(idevice_t device, reverse_proxy_client_t* client, const char* label) +{ + reverse_proxy_error_t err = REVERSE_PROXY_E_UNKNOWN_ERROR; + service_client_factory_start_service(device, "com.apple.PurpleReverseProxy.Ctrl", (void**)client, label, SERVICE_CONSTRUCTOR(reverse_proxy_client_new), &err); + if (!*client) { + return err; + } + (*client)->label = strdup(label); + (*client)->type = RP_TYPE_CTRL; + + return REVERSE_PROXY_E_SUCCESS; +} + +reverse_proxy_error_t reverse_proxy_client_create_with_port(idevice_t device, reverse_proxy_client_t* client, uint16_t device_port) +{ + reverse_proxy_client_t client_loc = NULL; + reverse_proxy_error_t err; + + struct lockdownd_service_descriptor svc; + svc.port = device_port; + svc.ssl_enabled = 0; + svc.identifier = NULL; + + err = reverse_proxy_client_new(device, &svc, &client_loc); + if (err != REVERSE_PROXY_E_SUCCESS) { + return err; + } + + client_loc->type = RP_TYPE_CTRL; + *client = client_loc; + + return REVERSE_PROXY_E_SUCCESS; +} + +reverse_proxy_error_t reverse_proxy_client_free(reverse_proxy_client_t client) +{ + if (!client) + return REVERSE_PROXY_E_INVALID_ARG; + service_client_t parent = client->parent; + client->parent = NULL; + if (client->th_ctrl) { + debug_info("joining control thread"); + thread_join(client->th_ctrl); + thread_free(client->th_ctrl); + client->th_ctrl = THREAD_T_NULL; + } + reverse_proxy_error_t err = reverse_proxy_error(service_client_free(parent)); + free(client->label); + free(client); + + return err; +} + +reverse_proxy_client_type_t reverse_proxy_get_type(reverse_proxy_client_t client) +{ + if (!client) + return 0; + return client->type; +} + +void reverse_proxy_client_set_status_callback(reverse_proxy_client_t client, reverse_proxy_status_cb_t status_callback, void* user_data) +{ + if (!client) { + return; + } + client->status_cb = status_callback; + client->status_cb_user_data = user_data; +} + +void reverse_proxy_client_set_log_callback(reverse_proxy_client_t client, reverse_proxy_log_cb_t log_callback, void* user_data) +{ + if (!client) { + return; + } + client->log_cb = log_callback; + client->log_cb_user_data = user_data; +} + +void reverse_proxy_client_set_data_callback(reverse_proxy_client_t client, reverse_proxy_data_cb_t data_callback, void* user_data) +{ + if (!client) { + return; + } + client->data_cb = data_callback; + client->data_cb_user_data = user_data; +} + +reverse_proxy_error_t reverse_proxy_send(reverse_proxy_client_t client, const char* data, uint32_t len, uint32_t* sent) +{ + reverse_proxy_error_t err = reverse_proxy_error(service_send(client->parent, data, len, sent)); + return err; +} + +reverse_proxy_error_t reverse_proxy_receive_with_timeout(reverse_proxy_client_t client, char* buffer, uint32_t len, uint32_t* received, unsigned int timeout) +{ + if (!client) + return REVERSE_PROXY_E_INVALID_ARG; + return reverse_proxy_error(service_receive_with_timeout(client->parent, buffer, len, received, timeout)); +} + +reverse_proxy_error_t reverse_proxy_receive(reverse_proxy_client_t client, char* buffer, uint32_t len, uint32_t* received) +{ + return reverse_proxy_receive_with_timeout(client, buffer, len, received, 20000); +} + +reverse_proxy_error_t reverse_proxy_send_plist(reverse_proxy_client_t client, plist_t plist) +{ + reverse_proxy_error_t err; + uint32_t len = 0; + char* buf = NULL; + uint32_t bytes = 0; + + plist_to_bin(plist, &buf, &len); + + if (!buf) { + return REVERSE_PROXY_E_INVALID_ARG; + } + + debug_info("Sending %u bytes", len); + + uint32_t slen = htole32(len); + err = reverse_proxy_send(client, (char*)&slen, sizeof(slen), &bytes); + if (err != REVERSE_PROXY_E_SUCCESS) { + free(buf); + debug_info("ERROR: Unable to send data length, error %d. Sent %u/%u bytes.", err, bytes, (uint32_t)sizeof(slen)); + return err; + } + uint32_t done = 0; + do { + bytes = 0; + err = reverse_proxy_send(client, buf+done, len-done, &bytes); + if (err != REVERSE_PROXY_E_SUCCESS) { + break; + } + done += bytes; + } while (done < len); + free(buf); + if (err != REVERSE_PROXY_E_SUCCESS || done != len) { + debug_info("ERROR: Unable to send data, error %d. Sent %u/%u bytes.", err, done, len); + return err; + } + + debug_info("Sent %u bytes", len); + + return REVERSE_PROXY_E_SUCCESS; +} + +reverse_proxy_error_t reverse_proxy_receive_plist(reverse_proxy_client_t client, plist_t* plist) +{ + return reverse_proxy_receive_plist_with_timeout(client, plist, 20000); +} + +reverse_proxy_error_t reverse_proxy_receive_plist_with_timeout(reverse_proxy_client_t client, plist_t * plist, uint32_t timeout_ms) +{ + uint32_t len; + uint32_t bytes; + reverse_proxy_error_t err; + + err = reverse_proxy_receive_with_timeout(client, (char*)&len, sizeof(len), &bytes, timeout_ms); + if (err != REVERSE_PROXY_E_SUCCESS) { + if (err != REVERSE_PROXY_E_TIMEOUT) { + debug_info("ERROR: Unable to receive packet length, error %d\n", err); + } + return err; + } + + len = le32toh(len); + char* buf = calloc(1, len); + if (!buf) { + debug_info("ERROR: Out of memory"); + return REVERSE_PROXY_E_UNKNOWN_ERROR; + } + + uint32_t done = 0; + do { + bytes = 0; + err = reverse_proxy_receive_with_timeout(client, buf+done, len-done, &bytes, timeout_ms); + if (err != REVERSE_PROXY_E_SUCCESS) { + break; + } + done += bytes; + } while (done < len); + + if (err != REVERSE_PROXY_E_SUCCESS || done != len) { + free(buf); + debug_info("ERROR: Unable to receive data, error %d. Received %u/%u bytes.", err, done, len); + return err; + } + + debug_info("Received %u bytes", len); + + plist_from_bin(buf, len, plist); + free(buf); + + if (!(*plist)) { + debug_info("ERROR: Failed to convert buffer to plist"); + return REVERSE_PROXY_E_PLIST_ERROR; + } + + return REVERSE_PROXY_E_SUCCESS; +} diff --git a/src/reverse_proxy.h b/src/reverse_proxy.h new file mode 100644 index 0000000..7f441bd --- /dev/null +++ b/src/reverse_proxy.h @@ -0,0 +1,51 @@ +/* + * reverse_proxy.h + * com.apple.PurpleReverseProxy service header file. + * + * Copyright (c) 2021 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 __REVERSE_PROXY_H +#define __REVERSE_PROXY_H + +#include "idevice.h" +#include "libimobiledevice/reverse_proxy.h" +#include "service.h" + +struct reverse_proxy_client_private { + service_client_t parent; + char* label; + int type; + int protoversion; + THREAD_T th_ctrl; + uint16_t conn_port; + reverse_proxy_log_cb_t log_cb; + void* log_cb_user_data; + reverse_proxy_data_cb_t data_cb; + void* data_cb_user_data; + reverse_proxy_status_cb_t status_cb; + void* status_cb_user_data; +}; + +reverse_proxy_error_t reverse_proxy_send(reverse_proxy_client_t client, const char* data, uint32_t len, uint32_t* sent); +reverse_proxy_error_t reverse_proxy_receive(reverse_proxy_client_t client, char* buffer, uint32_t len, uint32_t* received); +reverse_proxy_error_t reverse_proxy_receive_with_timeout(reverse_proxy_client_t client, char* buffer, uint32_t len, uint32_t* received, unsigned int timeout); +reverse_proxy_error_t reverse_proxy_send_plist(reverse_proxy_client_t client, plist_t plist); +reverse_proxy_error_t reverse_proxy_receive_plist(reverse_proxy_client_t client, plist_t* plist); +reverse_proxy_error_t reverse_proxy_receive_plist_with_timeout(reverse_proxy_client_t client, plist_t * plist, uint32_t timeout_ms); + +#endif diff --git a/src/sbservices.c b/src/sbservices.c index ccb7c4b..365e130 100644 --- a/src/sbservices.c +++ b/src/sbservices.c @@ -79,7 +79,7 @@ static sbservices_error_t sbservices_error(property_list_service_error_t err) return SBSERVICES_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API sbservices_error_t sbservices_client_new(idevice_t device, lockdownd_service_descriptor_t service, sbservices_client_t *client) +sbservices_error_t sbservices_client_new(idevice_t device, lockdownd_service_descriptor_t service, sbservices_client_t *client) { property_list_service_client_t plistclient = NULL; sbservices_error_t err = sbservices_error(property_list_service_client_new(device, service, &plistclient)); @@ -95,14 +95,14 @@ LIBIMOBILEDEVICE_API sbservices_error_t sbservices_client_new(idevice_t device, return SBSERVICES_E_SUCCESS; } -LIBIMOBILEDEVICE_API sbservices_error_t sbservices_client_start_service(idevice_t device, sbservices_client_t * client, const char* label) +sbservices_error_t sbservices_client_start_service(idevice_t device, sbservices_client_t * client, const char* label) { sbservices_error_t err = SBSERVICES_E_UNKNOWN_ERROR; service_client_factory_start_service(device, SBSERVICES_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(sbservices_client_new), &err); return err; } -LIBIMOBILEDEVICE_API sbservices_error_t sbservices_client_free(sbservices_client_t client) +sbservices_error_t sbservices_client_free(sbservices_client_t client) { if (!client) return SBSERVICES_E_INVALID_ARG; @@ -115,7 +115,7 @@ LIBIMOBILEDEVICE_API sbservices_error_t sbservices_client_free(sbservices_client return err; } -LIBIMOBILEDEVICE_API sbservices_error_t sbservices_get_icon_state(sbservices_client_t client, plist_t *state, const char *format_version) +sbservices_error_t sbservices_get_icon_state(sbservices_client_t client, plist_t *state, const char *format_version) { if (!client || !client->parent || !state) return SBSERVICES_E_INVALID_ARG; @@ -155,7 +155,7 @@ leave_unlock: return res; } -LIBIMOBILEDEVICE_API sbservices_error_t sbservices_set_icon_state(sbservices_client_t client, plist_t newstate) +sbservices_error_t sbservices_set_icon_state(sbservices_client_t client, plist_t newstate) { if (!client || !client->parent || !newstate) return SBSERVICES_E_INVALID_ARG; @@ -172,7 +172,10 @@ LIBIMOBILEDEVICE_API sbservices_error_t sbservices_set_icon_state(sbservices_cli if (res != SBSERVICES_E_SUCCESS) { debug_info("could not send plist, error %d", res); } - /* NO RESPONSE */ + + uint32_t bytes = 0; + service_receive_with_timeout(client->parent->parent, malloc(4), 4, &bytes, 2000); + debug_info("setIconState response: %u", bytes); if (dict) { plist_free(dict); @@ -181,7 +184,7 @@ LIBIMOBILEDEVICE_API sbservices_error_t sbservices_set_icon_state(sbservices_cli return res; } -LIBIMOBILEDEVICE_API sbservices_error_t sbservices_get_icon_pngdata(sbservices_client_t client, const char *bundleId, char **pngdata, uint64_t *pngsize) +sbservices_error_t sbservices_get_icon_pngdata(sbservices_client_t client, const char *bundleId, char **pngdata, uint64_t *pngsize) { if (!client || !client->parent || !bundleId || !pngdata) return SBSERVICES_E_INVALID_ARG; @@ -218,7 +221,7 @@ leave_unlock: return res; } -LIBIMOBILEDEVICE_API sbservices_error_t sbservices_get_interface_orientation(sbservices_client_t client, sbservices_interface_orientation_t* interface_orientation) +sbservices_error_t sbservices_get_interface_orientation(sbservices_client_t client, sbservices_interface_orientation_t* interface_orientation) { if (!client || !client->parent || !interface_orientation) return SBSERVICES_E_INVALID_ARG; @@ -256,7 +259,7 @@ leave_unlock: return res; } -LIBIMOBILEDEVICE_API sbservices_error_t sbservices_get_home_screen_wallpaper_pngdata(sbservices_client_t client, char **pngdata, uint64_t *pngsize) +sbservices_error_t sbservices_get_home_screen_wallpaper_pngdata(sbservices_client_t client, char **pngdata, uint64_t *pngsize) { if (!client || !client->parent || !pngdata) return SBSERVICES_E_INVALID_ARG; diff --git a/src/sbservices.h b/src/sbservices.h index 39d822c..b67281e 100644 --- a/src/sbservices.h +++ b/src/sbservices.h @@ -22,6 +22,7 @@ #ifndef __SBSERVICES_H #define __SBSERVICES_H +#include "idevice.h" #include "libimobiledevice/sbservices.h" #include "property_list_service.h" #include <libimobiledevice-glue/thread.h> diff --git a/src/screenshotr.c b/src/screenshotr.c index 11d6506..c3cc9ba 100644 --- a/src/screenshotr.c +++ b/src/screenshotr.c @@ -65,7 +65,7 @@ static screenshotr_error_t screenshotr_error(device_link_service_error_t err) return SCREENSHOTR_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API screenshotr_error_t screenshotr_client_new(idevice_t device, lockdownd_service_descriptor_t service, +screenshotr_error_t screenshotr_client_new(idevice_t device, lockdownd_service_descriptor_t service, screenshotr_client_t * client) { if (!device || !service || service->port == 0 || !client || *client) @@ -93,14 +93,14 @@ LIBIMOBILEDEVICE_API screenshotr_error_t screenshotr_client_new(idevice_t device return ret; } -LIBIMOBILEDEVICE_API screenshotr_error_t screenshotr_client_start_service(idevice_t device, screenshotr_client_t * client, const char* label) +screenshotr_error_t screenshotr_client_start_service(idevice_t device, screenshotr_client_t * client, const char* label) { screenshotr_error_t err = SCREENSHOTR_E_UNKNOWN_ERROR; service_client_factory_start_service(device, SCREENSHOTR_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(screenshotr_client_new), &err); return err; } -LIBIMOBILEDEVICE_API screenshotr_error_t screenshotr_client_free(screenshotr_client_t client) +screenshotr_error_t screenshotr_client_free(screenshotr_client_t client) { if (!client) return SCREENSHOTR_E_INVALID_ARG; @@ -110,7 +110,7 @@ LIBIMOBILEDEVICE_API screenshotr_error_t screenshotr_client_free(screenshotr_cli return err; } -LIBIMOBILEDEVICE_API screenshotr_error_t screenshotr_take_screenshot(screenshotr_client_t client, char **imgdata, uint64_t *imgsize) +screenshotr_error_t screenshotr_take_screenshot(screenshotr_client_t client, char **imgdata, uint64_t *imgsize) { if (!client || !client->parent || !imgdata) return SCREENSHOTR_E_INVALID_ARG; @@ -142,7 +142,7 @@ LIBIMOBILEDEVICE_API screenshotr_error_t screenshotr_take_screenshot(screenshotr plist_t node = plist_dict_get_item(dict, "MessageType"); char *strval = NULL; plist_get_string_val(node, &strval); - if (!strval || strcmp(strval, "ScreenShotReply")) { + if (!strval || strcmp(strval, "ScreenShotReply") != 0) { debug_info("invalid screenshot data received!"); res = SCREENSHOTR_E_PLIST_ERROR; goto leave; diff --git a/src/screenshotr.h b/src/screenshotr.h index 47d4e42..1319ec0 100644 --- a/src/screenshotr.h +++ b/src/screenshotr.h @@ -22,6 +22,7 @@ #ifndef __SCREENSHOTR_H #define __SCREENSHOTR_H +#include "idevice.h" #include "libimobiledevice/screenshotr.h" #include "device_link_service.h" diff --git a/src/service.c b/src/service.c index 88132d2..9474021 100644 --- a/src/service.c +++ b/src/service.c @@ -56,7 +56,7 @@ static service_error_t idevice_to_service_error(idevice_error_t err) return SERVICE_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API service_error_t service_client_new(idevice_t device, lockdownd_service_descriptor_t service, service_client_t *client) +service_error_t service_client_new(idevice_t device, lockdownd_service_descriptor_t service, service_client_t *client) { if (!device || !service || service->port == 0 || !client || *client) return SERVICE_E_INVALID_ARG; @@ -80,7 +80,7 @@ LIBIMOBILEDEVICE_API service_error_t service_client_new(idevice_t device, lockdo return SERVICE_E_SUCCESS; } -LIBIMOBILEDEVICE_API service_error_t service_client_factory_start_service(idevice_t device, const char* service_name, void **client, const char* label, int32_t (*constructor_func)(idevice_t, lockdownd_service_descriptor_t, void**), int32_t *error_code) +service_error_t service_client_factory_start_service(idevice_t device, const char* service_name, void **client, const char* label, int32_t (*constructor_func)(idevice_t, lockdownd_service_descriptor_t, void**), int32_t *error_code) { *client = NULL; @@ -91,11 +91,11 @@ LIBIMOBILEDEVICE_API service_error_t service_client_factory_start_service(idevic } lockdownd_service_descriptor_t service = NULL; - lockdownd_start_service(lckd, service_name, &service); + lockdownd_error_t lerr = lockdownd_start_service(lckd, service_name, &service); lockdownd_client_free(lckd); - if (!service || service->port == 0) { - debug_info("Could not start service %s!", service_name); + if (lerr != LOCKDOWN_E_SUCCESS) { + debug_info("Could not start service %s: %s", service_name, lockdownd_strerror(lerr)); return SERVICE_E_START_SERVICE_ERROR; } @@ -119,7 +119,7 @@ LIBIMOBILEDEVICE_API service_error_t service_client_factory_start_service(idevic return (ec == SERVICE_E_SUCCESS) ? SERVICE_E_SUCCESS : SERVICE_E_START_SERVICE_ERROR; } -LIBIMOBILEDEVICE_API service_error_t service_client_free(service_client_t client) +service_error_t service_client_free(service_client_t client) { if (!client) return SERVICE_E_INVALID_ARG; @@ -132,7 +132,7 @@ LIBIMOBILEDEVICE_API service_error_t service_client_free(service_client_t client return err; } -LIBIMOBILEDEVICE_API service_error_t service_send(service_client_t client, const char* data, uint32_t size, uint32_t *sent) +service_error_t service_send(service_client_t client, const char* data, uint32_t size, uint32_t *sent) { service_error_t res = SERVICE_E_UNKNOWN_ERROR; uint32_t bytes = 0; @@ -153,7 +153,7 @@ LIBIMOBILEDEVICE_API service_error_t service_send(service_client_t client, const return res; } -LIBIMOBILEDEVICE_API service_error_t service_receive_with_timeout(service_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout) +service_error_t service_receive_with_timeout(service_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout) { service_error_t res = SERVICE_E_UNKNOWN_ERROR; uint32_t bytes = 0; @@ -174,27 +174,34 @@ LIBIMOBILEDEVICE_API service_error_t service_receive_with_timeout(service_client return res; } -LIBIMOBILEDEVICE_API service_error_t service_receive(service_client_t client, char* data, uint32_t size, uint32_t *received) +service_error_t service_receive(service_client_t client, char* data, uint32_t size, uint32_t *received) { return service_receive_with_timeout(client, data, size, received, 30000); } -LIBIMOBILEDEVICE_API service_error_t service_enable_ssl(service_client_t client) +service_error_t service_enable_ssl(service_client_t client) { if (!client || !client->connection) return SERVICE_E_INVALID_ARG; return idevice_to_service_error(idevice_connection_enable_ssl(client->connection)); } -LIBIMOBILEDEVICE_API service_error_t service_disable_ssl(service_client_t client) +service_error_t service_disable_ssl(service_client_t client) { return service_disable_bypass_ssl(client, 0); } -LIBIMOBILEDEVICE_API service_error_t service_disable_bypass_ssl(service_client_t client, uint8_t sslBypass) +service_error_t service_disable_bypass_ssl(service_client_t client, uint8_t sslBypass) { if (!client || !client->connection) return SERVICE_E_INVALID_ARG; return idevice_to_service_error(idevice_connection_disable_bypass_ssl(client->connection, sslBypass)); } +service_error_t service_get_connection(service_client_t client, idevice_connection_t *connection) +{ + if (!client || !client->connection || !connection) + return SERVICE_E_INVALID_ARG; + *connection = client->connection; + return SERVICE_E_SUCCESS; +} diff --git a/src/service.h b/src/service.h index 3fc3077..071fe3f 100644 --- a/src/service.h +++ b/src/service.h @@ -21,9 +21,9 @@ #ifndef SERVICE_H #define SERVICE_H +#include "idevice.h" #include "libimobiledevice/service.h" #include "libimobiledevice/lockdown.h" -#include "idevice.h" struct service_client_private { idevice_connection_t connection; diff --git a/src/syslog_relay.c b/src/syslog_relay.c index c137297..9f4296e 100644 --- a/src/syslog_relay.c +++ b/src/syslog_relay.c @@ -67,7 +67,7 @@ static syslog_relay_error_t syslog_relay_error(service_error_t err) return SYSLOG_RELAY_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, syslog_relay_client_t * client) +syslog_relay_error_t syslog_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, syslog_relay_client_t * client) { *client = NULL; @@ -95,14 +95,14 @@ LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_client_new(idevice_t devi return 0; } -LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_client_start_service(idevice_t device, syslog_relay_client_t * client, const char* label) +syslog_relay_error_t syslog_relay_client_start_service(idevice_t device, syslog_relay_client_t * client, const char* label) { syslog_relay_error_t err = SYSLOG_RELAY_E_UNKNOWN_ERROR; service_client_factory_start_service(device, SYSLOG_RELAY_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(syslog_relay_client_new), &err); return err; } -LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_client_free(syslog_relay_client_t client) +syslog_relay_error_t syslog_relay_client_free(syslog_relay_client_t client) { if (!client) return SYSLOG_RELAY_E_INVALID_ARG; @@ -113,12 +113,12 @@ LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_client_free(syslog_relay_ return err; } -LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_receive(syslog_relay_client_t client, char* data, uint32_t size, uint32_t *received) +syslog_relay_error_t syslog_relay_receive(syslog_relay_client_t client, char* data, uint32_t size, uint32_t *received) { return syslog_relay_receive_with_timeout(client, data, size, received, 1000); } -LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_receive_with_timeout(syslog_relay_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout) +syslog_relay_error_t syslog_relay_receive_with_timeout(syslog_relay_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout) { syslog_relay_error_t res = SYSLOG_RELAY_E_UNKNOWN_ERROR; int bytes = 0; @@ -154,16 +154,15 @@ void *syslog_relay_worker(void *arg) ret = syslog_relay_receive_with_timeout(srwt->client, &c, 1, &bytes, 100); if (ret == SYSLOG_RELAY_E_TIMEOUT || ret == SYSLOG_RELAY_E_NOT_ENOUGH_DATA || ((bytes == 0) && (ret == SYSLOG_RELAY_E_SUCCESS))) { continue; - } else if (ret < 0) { + } + if (ret < 0) { debug_info("Connection to syslog relay interrupted"); break; } if (srwt->is_raw) { srwt->cbfunc(c, srwt->user_data); - } else { - if (c != 0) { - srwt->cbfunc(c, srwt->user_data); - } + } else if (c != 0) { + srwt->cbfunc(c, srwt->user_data); } } @@ -176,7 +175,7 @@ void *syslog_relay_worker(void *arg) return NULL; } -LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_start_capture(syslog_relay_client_t client, syslog_relay_receive_cb_t callback, void* user_data) +syslog_relay_error_t syslog_relay_start_capture(syslog_relay_client_t client, syslog_relay_receive_cb_t callback, void* user_data) { if (!client || !callback) return SYSLOG_RELAY_E_INVALID_ARG; @@ -204,7 +203,7 @@ LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_start_capture(syslog_rela return res; } -LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_start_capture_raw(syslog_relay_client_t client, syslog_relay_receive_cb_t callback, void* user_data) +syslog_relay_error_t syslog_relay_start_capture_raw(syslog_relay_client_t client, syslog_relay_receive_cb_t callback, void* user_data) { if (!client || !callback) return SYSLOG_RELAY_E_INVALID_ARG; @@ -232,7 +231,7 @@ LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_start_capture_raw(syslog_ return res; } -LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_stop_capture(syslog_relay_client_t client) +syslog_relay_error_t syslog_relay_stop_capture(syslog_relay_client_t client) { if (client->worker) { /* notify thread to finish */ diff --git a/src/syslog_relay.h b/src/syslog_relay.h index 86d798e..d5263e2 100644 --- a/src/syslog_relay.h +++ b/src/syslog_relay.h @@ -22,6 +22,7 @@ #ifndef _SYSLOG_RELAY_H #define _SYSLOG_RELAY_H +#include "idevice.h" #include "libimobiledevice/syslog_relay.h" #include "service.h" #include <libimobiledevice-glue/thread.h> diff --git a/src/webinspector.c b/src/webinspector.c index 3360597..f960fcc 100644 --- a/src/webinspector.c +++ b/src/webinspector.c @@ -62,7 +62,7 @@ static webinspector_error_t webinspector_error(property_list_service_error_t err return WEBINSPECTOR_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API webinspector_error_t webinspector_client_new(idevice_t device, lockdownd_service_descriptor_t service, webinspector_client_t * client) +webinspector_error_t webinspector_client_new(idevice_t device, lockdownd_service_descriptor_t service, webinspector_client_t * client) { *client = NULL; @@ -89,14 +89,14 @@ LIBIMOBILEDEVICE_API webinspector_error_t webinspector_client_new(idevice_t devi return 0; } -LIBIMOBILEDEVICE_API webinspector_error_t webinspector_client_start_service(idevice_t device, webinspector_client_t * client, const char* label) +webinspector_error_t webinspector_client_start_service(idevice_t device, webinspector_client_t * client, const char* label) { webinspector_error_t err = WEBINSPECTOR_E_UNKNOWN_ERROR; service_client_factory_start_service(device, WEBINSPECTOR_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(webinspector_client_new), &err); return err; } -LIBIMOBILEDEVICE_API webinspector_error_t webinspector_client_free(webinspector_client_t client) +webinspector_error_t webinspector_client_free(webinspector_client_t client) { if (!client) return WEBINSPECTOR_E_INVALID_ARG; @@ -107,7 +107,7 @@ LIBIMOBILEDEVICE_API webinspector_error_t webinspector_client_free(webinspector_ return err; } -LIBIMOBILEDEVICE_API webinspector_error_t webinspector_send(webinspector_client_t client, plist_t plist) +webinspector_error_t webinspector_send(webinspector_client_t client, plist_t plist) { webinspector_error_t res = WEBINSPECTOR_E_UNKNOWN_ERROR; @@ -164,12 +164,12 @@ LIBIMOBILEDEVICE_API webinspector_error_t webinspector_send(webinspector_client_ return res; } -LIBIMOBILEDEVICE_API webinspector_error_t webinspector_receive(webinspector_client_t client, plist_t * plist) +webinspector_error_t webinspector_receive(webinspector_client_t client, plist_t * plist) { return webinspector_receive_with_timeout(client, plist, 5000); } -LIBIMOBILEDEVICE_API webinspector_error_t webinspector_receive_with_timeout(webinspector_client_t client, plist_t * plist, uint32_t timeout_ms) +webinspector_error_t webinspector_receive_with_timeout(webinspector_client_t client, plist_t * plist, uint32_t timeout_ms) { webinspector_error_t res = WEBINSPECTOR_E_UNKNOWN_ERROR; plist_t message = NULL; diff --git a/src/webinspector.h b/src/webinspector.h index 67421bc..d249c58 100644 --- a/src/webinspector.h +++ b/src/webinspector.h @@ -22,6 +22,7 @@ #ifndef __WEBINSPECTOR_H #define __WEBINSPECTOR_H +#include "idevice.h" #include "libimobiledevice/webinspector.h" #include "property_list_service.h" |