summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am1
-rw-r--r--src/afc.c205
-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, 847 insertions, 142 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 = \
58 companion_proxy.c companion_proxy.h \ 58 companion_proxy.c companion_proxy.h \
59 reverse_proxy.c reverse_proxy.h \ 59 reverse_proxy.c reverse_proxy.h \
60 syslog_relay.c syslog_relay.h \ 60 syslog_relay.c syslog_relay.h \
61 ostrace.c ostrace.h \
61 bt_packet_logger.c bt_packet_logger.h 62 bt_packet_logger.c bt_packet_logger.h
62 63
63if WIN32 64if WIN32
diff --git a/src/afc.c b/src/afc.c
index 1b4070b..e2e5ba1 100644
--- a/src/afc.c
+++ b/src/afc.c
@@ -26,9 +26,12 @@
26#endif 26#endif
27#include <stdio.h> 27#include <stdio.h>
28#include <stdlib.h> 28#include <stdlib.h>
29#include <unistd.h>
30#include <string.h> 29#include <string.h>
31 30
31#ifndef _MSC_VER
32#include <unistd.h>
33#endif
34
32#include "idevice.h" 35#include "idevice.h"
33#include "afc.h" 36#include "afc.h"
34#include "common/debug.h" 37#include "common/debug.h"
@@ -56,6 +59,27 @@ static void afc_unlock(afc_client_t client)
56 mutex_unlock(&client->mutex); 59 mutex_unlock(&client->mutex);
57} 60}
58 61
62static afc_error_t service_to_afc_error(service_error_t err)
63{
64 switch (err) {
65 case SERVICE_E_SUCCESS:
66 return AFC_E_SUCCESS;
67 case SERVICE_E_INVALID_ARG:
68 return AFC_E_INVALID_ARG;
69 case SERVICE_E_MUX_ERROR:
70 return AFC_E_MUX_ERROR;
71 case SERVICE_E_SSL_ERROR:
72 return AFC_E_SSL_ERROR;
73 case SERVICE_E_NOT_ENOUGH_DATA:
74 return AFC_E_NOT_ENOUGH_DATA;
75 case SERVICE_E_TIMEOUT:
76 return AFC_E_OP_TIMEOUT;
77 default:
78 break;
79 }
80 return AFC_E_UNKNOWN_ERROR;
81}
82
59/** 83/**
60 * Makes a connection to the AFC service on the device using the given 84 * Makes a connection to the AFC service on the device using the given
61 * connection. 85 * connection.
@@ -115,7 +139,7 @@ afc_error_t afc_client_new(idevice_t device, lockdownd_service_descriptor_t serv
115 139
116afc_error_t afc_client_start_service(idevice_t device, afc_client_t * client, const char* label) 140afc_error_t afc_client_start_service(idevice_t device, afc_client_t * client, const char* label)
117{ 141{
118 afc_error_t err = AFC_E_UNKNOWN_ERROR; 142 int32_t err = AFC_E_UNKNOWN_ERROR;
119 service_client_factory_start_service(device, AFC_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(afc_client_new), &err); 143 service_client_factory_start_service(device, AFC_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(afc_client_new), &err);
120 return err; 144 return err;
121} 145}
@@ -171,11 +195,16 @@ static afc_error_t afc_dispatch_packet(afc_client_t client, uint64_t operation,
171 AFCPacket_to_LE(client->afc_packet); 195 AFCPacket_to_LE(client->afc_packet);
172 debug_buffer((char*)client->afc_packet, sizeof(AFCPacket) + data_length); 196 debug_buffer((char*)client->afc_packet, sizeof(AFCPacket) + data_length);
173 sent = 0; 197 sent = 0;
174 service_send(client->parent, (void*)client->afc_packet, sizeof(AFCPacket) + data_length, &sent); 198 afc_error_t err = service_to_afc_error(service_send(client->parent, (void*)client->afc_packet, sizeof(AFCPacket) + data_length, &sent));
175 AFCPacket_from_LE(client->afc_packet); 199 AFCPacket_from_LE(client->afc_packet);
200 if (err != AFC_E_SUCCESS) {
201 debug_info("Failed to send packet (sent %i/%i): %s (%d)", sent, sizeof(AFCPacket) + data_length, afc_strerror(err), err);
202 return err;
203 }
176 *bytes_sent += sent; 204 *bytes_sent += sent;
177 if (sent < sizeof(AFCPacket) + data_length) { 205 if (sent < sizeof(AFCPacket) + data_length) {
178 return AFC_E_SUCCESS; 206 debug_info("Failed to send entire packet (sent %i/%i)", sent, sizeof(AFCPacket) + data_length);
207 return AFC_E_NOT_ENOUGH_DATA;
179 } 208 }
180 209
181 sent = 0; 210 sent = 0;
@@ -187,11 +216,16 @@ static afc_error_t afc_dispatch_packet(afc_client_t client, uint64_t operation,
187 debug_info("packet payload follows"); 216 debug_info("packet payload follows");
188 debug_buffer(payload, payload_length); 217 debug_buffer(payload, payload_length);
189 } 218 }
190 service_send(client->parent, payload, payload_length, &sent); 219 err = service_to_afc_error(service_send(client->parent, payload, payload_length, &sent));
220 if (err != AFC_E_SUCCESS) {
221 debug_info("Failed to send payload (sent: %i/%i): %s (%d)", sent, payload_length, afc_strerror(err), err);
222 return err;
223 }
191 } 224 }
192 *bytes_sent += sent; 225 *bytes_sent += sent;
193 if (sent < payload_length) { 226 if (sent < payload_length) {
194 return AFC_E_SUCCESS; 227 debug_info("Failed to send entire payload (sent: %i/%i): %s (%d)", sent, payload_length, afc_strerror(err), err);
228 return AFC_E_NOT_ENOUGH_DATA;
195 } 229 }
196 230
197 return AFC_E_SUCCESS; 231 return AFC_E_SUCCESS;
@@ -224,21 +258,28 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t
224 } 258 }
225 259
226 /* first, read the AFC header */ 260 /* first, read the AFC header */
227 service_receive(client->parent, (char*)&header, sizeof(AFCPacket), &recv_len); 261 afc_error_t err = service_to_afc_error(service_receive(client->parent, (char*)&header, sizeof(AFCPacket), &recv_len));
228 AFCPacket_from_LE(&header); 262 if (err != AFC_E_SUCCESS) {
263 debug_info("Failed to receive AFC header: %s (%d)", afc_strerror(err), err);
264 return err;
265 }
229 if (recv_len == 0) { 266 if (recv_len == 0) {
230 debug_info("Just didn't get enough."); 267 debug_info("Just didn't get enough.");
231 return AFC_E_MUX_ERROR; 268 return AFC_E_NOT_ENOUGH_DATA;
232 } 269 }
233 270
234 if (recv_len < sizeof(AFCPacket)) { 271 if (recv_len < sizeof(AFCPacket)) {
235 debug_info("Did not even get the AFCPacket header"); 272 debug_info("Did not even get the AFCPacket header");
236 return AFC_E_MUX_ERROR; 273 return AFC_E_NOT_ENOUGH_DATA;
237 } 274 }
238 275
276 /* make sure endianness is correct */
277 AFCPacket_from_LE(&header);
278
239 /* check if it's a valid AFC header */ 279 /* check if it's a valid AFC header */
240 if (strncmp(header.magic, AFC_MAGIC, AFC_MAGIC_LEN) != 0) { 280 if (strncmp(header.magic, AFC_MAGIC, AFC_MAGIC_LEN) != 0) {
241 debug_info("Invalid AFC packet received (magic != " AFC_MAGIC ")!"); 281 debug_info("Invalid AFC packet received (magic != " AFC_MAGIC ")!");
282 return AFC_E_UNKNOWN_PACKET_TYPE;
242 } 283 }
243 284
244 /* check if it has the correct packet number */ 285 /* check if it has the correct packet number */
@@ -270,16 +311,20 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t
270 buf = (char*)malloc(entire_len); 311 buf = (char*)malloc(entire_len);
271 if (this_len > 0) { 312 if (this_len > 0) {
272 recv_len = 0; 313 recv_len = 0;
273 service_receive(client->parent, buf, this_len, &recv_len); 314 err = service_to_afc_error(service_receive(client->parent, buf, this_len, &recv_len));
315 if (err != AFC_E_SUCCESS) {
316 free(buf);
317 debug_info("Failed to receive data: %s (%d)", afc_strerror(err), err);
318 }
274 if (recv_len <= 0) { 319 if (recv_len <= 0) {
275 free(buf); 320 free(buf);
276 debug_info("Did not get packet contents!"); 321 debug_info("Did not get packet contents!");
277 return AFC_E_NOT_ENOUGH_DATA; 322 return (err == AFC_E_SUCCESS) ? AFC_E_NOT_ENOUGH_DATA : err;
278 } 323 }
279 if (recv_len < this_len) { 324 if (recv_len < this_len) {
280 free(buf); 325 free(buf);
281 debug_info("Could not receive this_len=%d bytes", this_len); 326 debug_info("Could not receive this_len=%d bytes", this_len);
282 return AFC_E_NOT_ENOUGH_DATA; 327 return (err == AFC_E_SUCCESS) ? AFC_E_END_OF_DATA : err;
283 } 328 }
284 } 329 }
285 330
@@ -288,7 +333,11 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t
288 if (entire_len > this_len) { 333 if (entire_len > this_len) {
289 while (current_count < entire_len) { 334 while (current_count < entire_len) {
290 recv_len = 0; 335 recv_len = 0;
291 service_receive(client->parent, buf+current_count, entire_len - current_count, &recv_len); 336 err = service_to_afc_error(service_receive(client->parent, buf+current_count, entire_len - current_count, &recv_len));
337 if (err != AFC_E_SUCCESS) {
338 debug_info("Error receiving data: %s (%d)", afc_strerror(err), err);
339 break;
340 }
292 if (recv_len <= 0) { 341 if (recv_len <= 0) {
293 debug_info("Error receiving data (recv returned %d)", recv_len); 342 debug_info("Error receiving data (recv returned %d)", recv_len);
294 break; 343 break;
@@ -296,7 +345,9 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t
296 current_count += recv_len; 345 current_count += recv_len;
297 } 346 }
298 if (current_count < entire_len) { 347 if (current_count < entire_len) {
299 debug_info("WARNING: could not receive full packet (read %s, size %d)", current_count, entire_len); 348 free(buf);
349 debug_info("ERROR: Could not receive entire packet (read %i/%i)", current_count, entire_len);
350 return (err == AFC_E_SUCCESS) ? AFC_E_END_OF_DATA : err;
300 } 351 }
301 } 352 }
302 353
@@ -338,7 +389,7 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t
338 free(buf); 389 free(buf);
339 390
340 debug_info("WARNING: Unknown operation code received 0x%llx param1=%lld", header.operation, param1); 391 debug_info("WARNING: Unknown operation code received 0x%llx param1=%lld", header.operation, param1);
341#ifndef WIN32 392#ifndef _WIN32
342 fprintf(stderr, "%s: WARNING: Unknown operation code received 0x%llx param1=%lld", __func__, (long long)header.operation, (long long)param1); 393 fprintf(stderr, "%s: WARNING: Unknown operation code received 0x%llx param1=%lld", __func__, (long long)header.operation, (long long)param1);
343#endif 394#endif
344 395
@@ -399,6 +450,50 @@ static char **make_strings_list(char *tokens, uint32_t length)
399 return list; 450 return list;
400} 451}
401 452
453static plist_t *make_dictionary(char *tokens, size_t length)
454{
455 size_t j = 0;
456 plist_t dict = NULL;
457
458 if (!tokens || !length)
459 return NULL;
460
461 dict = plist_new_dict();
462
463 while (j < length) {
464 size_t key_len = strnlen(tokens + j, length - j);
465 if (j + key_len >= length) {
466 plist_free(dict);
467 return NULL;
468 }
469 char* key = tokens + j;
470 j += key_len + 1;
471
472 if (j >= length) {
473 plist_free(dict);
474 return NULL;
475 }
476
477 size_t val_len = strnlen(tokens + j, length - j);
478 if (j + val_len >= length) {
479 plist_free(dict);
480 return NULL;
481 }
482 char* val = tokens + j;
483 j += val_len + 1;
484
485 char* endp = NULL;
486 unsigned long long u64val = strtoull(val, &endp, 10);
487 if (endp && *endp == '\0') {
488 plist_dict_set_item(dict, key, plist_new_uint(u64val));
489 } else {
490 plist_dict_set_item(dict, key, plist_new_string(val));
491 }
492 }
493
494 return dict;
495}
496
402static int _afc_check_packet_buffer(afc_client_t client, uint32_t data_len) 497static int _afc_check_packet_buffer(afc_client_t client, uint32_t data_len)
403{ 498{
404 if (data_len > client->packet_extra) { 499 if (data_len > client->packet_extra) {
@@ -495,6 +590,40 @@ afc_error_t afc_get_device_info(afc_client_t client, char ***device_information)
495 return ret; 590 return ret;
496} 591}
497 592
593afc_error_t afc_get_device_info_plist(afc_client_t client, plist_t *device_information)
594{
595 uint32_t bytes = 0;
596 char *data = NULL;
597 afc_error_t ret = AFC_E_UNKNOWN_ERROR;
598
599 if (!client || !device_information)
600 return AFC_E_INVALID_ARG;
601
602 afc_lock(client);
603
604 /* Send the command */
605 ret = afc_dispatch_packet(client, AFC_OP_GET_DEVINFO, 0, NULL, 0, &bytes);
606 if (ret != AFC_E_SUCCESS) {
607 afc_unlock(client);
608 return AFC_E_NOT_ENOUGH_DATA;
609 }
610 /* Receive the data */
611 ret = afc_receive_data(client, &data, &bytes);
612 if (ret != AFC_E_SUCCESS) {
613 if (data)
614 free(data);
615 afc_unlock(client);
616 return ret;
617 }
618 /* Parse the data */
619 *device_information = make_dictionary(data, bytes);
620 free(data);
621
622 afc_unlock(client);
623
624 return ret;
625}
626
498afc_error_t afc_get_device_info_key(afc_client_t client, const char *key, char **value) 627afc_error_t afc_get_device_info_key(afc_client_t client, const char *key, char **value)
499{ 628{
500 afc_error_t ret = AFC_E_INTERNAL_ERROR; 629 afc_error_t ret = AFC_E_INTERNAL_ERROR;
@@ -644,8 +773,6 @@ afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***fil
644 return AFC_E_NO_MEM; 773 return AFC_E_NO_MEM;
645 } 774 }
646 775
647 debug_info("We got %p and %p", client->afc_packet, AFC_PACKET_DATA_PTR);
648
649 /* Send command */ 776 /* Send command */
650 memcpy(AFC_PACKET_DATA_PTR, path, data_len); 777 memcpy(AFC_PACKET_DATA_PTR, path, data_len);
651 ret = afc_dispatch_packet(client, AFC_OP_GET_FILE_INFO, data_len, NULL, 0, &bytes); 778 ret = afc_dispatch_packet(client, AFC_OP_GET_FILE_INFO, data_len, NULL, 0, &bytes);
@@ -666,6 +793,44 @@ afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***fil
666 return ret; 793 return ret;
667} 794}
668 795
796afc_error_t afc_get_file_info_plist(afc_client_t client, const char *path, plist_t *file_information)
797{
798 char *received = NULL;
799 uint32_t bytes = 0;
800 afc_error_t ret = AFC_E_UNKNOWN_ERROR;
801
802 if (!client || !path || !file_information)
803 return AFC_E_INVALID_ARG;
804
805 afc_lock(client);
806
807 uint32_t data_len = (uint32_t)strlen(path)+1;
808 if (_afc_check_packet_buffer(client, data_len) < 0) {
809 afc_unlock(client);
810 debug_info("Failed to realloc packet buffer");
811 return AFC_E_NO_MEM;
812 }
813
814 /* Send command */
815 memcpy(AFC_PACKET_DATA_PTR, path, data_len);
816 ret = afc_dispatch_packet(client, AFC_OP_GET_FILE_INFO, data_len, NULL, 0, &bytes);
817 if (ret != AFC_E_SUCCESS) {
818 afc_unlock(client);
819 return AFC_E_NOT_ENOUGH_DATA;
820 }
821
822 /* Receive data */
823 ret = afc_receive_data(client, &received, &bytes);
824 if (received) {
825 *file_information = make_dictionary(received, bytes);
826 free(received);
827 }
828
829 afc_unlock(client);
830
831 return ret;
832}
833
669afc_error_t afc_file_open(afc_client_t client, const char *filename, afc_file_mode_t file_mode, uint64_t *handle) 834afc_error_t afc_file_open(afc_client_t client, const char *filename, afc_file_mode_t file_mode, uint64_t *handle)
670{ 835{
671 if (!client || !client->parent || !client->afc_packet) 836 if (!client || !client->parent || !client->afc_packet)
@@ -1182,14 +1347,14 @@ const char* afc_strerror(afc_error_t err)
1182 return "Internal error"; 1347 return "Internal error";
1183 case AFC_E_MUX_ERROR: 1348 case AFC_E_MUX_ERROR:
1184 return "MUX error"; 1349 return "MUX error";
1350 case AFC_E_SSL_ERROR:
1351 return "SSL error";
1185 case AFC_E_NO_MEM: 1352 case AFC_E_NO_MEM:
1186 return "Out of memory"; 1353 return "Out of memory";
1187 case AFC_E_NOT_ENOUGH_DATA: 1354 case AFC_E_NOT_ENOUGH_DATA:
1188 return "Not enough data"; 1355 return "Not enough data";
1189 case AFC_E_DIR_NOT_EMPTY: 1356 case AFC_E_DIR_NOT_EMPTY:
1190 return "Directory not empty"; 1357 return "Directory not empty";
1191 case AFC_E_FORCE_SIGNED_TYPE:
1192 return "Force signed type";
1193 default: 1358 default:
1194 break; 1359 break;
1195 } 1360 }
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 @@
24#endif 24#endif
25#include <string.h> 25#include <string.h>
26#include <stdlib.h> 26#include <stdlib.h>
27
28#ifndef _MSC_VER
27#include <unistd.h> 29#include <unistd.h>
30#endif
31
28#include <plist/plist.h> 32#include <plist/plist.h>
29 33
30#include "house_arrest.h" 34#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 @@
30#include <errno.h> 30#include <errno.h>
31#include <time.h> 31#include <time.h>
32 32
33#ifdef WIN32 33#ifdef _WIN32
34#include <winsock2.h> 34#include <winsock2.h>
35#include <ws2tcpip.h> 35#include <ws2tcpip.h>
36#include <windows.h> 36#include <windows.h>
@@ -124,32 +124,32 @@ static void id_function(CRYPTO_THREADID *thread)
124#endif 124#endif
125#endif /* HAVE_OPENSSL */ 125#endif /* HAVE_OPENSSL */
126 126
127static void internal_idevice_init(void) 127// Reference: https://stackoverflow.com/a/2390626/1806760
128{ 128// Initializer/finalizer sample for MSVC and GCC/Clang.
129#if defined(HAVE_OPENSSL) 129// 2010-2016 Joe Lowe. Released into the public domain.
130#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) 130
131 int i; 131#ifdef __cplusplus
132 SSL_library_init(); 132 #define INITIALIZER(f) \
133 133 static void f(void); \
134 mutex_buf = malloc(CRYPTO_num_locks() * sizeof(mutex_t)); 134 struct f##_t_ { f##_t_(void) { f(); } }; static f##_t_ f##_; \
135 if (!mutex_buf) 135 static void f(void)
136 return; 136#elif defined(_MSC_VER)
137 for (i = 0; i < CRYPTO_num_locks(); i++) 137 #pragma section(".CRT$XCU",read)
138 mutex_init(&mutex_buf[i]); 138 #define INITIALIZER2_(f,p) \
139 139 static void f(void); \
140#if OPENSSL_VERSION_NUMBER < 0x10000000L 140 __declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \
141 CRYPTO_set_id_callback(id_function); 141 __pragma(comment(linker,"/include:" p #f "_")) \
142 static void f(void)
143 #ifdef _WIN64
144 #define INITIALIZER(f) INITIALIZER2_(f,"")
145 #else
146 #define INITIALIZER(f) INITIALIZER2_(f,"_")
147 #endif
142#else 148#else
143 CRYPTO_THREADID_set_callback(id_function); 149 #define INITIALIZER(f) \
144#endif 150 static void f(void) __attribute__((__constructor__)); \
145 CRYPTO_set_locking_callback(locking_function); 151 static void f(void)
146#endif
147#elif defined(HAVE_GNUTLS)
148 gnutls_global_init();
149#elif defined(HAVE_MBEDTLS)
150 // NO-OP
151#endif 152#endif
152}
153 153
154static void internal_idevice_deinit(void) 154static void internal_idevice_deinit(void)
155{ 155{
@@ -181,43 +181,33 @@ static void internal_idevice_deinit(void)
181#endif 181#endif
182} 182}
183 183
184static thread_once_t init_once = THREAD_ONCE_INIT; 184INITIALIZER(internal_idevice_init)
185static thread_once_t deinit_once = THREAD_ONCE_INIT;
186
187#ifndef HAVE_ATTRIBUTE_CONSTRUCTOR
188 #if defined(__llvm__) || defined(__GNUC__)
189 #define HAVE_ATTRIBUTE_CONSTRUCTOR
190 #endif
191#endif
192
193#ifdef HAVE_ATTRIBUTE_CONSTRUCTOR
194static void __attribute__((constructor)) libimobiledevice_initialize(void)
195{ 185{
196 thread_once(&init_once, internal_idevice_init); 186#if defined(HAVE_OPENSSL)
197} 187#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
188 int i;
189 SSL_library_init();
198 190
199static void __attribute__((destructor)) libimobiledevice_deinitialize(void) 191 mutex_buf = malloc(CRYPTO_num_locks() * sizeof(mutex_t));
200{ 192 if (!mutex_buf)
201 thread_once(&deinit_once, internal_idevice_deinit); 193 return;
202} 194 for (i = 0; i < CRYPTO_num_locks(); i++)
203#elif defined(WIN32) 195 mutex_init(&mutex_buf[i]);
204BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved) 196
205{ 197#if OPENSSL_VERSION_NUMBER < 0x10000000L
206 switch (dwReason) { 198 CRYPTO_set_id_callback(id_function);
207 case DLL_PROCESS_ATTACH:
208 thread_once(&init_once, internal_idevice_init);
209 break;
210 case DLL_PROCESS_DETACH:
211 thread_once(&deinit_once, internal_idevice_deinit);
212 break;
213 default:
214 break;
215 }
216 return 1;
217}
218#else 199#else
219#warning No compiler support for constructor/destructor attributes, some features might not be available. 200 CRYPTO_THREADID_set_callback(id_function);
201#endif
202 CRYPTO_set_locking_callback(locking_function);
203#endif
204#elif defined(HAVE_GNUTLS)
205 gnutls_global_init();
206#elif defined(HAVE_MBEDTLS)
207 // NO-OP
220#endif 208#endif
209 atexit(internal_idevice_deinit);
210}
221 211
222const char* libimobiledevice_version() 212const char* libimobiledevice_version()
223{ 213{
@@ -548,7 +538,7 @@ idevice_error_t idevice_connect(idevice_t device, uint16_t port, idevice_connect
548 } 538 }
549 idevice_connection_t new_connection = (idevice_connection_t)malloc(sizeof(struct idevice_connection_private)); 539 idevice_connection_t new_connection = (idevice_connection_t)malloc(sizeof(struct idevice_connection_private));
550 new_connection->type = CONNECTION_USBMUXD; 540 new_connection->type = CONNECTION_USBMUXD;
551 new_connection->data = (void*)(long)sfd; 541 new_connection->data = (void*)(uintptr_t)sfd;
552 new_connection->ssl_data = NULL; 542 new_connection->ssl_data = NULL;
553 new_connection->device = device; 543 new_connection->device = device;
554 new_connection->ssl_recv_timeout = (unsigned int)-1; 544 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
593 583
594 idevice_connection_t new_connection = (idevice_connection_t)malloc(sizeof(struct idevice_connection_private)); 584 idevice_connection_t new_connection = (idevice_connection_t)malloc(sizeof(struct idevice_connection_private));
595 new_connection->type = CONNECTION_NETWORK; 585 new_connection->type = CONNECTION_NETWORK;
596 new_connection->data = (void*)(long)sfd; 586 new_connection->data = (void*)(uintptr_t)sfd;
597 new_connection->ssl_data = NULL; 587 new_connection->ssl_data = NULL;
598 new_connection->device = device; 588 new_connection->device = device;
599 new_connection->ssl_recv_timeout = (unsigned int)-1; 589 new_connection->ssl_recv_timeout = (unsigned int)-1;
@@ -618,11 +608,11 @@ idevice_error_t idevice_disconnect(idevice_connection_t connection)
618 } 608 }
619 idevice_error_t result = IDEVICE_E_UNKNOWN_ERROR; 609 idevice_error_t result = IDEVICE_E_UNKNOWN_ERROR;
620 if (connection->type == CONNECTION_USBMUXD) { 610 if (connection->type == CONNECTION_USBMUXD) {
621 usbmuxd_disconnect((int)(long)connection->data); 611 usbmuxd_disconnect((int)(uintptr_t)connection->data);
622 connection->data = NULL; 612 connection->data = NULL;
623 result = IDEVICE_E_SUCCESS; 613 result = IDEVICE_E_SUCCESS;
624 } else if (connection->type == CONNECTION_NETWORK) { 614 } else if (connection->type == CONNECTION_NETWORK) {
625 socket_close((int)(long)connection->data); 615 socket_close((int)(uintptr_t)connection->data);
626 connection->data = NULL; 616 connection->data = NULL;
627 result = IDEVICE_E_SUCCESS; 617 result = IDEVICE_E_SUCCESS;
628 } else { 618 } else {
@@ -647,7 +637,7 @@ static idevice_error_t internal_connection_send(idevice_connection_t connection,
647 if (connection->type == CONNECTION_USBMUXD) { 637 if (connection->type == CONNECTION_USBMUXD) {
648 int res; 638 int res;
649 do { 639 do {
650 res = usbmuxd_send((int)(long)connection->data, data, len, sent_bytes); 640 res = usbmuxd_send((int)(uintptr_t)connection->data, data, len, sent_bytes);
651 } while (res == -EAGAIN); 641 } while (res == -EAGAIN);
652 if (res < 0) { 642 if (res < 0) {
653 debug_info("ERROR: usbmuxd_send returned %d (%s)", res, strerror(-res)); 643 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,
656 return IDEVICE_E_SUCCESS; 646 return IDEVICE_E_SUCCESS;
657 } 647 }
658 if (connection->type == CONNECTION_NETWORK) { 648 if (connection->type == CONNECTION_NETWORK) {
659 int s = socket_send((int)(long)connection->data, (void*)data, len); 649 int s = socket_send((int)(uintptr_t)connection->data, (void*)data, len);
660 if (s < 0) { 650 if (s < 0) {
661 *sent_bytes = 0; 651 *sent_bytes = 0;
662 return IDEVICE_E_UNKNOWN_ERROR; 652 return IDEVICE_E_UNKNOWN_ERROR;
@@ -763,7 +753,7 @@ static idevice_error_t internal_connection_receive_timeout(idevice_connection_t
763 } 753 }
764 754
765 if (connection->type == CONNECTION_USBMUXD) { 755 if (connection->type == CONNECTION_USBMUXD) {
766 int conn_error = usbmuxd_recv_timeout((int)(long)connection->data, data, len, recv_bytes, timeout); 756 int conn_error = usbmuxd_recv_timeout((int)(uintptr_t)connection->data, data, len, recv_bytes, timeout);
767 idevice_error_t error = socket_recv_to_idevice_error(conn_error, len, *recv_bytes); 757 idevice_error_t error = socket_recv_to_idevice_error(conn_error, len, *recv_bytes);
768 if (error == IDEVICE_E_UNKNOWN_ERROR) { 758 if (error == IDEVICE_E_UNKNOWN_ERROR) {
769 debug_info("ERROR: usbmuxd_recv_timeout returned %d (%s)", conn_error, strerror(-conn_error)); 759 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
771 return error; 761 return error;
772 } 762 }
773 if (connection->type == CONNECTION_NETWORK) { 763 if (connection->type == CONNECTION_NETWORK) {
774 int res = socket_receive_timeout((int)(long)connection->data, data, len, 0, timeout); 764 int res = socket_receive_timeout((int)(uintptr_t)connection->data, data, len, 0, timeout);
775 idevice_error_t error = socket_recv_to_idevice_error(res, 0, 0); 765 idevice_error_t error = socket_recv_to_idevice_error(res, 0, 0);
776 if (error == IDEVICE_E_SUCCESS) { 766 if (error == IDEVICE_E_SUCCESS) {
777 *recv_bytes = (uint32_t)res; 767 *recv_bytes = (uint32_t)res;
@@ -863,7 +853,7 @@ static idevice_error_t internal_connection_receive(idevice_connection_t connecti
863 } 853 }
864 854
865 if (connection->type == CONNECTION_USBMUXD) { 855 if (connection->type == CONNECTION_USBMUXD) {
866 int res = usbmuxd_recv((int)(long)connection->data, data, len, recv_bytes); 856 int res = usbmuxd_recv((int)(uintptr_t)connection->data, data, len, recv_bytes);
867 if (res < 0) { 857 if (res < 0) {
868 debug_info("ERROR: usbmuxd_recv returned %d (%s)", res, strerror(-res)); 858 debug_info("ERROR: usbmuxd_recv returned %d (%s)", res, strerror(-res));
869 return IDEVICE_E_UNKNOWN_ERROR; 859 return IDEVICE_E_UNKNOWN_ERROR;
@@ -871,7 +861,7 @@ static idevice_error_t internal_connection_receive(idevice_connection_t connecti
871 return IDEVICE_E_SUCCESS; 861 return IDEVICE_E_SUCCESS;
872 } 862 }
873 if (connection->type == CONNECTION_NETWORK) { 863 if (connection->type == CONNECTION_NETWORK) {
874 int res = socket_receive((int)(long)connection->data, data, len); 864 int res = socket_receive((int)(uintptr_t)connection->data, data, len);
875 if (res < 0) { 865 if (res < 0) {
876 debug_info("ERROR: socket_receive returned %d (%s)", res, strerror(-res)); 866 debug_info("ERROR: socket_receive returned %d (%s)", res, strerror(-res));
877 return IDEVICE_E_UNKNOWN_ERROR; 867 return IDEVICE_E_UNKNOWN_ERROR;
@@ -924,11 +914,11 @@ idevice_error_t idevice_connection_get_fd(idevice_connection_t connection, int *
924 } 914 }
925 915
926 if (connection->type == CONNECTION_USBMUXD) { 916 if (connection->type == CONNECTION_USBMUXD) {
927 *fd = (int)(long)connection->data; 917 *fd = (int)(uintptr_t)connection->data;
928 return IDEVICE_E_SUCCESS; 918 return IDEVICE_E_SUCCESS;
929 } 919 }
930 if (connection->type == CONNECTION_NETWORK) { 920 if (connection->type == CONNECTION_NETWORK) {
931 *fd = (int)(long)connection->data; 921 *fd = (int)(uintptr_t)connection->data;
932 return IDEVICE_E_SUCCESS; 922 return IDEVICE_E_SUCCESS;
933 } 923 }
934 924
@@ -956,6 +946,20 @@ idevice_error_t idevice_get_udid(idevice_t device, char **udid)
956 return IDEVICE_E_SUCCESS; 946 return IDEVICE_E_SUCCESS;
957} 947}
958 948
949unsigned int idevice_get_device_version(idevice_t device)
950{
951 if (!device) {
952 return 0;
953 }
954 if (!device->version) {
955 lockdownd_client_t lockdown = NULL;
956 lockdownd_client_new(device, &lockdown, NULL);
957 // we don't handle any errors here. We should have the product version cached now.
958 lockdownd_client_free(lockdown);
959 }
960 return device->version;
961}
962
959#if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS) 963#if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS)
960typedef ssize_t ssl_cb_ret_type_t; 964typedef ssize_t ssl_cb_ret_type_t;
961#elif defined(HAVE_MBEDTLS) 965#elif defined(HAVE_MBEDTLS)
@@ -1075,13 +1079,14 @@ static long ssl_idevice_bio_callback(BIO *b, int oper, const char *argp, int arg
1075 idevice_connection_t conn = (idevice_connection_t)BIO_get_callback_arg(b); 1079 idevice_connection_t conn = (idevice_connection_t)BIO_get_callback_arg(b);
1076#if OPENSSL_VERSION_NUMBER < 0x30000000L 1080#if OPENSSL_VERSION_NUMBER < 0x30000000L
1077 size_t len = (size_t)argi; 1081 size_t len = (size_t)argi;
1078 size_t *processed = (size_t*)&bytes;
1079#endif 1082#endif
1080 switch (oper) { 1083 switch (oper) {
1081 case (BIO_CB_READ|BIO_CB_RETURN): 1084 case (BIO_CB_READ|BIO_CB_RETURN):
1082 if (argp) { 1085 if (argp) {
1083 bytes = internal_ssl_read(conn, (char *)argp, len); 1086 bytes = internal_ssl_read(conn, (char *)argp, len);
1084 *processed = bytes; 1087#if OPENSSL_VERSION_NUMBER >= 0x30000000L
1088 *processed = (size_t)(bytes < 0) ? 0 : bytes;
1089#endif
1085 return (long)bytes; 1090 return (long)bytes;
1086 } 1091 }
1087 return 0; 1092 return 0;
@@ -1090,7 +1095,9 @@ static long ssl_idevice_bio_callback(BIO *b, int oper, const char *argp, int arg
1090 // fallthrough 1095 // fallthrough
1091 case (BIO_CB_WRITE|BIO_CB_RETURN): 1096 case (BIO_CB_WRITE|BIO_CB_RETURN):
1092 bytes = internal_ssl_write(conn, argp, len); 1097 bytes = internal_ssl_write(conn, argp, len);
1093 *processed = bytes; 1098#if OPENSSL_VERSION_NUMBER >= 0x30000000L
1099 *processed = (size_t)(bytes < 0) ? 0 : bytes;
1100#endif
1094 return (long)bytes; 1101 return (long)bytes;
1095 default: 1102 default:
1096 return retvalue; 1103 return retvalue;
@@ -1239,7 +1246,7 @@ idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection)
1239#if OPENSSL_VERSION_NUMBER < 0x10100002L || \ 1246#if OPENSSL_VERSION_NUMBER < 0x10100002L || \
1240 (defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x2060000fL)) 1247 (defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x2060000fL))
1241 /* force use of TLSv1 for older devices */ 1248 /* force use of TLSv1 for older devices */
1242 if (connection->device->version < DEVICE_VERSION(10,0,0)) { 1249 if (connection->device->version < IDEVICE_DEVICE_VERSION(10,0,0)) {
1243#ifdef SSL_OP_NO_TLSv1_1 1250#ifdef SSL_OP_NO_TLSv1_1
1244 SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_1); 1251 SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_1);
1245#endif 1252#endif
@@ -1252,7 +1259,7 @@ idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection)
1252 } 1259 }
1253#else 1260#else
1254 SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_VERSION); 1261 SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_VERSION);
1255 if (connection->device->version < DEVICE_VERSION(10,0,0)) { 1262 if (connection->device->version < IDEVICE_DEVICE_VERSION(10,0,0)) {
1256 SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_VERSION); 1263 SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_VERSION);
1257 if (connection->device->version == 0) { 1264 if (connection->device->version == 0) {
1258 /* 1265 /*
@@ -1338,7 +1345,7 @@ idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection)
1338 if (ssl_error == 0 || ssl_error != SSL_ERROR_WANT_READ) { 1345 if (ssl_error == 0 || ssl_error != SSL_ERROR_WANT_READ) {
1339 break; 1346 break;
1340 } 1347 }
1341#ifdef WIN32 1348#ifdef _WIN32
1342 Sleep(100); 1349 Sleep(100);
1343#else 1350#else
1344 struct timespec ts = { 0, 100000000 }; 1351 struct timespec ts = { 0, 100000000 };
@@ -1544,3 +1551,28 @@ idevice_error_t idevice_connection_disable_bypass_ssl(idevice_connection_t conne
1544 1551
1545 return IDEVICE_E_SUCCESS; 1552 return IDEVICE_E_SUCCESS;
1546} 1553}
1554
1555const char* idevice_strerror(idevice_error_t err)
1556{
1557 switch (err) {
1558 case IDEVICE_E_SUCCESS:
1559 return "Success";
1560 case IDEVICE_E_INVALID_ARG:
1561 return "Invalid argument";
1562 case IDEVICE_E_UNKNOWN_ERROR:
1563 return "Unknown Error";
1564 case IDEVICE_E_NO_DEVICE:
1565 return "No device";
1566 case IDEVICE_E_NOT_ENOUGH_DATA:
1567 return "Not enough data";
1568 case IDEVICE_E_CONNREFUSED:
1569 return "Connection refused";
1570 case IDEVICE_E_SSL_ERROR:
1571 return "SSL error";
1572 case IDEVICE_E_TIMEOUT:
1573 return "Timeout";
1574 default:
1575 break;
1576 }
1577 return "Unknown Error";
1578}
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 @@
52#include "common/userpref.h" 52#include "common/userpref.h"
53#include "libimobiledevice/libimobiledevice.h" 53#include "libimobiledevice/libimobiledevice.h"
54 54
55#define DEVICE_VERSION(maj, min, patch) (((maj & 0xFF) << 16) | ((min & 0xFF) << 8) | (patch & 0xFF))
56
57#define DEVICE_CLASS_IPHONE 1 55#define DEVICE_CLASS_IPHONE 1
58#define DEVICE_CLASS_IPAD 2 56#define DEVICE_CLASS_IPAD 2
59#define DEVICE_CLASS_IPOD 3 57#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 @@
26#include <string.h> 26#include <string.h>
27#include <stdlib.h> 27#include <stdlib.h>
28#include <inttypes.h> 28#include <inttypes.h>
29
30#ifndef _MSC_VER
29#include <unistd.h> 31#include <unistd.h>
32#endif
33
30#include <plist/plist.h> 34#include <plist/plist.h>
31 35
32#include "installation_proxy.h" 36#include "installation_proxy.h"
@@ -251,7 +255,7 @@ instproxy_error_t instproxy_client_new(idevice_t device, lockdownd_service_descr
251 255
252instproxy_error_t instproxy_client_start_service(idevice_t device, instproxy_client_t * client, const char* label) 256instproxy_error_t instproxy_client_start_service(idevice_t device, instproxy_client_t * client, const char* label)
253{ 257{
254 instproxy_error_t err = INSTPROXY_E_UNKNOWN_ERROR; 258 int32_t err = INSTPROXY_E_UNKNOWN_ERROR;
255 service_client_factory_start_service(device, INSTPROXY_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(instproxy_client_new), &err); 259 service_client_factory_start_service(device, INSTPROXY_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(instproxy_client_new), &err);
256 return err; 260 return err;
257} 261}
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 @@
29#define __USE_GNU 1 29#define __USE_GNU 1
30#include <stdio.h> 30#include <stdio.h>
31#include <ctype.h> 31#include <ctype.h>
32
33#ifndef _MSC_VER
32#include <unistd.h> 34#include <unistd.h>
35#endif
36
33#include <plist/plist.h> 37#include <plist/plist.h>
34 38
35#include "idevice.h" 39#include "idevice.h"
@@ -505,7 +509,7 @@ lockdownd_error_t lockdownd_cu_pairing_create(lockdownd_client_t client, lockdow
505 char *s_version = NULL; 509 char *s_version = NULL;
506 plist_get_string_val(p_version, &s_version); 510 plist_get_string_val(p_version, &s_version);
507 if (s_version && sscanf(s_version, "%d.%d.%d", &vers[0], &vers[1], &vers[2]) >= 2) { 511 if (s_version && sscanf(s_version, "%d.%d.%d", &vers[0], &vers[1], &vers[2]) >= 2) {
508 client->device->version = DEVICE_VERSION(vers[0], vers[1], vers[2]); 512 client->device->version = IDEVICE_DEVICE_VERSION(vers[0], vers[1], vers[2]);
509 } 513 }
510 free(s_version); 514 free(s_version);
511 } 515 }
@@ -653,7 +657,7 @@ lockdownd_error_t lockdownd_cu_pairing_create(lockdownd_client_t client, lockdow
653 CFStringGetCString(cname, hostname, sizeof(hostname), kCFStringEncodingUTF8); 657 CFStringGetCString(cname, hostname, sizeof(hostname), kCFStringEncodingUTF8);
654 CFRelease(cname); 658 CFRelease(cname);
655#else 659#else
656#ifdef WIN32 660#ifdef _WIN32
657 DWORD hostname_len = sizeof(hostname); 661 DWORD hostname_len = sizeof(hostname);
658 GetComputerName(hostname, &hostname_len); 662 GetComputerName(hostname, &hostname_len);
659#else 663#else
@@ -957,12 +961,12 @@ lockdownd_error_t lockdownd_cu_send_request_and_get_reply(lockdownd_client_t cli
957 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); 961 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);
958 962
959 // 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". 963 // 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".
960 unsigned char cu_nonce[12] = "sendone01234"; // guaranteed to be random by fair dice troll 964 unsigned char cu_nonce[] = "sendone01234"; // guaranteed to be random by fair dice troll
961 if (client->device->version >= DEVICE_VERSION(11,2,0)) { 965 if (client->device->version >= IDEVICE_DEVICE_VERSION(11,2,0)) {
962#if defined(HAVE_OPENSSL) 966#if defined(HAVE_OPENSSL)
963 RAND_bytes(cu_nonce, sizeof(cu_nonce)); 967 RAND_bytes(cu_nonce, sizeof(cu_nonce)-1);
964#elif defined(HAVE_GCRYPT) 968#elif defined(HAVE_GCRYPT)
965 gcry_create_nonce(cu_nonce, sizeof(cu_nonce)); 969 gcry_create_nonce(cu_nonce, sizeof(cu_nonce)-1);
966#endif 970#endif
967 } 971 }
968 972
@@ -1128,7 +1132,7 @@ lockdownd_error_t lockdownd_pair_cu(lockdownd_client_t client)
1128 plist_free(pubkey); 1132 plist_free(pubkey);
1129 1133
1130 plist_t pair_record_plist = plist_new_dict(); 1134 plist_t pair_record_plist = plist_new_dict();
1131 pair_record_generate_keys_and_certs(pair_record_plist, public_key); 1135 pair_record_generate_keys_and_certs(pair_record_plist, public_key, client->device->version);
1132 1136
1133 char* host_id = NULL; 1137 char* host_id = NULL;
1134 char* system_buid = NULL; 1138 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 @@
32#define __USE_GNU 1 32#define __USE_GNU 1
33#include <stdio.h> 33#include <stdio.h>
34#include <ctype.h> 34#include <ctype.h>
35
36#ifndef _MSC_VER
35#include <unistd.h> 37#include <unistd.h>
38#endif
39
36#include <plist/plist.h> 40#include <plist/plist.h>
37#include <libimobiledevice-glue/utils.h> 41#include <libimobiledevice-glue/utils.h>
38 42
@@ -43,7 +47,7 @@
43#include "common/userpref.h" 47#include "common/userpref.h"
44#include "asprintf.h" 48#include "asprintf.h"
45 49
46#ifdef WIN32 50#ifdef _WIN32
47#include <windows.h> 51#include <windows.h>
48#define sleep(x) Sleep(x*1000) 52#define sleep(x) Sleep(x*1000)
49#endif 53#endif
@@ -617,6 +621,7 @@ lockdownd_error_t lockdownd_client_new(idevice_t device, lockdownd_client_t *cli
617 .port = 0xf27e, 621 .port = 0xf27e,
618 .ssl_enabled = 0 622 .ssl_enabled = 0
619 }; 623 };
624 char *type = NULL;
620 625
621 property_list_service_client_t plistclient = NULL; 626 property_list_service_client_t plistclient = NULL;
622 if (property_list_service_client_new(device, (lockdownd_service_descriptor_t)&service, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) { 627 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
638 643
639 client_loc->label = label ? strdup(label) : NULL; 644 client_loc->label = label ? strdup(label) : NULL;
640 645
641 *client = client_loc; 646 int is_lockdownd = 0;
642 647 if (lockdownd_query_type(client_loc, &type) != LOCKDOWN_E_SUCCESS) {
643 return LOCKDOWN_E_SUCCESS;
644}
645
646lockdownd_error_t lockdownd_client_new_with_handshake(idevice_t device, lockdownd_client_t *client, const char *label)
647{
648 if (!client)
649 return LOCKDOWN_E_INVALID_ARG;
650
651 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;
652 lockdownd_client_t client_loc = NULL;
653 plist_t pair_record = NULL;
654 char *host_id = NULL;
655 char *type = NULL;
656
657 ret = lockdownd_client_new(device, &client_loc, label);
658 if (LOCKDOWN_E_SUCCESS != ret) {
659 debug_info("failed to create lockdownd client.");
660 return ret;
661 }
662
663 /* perform handshake */
664 ret = lockdownd_query_type(client_loc, &type);
665 if (LOCKDOWN_E_SUCCESS != ret) {
666 debug_info("QueryType failed in the lockdownd client."); 648 debug_info("QueryType failed in the lockdownd client.");
667 } else if (strcmp("com.apple.mobile.lockdown", type) != 0) { 649 } else if (!strcmp("com.apple.mobile.lockdown", type)) {
668 debug_info("Warning QueryType request returned \"%s\".", type); 650 is_lockdownd = 1;
651 } else {
652 debug_info("QueryType request returned \"%s\"", type);
669 } 653 }
670 free(type); 654 free(type);
671 655
672 if (device->version == 0) { 656 *client = client_loc;
657
658 if (is_lockdownd && device->version == 0) {
673 plist_t p_version = NULL; 659 plist_t p_version = NULL;
674 if (lockdownd_get_value(client_loc, NULL, "ProductVersion", &p_version) == LOCKDOWN_E_SUCCESS) { 660 if (lockdownd_get_value(client_loc, NULL, "ProductVersion", &p_version) == LOCKDOWN_E_SUCCESS) {
675 int vers[3] = {0, 0, 0}; 661 int vers[3] = {0, 0, 0};
676 char *s_version = NULL; 662 char *s_version = NULL;
677 plist_get_string_val(p_version, &s_version); 663 plist_get_string_val(p_version, &s_version);
678 if (s_version && sscanf(s_version, "%d.%d.%d", &vers[0], &vers[1], &vers[2]) >= 2) { 664 if (s_version && sscanf(s_version, "%d.%d.%d", &vers[0], &vers[1], &vers[2]) >= 2) {
679 device->version = DEVICE_VERSION(vers[0], vers[1], vers[2]); 665 device->version = IDEVICE_DEVICE_VERSION(vers[0], vers[1], vers[2]);
680 } 666 }
681 free(s_version); 667 free(s_version);
682 } 668 }
683 plist_free(p_version); 669 plist_free(p_version);
684 } 670 }
685 if (device->device_class == 0) { 671 if (is_lockdownd && device->device_class == 0) {
686 plist_t p_device_class = NULL; 672 plist_t p_device_class = NULL;
687 if (lockdownd_get_value(client_loc, NULL, "DeviceClass", &p_device_class) == LOCKDOWN_E_SUCCESS) { 673 if (lockdownd_get_value(client_loc, NULL, "DeviceClass", &p_device_class) == LOCKDOWN_E_SUCCESS) {
688 char* s_device_class = NULL; 674 char* s_device_class = NULL;
@@ -707,6 +693,26 @@ lockdownd_error_t lockdownd_client_new_with_handshake(idevice_t device, lockdown
707 plist_free(p_device_class); 693 plist_free(p_device_class);
708 } 694 }
709 695
696 return LOCKDOWN_E_SUCCESS;
697}
698
699lockdownd_error_t lockdownd_client_new_with_handshake(idevice_t device, lockdownd_client_t *client, const char *label)
700{
701 if (!client)
702 return LOCKDOWN_E_INVALID_ARG;
703
704 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;
705 lockdownd_client_t client_loc = NULL;
706 plist_t pair_record = NULL;
707 char *host_id = NULL;
708
709 ret = lockdownd_client_new(device, &client_loc, label);
710 if (LOCKDOWN_E_SUCCESS != ret) {
711 debug_info("failed to create lockdownd client.");
712 return ret;
713 }
714
715 /* perform handshake */
710 userpref_error_t uerr = userpref_read_pair_record(client_loc->device->udid, &pair_record); 716 userpref_error_t uerr = userpref_read_pair_record(client_loc->device->udid, &pair_record);
711 if (uerr == USERPREF_E_READ_ERROR) { 717 if (uerr == USERPREF_E_READ_ERROR) {
712 debug_info("ERROR: Failed to retrieve pair record for %s", client_loc->device->udid); 718 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
730 plist_free(pair_record); 736 plist_free(pair_record);
731 pair_record = NULL; 737 pair_record = NULL;
732 738
733 if (device->version < DEVICE_VERSION(7,0,0) && device->device_class != DEVICE_CLASS_WATCH) { 739 if (device->version < IDEVICE_DEVICE_VERSION(7,0,0) && device->device_class != DEVICE_CLASS_WATCH) {
734 /* for older devices, we need to validate pairing to receive trusted host status */ 740 /* for older devices, we need to validate pairing to receive trusted host status */
735 ret = lockdownd_validate_pair(client_loc, NULL); 741 ret = lockdownd_validate_pair(client_loc, NULL);
736 742
@@ -836,7 +842,7 @@ static lockdownd_error_t pair_record_generate(lockdownd_client_t client, plist_t
836 842
837 /* generate keys and certificates into pair record */ 843 /* generate keys and certificates into pair record */
838 userpref_error_t uret = USERPREF_E_SUCCESS; 844 userpref_error_t uret = USERPREF_E_SUCCESS;
839 uret = pair_record_generate_keys_and_certs(*pair_record, public_key); 845 uret = pair_record_generate_keys_and_certs(*pair_record, public_key, client->device->version);
840 switch(uret) { 846 switch(uret) {
841 case USERPREF_E_INVALID_ARG: 847 case USERPREF_E_INVALID_ARG:
842 ret = LOCKDOWN_E_INVALID_ARG; 848 ret = LOCKDOWN_E_INVALID_ARG;
@@ -846,6 +852,7 @@ static lockdownd_error_t pair_record_generate(lockdownd_client_t client, plist_t
846 break; 852 break;
847 case USERPREF_E_SSL_ERROR: 853 case USERPREF_E_SSL_ERROR:
848 ret = LOCKDOWN_E_SSL_ERROR; 854 ret = LOCKDOWN_E_SSL_ERROR;
855 break;
849 default: 856 default:
850 break; 857 break;
851 } 858 }
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 @@
24#endif 24#endif
25#include <string.h> 25#include <string.h>
26#include <stdlib.h> 26#include <stdlib.h>
27#include <stdio.h>
28
29#ifndef _MSC_VER
27#include <unistd.h> 30#include <unistd.h>
31#endif
32
28#include <plist/plist.h> 33#include <plist/plist.h>
29#include <stdio.h>
30 34
31#include "misagent.h" 35#include "misagent.h"
32#include "property_list_service.h" 36#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 @@
24#endif 24#endif
25#include <string.h> 25#include <string.h>
26#include <stdlib.h> 26#include <stdlib.h>
27
28#ifndef _MSC_VER
27#include <unistd.h> 29#include <unistd.h>
30#endif
31
28#include <plist/plist.h> 32#include <plist/plist.h>
29 33
30#include "mobile_image_mounter.h" 34#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 @@
24#endif 24#endif
25#include <string.h> 25#include <string.h>
26#include <stdlib.h> 26#include <stdlib.h>
27
28#ifndef _MSC_VER
27#include <unistd.h> 29#include <unistd.h>
30#endif
31
28#include <plist/plist.h> 32#include <plist/plist.h>
29 33
30#include "notification_proxy.h" 34#include "notification_proxy.h"
31#include "property_list_service.h" 35#include "property_list_service.h"
32#include "common/debug.h" 36#include "common/debug.h"
33 37
34#ifdef WIN32 38#ifdef _WIN32
39#include <windows.h>
35#define sleep(x) Sleep(x*1000) 40#define sleep(x) Sleep(x*1000)
36#endif 41#endif
37 42
@@ -109,7 +114,7 @@ np_error_t np_client_new(idevice_t device, lockdownd_service_descriptor_t servic
109 114
110np_error_t np_client_start_service(idevice_t device, np_client_t* client, const char* label) 115np_error_t np_client_start_service(idevice_t device, np_client_t* client, const char* label)
111{ 116{
112 np_error_t err = NP_E_UNKNOWN_ERROR; 117 int32_t err = NP_E_UNKNOWN_ERROR;
113 service_client_factory_start_service(device, NP_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(np_client_new), &err); 118 service_client_factory_start_service(device, NP_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(np_client_new), &err);
114 return err; 119 return err;
115} 120}
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 @@
1/*
2 * ostrace.c
3 * com.apple.os_trace_relay service implementation.
4 *
5 * Copyright (c) 2020-2025 Nikias Bassen, All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
25#include <string.h>
26#include <stdlib.h>
27
28#include <plist/plist.h>
29
30#include "ostrace.h"
31#include "lockdown.h"
32#include "common/debug.h"
33#include "endianness.h"
34
35struct ostrace_worker_thread {
36 ostrace_client_t client;
37 ostrace_activity_cb_t cbfunc;
38 void *user_data;
39};
40
41/**
42 * Convert a service_error_t value to a ostrace_error_t value.
43 * Used internally to get correct error codes.
44 *
45 * @param err An service_error_t error code
46 *
47 * @return A matching ostrace_error_t error code,
48 * OSTRACE_E_UNKNOWN_ERROR otherwise.
49 */
50static ostrace_error_t ostrace_error(service_error_t err)
51{
52 switch (err) {
53 case SERVICE_E_SUCCESS:
54 return OSTRACE_E_SUCCESS;
55 case SERVICE_E_INVALID_ARG:
56 return OSTRACE_E_INVALID_ARG;
57 case SERVICE_E_MUX_ERROR:
58 return OSTRACE_E_MUX_ERROR;
59 case SERVICE_E_SSL_ERROR:
60 return OSTRACE_E_SSL_ERROR;
61 case SERVICE_E_NOT_ENOUGH_DATA:
62 return OSTRACE_E_NOT_ENOUGH_DATA;
63 case SERVICE_E_TIMEOUT:
64 return OSTRACE_E_TIMEOUT;
65 default:
66 break;
67 }
68 return OSTRACE_E_UNKNOWN_ERROR;
69}
70
71ostrace_error_t ostrace_client_new(idevice_t device, lockdownd_service_descriptor_t service, ostrace_client_t * client)
72{
73 *client = NULL;
74
75 if (!device || !service || service->port == 0 || !client || *client) {
76 debug_info("Incorrect parameter passed to ostrace_client_new.");
77 return OSTRACE_E_INVALID_ARG;
78 }
79
80 debug_info("Creating ostrace_client, port = %d.", service->port);
81
82 service_client_t parent = NULL;
83 ostrace_error_t ret = ostrace_error(service_client_new(device, service, &parent));
84 if (ret != OSTRACE_E_SUCCESS) {
85 debug_info("Creating base service client failed. Error: %i", ret);
86 return ret;
87 }
88
89 ostrace_client_t client_loc = (ostrace_client_t) malloc(sizeof(struct ostrace_client_private));
90 client_loc->parent = parent;
91 client_loc->worker = THREAD_T_NULL;
92
93 *client = client_loc;
94
95 debug_info("ostrace_client successfully created.");
96 return 0;
97}
98
99ostrace_error_t ostrace_client_start_service(idevice_t device, ostrace_client_t * client, const char* label)
100{
101 ostrace_error_t err = OSTRACE_E_UNKNOWN_ERROR;
102 service_client_factory_start_service(device, OSTRACE_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(ostrace_client_new), &err);
103 return err;
104}
105
106ostrace_error_t ostrace_client_free(ostrace_client_t client)
107{
108 if (!client)
109 return OSTRACE_E_INVALID_ARG;
110 ostrace_stop_activity(client);
111 ostrace_error_t err = ostrace_error(service_client_free(client->parent));
112 free(client);
113
114 return err;
115}
116
117static ostrace_error_t ostrace_send_plist(ostrace_client_t client, plist_t plist)
118{
119 ostrace_error_t res = OSTRACE_E_UNKNOWN_ERROR;
120 uint32_t blen = 0;
121 char* bin = NULL;
122 uint32_t sent = 0;
123 uint32_t swapped_len = 0;
124
125 if (!client || !plist) {
126 return OSTRACE_E_INVALID_ARG;
127 }
128
129 plist_to_bin(plist, &bin, &blen);
130 swapped_len = htobe32(blen);
131
132 res = ostrace_error(service_send(client->parent, (char*)&swapped_len, 4, &sent));
133 if (res == OSTRACE_E_SUCCESS) {
134 res = ostrace_error(service_send(client->parent, bin, blen, &sent));
135 }
136 free(bin);
137 return res;
138}
139
140static ostrace_error_t ostrace_receive_plist(ostrace_client_t client, plist_t *plist)
141{
142 ostrace_error_t res = OSTRACE_E_UNKNOWN_ERROR;
143 uint8_t msgtype = 0;
144 uint32_t received = 0;
145 res = ostrace_error(service_receive(client->parent, (char*)&msgtype, 1, &received));
146 if (res != OSTRACE_E_SUCCESS) {
147 debug_info("Failed to read message type from service");
148 return res;
149 }
150 uint32_t rlen = 0;
151 res = ostrace_error(service_receive(client->parent, (char*)&rlen, 4, &received));
152 if (res != OSTRACE_E_SUCCESS) {
153 debug_info("Failed to read message size from service");
154 return res;
155 }
156
157 if (msgtype == 1) {
158 rlen = be32toh(rlen);
159 } else if (msgtype == 2) {
160 rlen = le32toh(rlen);
161 } else {
162 debug_info("Unexpected message type %d", msgtype);
163 return OSTRACE_E_UNKNOWN_ERROR;
164 }
165 debug_info("got length %d", rlen);
166
167 char* buf = (char*)malloc(rlen);
168 res = ostrace_error(service_receive(client->parent, buf, rlen, &received));
169 if (res != OSTRACE_E_SUCCESS) {
170 return res;
171 }
172
173 plist_t reply = NULL;
174 plist_err_t perr = plist_from_memory(buf, received, &reply, NULL);
175 free(buf);
176 if (perr != PLIST_ERR_SUCCESS) {
177 return OSTRACE_E_UNKNOWN_ERROR;
178 }
179 *plist = reply;
180 return OSTRACE_E_SUCCESS;
181}
182
183static ostrace_error_t _ostrace_check_result(plist_t reply)
184{
185 ostrace_error_t res = OSTRACE_E_REQUEST_FAILED;
186 if (!reply) {
187 return res;
188 }
189 plist_t p_status = plist_dict_get_item(reply, "Status");
190 if (!p_status) {
191 return res;
192 }
193 const char* status = plist_get_string_ptr(p_status, NULL);
194 if (!status) {
195 return res;
196 }
197 if (!strcmp(status, "RequestSuccessful")) {
198 res = OSTRACE_E_SUCCESS;
199 }
200 return res;
201}
202
203void *ostrace_worker(void *arg)
204{
205 ostrace_error_t res = OSTRACE_E_UNKNOWN_ERROR;
206 struct ostrace_worker_thread *oswt = (struct ostrace_worker_thread*)arg;
207
208 if (!oswt)
209 return NULL;
210
211 uint8_t msgtype = 0;
212 uint32_t received = 0;
213
214 debug_info("Running");
215
216 while (oswt->client->parent) {
217 res = ostrace_error(service_receive_with_timeout(oswt->client->parent, (char*)&msgtype, 1, &received, 100));
218 if (res == OSTRACE_E_TIMEOUT) {
219 continue;
220 }
221 if (res != OSTRACE_E_SUCCESS) {
222 debug_info("Failed to read message type from service");
223 break;
224 }
225 uint32_t rlen = 0;
226 res = ostrace_error(service_receive(oswt->client->parent, (char*)&rlen, 4, &received));
227 if (res != OSTRACE_E_SUCCESS) {
228 debug_info("Failed to read message size from service");
229 break;
230 }
231
232 if (msgtype == 1) {
233 rlen = be32toh(rlen);
234 } else if (msgtype == 2) {
235 rlen = le32toh(rlen);
236 } else {
237 debug_info("Unexpected message type %d", msgtype);
238 break;
239 }
240
241 debug_info("got length %d", rlen);
242
243 void* buf = malloc(rlen);
244 res = ostrace_error(service_receive(oswt->client->parent, (char*)buf, rlen, &received));
245 if (res != OSTRACE_E_SUCCESS) {
246 debug_info("Failed to receive %d bytes, error %d", rlen, res);
247 break;
248 }
249 if (received < rlen) {
250 debug_info("Failed to receive all data, got %d/%d", received, rlen);
251 break;
252 }
253 oswt->cbfunc(buf, received, oswt->user_data);
254 }
255
256 if (oswt) {
257 free(oswt);
258 }
259
260 debug_info("Exiting");
261
262 return NULL;
263}
264
265ostrace_error_t ostrace_start_activity(ostrace_client_t client, plist_t options, ostrace_activity_cb_t callback, void* user_data)
266{
267 if (!client || !callback)
268 return OSTRACE_E_INVALID_ARG;
269
270 ostrace_error_t res = OSTRACE_E_UNKNOWN_ERROR;
271
272 if (client->worker) {
273 debug_info("Another ostrace activity thread appears to be running already.");
274 return res;
275 }
276
277 plist_t dict = plist_new_dict();
278 plist_dict_set_item(dict, "Pid", plist_new_uint(0x0FFFFFFFF));
279 plist_dict_set_item(dict, "MessageFilter", plist_new_uint(0xFFFF));
280 plist_dict_set_item(dict, "StreamFlags", plist_new_uint(0x3C));
281 if (options) {
282 plist_dict_merge(&dict, options);
283 }
284 plist_dict_set_item(dict, "Request", plist_new_string("StartActivity"));
285
286 res = ostrace_send_plist(client, dict);
287 plist_free(dict);
288 if (res != OSTRACE_E_SUCCESS) {
289 return res;
290 }
291
292 dict = NULL;
293 res = ostrace_receive_plist(client, &dict);
294 if (res != OSTRACE_E_SUCCESS) {
295 return res;
296 }
297 res = _ostrace_check_result(dict);
298 if (res != OSTRACE_E_SUCCESS) {
299 return res;
300 }
301
302 /* start worker thread */
303 struct ostrace_worker_thread *oswt = (struct ostrace_worker_thread*)malloc(sizeof(struct ostrace_worker_thread));
304 if (oswt) {
305 oswt->client = client;
306 oswt->cbfunc = callback;
307 oswt->user_data = user_data;
308
309 if (thread_new(&client->worker, ostrace_worker, oswt) == 0) {
310 res = OSTRACE_E_SUCCESS;
311 }
312 }
313
314 return res;
315}
316
317ostrace_error_t ostrace_stop_activity(ostrace_client_t client)
318{
319 if (client->worker) {
320 /* notify thread to finish */
321 service_client_t parent = client->parent;
322 client->parent = NULL;
323 /* join thread to make it exit */
324 thread_join(client->worker);
325 thread_free(client->worker);
326 client->worker = THREAD_T_NULL;
327 client->parent = parent;
328 }
329
330 return OSTRACE_E_SUCCESS;
331}
332
333ostrace_error_t ostrace_get_pid_list(ostrace_client_t client, plist_t* list)
334{
335 ostrace_error_t res = OSTRACE_E_UNKNOWN_ERROR;
336 plist_t dict = plist_new_dict();
337 plist_dict_set_item(dict, "Request", plist_new_string("PidList"));
338
339 if (!client || !list) {
340 return OSTRACE_E_INVALID_ARG;
341 }
342
343 res = ostrace_send_plist(client, dict);
344 plist_free(dict);
345 if (res != OSTRACE_E_SUCCESS) {
346 return res;
347 }
348
349 plist_t reply = NULL;
350 res = ostrace_receive_plist(client, &reply);
351 if (res != OSTRACE_E_SUCCESS) {
352 return res;
353 }
354 res = _ostrace_check_result(reply);
355 if (res != OSTRACE_E_SUCCESS) {
356 return res;
357 }
358
359 plist_t payload = plist_dict_get_item(reply, "Payload");
360 if (!payload) {
361 return OSTRACE_E_REQUEST_FAILED;
362 }
363 *list = plist_copy(payload);
364 plist_free(reply);
365
366 return OSTRACE_E_SUCCESS;
367}
368
369ostrace_error_t ostrace_create_archive(ostrace_client_t client, plist_t options, ostrace_archive_write_cb_t callback, void* user_data)
370{
371 ostrace_error_t res = OSTRACE_E_UNKNOWN_ERROR;
372 if (!client || !callback) {
373 return OSTRACE_E_INVALID_ARG;
374 }
375 plist_t dict = plist_new_dict();
376 if (options) {
377 plist_dict_merge(&dict, options);
378 }
379 plist_dict_set_item(dict, "Request", plist_new_string("CreateArchive"));
380
381 res = ostrace_send_plist(client, dict);
382 plist_free(dict);
383 if (res != OSTRACE_E_SUCCESS) {
384 return res;
385 }
386
387 plist_t reply = NULL;
388 res = ostrace_receive_plist(client, &reply);
389 if (res != OSTRACE_E_SUCCESS) {
390 return res;
391 }
392
393 res = _ostrace_check_result(reply);
394 if (res != OSTRACE_E_SUCCESS) {
395 return res;
396 }
397
398 debug_info("Receiving archive...\n");
399 while (1) {
400 uint8_t msgtype = 0;
401 uint32_t received = 0;
402 res = ostrace_error(service_receive(client->parent, (char*)&msgtype, 1, &received));
403 if (res != OSTRACE_E_SUCCESS) {
404 debug_info("Could not read message type from service: %d", res);
405 break;
406 }
407 if (msgtype != 3) {
408 debug_info("Unexpected packet type %d", msgtype);
409 return OSTRACE_E_REQUEST_FAILED;
410 }
411 uint32_t rlen = 0;
412 res = ostrace_error(service_receive(client->parent, (char*)&rlen, 4, &received));
413 if (res != OSTRACE_E_SUCCESS) {
414 debug_info("Failed to read message size from service");
415 break;
416 }
417
418 rlen = le32toh(rlen);
419 debug_info("got length %d", rlen);
420
421 unsigned char* buf = (unsigned char*)malloc(rlen);
422 res = ostrace_error(service_receive(client->parent, (char*)buf, rlen, &received));
423 if (res != OSTRACE_E_SUCCESS) {
424 debug_info("Could not read data from service: %d", res);
425 break;
426 }
427 if (callback(buf, received, user_data) < 0) {
428 debug_info("Aborted through callback");
429 return OSTRACE_E_REQUEST_FAILED;
430 }
431 }
432 debug_info("Done.\n");
433
434 return OSTRACE_E_SUCCESS;
435}
436
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 @@
1/*
2 * ostrace.h
3 * com.apple.os_trace_relay service header file.
4 *
5 * Copyright (c) 2020-2025 Nikias Bassen, All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#ifndef _OSTRACE_H
23#define _OSTRACE_H
24
25#include "idevice.h"
26#include "libimobiledevice/ostrace.h"
27#include "service.h"
28#include <libimobiledevice-glue/thread.h>
29
30struct ostrace_client_private {
31 service_client_t parent;
32 THREAD_T worker;
33};
34
35void *ostrace_worker(void *arg);
36
37#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 @@
24#endif 24#endif
25#include <string.h> 25#include <string.h>
26#include <stdlib.h> 26#include <stdlib.h>
27
28#ifndef _MSC_VER
27#include <unistd.h> 29#include <unistd.h>
30#endif
31
28#include <plist/plist.h> 32#include <plist/plist.h>
29 33
30#include "sbservices.h" 34#include "sbservices.h"