summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am27
-rw-r--r--src/afc.c200
-rw-r--r--src/bt_packet_logger.c231
-rw-r--r--src/bt_packet_logger.h37
-rw-r--r--src/companion_proxy.c24
-rw-r--r--src/companion_proxy.h1
-rw-r--r--src/debugserver.c259
-rw-r--r--src/debugserver.h3
-rw-r--r--src/device_link_service.c8
-rw-r--r--src/device_link_service.h1
-rw-r--r--src/diagnostics_relay.c31
-rw-r--r--src/diagnostics_relay.h1
-rw-r--r--src/file_relay.c12
-rw-r--r--src/file_relay.h1
-rw-r--r--src/heartbeat.c12
-rw-r--r--src/heartbeat.h1
-rw-r--r--src/house_arrest.c14
-rw-r--r--src/house_arrest.h1
-rw-r--r--src/idevice.c346
-rw-r--r--src/idevice.h16
-rw-r--r--src/installation_proxy.c71
-rw-r--r--src/installation_proxy.h1
-rw-r--r--src/lockdown-cu.c1193
-rw-r--r--src/lockdown.c139
-rw-r--r--src/lockdown.h5
-rw-r--r--src/misagent.c19
-rw-r--r--src/misagent.h1
-rw-r--r--src/mobile_image_mounter.c14
-rw-r--r--src/mobile_image_mounter.h1
-rw-r--r--src/mobileactivation.c35
-rw-r--r--src/mobileactivation.h1
-rw-r--r--src/mobilebackup.c47
-rw-r--r--src/mobilebackup.h1
-rw-r--r--src/mobilebackup2.c31
-rw-r--r--src/mobilebackup2.h1
-rw-r--r--src/mobilesync.c44
-rw-r--r--src/mobilesync.h1
-rw-r--r--src/notification_proxy.c14
-rw-r--r--src/notification_proxy.h1
-rw-r--r--src/preboard.c19
-rw-r--r--src/preboard.h1
-rw-r--r--src/property_list_service.c23
-rw-r--r--src/property_list_service.h1
-rw-r--r--src/restore.c40
-rw-r--r--src/restore.h1
-rw-r--r--src/reverse_proxy.c810
-rw-r--r--src/reverse_proxy.h51
-rw-r--r--src/sbservices.c21
-rw-r--r--src/sbservices.h1
-rw-r--r--src/screenshotr.c10
-rw-r--r--src/screenshotr.h1
-rw-r--r--src/service.c31
-rw-r--r--src/service.h2
-rw-r--r--src/syslog_relay.c25
-rw-r--r--src/syslog_relay.h1
-rw-r--r--src/webinspector.c12
-rw-r--r--src/webinspector.h1
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
diff --git a/src/afc.c b/src/afc.c
index a17226b..1b4070b 100644
--- a/src/afc.c
+++ b/src/afc.c
@@ -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, &current_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"