summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am1
-rw-r--r--src/afc.c127
-rw-r--r--src/house_arrest.c4
-rw-r--r--src/idevice.c184
-rw-r--r--src/idevice.h2
-rw-r--r--src/installation_proxy.c6
-rw-r--r--src/lockdown-cu.c18
-rw-r--r--src/lockdown.c73
-rw-r--r--src/misagent.c6
-rw-r--r--src/mobile_image_mounter.c4
-rw-r--r--src/notification_proxy.c9
-rw-r--r--src/ostrace.c436
-rw-r--r--src/ostrace.h37
-rw-r--r--src/sbservices.c4
14 files changed, 784 insertions, 127 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 58cf07c..1ee9be8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -58,6 +58,7 @@ libimobiledevice_1_0_la_SOURCES = \
companion_proxy.c companion_proxy.h \
reverse_proxy.c reverse_proxy.h \
syslog_relay.c syslog_relay.h \
+ ostrace.c ostrace.h \
bt_packet_logger.c bt_packet_logger.h
if WIN32
diff --git a/src/afc.c b/src/afc.c
index 1b4070b..c7eed5c 100644
--- a/src/afc.c
+++ b/src/afc.c
@@ -26,9 +26,12 @@
#endif
#include <stdio.h>
#include <stdlib.h>
-#include <unistd.h>
#include <string.h>
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif
+
#include "idevice.h"
#include "afc.h"
#include "common/debug.h"
@@ -115,7 +118,7 @@ afc_error_t afc_client_new(idevice_t device, lockdownd_service_descriptor_t serv
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;
+ int32_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;
}
@@ -338,7 +341,7 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t
free(buf);
debug_info("WARNING: Unknown operation code received 0x%llx param1=%lld", header.operation, param1);
-#ifndef WIN32
+#ifndef _WIN32
fprintf(stderr, "%s: WARNING: Unknown operation code received 0x%llx param1=%lld", __func__, (long long)header.operation, (long long)param1);
#endif
@@ -399,6 +402,50 @@ static char **make_strings_list(char *tokens, uint32_t length)
return list;
}
+static plist_t *make_dictionary(char *tokens, size_t length)
+{
+ size_t j = 0;
+ plist_t dict = NULL;
+
+ if (!tokens || !length)
+ return NULL;
+
+ dict = plist_new_dict();
+
+ while (j < length) {
+ size_t key_len = strnlen(tokens + j, length - j);
+ if (j + key_len >= length) {
+ plist_free(dict);
+ return NULL;
+ }
+ char* key = tokens + j;
+ j += key_len + 1;
+
+ if (j >= length) {
+ plist_free(dict);
+ return NULL;
+ }
+
+ size_t val_len = strnlen(tokens + j, length - j);
+ if (j + val_len >= length) {
+ plist_free(dict);
+ return NULL;
+ }
+ char* val = tokens + j;
+ j += val_len + 1;
+
+ char* endp = NULL;
+ unsigned long long u64val = strtoull(val, &endp, 10);
+ if (endp && *endp == '\0') {
+ plist_dict_set_item(dict, key, plist_new_uint(u64val));
+ } else {
+ plist_dict_set_item(dict, key, plist_new_string(val));
+ }
+ }
+
+ return dict;
+}
+
static int _afc_check_packet_buffer(afc_client_t client, uint32_t data_len)
{
if (data_len > client->packet_extra) {
@@ -495,6 +542,40 @@ afc_error_t afc_get_device_info(afc_client_t client, char ***device_information)
return ret;
}
+afc_error_t afc_get_device_info_plist(afc_client_t client, plist_t *device_information)
+{
+ uint32_t bytes = 0;
+ char *data = NULL;
+ afc_error_t ret = AFC_E_UNKNOWN_ERROR;
+
+ if (!client || !device_information)
+ return AFC_E_INVALID_ARG;
+
+ afc_lock(client);
+
+ /* Send the command */
+ ret = afc_dispatch_packet(client, AFC_OP_GET_DEVINFO, 0, NULL, 0, &bytes);
+ if (ret != AFC_E_SUCCESS) {
+ afc_unlock(client);
+ return AFC_E_NOT_ENOUGH_DATA;
+ }
+ /* Receive the data */
+ ret = afc_receive_data(client, &data, &bytes);
+ if (ret != AFC_E_SUCCESS) {
+ if (data)
+ free(data);
+ afc_unlock(client);
+ return ret;
+ }
+ /* Parse the data */
+ *device_information = make_dictionary(data, bytes);
+ free(data);
+
+ afc_unlock(client);
+
+ return ret;
+}
+
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;
@@ -644,8 +725,6 @@ afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***fil
return AFC_E_NO_MEM;
}
- debug_info("We got %p and %p", client->afc_packet, AFC_PACKET_DATA_PTR);
-
/* Send command */
memcpy(AFC_PACKET_DATA_PTR, path, data_len);
ret = afc_dispatch_packet(client, AFC_OP_GET_FILE_INFO, data_len, NULL, 0, &bytes);
@@ -666,6 +745,44 @@ afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***fil
return ret;
}
+afc_error_t afc_get_file_info_plist(afc_client_t client, const char *path, plist_t *file_information)
+{
+ char *received = NULL;
+ uint32_t bytes = 0;
+ afc_error_t ret = AFC_E_UNKNOWN_ERROR;
+
+ if (!client || !path || !file_information)
+ return AFC_E_INVALID_ARG;
+
+ afc_lock(client);
+
+ uint32_t data_len = (uint32_t)strlen(path)+1;
+ if (_afc_check_packet_buffer(client, data_len) < 0) {
+ afc_unlock(client);
+ debug_info("Failed to realloc packet buffer");
+ return AFC_E_NO_MEM;
+ }
+
+ /* Send command */
+ memcpy(AFC_PACKET_DATA_PTR, path, data_len);
+ ret = afc_dispatch_packet(client, AFC_OP_GET_FILE_INFO, data_len, NULL, 0, &bytes);
+ if (ret != AFC_E_SUCCESS) {
+ afc_unlock(client);
+ return AFC_E_NOT_ENOUGH_DATA;
+ }
+
+ /* Receive data */
+ ret = afc_receive_data(client, &received, &bytes);
+ if (received) {
+ *file_information = make_dictionary(received, bytes);
+ free(received);
+ }
+
+ afc_unlock(client);
+
+ return ret;
+}
+
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)
diff --git a/src/house_arrest.c b/src/house_arrest.c
index caad731..06068c6 100644
--- a/src/house_arrest.c
+++ b/src/house_arrest.c
@@ -24,7 +24,11 @@
#endif
#include <string.h>
#include <stdlib.h>
+
+#ifndef _MSC_VER
#include <unistd.h>
+#endif
+
#include <plist/plist.h>
#include "house_arrest.h"
diff --git a/src/idevice.c b/src/idevice.c
index b9bbb1f..0af27fd 100644
--- a/src/idevice.c
+++ b/src/idevice.c
@@ -30,7 +30,7 @@
#include <errno.h>
#include <time.h>
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
@@ -124,32 +124,32 @@ static void id_function(CRYPTO_THREADID *thread)
#endif
#endif /* HAVE_OPENSSL */
-static void internal_idevice_init(void)
-{
-#if defined(HAVE_OPENSSL)
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
- int i;
- SSL_library_init();
-
- mutex_buf = malloc(CRYPTO_num_locks() * sizeof(mutex_t));
- if (!mutex_buf)
- return;
- for (i = 0; i < CRYPTO_num_locks(); i++)
- mutex_init(&mutex_buf[i]);
-
-#if OPENSSL_VERSION_NUMBER < 0x10000000L
- CRYPTO_set_id_callback(id_function);
+// Reference: https://stackoverflow.com/a/2390626/1806760
+// Initializer/finalizer sample for MSVC and GCC/Clang.
+// 2010-2016 Joe Lowe. Released into the public domain.
+
+#ifdef __cplusplus
+ #define INITIALIZER(f) \
+ static void f(void); \
+ struct f##_t_ { f##_t_(void) { f(); } }; static f##_t_ f##_; \
+ static void f(void)
+#elif defined(_MSC_VER)
+ #pragma section(".CRT$XCU",read)
+ #define INITIALIZER2_(f,p) \
+ static void f(void); \
+ __declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \
+ __pragma(comment(linker,"/include:" p #f "_")) \
+ static void f(void)
+ #ifdef _WIN64
+ #define INITIALIZER(f) INITIALIZER2_(f,"")
+ #else
+ #define INITIALIZER(f) INITIALIZER2_(f,"_")
+ #endif
#else
- CRYPTO_THREADID_set_callback(id_function);
-#endif
- CRYPTO_set_locking_callback(locking_function);
-#endif
-#elif defined(HAVE_GNUTLS)
- gnutls_global_init();
-#elif defined(HAVE_MBEDTLS)
- // NO-OP
+ #define INITIALIZER(f) \
+ static void f(void) __attribute__((__constructor__)); \
+ static void f(void)
#endif
-}
static void internal_idevice_deinit(void)
{
@@ -181,43 +181,33 @@ static void internal_idevice_deinit(void)
#endif
}
-static thread_once_t init_once = THREAD_ONCE_INIT;
-static thread_once_t deinit_once = THREAD_ONCE_INIT;
-
-#ifndef HAVE_ATTRIBUTE_CONSTRUCTOR
- #if defined(__llvm__) || defined(__GNUC__)
- #define HAVE_ATTRIBUTE_CONSTRUCTOR
- #endif
-#endif
-
-#ifdef HAVE_ATTRIBUTE_CONSTRUCTOR
-static void __attribute__((constructor)) libimobiledevice_initialize(void)
+INITIALIZER(internal_idevice_init)
{
- thread_once(&init_once, internal_idevice_init);
-}
+#if defined(HAVE_OPENSSL)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+ int i;
+ SSL_library_init();
-static void __attribute__((destructor)) libimobiledevice_deinitialize(void)
-{
- thread_once(&deinit_once, internal_idevice_deinit);
-}
-#elif defined(WIN32)
-BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
-{
- switch (dwReason) {
- case DLL_PROCESS_ATTACH:
- thread_once(&init_once, internal_idevice_init);
- break;
- case DLL_PROCESS_DETACH:
- thread_once(&deinit_once, internal_idevice_deinit);
- break;
- default:
- break;
- }
- return 1;
-}
+ mutex_buf = malloc(CRYPTO_num_locks() * sizeof(mutex_t));
+ if (!mutex_buf)
+ return;
+ for (i = 0; i < CRYPTO_num_locks(); i++)
+ mutex_init(&mutex_buf[i]);
+
+#if OPENSSL_VERSION_NUMBER < 0x10000000L
+ CRYPTO_set_id_callback(id_function);
#else
-#warning No compiler support for constructor/destructor attributes, some features might not be available.
+ CRYPTO_THREADID_set_callback(id_function);
+#endif
+ CRYPTO_set_locking_callback(locking_function);
+#endif
+#elif defined(HAVE_GNUTLS)
+ gnutls_global_init();
+#elif defined(HAVE_MBEDTLS)
+ // NO-OP
#endif
+ atexit(internal_idevice_deinit);
+}
const char* libimobiledevice_version()
{
@@ -548,7 +538,7 @@ idevice_error_t idevice_connect(idevice_t device, uint16_t port, idevice_connect
}
idevice_connection_t new_connection = (idevice_connection_t)malloc(sizeof(struct idevice_connection_private));
new_connection->type = CONNECTION_USBMUXD;
- new_connection->data = (void*)(long)sfd;
+ new_connection->data = (void*)(uintptr_t)sfd;
new_connection->ssl_data = NULL;
new_connection->device = device;
new_connection->ssl_recv_timeout = (unsigned int)-1;
@@ -593,7 +583,7 @@ idevice_error_t idevice_connect(idevice_t device, uint16_t port, idevice_connect
idevice_connection_t new_connection = (idevice_connection_t)malloc(sizeof(struct idevice_connection_private));
new_connection->type = CONNECTION_NETWORK;
- new_connection->data = (void*)(long)sfd;
+ new_connection->data = (void*)(uintptr_t)sfd;
new_connection->ssl_data = NULL;
new_connection->device = device;
new_connection->ssl_recv_timeout = (unsigned int)-1;
@@ -618,11 +608,11 @@ idevice_error_t idevice_disconnect(idevice_connection_t connection)
}
idevice_error_t result = IDEVICE_E_UNKNOWN_ERROR;
if (connection->type == CONNECTION_USBMUXD) {
- usbmuxd_disconnect((int)(long)connection->data);
+ usbmuxd_disconnect((int)(uintptr_t)connection->data);
connection->data = NULL;
result = IDEVICE_E_SUCCESS;
} else if (connection->type == CONNECTION_NETWORK) {
- socket_close((int)(long)connection->data);
+ socket_close((int)(uintptr_t)connection->data);
connection->data = NULL;
result = IDEVICE_E_SUCCESS;
} else {
@@ -647,7 +637,7 @@ static idevice_error_t internal_connection_send(idevice_connection_t connection,
if (connection->type == CONNECTION_USBMUXD) {
int res;
do {
- res = usbmuxd_send((int)(long)connection->data, data, len, sent_bytes);
+ res = usbmuxd_send((int)(uintptr_t)connection->data, data, len, sent_bytes);
} while (res == -EAGAIN);
if (res < 0) {
debug_info("ERROR: usbmuxd_send returned %d (%s)", res, strerror(-res));
@@ -656,7 +646,7 @@ static idevice_error_t internal_connection_send(idevice_connection_t connection,
return IDEVICE_E_SUCCESS;
}
if (connection->type == CONNECTION_NETWORK) {
- int s = socket_send((int)(long)connection->data, (void*)data, len);
+ int s = socket_send((int)(uintptr_t)connection->data, (void*)data, len);
if (s < 0) {
*sent_bytes = 0;
return IDEVICE_E_UNKNOWN_ERROR;
@@ -763,7 +753,7 @@ static idevice_error_t internal_connection_receive_timeout(idevice_connection_t
}
if (connection->type == CONNECTION_USBMUXD) {
- int conn_error = usbmuxd_recv_timeout((int)(long)connection->data, data, len, recv_bytes, timeout);
+ int conn_error = usbmuxd_recv_timeout((int)(uintptr_t)connection->data, data, len, recv_bytes, timeout);
idevice_error_t error = socket_recv_to_idevice_error(conn_error, len, *recv_bytes);
if (error == IDEVICE_E_UNKNOWN_ERROR) {
debug_info("ERROR: usbmuxd_recv_timeout returned %d (%s)", conn_error, strerror(-conn_error));
@@ -771,7 +761,7 @@ static idevice_error_t internal_connection_receive_timeout(idevice_connection_t
return error;
}
if (connection->type == CONNECTION_NETWORK) {
- int res = socket_receive_timeout((int)(long)connection->data, data, len, 0, timeout);
+ int res = socket_receive_timeout((int)(uintptr_t)connection->data, data, len, 0, timeout);
idevice_error_t error = socket_recv_to_idevice_error(res, 0, 0);
if (error == IDEVICE_E_SUCCESS) {
*recv_bytes = (uint32_t)res;
@@ -863,7 +853,7 @@ static idevice_error_t internal_connection_receive(idevice_connection_t connecti
}
if (connection->type == CONNECTION_USBMUXD) {
- int res = usbmuxd_recv((int)(long)connection->data, data, len, recv_bytes);
+ int res = usbmuxd_recv((int)(uintptr_t)connection->data, data, len, recv_bytes);
if (res < 0) {
debug_info("ERROR: usbmuxd_recv returned %d (%s)", res, strerror(-res));
return IDEVICE_E_UNKNOWN_ERROR;
@@ -871,7 +861,7 @@ static idevice_error_t internal_connection_receive(idevice_connection_t connecti
return IDEVICE_E_SUCCESS;
}
if (connection->type == CONNECTION_NETWORK) {
- int res = socket_receive((int)(long)connection->data, data, len);
+ int res = socket_receive((int)(uintptr_t)connection->data, data, len);
if (res < 0) {
debug_info("ERROR: socket_receive returned %d (%s)", res, strerror(-res));
return IDEVICE_E_UNKNOWN_ERROR;
@@ -924,11 +914,11 @@ idevice_error_t idevice_connection_get_fd(idevice_connection_t connection, int *
}
if (connection->type == CONNECTION_USBMUXD) {
- *fd = (int)(long)connection->data;
+ *fd = (int)(uintptr_t)connection->data;
return IDEVICE_E_SUCCESS;
}
if (connection->type == CONNECTION_NETWORK) {
- *fd = (int)(long)connection->data;
+ *fd = (int)(uintptr_t)connection->data;
return IDEVICE_E_SUCCESS;
}
@@ -956,6 +946,20 @@ idevice_error_t idevice_get_udid(idevice_t device, char **udid)
return IDEVICE_E_SUCCESS;
}
+unsigned int idevice_get_device_version(idevice_t device)
+{
+ if (!device) {
+ return 0;
+ }
+ if (!device->version) {
+ lockdownd_client_t lockdown = NULL;
+ lockdownd_client_new(device, &lockdown, NULL);
+ // we don't handle any errors here. We should have the product version cached now.
+ lockdownd_client_free(lockdown);
+ }
+ return device->version;
+}
+
#if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS)
typedef ssize_t ssl_cb_ret_type_t;
#elif defined(HAVE_MBEDTLS)
@@ -1075,13 +1079,14 @@ static long ssl_idevice_bio_callback(BIO *b, int oper, const char *argp, int arg
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):
if (argp) {
bytes = internal_ssl_read(conn, (char *)argp, len);
- *processed = bytes;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ *processed = (size_t)(bytes < 0) ? 0 : bytes;
+#endif
return (long)bytes;
}
return 0;
@@ -1090,7 +1095,9 @@ static long ssl_idevice_bio_callback(BIO *b, int oper, const char *argp, int arg
// fallthrough
case (BIO_CB_WRITE|BIO_CB_RETURN):
bytes = internal_ssl_write(conn, argp, len);
- *processed = bytes;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ *processed = (size_t)(bytes < 0) ? 0 : bytes;
+#endif
return (long)bytes;
default:
return retvalue;
@@ -1239,7 +1246,7 @@ idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection)
#if OPENSSL_VERSION_NUMBER < 0x10100002L || \
(defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x2060000fL))
/* force use of TLSv1 for older devices */
- if (connection->device->version < DEVICE_VERSION(10,0,0)) {
+ if (connection->device->version < IDEVICE_DEVICE_VERSION(10,0,0)) {
#ifdef SSL_OP_NO_TLSv1_1
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_1);
#endif
@@ -1252,7 +1259,7 @@ idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection)
}
#else
SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_VERSION);
- if (connection->device->version < DEVICE_VERSION(10,0,0)) {
+ if (connection->device->version < IDEVICE_DEVICE_VERSION(10,0,0)) {
SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_VERSION);
if (connection->device->version == 0) {
/*
@@ -1338,7 +1345,7 @@ idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection)
if (ssl_error == 0 || ssl_error != SSL_ERROR_WANT_READ) {
break;
}
-#ifdef WIN32
+#ifdef _WIN32
Sleep(100);
#else
struct timespec ts = { 0, 100000000 };
@@ -1544,3 +1551,28 @@ idevice_error_t idevice_connection_disable_bypass_ssl(idevice_connection_t conne
return IDEVICE_E_SUCCESS;
}
+
+const char* idevice_strerror(idevice_error_t err)
+{
+ switch (err) {
+ case IDEVICE_E_SUCCESS:
+ return "Success";
+ case IDEVICE_E_INVALID_ARG:
+ return "Invalid argument";
+ case IDEVICE_E_UNKNOWN_ERROR:
+ return "Unknown Error";
+ case IDEVICE_E_NO_DEVICE:
+ return "No device";
+ case IDEVICE_E_NOT_ENOUGH_DATA:
+ return "Not enough data";
+ case IDEVICE_E_CONNREFUSED:
+ return "Connection refused";
+ case IDEVICE_E_SSL_ERROR:
+ return "SSL error";
+ case IDEVICE_E_TIMEOUT:
+ return "Timeout";
+ default:
+ break;
+ }
+ return "Unknown Error";
+}
diff --git a/src/idevice.h b/src/idevice.h
index dd72f9d..e05338e 100644
--- a/src/idevice.h
+++ b/src/idevice.h
@@ -52,8 +52,6 @@
#include "common/userpref.h"
#include "libimobiledevice/libimobiledevice.h"
-#define DEVICE_VERSION(maj, min, patch) (((maj & 0xFF) << 16) | ((min & 0xFF) << 8) | (patch & 0xFF))
-
#define DEVICE_CLASS_IPHONE 1
#define DEVICE_CLASS_IPAD 2
#define DEVICE_CLASS_IPOD 3
diff --git a/src/installation_proxy.c b/src/installation_proxy.c
index ec19da0..bb6ef01 100644
--- a/src/installation_proxy.c
+++ b/src/installation_proxy.c
@@ -26,7 +26,11 @@
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
+
+#ifndef _MSC_VER
#include <unistd.h>
+#endif
+
#include <plist/plist.h>
#include "installation_proxy.h"
@@ -251,7 +255,7 @@ instproxy_error_t instproxy_client_new(idevice_t device, lockdownd_service_descr
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;
+ int32_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;
}
diff --git a/src/lockdown-cu.c b/src/lockdown-cu.c
index 1afc2c5..c457cb2 100644
--- a/src/lockdown-cu.c
+++ b/src/lockdown-cu.c
@@ -29,7 +29,11 @@
#define __USE_GNU 1
#include <stdio.h>
#include <ctype.h>
+
+#ifndef _MSC_VER
#include <unistd.h>
+#endif
+
#include <plist/plist.h>
#include "idevice.h"
@@ -505,7 +509,7 @@ lockdownd_error_t lockdownd_cu_pairing_create(lockdownd_client_t client, lockdow
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]);
+ client->device->version = IDEVICE_DEVICE_VERSION(vers[0], vers[1], vers[2]);
}
free(s_version);
}
@@ -653,7 +657,7 @@ lockdownd_error_t lockdownd_cu_pairing_create(lockdownd_client_t client, lockdow
CFStringGetCString(cname, hostname, sizeof(hostname), kCFStringEncodingUTF8);
CFRelease(cname);
#else
-#ifdef WIN32
+#ifdef _WIN32
DWORD hostname_len = sizeof(hostname);
GetComputerName(hostname, &hostname_len);
#else
@@ -957,12 +961,12 @@ lockdownd_error_t lockdownd_cu_send_request_and_get_reply(lockdownd_client_t cli
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)) {
+ unsigned char cu_nonce[] = "sendone01234"; // guaranteed to be random by fair dice troll
+ if (client->device->version >= IDEVICE_DEVICE_VERSION(11,2,0)) {
#if defined(HAVE_OPENSSL)
- RAND_bytes(cu_nonce, sizeof(cu_nonce));
+ RAND_bytes(cu_nonce, sizeof(cu_nonce)-1);
#elif defined(HAVE_GCRYPT)
- gcry_create_nonce(cu_nonce, sizeof(cu_nonce));
+ gcry_create_nonce(cu_nonce, sizeof(cu_nonce)-1);
#endif
}
@@ -1128,7 +1132,7 @@ lockdownd_error_t lockdownd_pair_cu(lockdownd_client_t client)
plist_free(pubkey);
plist_t pair_record_plist = plist_new_dict();
- pair_record_generate_keys_and_certs(pair_record_plist, public_key);
+ pair_record_generate_keys_and_certs(pair_record_plist, public_key, client->device->version);
char* host_id = NULL;
char* system_buid = NULL;
diff --git a/src/lockdown.c b/src/lockdown.c
index 256bff0..32389c9 100644
--- a/src/lockdown.c
+++ b/src/lockdown.c
@@ -32,7 +32,11 @@
#define __USE_GNU 1
#include <stdio.h>
#include <ctype.h>
+
+#ifndef _MSC_VER
#include <unistd.h>
+#endif
+
#include <plist/plist.h>
#include <libimobiledevice-glue/utils.h>
@@ -43,7 +47,7 @@
#include "common/userpref.h"
#include "asprintf.h"
-#ifdef WIN32
+#ifdef _WIN32
#include <windows.h>
#define sleep(x) Sleep(x*1000)
#endif
@@ -617,6 +621,7 @@ lockdownd_error_t lockdownd_client_new(idevice_t device, lockdownd_client_t *cli
.port = 0xf27e,
.ssl_enabled = 0
};
+ char *type = NULL;
property_list_service_client_t plistclient = NULL;
if (property_list_service_client_new(device, (lockdownd_service_descriptor_t)&service, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
@@ -638,51 +643,32 @@ lockdownd_error_t lockdownd_client_new(idevice_t device, lockdownd_client_t *cli
client_loc->label = label ? strdup(label) : NULL;
- *client = client_loc;
-
- return LOCKDOWN_E_SUCCESS;
-}
-
-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;
-
- lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;
- lockdownd_client_t client_loc = NULL;
- plist_t pair_record = NULL;
- char *host_id = NULL;
- char *type = NULL;
-
- ret = lockdownd_client_new(device, &client_loc, label);
- if (LOCKDOWN_E_SUCCESS != ret) {
- debug_info("failed to create lockdownd client.");
- return ret;
- }
-
- /* perform handshake */
- ret = lockdownd_query_type(client_loc, &type);
- if (LOCKDOWN_E_SUCCESS != ret) {
+ int is_lockdownd = 0;
+ if (lockdownd_query_type(client_loc, &type) != LOCKDOWN_E_SUCCESS) {
debug_info("QueryType failed in the lockdownd client.");
- } else if (strcmp("com.apple.mobile.lockdown", type) != 0) {
- debug_info("Warning QueryType request returned \"%s\".", type);
+ } else if (!strcmp("com.apple.mobile.lockdown", type)) {
+ is_lockdownd = 1;
+ } else {
+ debug_info("QueryType request returned \"%s\"", type);
}
free(type);
- if (device->version == 0) {
+ *client = client_loc;
+
+ if (is_lockdownd && device->version == 0) {
plist_t p_version = NULL;
if (lockdownd_get_value(client_loc, 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) {
- device->version = DEVICE_VERSION(vers[0], vers[1], vers[2]);
+ device->version = IDEVICE_DEVICE_VERSION(vers[0], vers[1], vers[2]);
}
free(s_version);
}
plist_free(p_version);
}
- if (device->device_class == 0) {
+ if (is_lockdownd && device->device_class == 0) {
plist_t p_device_class = NULL;
if (lockdownd_get_value(client_loc, NULL, "DeviceClass", &p_device_class) == LOCKDOWN_E_SUCCESS) {
char* s_device_class = NULL;
@@ -707,6 +693,26 @@ lockdownd_error_t lockdownd_client_new_with_handshake(idevice_t device, lockdown
plist_free(p_device_class);
}
+ return LOCKDOWN_E_SUCCESS;
+}
+
+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;
+
+ lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;
+ lockdownd_client_t client_loc = NULL;
+ plist_t pair_record = NULL;
+ char *host_id = NULL;
+
+ ret = lockdownd_client_new(device, &client_loc, label);
+ if (LOCKDOWN_E_SUCCESS != ret) {
+ debug_info("failed to create lockdownd client.");
+ return ret;
+ }
+
+ /* perform handshake */
userpref_error_t 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);
@@ -730,7 +736,7 @@ lockdownd_error_t lockdownd_client_new_with_handshake(idevice_t device, lockdown
plist_free(pair_record);
pair_record = NULL;
- if (device->version < DEVICE_VERSION(7,0,0) && device->device_class != DEVICE_CLASS_WATCH) {
+ if (device->version < IDEVICE_DEVICE_VERSION(7,0,0) && device->device_class != DEVICE_CLASS_WATCH) {
/* for older devices, we need to validate pairing to receive trusted host status */
ret = lockdownd_validate_pair(client_loc, NULL);
@@ -836,7 +842,7 @@ static lockdownd_error_t pair_record_generate(lockdownd_client_t client, plist_t
/* generate keys and certificates into pair record */
userpref_error_t uret = USERPREF_E_SUCCESS;
- uret = pair_record_generate_keys_and_certs(*pair_record, public_key);
+ uret = pair_record_generate_keys_and_certs(*pair_record, public_key, client->device->version);
switch(uret) {
case USERPREF_E_INVALID_ARG:
ret = LOCKDOWN_E_INVALID_ARG;
@@ -846,6 +852,7 @@ static lockdownd_error_t pair_record_generate(lockdownd_client_t client, plist_t
break;
case USERPREF_E_SSL_ERROR:
ret = LOCKDOWN_E_SSL_ERROR;
+ break;
default:
break;
}
diff --git a/src/misagent.c b/src/misagent.c
index e3da997..3fdca4d 100644
--- a/src/misagent.c
+++ b/src/misagent.c
@@ -24,9 +24,13 @@
#endif
#include <string.h>
#include <stdlib.h>
+#include <stdio.h>
+
+#ifndef _MSC_VER
#include <unistd.h>
+#endif
+
#include <plist/plist.h>
-#include <stdio.h>
#include "misagent.h"
#include "property_list_service.h"
diff --git a/src/mobile_image_mounter.c b/src/mobile_image_mounter.c
index 6df50c4..6677882 100644
--- a/src/mobile_image_mounter.c
+++ b/src/mobile_image_mounter.c
@@ -24,7 +24,11 @@
#endif
#include <string.h>
#include <stdlib.h>
+
+#ifndef _MSC_VER
#include <unistd.h>
+#endif
+
#include <plist/plist.h>
#include "mobile_image_mounter.h"
diff --git a/src/notification_proxy.c b/src/notification_proxy.c
index 60b2e03..c7e4660 100644
--- a/src/notification_proxy.c
+++ b/src/notification_proxy.c
@@ -24,14 +24,19 @@
#endif
#include <string.h>
#include <stdlib.h>
+
+#ifndef _MSC_VER
#include <unistd.h>
+#endif
+
#include <plist/plist.h>
#include "notification_proxy.h"
#include "property_list_service.h"
#include "common/debug.h"
-#ifdef WIN32
+#ifdef _WIN32
+#include <windows.h>
#define sleep(x) Sleep(x*1000)
#endif
@@ -109,7 +114,7 @@ np_error_t np_client_new(idevice_t device, lockdownd_service_descriptor_t servic
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;
+ int32_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;
}
diff --git a/src/ostrace.c b/src/ostrace.c
new file mode 100644
index 0000000..68eb6bf
--- /dev/null
+++ b/src/ostrace.c
@@ -0,0 +1,436 @@
+/*
+ * ostrace.c
+ * com.apple.os_trace_relay service implementation.
+ *
+ * Copyright (c) 2020-2025 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>
+
+#include <plist/plist.h>
+
+#include "ostrace.h"
+#include "lockdown.h"
+#include "common/debug.h"
+#include "endianness.h"
+
+struct ostrace_worker_thread {
+ ostrace_client_t client;
+ ostrace_activity_cb_t cbfunc;
+ void *user_data;
+};
+
+/**
+ * Convert a service_error_t value to a ostrace_error_t value.
+ * Used internally to get correct error codes.
+ *
+ * @param err An service_error_t error code
+ *
+ * @return A matching ostrace_error_t error code,
+ * OSTRACE_E_UNKNOWN_ERROR otherwise.
+ */
+static ostrace_error_t ostrace_error(service_error_t err)
+{
+ switch (err) {
+ case SERVICE_E_SUCCESS:
+ return OSTRACE_E_SUCCESS;
+ case SERVICE_E_INVALID_ARG:
+ return OSTRACE_E_INVALID_ARG;
+ case SERVICE_E_MUX_ERROR:
+ return OSTRACE_E_MUX_ERROR;
+ case SERVICE_E_SSL_ERROR:
+ return OSTRACE_E_SSL_ERROR;
+ case SERVICE_E_NOT_ENOUGH_DATA:
+ return OSTRACE_E_NOT_ENOUGH_DATA;
+ case SERVICE_E_TIMEOUT:
+ return OSTRACE_E_TIMEOUT;
+ default:
+ break;
+ }
+ return OSTRACE_E_UNKNOWN_ERROR;
+}
+
+ostrace_error_t ostrace_client_new(idevice_t device, lockdownd_service_descriptor_t service, ostrace_client_t * client)
+{
+ *client = NULL;
+
+ if (!device || !service || service->port == 0 || !client || *client) {
+ debug_info("Incorrect parameter passed to ostrace_client_new.");
+ return OSTRACE_E_INVALID_ARG;
+ }
+
+ debug_info("Creating ostrace_client, port = %d.", service->port);
+
+ service_client_t parent = NULL;
+ ostrace_error_t ret = ostrace_error(service_client_new(device, service, &parent));
+ if (ret != OSTRACE_E_SUCCESS) {
+ debug_info("Creating base service client failed. Error: %i", ret);
+ return ret;
+ }
+
+ ostrace_client_t client_loc = (ostrace_client_t) malloc(sizeof(struct ostrace_client_private));
+ client_loc->parent = parent;
+ client_loc->worker = THREAD_T_NULL;
+
+ *client = client_loc;
+
+ debug_info("ostrace_client successfully created.");
+ return 0;
+}
+
+ostrace_error_t ostrace_client_start_service(idevice_t device, ostrace_client_t * client, const char* label)
+{
+ ostrace_error_t err = OSTRACE_E_UNKNOWN_ERROR;
+ service_client_factory_start_service(device, OSTRACE_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(ostrace_client_new), &err);
+ return err;
+}
+
+ostrace_error_t ostrace_client_free(ostrace_client_t client)
+{
+ if (!client)
+ return OSTRACE_E_INVALID_ARG;
+ ostrace_stop_activity(client);
+ ostrace_error_t err = ostrace_error(service_client_free(client->parent));
+ free(client);
+
+ return err;
+}
+
+static ostrace_error_t ostrace_send_plist(ostrace_client_t client, plist_t plist)
+{
+ ostrace_error_t res = OSTRACE_E_UNKNOWN_ERROR;
+ uint32_t blen = 0;
+ char* bin = NULL;
+ uint32_t sent = 0;
+ uint32_t swapped_len = 0;
+
+ if (!client || !plist) {
+ return OSTRACE_E_INVALID_ARG;
+ }
+
+ plist_to_bin(plist, &bin, &blen);
+ swapped_len = htobe32(blen);
+
+ res = ostrace_error(service_send(client->parent, (char*)&swapped_len, 4, &sent));
+ if (res == OSTRACE_E_SUCCESS) {
+ res = ostrace_error(service_send(client->parent, bin, blen, &sent));
+ }
+ free(bin);
+ return res;
+}
+
+static ostrace_error_t ostrace_receive_plist(ostrace_client_t client, plist_t *plist)
+{
+ ostrace_error_t res = OSTRACE_E_UNKNOWN_ERROR;
+ uint8_t msgtype = 0;
+ uint32_t received = 0;
+ res = ostrace_error(service_receive(client->parent, (char*)&msgtype, 1, &received));
+ if (res != OSTRACE_E_SUCCESS) {
+ debug_info("Failed to read message type from service");
+ return res;
+ }
+ uint32_t rlen = 0;
+ res = ostrace_error(service_receive(client->parent, (char*)&rlen, 4, &received));
+ if (res != OSTRACE_E_SUCCESS) {
+ debug_info("Failed to read message size from service");
+ return res;
+ }
+
+ if (msgtype == 1) {
+ rlen = be32toh(rlen);
+ } else if (msgtype == 2) {
+ rlen = le32toh(rlen);
+ } else {
+ debug_info("Unexpected message type %d", msgtype);
+ return OSTRACE_E_UNKNOWN_ERROR;
+ }
+ debug_info("got length %d", rlen);
+
+ char* buf = (char*)malloc(rlen);
+ res = ostrace_error(service_receive(client->parent, buf, rlen, &received));
+ if (res != OSTRACE_E_SUCCESS) {
+ return res;
+ }
+
+ plist_t reply = NULL;
+ plist_err_t perr = plist_from_memory(buf, received, &reply, NULL);
+ free(buf);
+ if (perr != PLIST_ERR_SUCCESS) {
+ return OSTRACE_E_UNKNOWN_ERROR;
+ }
+ *plist = reply;
+ return OSTRACE_E_SUCCESS;
+}
+
+static ostrace_error_t _ostrace_check_result(plist_t reply)
+{
+ ostrace_error_t res = OSTRACE_E_REQUEST_FAILED;
+ if (!reply) {
+ return res;
+ }
+ plist_t p_status = plist_dict_get_item(reply, "Status");
+ if (!p_status) {
+ return res;
+ }
+ const char* status = plist_get_string_ptr(p_status, NULL);
+ if (!status) {
+ return res;
+ }
+ if (!strcmp(status, "RequestSuccessful")) {
+ res = OSTRACE_E_SUCCESS;
+ }
+ return res;
+}
+
+void *ostrace_worker(void *arg)
+{
+ ostrace_error_t res = OSTRACE_E_UNKNOWN_ERROR;
+ struct ostrace_worker_thread *oswt = (struct ostrace_worker_thread*)arg;
+
+ if (!oswt)
+ return NULL;
+
+ uint8_t msgtype = 0;
+ uint32_t received = 0;
+
+ debug_info("Running");
+
+ while (oswt->client->parent) {
+ res = ostrace_error(service_receive_with_timeout(oswt->client->parent, (char*)&msgtype, 1, &received, 100));
+ if (res == OSTRACE_E_TIMEOUT) {
+ continue;
+ }
+ if (res != OSTRACE_E_SUCCESS) {
+ debug_info("Failed to read message type from service");
+ break;
+ }
+ uint32_t rlen = 0;
+ res = ostrace_error(service_receive(oswt->client->parent, (char*)&rlen, 4, &received));
+ if (res != OSTRACE_E_SUCCESS) {
+ debug_info("Failed to read message size from service");
+ break;
+ }
+
+ if (msgtype == 1) {
+ rlen = be32toh(rlen);
+ } else if (msgtype == 2) {
+ rlen = le32toh(rlen);
+ } else {
+ debug_info("Unexpected message type %d", msgtype);
+ break;
+ }
+
+ debug_info("got length %d", rlen);
+
+ void* buf = malloc(rlen);
+ res = ostrace_error(service_receive(oswt->client->parent, (char*)buf, rlen, &received));
+ if (res != OSTRACE_E_SUCCESS) {
+ debug_info("Failed to receive %d bytes, error %d", rlen, res);
+ break;
+ }
+ if (received < rlen) {
+ debug_info("Failed to receive all data, got %d/%d", received, rlen);
+ break;
+ }
+ oswt->cbfunc(buf, received, oswt->user_data);
+ }
+
+ if (oswt) {
+ free(oswt);
+ }
+
+ debug_info("Exiting");
+
+ return NULL;
+}
+
+ostrace_error_t ostrace_start_activity(ostrace_client_t client, plist_t options, ostrace_activity_cb_t callback, void* user_data)
+{
+ if (!client || !callback)
+ return OSTRACE_E_INVALID_ARG;
+
+ ostrace_error_t res = OSTRACE_E_UNKNOWN_ERROR;
+
+ if (client->worker) {
+ debug_info("Another ostrace activity thread appears to be running already.");
+ return res;
+ }
+
+ plist_t dict = plist_new_dict();
+ plist_dict_set_item(dict, "Pid", plist_new_uint(0x0FFFFFFFF));
+ plist_dict_set_item(dict, "MessageFilter", plist_new_uint(0xFFFF));
+ plist_dict_set_item(dict, "StreamFlags", plist_new_uint(0x3C));
+ if (options) {
+ plist_dict_merge(&dict, options);
+ }
+ plist_dict_set_item(dict, "Request", plist_new_string("StartActivity"));
+
+ res = ostrace_send_plist(client, dict);
+ plist_free(dict);
+ if (res != OSTRACE_E_SUCCESS) {
+ return res;
+ }
+
+ dict = NULL;
+ res = ostrace_receive_plist(client, &dict);
+ if (res != OSTRACE_E_SUCCESS) {
+ return res;
+ }
+ res = _ostrace_check_result(dict);
+ if (res != OSTRACE_E_SUCCESS) {
+ return res;
+ }
+
+ /* start worker thread */
+ struct ostrace_worker_thread *oswt = (struct ostrace_worker_thread*)malloc(sizeof(struct ostrace_worker_thread));
+ if (oswt) {
+ oswt->client = client;
+ oswt->cbfunc = callback;
+ oswt->user_data = user_data;
+
+ if (thread_new(&client->worker, ostrace_worker, oswt) == 0) {
+ res = OSTRACE_E_SUCCESS;
+ }
+ }
+
+ return res;
+}
+
+ostrace_error_t ostrace_stop_activity(ostrace_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 OSTRACE_E_SUCCESS;
+}
+
+ostrace_error_t ostrace_get_pid_list(ostrace_client_t client, plist_t* list)
+{
+ ostrace_error_t res = OSTRACE_E_UNKNOWN_ERROR;
+ plist_t dict = plist_new_dict();
+ plist_dict_set_item(dict, "Request", plist_new_string("PidList"));
+
+ if (!client || !list) {
+ return OSTRACE_E_INVALID_ARG;
+ }
+
+ res = ostrace_send_plist(client, dict);
+ plist_free(dict);
+ if (res != OSTRACE_E_SUCCESS) {
+ return res;
+ }
+
+ plist_t reply = NULL;
+ res = ostrace_receive_plist(client, &reply);
+ if (res != OSTRACE_E_SUCCESS) {
+ return res;
+ }
+ res = _ostrace_check_result(reply);
+ if (res != OSTRACE_E_SUCCESS) {
+ return res;
+ }
+
+ plist_t payload = plist_dict_get_item(reply, "Payload");
+ if (!payload) {
+ return OSTRACE_E_REQUEST_FAILED;
+ }
+ *list = plist_copy(payload);
+ plist_free(reply);
+
+ return OSTRACE_E_SUCCESS;
+}
+
+ostrace_error_t ostrace_create_archive(ostrace_client_t client, plist_t options, ostrace_archive_write_cb_t callback, void* user_data)
+{
+ ostrace_error_t res = OSTRACE_E_UNKNOWN_ERROR;
+ if (!client || !callback) {
+ return OSTRACE_E_INVALID_ARG;
+ }
+ plist_t dict = plist_new_dict();
+ if (options) {
+ plist_dict_merge(&dict, options);
+ }
+ plist_dict_set_item(dict, "Request", plist_new_string("CreateArchive"));
+
+ res = ostrace_send_plist(client, dict);
+ plist_free(dict);
+ if (res != OSTRACE_E_SUCCESS) {
+ return res;
+ }
+
+ plist_t reply = NULL;
+ res = ostrace_receive_plist(client, &reply);
+ if (res != OSTRACE_E_SUCCESS) {
+ return res;
+ }
+
+ res = _ostrace_check_result(reply);
+ if (res != OSTRACE_E_SUCCESS) {
+ return res;
+ }
+
+ debug_info("Receiving archive...\n");
+ while (1) {
+ uint8_t msgtype = 0;
+ uint32_t received = 0;
+ res = ostrace_error(service_receive(client->parent, (char*)&msgtype, 1, &received));
+ if (res != OSTRACE_E_SUCCESS) {
+ debug_info("Could not read message type from service: %d", res);
+ break;
+ }
+ if (msgtype != 3) {
+ debug_info("Unexpected packet type %d", msgtype);
+ return OSTRACE_E_REQUEST_FAILED;
+ }
+ uint32_t rlen = 0;
+ res = ostrace_error(service_receive(client->parent, (char*)&rlen, 4, &received));
+ if (res != OSTRACE_E_SUCCESS) {
+ debug_info("Failed to read message size from service");
+ break;
+ }
+
+ rlen = le32toh(rlen);
+ debug_info("got length %d", rlen);
+
+ unsigned char* buf = (unsigned char*)malloc(rlen);
+ res = ostrace_error(service_receive(client->parent, (char*)buf, rlen, &received));
+ if (res != OSTRACE_E_SUCCESS) {
+ debug_info("Could not read data from service: %d", res);
+ break;
+ }
+ if (callback(buf, received, user_data) < 0) {
+ debug_info("Aborted through callback");
+ return OSTRACE_E_REQUEST_FAILED;
+ }
+ }
+ debug_info("Done.\n");
+
+ return OSTRACE_E_SUCCESS;
+}
+
diff --git a/src/ostrace.h b/src/ostrace.h
new file mode 100644
index 0000000..dcc3e8d
--- /dev/null
+++ b/src/ostrace.h
@@ -0,0 +1,37 @@
+/*
+ * ostrace.h
+ * com.apple.os_trace_relay service header file.
+ *
+ * Copyright (c) 2020-2025 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 _OSTRACE_H
+#define _OSTRACE_H
+
+#include "idevice.h"
+#include "libimobiledevice/ostrace.h"
+#include "service.h"
+#include <libimobiledevice-glue/thread.h>
+
+struct ostrace_client_private {
+ service_client_t parent;
+ THREAD_T worker;
+};
+
+void *ostrace_worker(void *arg);
+
+#endif
diff --git a/src/sbservices.c b/src/sbservices.c
index 365e130..5df5122 100644
--- a/src/sbservices.c
+++ b/src/sbservices.c
@@ -24,7 +24,11 @@
#endif
#include <string.h>
#include <stdlib.h>
+
+#ifndef _MSC_VER
#include <unistd.h>
+#endif
+
#include <plist/plist.h>
#include "sbservices.h"