summaryrefslogtreecommitdiffstats
path: root/src/idevice.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/idevice.c')
-rw-r--r--src/idevice.c379
1 files changed, 253 insertions, 126 deletions
diff --git a/src/idevice.c b/src/idevice.c
index 3984583..0af27fd 100644
--- a/src/idevice.c
+++ b/src/idevice.c
@@ -30,9 +30,13 @@
#include <errno.h>
#include <time.h>
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
+#include <ws2tcpip.h>
#include <windows.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
#endif
#include <usbmuxd.h>
@@ -120,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)
{
@@ -177,43 +181,41 @@ 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;
+INITIALIZER(internal_idevice_init)
+{
+#if defined(HAVE_OPENSSL)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+ int i;
+ SSL_library_init();
-#ifndef HAVE_ATTRIBUTE_CONSTRUCTOR
- #if defined(__llvm__) || defined(__GNUC__)
- #define HAVE_ATTRIBUTE_CONSTRUCTOR
- #endif
-#endif
+ 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]);
-#ifdef HAVE_ATTRIBUTE_CONSTRUCTOR
-static void __attribute__((constructor)) libimobiledevice_initialize(void)
-{
- thread_once(&init_once, internal_idevice_init);
+#if OPENSSL_VERSION_NUMBER < 0x10000000L
+ CRYPTO_set_id_callback(id_function);
+#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
+#endif
+ atexit(internal_idevice_deinit);
}
-static void __attribute__((destructor)) libimobiledevice_deinitialize(void)
+const char* libimobiledevice_version()
{
- 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;
-}
-#else
-#warning No compiler support for constructor/destructor attributes, some features might not be available.
+#ifndef PACKAGE_VERSION
+#error PACKAGE_VERSION is not defined!
#endif
+ return PACKAGE_VERSION;
+}
struct idevice_subscription_context {
idevice_event_cb_t callback;
@@ -244,7 +246,7 @@ static void usbmux_event_cb(const usbmuxd_event_t *event, void *user_data)
}
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_events_subscribe(idevice_subscription_context_t *context, idevice_event_cb_t callback, void *user_data)
+idevice_error_t idevice_events_subscribe(idevice_subscription_context_t *context, idevice_event_cb_t callback, void *user_data)
{
if (!context || !callback) {
return IDEVICE_E_INVALID_ARG;
@@ -266,7 +268,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_events_subscribe(idevice_subscripti
return IDEVICE_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_events_unsubscribe(idevice_subscription_context_t context)
+idevice_error_t idevice_events_unsubscribe(idevice_subscription_context_t context)
{
if (!context) {
return IDEVICE_E_INVALID_ARG;
@@ -283,7 +285,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_events_unsubscribe(idevice_subscrip
return IDEVICE_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_event_subscribe(idevice_event_cb_t callback, void *user_data)
+idevice_error_t idevice_event_subscribe(idevice_event_cb_t callback, void *user_data)
{
if (event_ctx) {
idevice_events_unsubscribe(event_ctx);
@@ -291,7 +293,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_event_subscribe(idevice_event_cb_t
return idevice_events_subscribe(&event_ctx, callback, user_data);
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_event_unsubscribe(void)
+idevice_error_t idevice_event_unsubscribe(void)
{
if (!event_ctx) {
return IDEVICE_E_SUCCESS;
@@ -300,7 +302,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_event_unsubscribe(void)
return idevice_events_unsubscribe(event_ctx);
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_get_device_list_extended(idevice_info_t **devices, int *count)
+idevice_error_t idevice_get_device_list_extended(idevice_info_t **devices, int *count)
{
usbmuxd_device_info_t *dev_list;
@@ -324,7 +326,21 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_get_device_list_extended(idevice_in
newlist[newcount]->conn_data = NULL;
} else if (dev_list[i].conn_type == CONNECTION_TYPE_NETWORK) {
newlist[newcount]->conn_type = CONNECTION_NETWORK;
- size_t addrlen = ((uint8_t*)dev_list[i].conn_data)[0];
+ struct sockaddr* saddr = (struct sockaddr*)(dev_list[i].conn_data);
+ size_t addrlen = 0;
+ switch (saddr->sa_family) {
+ case AF_INET:
+ addrlen = sizeof(struct sockaddr_in);
+ break;
+#ifdef AF_INET6
+ case AF_INET6:
+ addrlen = sizeof(struct sockaddr_in6);
+ break;
+#endif
+ default:
+ debug_info("Unsupported address family 0x%02x\n", saddr->sa_family);
+ continue;
+ }
newlist[newcount]->conn_data = malloc(addrlen);
memcpy(newlist[newcount]->conn_data, dev_list[i].conn_data, addrlen);
}
@@ -341,7 +357,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_get_device_list_extended(idevice_in
return IDEVICE_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_device_list_extended_free(idevice_info_t *devices)
+idevice_error_t idevice_device_list_extended_free(idevice_info_t *devices)
{
if (devices) {
int i = 0;
@@ -356,7 +372,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_device_list_extended_free(idevice_i
return IDEVICE_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_get_device_list(char ***devices, int *count)
+idevice_error_t idevice_get_device_list(char ***devices, int *count)
{
usbmuxd_device_info_t *dev_list;
@@ -388,7 +404,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_get_device_list(char ***devices, in
return IDEVICE_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_device_list_free(char **devices)
+idevice_error_t idevice_device_list_free(char **devices)
{
if (devices) {
int i = 0;
@@ -401,7 +417,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_device_list_free(char **devices)
return IDEVICE_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API void idevice_set_debug_level(int level)
+void idevice_set_debug_level(int level)
{
internal_set_debug_level(level);
}
@@ -426,9 +442,25 @@ static idevice_t idevice_from_mux_device(usbmuxd_device_info_t *muxdev)
break;
case CONNECTION_TYPE_NETWORK:
device->conn_type = CONNECTION_NETWORK;
- size_t len = ((uint8_t*)muxdev->conn_data)[0];
- device->conn_data = malloc(len);
- memcpy(device->conn_data, muxdev->conn_data, len);
+ struct sockaddr* saddr = (struct sockaddr*)(muxdev->conn_data);
+ size_t addrlen = 0;
+ switch (saddr->sa_family) {
+ case AF_INET:
+ addrlen = sizeof(struct sockaddr_in);
+ break;
+#ifdef AF_INET6
+ case AF_INET6:
+ addrlen = sizeof(struct sockaddr_in6);
+ break;
+#endif
+ default:
+ debug_info("Unsupported address family 0x%02x\n", saddr->sa_family);
+ free(device->udid);
+ free(device);
+ return NULL;
+ }
+ device->conn_data = malloc(addrlen);
+ memcpy(device->conn_data, muxdev->conn_data, addrlen);
break;
default:
device->conn_type = 0;
@@ -438,7 +470,7 @@ static idevice_t idevice_from_mux_device(usbmuxd_device_info_t *muxdev)
return device;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_new_with_options(idevice_t * device, const char *udid, enum idevice_options options)
+idevice_error_t idevice_new_with_options(idevice_t * device, const char *udid, enum idevice_options options)
{
usbmuxd_device_info_t muxdev;
int usbmux_options = 0;
@@ -462,12 +494,12 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_new_with_options(idevice_t * device
return IDEVICE_E_NO_DEVICE;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_new(idevice_t * device, const char *udid)
+idevice_error_t idevice_new(idevice_t * device, const char *udid)
{
return idevice_new_with_options(device, udid, 0);
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_free(idevice_t device)
+idevice_error_t idevice_free(idevice_t device)
{
if (!device)
return IDEVICE_E_INVALID_ARG;
@@ -484,7 +516,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_free(idevice_t device)
return ret;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_connect(idevice_t device, uint16_t port, idevice_connection_t *connection)
+idevice_error_t idevice_connect(idevice_t device, uint16_t port, idevice_connection_t *connection)
{
if (!device) {
return IDEVICE_E_INVALID_ARG;
@@ -506,7 +538,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connect(idevice_t device, uint16_t
}
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;
@@ -515,27 +547,16 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connect(idevice_t device, uint16_t
return IDEVICE_E_SUCCESS;
}
if (device->conn_type == CONNECTION_NETWORK) {
- struct sockaddr_storage saddr_storage;
- struct sockaddr* saddr = (struct sockaddr*)&saddr_storage;
-
- /* FIXME: Improve handling of this platform/host dependent connection data */
- if (((char*)device->conn_data)[1] == 0x02) { // AF_INET
- saddr->sa_family = AF_INET;
- memcpy(&saddr->sa_data[0], (char*)device->conn_data + 2, 14);
- }
- else if (((char*)device->conn_data)[1] == 0x1E) { // AF_INET6 (bsd)
+ struct sockaddr* saddr = (struct sockaddr*)(device->conn_data);
+ switch (saddr->sa_family) {
+ case AF_INET:
#ifdef AF_INET6
- saddr->sa_family = AF_INET6;
- /* copy the address and the host dependent scope id */
- memcpy(&saddr->sa_data[0], (char*)device->conn_data + 2, 26);
-#else
- debug_info("ERROR: Got an IPv6 address but this system doesn't support IPv6");
- return IDEVICE_E_UNKNOWN_ERROR;
+ case AF_INET6:
#endif
- }
- else {
- debug_info("Unsupported address family 0x%02x", ((char*)device->conn_data)[1]);
- return IDEVICE_E_UNKNOWN_ERROR;
+ break;
+ default:
+ debug_info("Unsupported address family 0x%02x", saddr->sa_family);
+ return IDEVICE_E_UNKNOWN_ERROR;
}
char addrtxt[48];
@@ -562,7 +583,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connect(idevice_t device, uint16_t
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;
@@ -576,7 +597,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connect(idevice_t device, uint16_t
return IDEVICE_E_UNKNOWN_ERROR;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_disconnect(idevice_connection_t connection)
+idevice_error_t idevice_disconnect(idevice_connection_t connection)
{
if (!connection) {
return IDEVICE_E_INVALID_ARG;
@@ -587,11 +608,11 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_disconnect(idevice_connection_t con
}
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 {
@@ -616,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));
@@ -625,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;
@@ -639,7 +660,7 @@ static idevice_error_t internal_connection_send(idevice_connection_t connection,
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_send(idevice_connection_t connection, const char *data, uint32_t len, uint32_t *sent_bytes)
+idevice_error_t idevice_connection_send(idevice_connection_t connection, const char *data, uint32_t len, uint32_t *sent_bytes)
{
if (!connection || !data
#if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS)
@@ -732,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));
@@ -740,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;
@@ -754,7 +775,7 @@ static idevice_error_t internal_connection_receive_timeout(idevice_connection_t
return IDEVICE_E_UNKNOWN_ERROR;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive_timeout(idevice_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout)
+idevice_error_t idevice_connection_receive_timeout(idevice_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout)
{
if (!connection
#if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS)
@@ -785,6 +806,10 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive_timeout(idevice_
int sslerr = SSL_get_error(connection->ssl_data->session, r);
if (sslerr == SSL_ERROR_WANT_READ) {
continue;
+ } else if (sslerr == SSL_ERROR_ZERO_RETURN) {
+ if (connection->status == IDEVICE_E_TIMEOUT) {
+ SSL_set_shutdown(connection->ssl_data->session, 0);
+ }
}
break;
}
@@ -828,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;
@@ -836,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;
@@ -849,7 +874,7 @@ static idevice_error_t internal_connection_receive(idevice_connection_t connecti
return IDEVICE_E_UNKNOWN_ERROR;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive(idevice_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes)
+idevice_error_t idevice_connection_receive(idevice_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes)
{
if (!connection
#if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS)
@@ -882,18 +907,18 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive(idevice_connecti
return internal_connection_receive(connection, data, len, recv_bytes);
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_get_fd(idevice_connection_t connection, int *fd)
+idevice_error_t idevice_connection_get_fd(idevice_connection_t connection, int *fd)
{
if (!connection || !fd) {
return IDEVICE_E_INVALID_ARG;
}
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;
}
@@ -901,7 +926,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_get_fd(idevice_connectio
return IDEVICE_E_UNKNOWN_ERROR;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_get_handle(idevice_t device, uint32_t *handle)
+idevice_error_t idevice_get_handle(idevice_t device, uint32_t *handle)
{
if (!device || !handle)
return IDEVICE_E_INVALID_ARG;
@@ -910,7 +935,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_get_handle(idevice_t device, uint32
return IDEVICE_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_get_udid(idevice_t device, char **udid)
+idevice_error_t idevice_get_udid(idevice_t device, char **udid)
{
if (!device || !udid)
return IDEVICE_E_INVALID_ARG;
@@ -921,6 +946,20 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_get_udid(idevice_t device, char **u
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)
@@ -1030,18 +1069,36 @@ static void internal_ssl_cleanup(ssl_data_t ssl_data)
}
#ifdef HAVE_OPENSSL
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+static long ssl_idevice_bio_callback(BIO *b, int oper, const char *argp, size_t len, int argi, long argl, int retvalue, size_t *processed)
+#else
static long ssl_idevice_bio_callback(BIO *b, int oper, const char *argp, int argi, long argl, long retvalue)
+#endif
{
+ ssize_t bytes = 0;
idevice_connection_t conn = (idevice_connection_t)BIO_get_callback_arg(b);
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
size_t len = (size_t)argi;
+#endif
switch (oper) {
case (BIO_CB_READ|BIO_CB_RETURN):
- return argp ? (long)internal_ssl_read(conn, (char *)argp, len) : 0;
+ if (argp) {
+ bytes = internal_ssl_read(conn, (char *)argp, len);
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ *processed = (size_t)(bytes < 0) ? 0 : bytes;
+#endif
+ return (long)bytes;
+ }
+ return 0;
case (BIO_CB_PUTS|BIO_CB_RETURN):
len = strlen(argp);
// fallthrough
case (BIO_CB_WRITE|BIO_CB_RETURN):
- return (long)internal_ssl_write(conn, argp, len);
+ bytes = internal_ssl_write(conn, argp, len);
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ *processed = (size_t)(bytes < 0) ? 0 : bytes;
+#endif
+ return (long)bytes;
default:
return retvalue;
}
@@ -1052,7 +1109,11 @@ static BIO *ssl_idevice_bio_new(idevice_connection_t conn)
BIO *b = BIO_new(BIO_s_null());
if (!b) return NULL;
BIO_set_callback_arg(b, (char *)conn);
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ BIO_set_callback_ex(b, ssl_idevice_bio_callback);
+#else
BIO_set_callback(b, ssl_idevice_bio_callback);
+#endif
return b;
}
@@ -1140,7 +1201,7 @@ static int _mbedtls_f_rng(void* p_rng, unsigned char* buf, size_t len)
}
#endif
-LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection)
+idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection)
{
if (!connection || connection->ssl_data)
return IDEVICE_E_INVALID_ARG;
@@ -1177,32 +1238,62 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_conne
return ret;
}
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) || \
+ (defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER >= 0x3060000fL))
SSL_CTX_set_security_level(ssl_ctx, 0);
#endif
#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
- long opts = SSL_CTX_get_options(ssl_ctx);
- opts |= SSL_OP_NO_TLSv1_1;
+ SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_1);
+#endif
#ifdef SSL_OP_NO_TLSv1_2
- opts |= SSL_OP_NO_TLSv1_2;
+ SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_2);
#endif
#ifdef SSL_OP_NO_TLSv1_3
- opts |= SSL_OP_NO_TLSv1_3;
-#endif
- SSL_CTX_set_options(ssl_ctx, opts);
+ SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_3);
#endif
}
#else
SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_VERSION);
- if (connection->device->version < DEVICE_VERSION(10,0,0)) {
+ 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) {
+ /*
+ iOS 1 doesn't understand TLS1_VERSION, it can only speak SSL3_VERSION.
+ However, modern OpenSSL is usually compiled without SSLv3 support.
+ So if we set min_proto_version to SSL3_VERSION on an OpenSSL instance which doesn't support it,
+ it will just ignore min_proto_version altogether and fall back to an even higher version.
+ To avoid accidentally breaking iOS 2.0+, we set min version to 0 instead.
+ Here is what documentation says:
+ Setting the minimum or maximum version to 0,
+ will enable protocol versions down to the lowest version,
+ or up to the highest version supported by the library, respectively.
+ */
+ SSL_CTX_set_min_proto_version(ssl_ctx, 0);
+ }
}
#endif
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#if defined(SSL_OP_IGNORE_UNEXPECTED_EOF)
+ /*
+ * For OpenSSL 3 and later, mark close_notify alerts as optional.
+ * For prior versions of OpenSSL we check for SSL_ERROR_SYSCALL when
+ * reading instead (this error changes to SSL_ERROR_SSL in OpenSSL 3).
+ */
+ SSL_CTX_set_options(ssl_ctx, SSL_OP_IGNORE_UNEXPECTED_EOF);
+#endif
+#if defined(SSL_OP_LEGACY_SERVER_CONNECT)
+ /*
+ * Without setting SSL_OP_LEGACY_SERVER_CONNECT, OpenSSL 3 fails with
+ * error "unsafe legacy renegotiation disabled" when talking to iOS 5
+ */
+ SSL_CTX_set_options(ssl_ctx, SSL_OP_LEGACY_SERVER_CONNECT);
+#endif
+#endif
BIO* membp;
X509* rootCert = NULL;
@@ -1215,6 +1306,16 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_conne
X509_free(rootCert);
free(root_cert.data);
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_PKEY* rootPrivKey = NULL;
+ membp = BIO_new_mem_buf(root_privkey.data, root_privkey.size);
+ PEM_read_bio_PrivateKey(membp, &rootPrivKey, NULL, NULL);
+ BIO_free(membp);
+ if (SSL_CTX_use_PrivateKey(ssl_ctx, rootPrivKey) != 1) {
+ debug_info("WARNING: Could not load RootPrivateKey");
+ }
+ EVP_PKEY_free(rootPrivKey);
+#else
RSA* rootPrivKey = NULL;
membp = BIO_new_mem_buf(root_privkey.data, root_privkey.size);
PEM_read_bio_RSAPrivateKey(membp, &rootPrivKey, NULL, NULL);
@@ -1223,6 +1324,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_conne
debug_info("WARNING: Could not load RootPrivateKey");
}
RSA_free(rootPrivKey);
+#endif
free(root_privkey.data);
SSL *ssl = SSL_new(ssl_ctx);
@@ -1243,7 +1345,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_conne
if (ssl_error == 0 || ssl_error != SSL_ERROR_WANT_READ) {
break;
}
-#ifdef WIN32
+#ifdef _WIN32
Sleep(100);
#else
struct timespec ts = { 0, 100000000 };
@@ -1402,12 +1504,12 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_conne
return ret;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_disable_ssl(idevice_connection_t connection)
+idevice_error_t idevice_connection_disable_ssl(idevice_connection_t connection)
{
return idevice_connection_disable_bypass_ssl(connection, 0);
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_disable_bypass_ssl(idevice_connection_t connection, uint8_t sslBypass)
+idevice_error_t idevice_connection_disable_bypass_ssl(idevice_connection_t connection, uint8_t sslBypass)
{
if (!connection)
return IDEVICE_E_INVALID_ARG;
@@ -1449,3 +1551,28 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_disable_bypass_ssl(idevi
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";
+}