diff options
151 files changed, 7372 insertions, 2105 deletions
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..e995b30 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,3 @@ +github: nikias +patreon: nikias +custom: ["https://www.paypal.me/NikiasBassen"] diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5302c01..fbbf10a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,10 @@ name: build -on: [push] +on: + push: + pull_request: + schedule: + - cron: '0 0 1 * *' jobs: build-linux-ubuntu: @@ -9,31 +13,38 @@ jobs: - name: install dependencies run: | sudo apt-get update - sudo apt-get install cython + pip install cython - name: prepare environment run: | echo "target_triplet=`gcc -dumpmachine`" >> $GITHUB_ENV - name: fetch libplist - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libplist-latest_${{env.target_triplet}} repo: libimobiledevice/libplist - name: fetch libusbmuxd - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libusbmuxd-latest_${{env.target_triplet}} repo: libimobiledevice/libusbmuxd - name: fetch libimobiledevice-glue - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libimobiledevice-glue-latest_${{env.target_triplet}} repo: libimobiledevice/libimobiledevice-glue + - name: fetch libtatsu + uses: dawidd6/action-download-artifact@v6 + with: + github_token: ${{secrets.GITHUB_TOKEN}} + workflow: build.yml + name: libtatsu-latest_${{env.target_triplet}} + repo: libimobiledevice/libtatsu - name: install external dependencies run: | mkdir extract @@ -42,7 +53,7 @@ jobs: done sudo cp -r extract/* / sudo ldconfig - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: autogen @@ -57,7 +68,7 @@ jobs: DESTDIR=`pwd`/dest make install tar -C dest -cf libimobiledevice.tar usr - name: publish artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: libimobiledevice-latest_${{env.target_triplet}} path: libimobiledevice.tar @@ -71,29 +82,36 @@ jobs: else brew install libtool autoconf automake pkgconfig fi - pip install cython + pip3 install --break-system-packages cython shell: bash - name: fetch libplist - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libplist-latest_macOS repo: libimobiledevice/libplist - name: fetch libusbmuxd - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libusbmuxd-latest_macOS repo: libimobiledevice/libusbmuxd - name: fetch libimobiledevice-glue - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libimobiledevice-glue-latest_macOS repo: libimobiledevice/libimobiledevice-glue + - name: fetch libtatsu + uses: dawidd6/action-download-artifact@v6 + with: + github_token: ${{secrets.GITHUB_TOKEN}} + workflow: build.yml + name: libtatsu-latest_macOS + repo: libimobiledevice/libtatsu - name: install external dependencies run: | mkdir extract @@ -101,7 +119,7 @@ jobs: tar -C extract -xvf $I done sudo cp -r extract/* / - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: install additional requirements run: | mkdir -p lib @@ -130,6 +148,17 @@ jobs: done export CFLAGS="$USEARCHS -isysroot $SDKDIR" echo "Using CFLAGS: $CFLAGS" + PYTHON3_BIN=`xcrun -f python3` + if test -x $PYTHON3_BIN; then + export PYTHON=$PYTHON3_BIN + PYTHON_VER=`$PYTHON3_BIN -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('VERSION'))"` + PYTHON_EXEC_PREFIX=`$PYTHON3_BIN -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('exec_prefix'))"` + PYTHON_LIBS_PATH=$PYTHON_EXEC_PREFIX/lib + PYTHON_FRAMEWORK_PATH=$PYTHON_EXEC_PREFIX/Python3 + export PYTHON_CPPFLAGS="-I$PYTHON_EXEC_PREFIX/Headers" + export PYTHON_LIBS="-L$PYTHON_LIBS_PATH -lpython$PYTHON_VER" + export PYTHON_EXTRA_LDFLAGS="-Wl,-stack_size,1000000 -framework CoreFoundation $PYTHON_FRAMEWORK_PATH" + fi ./autogen.sh PKG_CONFIG_PATH=/usr/local/lib/pkgconfig --enable-debug \ openssl_CFLAGS="-I${{ env.DEPSDIR }}/libressl-${{ env.LIBRESSL_VER }}/include" \ openssl_LIBS="-Xlinker ${{ env.LIBSSL }} -Xlinker ${{ env.LIBCRYPTO }}" @@ -143,12 +172,12 @@ jobs: DESTDIR=`pwd`/dest make install tar -C dest -cf libimobiledevice.tar usr - name: publish artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: libimobiledevice-latest_macOS path: libimobiledevice.tar build-windows: - runs-on: windows-2019 + runs-on: windows-latest defaults: run: shell: msys2 {0} @@ -169,6 +198,8 @@ jobs: base-devel git mingw-w64-${{ matrix.arch }}-gcc + mingw-w64-${{ matrix.arch }}-pkg-config + mingw-w64-${{ matrix.arch }}-openssl make libtool autoconf @@ -180,26 +211,33 @@ jobs: echo "target_triplet=`gcc -dumpmachine`" >> $GITHUB_ENV git config --global core.autocrlf false - name: fetch libplist - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libplist-latest_${{ matrix.arch }}-${{ env.dest }} repo: libimobiledevice/libplist - name: fetch libusbmuxd - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libusbmuxd-latest_${{ matrix.arch }}-${{ env.dest }} repo: libimobiledevice/libusbmuxd - name: fetch libimobiledevice-glue - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libimobiledevice-glue-latest_${{ matrix.arch }}-${{ env.dest }} repo: libimobiledevice/libimobiledevice-glue + - name: fetch libtatsu + uses: dawidd6/action-download-artifact@v6 + with: + github_token: ${{secrets.GITHUB_TOKEN}} + workflow: build.yml + name: libtatsu-latest_${{ matrix.arch }}-${{ env.dest }} + repo: libimobiledevice/libtatsu - name: install external dependencies run: | mkdir extract @@ -207,7 +245,7 @@ jobs: tar -C extract -xvf $I done cp -r extract/* / - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: autogen run: ./autogen.sh CC=gcc CXX=g++ --enable-debug - name: make @@ -220,7 +258,7 @@ jobs: DESTDIR=`pwd`/dest make install tar -C dest -cf libimobiledevice.tar ${{ env.dest }} - name: publish artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: libimobiledevice-latest_${{ matrix.arch }}-${{ env.dest }} path: libimobiledevice.tar @@ -37,6 +37,7 @@ docs/html libimobiledevice-1.0.pc tools/.libs/* tools/idevice* +tools/afcclient !tools/idevice*.[ch] cython/.libs/* cython/*.c diff --git a/3rd_party/ed25519/Makefile.am b/3rd_party/ed25519/Makefile.am index c475331..438cb53 100644 --- a/3rd_party/ed25519/Makefile.am +++ b/3rd_party/ed25519/Makefile.am @@ -6,7 +6,7 @@ AM_CPPFLAGS = \ AM_CFLAGS = \ $(GLOBAL_CFLAGS) \ - $(openssl_CFLAGS) + $(ssl_lib_CFLAGS) AM_LDFLAGS = @@ -15,12 +15,19 @@ libed25519_la_LIBADD = libed25519_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined libed25519_la_SOURCES = \ add_scalar.c \ + ed25519.h \ fe.c \ + fe.h \ + fixedint.h \ ge.c \ + ge.h \ keypair.c \ key_exchange.c \ + precomp_data.h \ sc.c \ + sc.h \ seed.c \ sign.c \ sha512.c \ + sha512.h \ verify.c diff --git a/3rd_party/ed25519/seed.c b/3rd_party/ed25519/seed.c index 11a2e3e..cf252b8 100644 --- a/3rd_party/ed25519/seed.c +++ b/3rd_party/ed25519/seed.c @@ -30,7 +30,7 @@ int ed25519_create_seed(unsigned char *seed) { return 1; } - fread(seed, 1, 32, f); + if(fread(seed, 1, 32, f)){} fclose(f); #endif diff --git a/3rd_party/libsrp6a-sha512/Makefile.am b/3rd_party/libsrp6a-sha512/Makefile.am index 8c6e2f5..bdacb5f 100644 --- a/3rd_party/libsrp6a-sha512/Makefile.am +++ b/3rd_party/libsrp6a-sha512/Makefile.am @@ -5,11 +5,9 @@ AM_CPPFLAGS = \ -I$(top_srcdir) \ -Wno-incompatible-pointer-types -include_HEADERS = srp.h srp_aux.h cstr.h - AM_CFLAGS = -DHAVE_CONFIG_H if HAVE_OPENSSL -AM_CFLAGS += -DOPENSSL=1 -DOPENSSL_ENGINE=1 $(openssl_CFLAGS) +AM_CFLAGS += -DOPENSSL=1 $(openssl_CFLAGS) else if HAVE_GCRYPT AM_CFLAGS += -DGCRYPT=1 $(libgcrypt_CFLAGS) @@ -25,7 +23,10 @@ noinst_LTLIBRARIES = libsrp6a-sha512.la libsrp6a_sha512_la_SOURCES = \ t_conv.c t_math.c t_misc.c \ t_truerand.c cstr.c \ - srp.c srp6a_sha512_client.c -if !HAVE_OPENSSL -libsrp6a_sha512_la_SOURCES += t_sha.c -endif + srp.c srp6a_sha512_client.c \ + srp.h srp_aux.h cstr.h \ + t_defines.h t_pwd.h \ + t_sha.c t_sha.h +#if !HAVE_OPENSSL +#libsrp6a_sha512_la_SOURCES += t_sha.c +#endif diff --git a/3rd_party/libsrp6a-sha512/cstr.c b/3rd_party/libsrp6a-sha512/cstr.c index 9856f46..58a5638 100644 --- a/3rd_party/libsrp6a-sha512/cstr.c +++ b/3rd_party/libsrp6a-sha512/cstr.c @@ -8,72 +8,31 @@ #define MINSIZE 4 /* Absolute minimum - one word */ static char cstr_empty_string[] = { '\0' }; -static cstr_allocator * default_alloc = NULL; - -/* - * It is assumed, for efficiency, that it is okay to pass more arguments - * to a function than are called for, as long as the required arguments - * are in proper form. If extra arguments to malloc() and free() cause - * problems, define PEDANTIC_ARGS below. - */ -#ifdef PEDANTIC_ARGS -static void * Cmalloc(int n, void * heap) { return malloc(n); } -static void Cfree(void * p, void * heap) { free(p); } -static cstr_allocator malloc_allocator = { Cmalloc, Cfree, NULL }; -#else -static cstr_allocator malloc_allocator = { malloc, free, NULL }; -#endif - -_TYPE( void ) -cstr_set_allocator(cstr_allocator * alloc) -{ - default_alloc = alloc; -} _TYPE( cstr * ) -cstr_new_alloc(cstr_allocator * alloc) +cstr_new() { cstr * str; - if(alloc == NULL) { - if(default_alloc == NULL) { - default_alloc = &malloc_allocator; - } - alloc = default_alloc; - } - - str = (cstr *) (*alloc->alloc)(sizeof(cstr), alloc->heap); + str = (cstr *) malloc(sizeof(cstr)); if(str) { str->data = cstr_empty_string; str->length = str->cap = 0; str->ref = 1; - str->allocator = alloc; } return str; } _TYPE( cstr * ) -cstr_new() -{ - return cstr_new_alloc(NULL); -} - -_TYPE( cstr * ) -cstr_dup_alloc(const cstr * str, cstr_allocator * alloc) +cstr_dup(const cstr * str) { - cstr * nstr = cstr_new_alloc(alloc); + cstr * nstr = cstr_new(); if(nstr) cstr_setn(nstr, str->data, str->length); return nstr; } _TYPE( cstr * ) -cstr_dup(const cstr * str) -{ - return cstr_dup_alloc(str, NULL); -} - -_TYPE( cstr * ) cstr_create(const char * s) { return cstr_createn(s, strlen(s)); @@ -101,9 +60,9 @@ cstr_clear_free(cstr * str) if(--str->ref == 0) { if(str->cap > 0) { memset(str->data, 0, str->cap); - (*str->allocator->free)(str->data, str->allocator->heap); + free(str->data); } - (*str->allocator->free)(str, str->allocator->heap); + free(str); } } @@ -112,8 +71,8 @@ cstr_free(cstr * str) { if(--str->ref == 0) { if(str->cap > 0) - (*str->allocator->free)(str->data, str->allocator->heap); - (*str->allocator->free)(str, str->allocator->heap); + free(str->data); + free(str); } } @@ -121,7 +80,7 @@ _TYPE( void ) cstr_empty(cstr * str) { if(str->cap > 0) - (*str->allocator->free)(str->data, str->allocator->heap); + free(str->data); str->data = cstr_empty_string; str->length = str->cap = 0; } @@ -137,8 +96,7 @@ cstr_alloc(cstr * str, int len) if(len < MINSIZE) len = MINSIZE; - t = (char *) (*str->allocator->alloc)(len * sizeof(char), - str->allocator->heap); + t = (char *) malloc(len * sizeof(char)); if(t) { if(str->data) { t[str->length] = 0; diff --git a/3rd_party/libsrp6a-sha512/cstr.h b/3rd_party/libsrp6a-sha512/cstr.h index 7cc019a..29afea7 100644 --- a/3rd_party/libsrp6a-sha512/cstr.h +++ b/3rd_party/libsrp6a-sha512/cstr.h @@ -38,7 +38,7 @@ #define _MSVC15DEXPORT #define _MSVC20EXPORT #define _DLLAPI -#if defined(WINDOWS) || defined(WIN32) +#if defined(WINDOWS) || defined(_WIN32) #define _CDECL _cdecl #else #define _CDECL @@ -51,27 +51,15 @@ extern "C" { #endif /* __cplusplus */ -/* Arguments to allocator methods ordered this way for compatibility */ -typedef struct cstr_alloc_st { - void * (_CDECL * alloc)(size_t n, void * heap); - void (_CDECL * free)(void * p, void * heap); - void * heap; -} cstr_allocator; - typedef struct cstr_st { char * data; /* Okay to access data and length fields directly */ int length; int cap; int ref; /* Simple reference counter */ - cstr_allocator * allocator; } cstr; -_TYPE( void ) cstr_set_allocator P((cstr_allocator * alloc)); - _TYPE( cstr * ) cstr_new P((void)); -_TYPE( cstr * ) cstr_new_alloc P((cstr_allocator * alloc)); _TYPE( cstr * ) cstr_dup P((const cstr * str)); -_TYPE( cstr * ) cstr_dup_alloc P((const cstr * str, cstr_allocator * alloc)); _TYPE( cstr * ) cstr_create P((const char * s)); _TYPE( cstr * ) cstr_createn P((const char * s, int len)); diff --git a/3rd_party/libsrp6a-sha512/t_conv.c b/3rd_party/libsrp6a-sha512/t_conv.c index f7f50e2..76d4e58 100644 --- a/3rd_party/libsrp6a-sha512/t_conv.c +++ b/3rd_party/libsrp6a-sha512/t_conv.c @@ -33,8 +33,7 @@ #include "cstr.h" static int -hexDigitToInt(c) - char c; +hexDigitToInt(char c) { if(c >= '0' && c <= '9') return c - '0'; @@ -50,9 +49,7 @@ hexDigitToInt(c) * Convert a hex string to a string of bytes; return size of dst */ _TYPE( int ) -t_fromhex(dst, src) - char * dst; - const char * src; +t_fromhex(char *dst, const char *src) { register char *chp = dst; register unsigned size = strlen(src); @@ -76,10 +73,7 @@ t_fromhex(dst, src) * Convert a string of bytes to their hex representation */ _TYPE( char * ) -t_tohex(dst, src, size) - char * dst; - const char * src; - unsigned size; +t_tohex(char *dst, const char *src, unsigned size) { int notleading = 0; @@ -103,10 +97,7 @@ t_tohex(dst, src, size) } _TYPE( char * ) -t_tohexcstr(dst, src, size) - cstr * dst; - const char * src; - unsigned size; +t_tohexcstr(cstr *dst, const char *src, unsigned size) { cstr_set_length(dst, 2 * size + 1); return t_tohex(dst->data, src, size); @@ -119,9 +110,7 @@ static char b64table[] = * Convert a base64 string into raw byte array representation. */ _TYPE( int ) -t_fromb64(dst, src) - char * dst; - const char * src; +t_fromb64(char *dst, const char *src) { unsigned char *a; char *loc; @@ -179,9 +168,7 @@ t_fromb64(dst, src) } _TYPE( int ) -t_cstrfromb64(dst, src) - cstr * dst; - const char * src; +t_cstrfromb64(cstr *dst, const char *src) { int len; cstr_set_length(dst, (strlen(src) * 6 + 7) / 8); @@ -194,10 +181,7 @@ t_cstrfromb64(dst, src) * Convert a raw byte string into a null-terminated base64 ASCII string. */ _TYPE( char * ) -t_tob64(dst, src, size) - char * dst; - const char * src; - unsigned size; +t_tob64(char *dst, const char *src, unsigned size) { int c, pos = size % 3; unsigned char b0 = 0, b1 = 0, b2 = 0, notleading = 0; @@ -248,10 +232,7 @@ t_tob64(dst, src, size) } _TYPE( char * ) -t_tob64cstr(dst, src, sz) - cstr * dst; - const char * src; - unsigned int sz; +t_tob64cstr(cstr *dst, const char *src, unsigned int sz) { cstr_set_length(dst, (sz * 8 + 5) / 6 + 1); return t_tob64(dst->data, src, sz); diff --git a/3rd_party/libsrp6a-sha512/t_defines.h b/3rd_party/libsrp6a-sha512/t_defines.h index 447263f..a2a5fe5 100644 --- a/3rd_party/libsrp6a-sha512/t_defines.h +++ b/3rd_party/libsrp6a-sha512/t_defines.h @@ -65,7 +65,7 @@ #define _MSVC15DEXPORT #define _MSVC20EXPORT #define _DLLAPI -#if defined(WINDOWS) || defined(WIN32) +#if defined(WINDOWS) || defined(_WIN32) #define _CDECL _cdecl #else #define _CDECL @@ -122,7 +122,7 @@ char *strchr(), *strrchr(), *strtok(); #define USE_SGTTY #endif -#ifdef WIN32 +#ifdef _WIN32 #define USE_FTIME 1 #define USE_RENAME 1 #define NO_FCHMOD 1 diff --git a/3rd_party/libsrp6a-sha512/t_math.c b/3rd_party/libsrp6a-sha512/t_math.c index 88ae12f..dac19ec 100644 --- a/3rd_party/libsrp6a-sha512/t_math.c +++ b/3rd_party/libsrp6a-sha512/t_math.c @@ -39,10 +39,13 @@ typedef BIGNUM * BigInteger; typedef BN_CTX * BigIntegerCtx; typedef BN_MONT_CTX * BigIntegerModAccel; #include <limits.h> -# ifdef OPENSSL_ENGINE +#if OPENSSL_VERSION_NUMBER < 0x30000000L +# ifndef OPENSSL_NO_ENGINE +# define OPENSSL_ENGINE # include "openssl/engine.h" static ENGINE * default_engine = NULL; # endif /* OPENSSL_ENGINE */ +#endif typedef int (*modexp_meth)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *mctx); static modexp_meth default_modexp = NULL; @@ -98,8 +101,7 @@ typedef void * BigIntegerModAccel; /* Math library interface stubs */ BigInteger -BigIntegerFromInt(n) - unsigned int n; +BigIntegerFromInt(unsigned int n) { #ifdef OPENSSL BIGNUM * a = BN_new(); @@ -135,9 +137,7 @@ BigIntegerFromInt(n) } BigInteger -BigIntegerFromBytes(bytes, length) - const unsigned char * bytes; - int length; +BigIntegerFromBytes(const unsigned char *bytes, int length) { #ifdef OPENSSL BIGNUM * a = BN_new(); @@ -205,10 +205,7 @@ BigIntegerFromBytes(bytes, length) } int -BigIntegerToBytes(src, dest, destlen) - BigInteger src; - unsigned char * dest; - int destlen; +BigIntegerToBytes(BigInteger src, unsigned char *dest, int destlen) { #ifdef OPENSSL return BN_bn2bin(src, dest); @@ -289,10 +286,7 @@ BigIntegerToCstrEx(BigInteger x, cstr * out, int len) } BigIntegerResult -BigIntegerToHex(src, dest, destlen) - BigInteger src; - char * dest; - int destlen; +BigIntegerToHex(BigInteger src, char *dest, int destlen) { #ifdef OPENSSL strncpy(dest, BN_bn2hex(src), destlen); @@ -316,11 +310,7 @@ static char b64table[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./"; BigIntegerResult -BigIntegerToString(src, dest, destlen, radix) - BigInteger src; - char * dest; - int destlen; - unsigned int radix; +BigIntegerToString(BigInteger src, char *dest, int destlen, unsigned int radix) { BigInteger t = BigIntegerFromInt(0); char * p = dest; @@ -344,8 +334,7 @@ BigIntegerToString(src, dest, destlen, radix) } int -BigIntegerBitLen(b) - BigInteger b; +BigIntegerBitLen(BigInteger b) { #ifdef OPENSSL return BN_num_bits(b); @@ -363,8 +352,7 @@ BigIntegerBitLen(b) } int -BigIntegerCmp(c1, c2) - BigInteger c1, c2; +BigIntegerCmp(BigInteger c1, BigInteger c2) { #ifdef OPENSSL return BN_cmp(c1, c2); @@ -382,9 +370,7 @@ BigIntegerCmp(c1, c2) } int -BigIntegerCmpInt(c1, c2) - BigInteger c1; - unsigned int c2; +BigIntegerCmpInt(BigInteger c1, unsigned int c2) { #ifdef OPENSSL BigInteger bc2 = BigIntegerFromInt(c2); @@ -413,9 +399,7 @@ BigIntegerCmpInt(c1, c2) } BigIntegerResult -BigIntegerLShift(result, x, bits) - BigInteger result, x; - unsigned int bits; +BigIntegerLShift(BigInteger result, BigInteger x, unsigned int bits) { #ifdef OPENSSL BN_lshift(result, x, bits); @@ -435,8 +419,7 @@ BigIntegerLShift(result, x, bits) } BigIntegerResult -BigIntegerAdd(result, a1, a2) - BigInteger result, a1, a2; +BigIntegerAdd(BigInteger result, BigInteger a1, BigInteger a2) { #ifdef OPENSSL BN_add(result, a1, a2); @@ -455,9 +438,7 @@ BigIntegerAdd(result, a1, a2) } BigIntegerResult -BigIntegerAddInt(result, a1, a2) - BigInteger result, a1; - unsigned int a2; +BigIntegerAddInt(BigInteger result, BigInteger a1, unsigned int a2) { #ifdef OPENSSL if(result != a1) @@ -482,8 +463,7 @@ BigIntegerAddInt(result, a1, a2) } BigIntegerResult -BigIntegerSub(result, s1, s2) - BigInteger result, s1, s2; +BigIntegerSub(BigInteger result, BigInteger s1, BigInteger s2) { #ifdef OPENSSL BN_sub(result, s1, s2); @@ -502,9 +482,7 @@ BigIntegerSub(result, s1, s2) } BigIntegerResult -BigIntegerSubInt(result, s1, s2) - BigInteger result, s1; - unsigned int s2; +BigIntegerSubInt(BigInteger result, BigInteger s1, unsigned int s2) { #ifdef OPENSSL if(result != s1) @@ -529,9 +507,7 @@ BigIntegerSubInt(result, s1, s2) } BigIntegerResult -BigIntegerMul(result, m1, m2, c) - BigInteger result, m1, m2; - BigIntegerCtx c; +BigIntegerMul(BigInteger result, BigInteger m1, BigInteger m2, BigIntegerCtx c) { #ifdef OPENSSL BN_CTX * ctx = NULL; @@ -555,10 +531,7 @@ BigIntegerMul(result, m1, m2, c) } BigIntegerResult -BigIntegerMulInt(result, m1, m2, c) - BigInteger result, m1; - unsigned int m2; - BigIntegerCtx c; +BigIntegerMulInt(BigInteger result, BigInteger m1, unsigned int m2, BigIntegerCtx c) { #ifdef OPENSSL if(result != m1) @@ -583,10 +556,7 @@ BigIntegerMulInt(result, m1, m2, c) } BigIntegerResult -BigIntegerDivInt(result, d, m, c) - BigInteger result, d; - unsigned int m; - BigIntegerCtx c; +BigIntegerDivInt(BigInteger result, BigInteger d, unsigned int m, BigIntegerCtx c) { #ifdef OPENSSL if(result != d) @@ -623,9 +593,7 @@ BigIntegerDivInt(result, d, m, c) } BigIntegerResult -BigIntegerMod(result, d, m, c) - BigInteger result, d, m; - BigIntegerCtx c; +BigIntegerMod(BigInteger result, BigInteger d, BigInteger m, BigIntegerCtx c) { #ifdef OPENSSL BN_CTX * ctx = NULL; @@ -649,10 +617,7 @@ BigIntegerMod(result, d, m, c) } unsigned int -BigIntegerModInt(d, m, c) - BigInteger d; - unsigned int m; - BigIntegerCtx c; +BigIntegerModInt(BigInteger d, unsigned int m, BigIntegerCtx c) { #ifdef OPENSSL return BN_mod_word(d, m); @@ -710,9 +675,7 @@ BigIntegerModInt(d, m, c) } BigIntegerResult -BigIntegerModMul(r, m1, m2, modulus, c) - BigInteger r, m1, m2, modulus; - BigIntegerCtx c; +BigIntegerModMul(BigInteger r, BigInteger m1, BigInteger m2, BigInteger modulus, BigIntegerCtx c) { #ifdef OPENSSL BN_CTX * ctx = NULL; @@ -742,10 +705,7 @@ BigIntegerModMul(r, m1, m2, modulus, c) } BigIntegerResult -BigIntegerModExp(r, b, e, m, c, a) - BigInteger r, b, e, m; - BigIntegerCtx c; - BigIntegerModAccel a; +BigIntegerModExp(BigInteger r, BigInteger b, BigInteger e, BigInteger m, BigIntegerCtx c, BigIntegerModAccel a) { #ifdef OPENSSL #if OPENSSL_VERSION_NUMBER >= 0x00906000 @@ -760,7 +720,11 @@ BigIntegerModExp(r, b, e, m, c, a) else if(a == NULL) { BN_mod_exp(r, b, e, m, c); } -#if OPENSSL_VERSION_NUMBER >= 0x00906000 +/* + * In LibreSSL BN_mod_exp_mont_word() is not a public symbol where BN_mod_exp() + * and BN_mod_exp_mont() will use the word optimization when appropriate. + */ +#if OPENSSL_VERSION_NUMBER >= 0x00906000 && !defined(LIBRESSL_VERSION_NUMBER) else if(B > 0 && B < ULONG_MAX) { /* 0.9.6 and above has mont_word optimization */ BN_mod_exp_mont_word(r, B, e, m, c, a); } @@ -792,9 +756,7 @@ int _mbedtls_f_rng(void* unused, unsigned char *buf, size_t size) #endif int -BigIntegerCheckPrime(n, c) - BigInteger n; - BigIntegerCtx c; +BigIntegerCheckPrime(BigInteger n, BigIntegerCtx c) { #ifdef OPENSSL int rv; @@ -802,7 +764,11 @@ BigIntegerCheckPrime(n, c) if(c == NULL) c = ctx = BN_CTX_new(); #if OPENSSL_VERSION_NUMBER >= 0x00908000 - rv = BN_is_prime_ex(n, 25, c, NULL); + #if OPENSSL_VERSION_NUMBER >= 0x30000000L + rv = BN_check_prime(n, c, NULL); + #else + rv = BN_is_prime_ex(n, 25, c, NULL); + #endif #else rv = BN_is_prime(n, 25, NULL, c, NULL); #endif @@ -845,8 +811,7 @@ BigIntegerCheckPrime(n, c) } BigIntegerResult -BigIntegerFree(b) - BigInteger b; +BigIntegerFree(BigInteger b) { #ifdef OPENSSL BN_free(b); @@ -868,8 +833,7 @@ BigIntegerFree(b) } BigIntegerResult -BigIntegerClearFree(b) - BigInteger b; +BigIntegerClearFree(BigInteger b) { #ifdef OPENSSL BN_clear_free(b); @@ -905,8 +869,7 @@ BigIntegerCtxNew() } BigIntegerResult -BigIntegerCtxFree(ctx) - BigIntegerCtx ctx; +BigIntegerCtxFree(BigIntegerCtx ctx) { #ifdef OPENSSL if(ctx) @@ -916,9 +879,7 @@ BigIntegerCtxFree(ctx) } BigIntegerModAccel -BigIntegerModAccelNew(m, c) - BigInteger m; - BigIntegerCtx c; +BigIntegerModAccelNew(BigInteger m, BigIntegerCtx c) { #ifdef OPENSSL BN_CTX * ctx = NULL; @@ -938,8 +899,7 @@ BigIntegerModAccelNew(m, c) } BigIntegerResult -BigIntegerModAccelFree(accel) - BigIntegerModAccel accel; +BigIntegerModAccelFree(BigIntegerModAccel accel) { #ifdef OPENSSL if(accel) @@ -951,7 +911,7 @@ BigIntegerModAccelFree(accel) BigIntegerResult BigIntegerInitialize() { -#if OPENSSL_VERSION_NUMBER >= 0x00907000 +#if OPENSSL_VERSION_NUMBER >= 0x00907000 && defined(OPENSSL_ENGINE) ENGINE_load_builtin_engines(); #endif return BIG_INTEGER_SUCCESS; diff --git a/3rd_party/libsrp6a-sha512/t_misc.c b/3rd_party/libsrp6a-sha512/t_misc.c index 3053358..abd8e55 100644 --- a/3rd_party/libsrp6a-sha512/t_misc.c +++ b/3rd_party/libsrp6a-sha512/t_misc.c @@ -38,7 +38,7 @@ #include <sys/stat.h> #include <fcntl.h> -#ifdef WIN32 +#ifdef _WIN32 #include <process.h> #include <io.h> #endif @@ -80,8 +80,7 @@ SHA1_CTX randctxt; extern char ** environ; static void -t_envhash(out) - unsigned char * out; +t_envhash(unsigned char * out) { char ** ptr; char ebuf[256]; @@ -115,8 +114,7 @@ t_envhash(out) * The entire buffer is run once through SHA to obtain the final result. */ static void -t_fshash(out) - unsigned char * out; +t_fshash(unsigned char * out) { char dotpath[128]; struct stat st; @@ -209,7 +207,7 @@ t_initrand() #if defined(OPENSSL) /* OpenSSL has nifty win32 entropy-gathering code */ #if OPENSSL_VERSION_NUMBER >= 0x00905100 r = RAND_status(); -#if defined(WINDOWS) || defined(WIN32) +#if defined(WINDOWS) || defined(_WIN32) if(r) /* Don't do the Unix-y stuff on Windows if possible */ return; #else @@ -222,7 +220,7 @@ t_initrand() if(r > 0) { yarrow_add_entropy(entropy, r, &g_rng); memset(entropy, 0, sizeof(entropy)); -# if defined(WINDOWS) || defined(WIN32) +# if defined(WINDOWS) || defined(_WIN32) /* Don't do the Unix-y stuff on Windows if possible */ yarrow_ready(&g_rng); return; @@ -230,13 +228,13 @@ t_initrand() } #endif -#if !defined(WINDOWS) && !defined(WIN32) +#if !defined(WINDOWS) && !defined(_WIN32) i = open("/dev/urandom", O_RDONLY); if(i > 0) { r += read(i, preseed.devrand, sizeof(preseed.devrand)); close(i); } -#endif /* !WINDOWS && !WIN32 */ +#endif /* !WINDOWS && !_WIN32 */ /* Resort to truerand only if desperate for some Real entropy */ if(r == 0) @@ -252,7 +250,7 @@ t_initrand() preseed.subsec = t.tv_usec; #endif preseed.pid = getpid(); -#ifndef WIN32 +#ifndef _WIN32 preseed.ppid = getppid(); #endif t_envhash(preseed.envh); @@ -317,9 +315,7 @@ t_stronginitrand() * Each cycle generates 20 bytes of new output. */ _TYPE( void ) -t_random(data, size) - unsigned char * data; - unsigned size; +t_random(unsigned char * data, unsigned size) { if(!initialized) t_initrand(); @@ -369,10 +365,7 @@ t_random(data, size) * single 320-bit value. */ _TYPE( unsigned char * ) -t_sessionkey(key, sk, sklen) - unsigned char * key; - unsigned char * sk; - unsigned sklen; +t_sessionkey(unsigned char * key, unsigned char * sk, unsigned sklen) { unsigned i, klen; unsigned char * hbuf; @@ -411,11 +404,7 @@ t_sessionkey(key, sk, sklen) } _TYPE( void ) -t_mgf1(mask, masklen, seed, seedlen) - unsigned char * mask; - unsigned masklen; - const unsigned char * seed; - unsigned seedlen; +t_mgf1(unsigned char * mask, unsigned masklen, const unsigned char * seed, unsigned seedlen) { SHA1_CTX ctxt; unsigned i = 0; diff --git a/3rd_party/libsrp6a-sha512/t_sha.c b/3rd_party/libsrp6a-sha512/t_sha.c index 4029de8..8e54cb6 100644 --- a/3rd_party/libsrp6a-sha512/t_sha.c +++ b/3rd_party/libsrp6a-sha512/t_sha.c @@ -107,6 +107,44 @@ SHA512Final_mbed(unsigned char digest[64], SHA512_CTX * ctx) mbedtls_md_free(ctx); } +#elif defined(OPENSSL_SHA) +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +void +SHA1Init_openssl(SHA1_CTX *ctx) +{ + *ctx = EVP_MD_CTX_new(); + EVP_DigestInit(*ctx, EVP_sha1()); +} + +void SHA1Update_openssl(SHA1_CTX *ctx, const void *data, unsigned int len) +{ + EVP_DigestUpdate(*ctx, data, (size_t)len); +} + +void SHA1Final_openssl(unsigned char digest[20], SHA1_CTX *ctx) +{ + EVP_DigestFinal(*ctx, digest, NULL); + EVP_MD_CTX_destroy(*ctx); +} + +void +SHA512Init_openssl(SHA512_CTX *ctx) +{ + *ctx = EVP_MD_CTX_new(); + EVP_DigestInit(*ctx, EVP_sha512()); +} + +void SHA512Update_openssl(SHA512_CTX *ctx, const void *data, unsigned int len) +{ + EVP_DigestUpdate(*ctx, data, (size_t)len); +} + +void SHA512Final_openssl(unsigned char digest[64], SHA512_CTX *ctx) +{ + EVP_DigestFinal(*ctx, digest, NULL); + EVP_MD_CTX_destroy(*ctx); +} +#endif #elif !defined(OPENSSL_SHA) && !defined(TOMCRYPT_SHA) /* Use the free SHA1 if the library doesn't have it */ @@ -273,4 +311,4 @@ unsigned char finalcount[8]; SHA1Transform(context->state, context->buffer); #endif } -#endif /* OPENSSL */ +#endif diff --git a/3rd_party/libsrp6a-sha512/t_sha.h b/3rd_party/libsrp6a-sha512/t_sha.h index 18deec5..2e38067 100644 --- a/3rd_party/libsrp6a-sha512/t_sha.h +++ b/3rd_party/libsrp6a-sha512/t_sha.h @@ -38,6 +38,28 @@ #endif #ifdef OPENSSL_SHA +#include <openssl/err.h> +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#include <openssl/evp.h> + +typedef EVP_MD_CTX* SHA1_CTX; +#define SHA1Init SHA1Init_openssl +#define SHA1Update SHA1Update_openssl +#define SHA1Final SHA1Final_openssl + +typedef EVP_MD_CTX* SHA512_CTX; +#define SHA512Init SHA512Init_openssl +#define SHA512Update SHA512Update_openssl +#define SHA512Final SHA512Final_openssl + +void SHA1Init_openssl(SHA1_CTX *ctx); +void SHA1Update_openssl(SHA1_CTX *ctx, const void *data, unsigned int len); +void SHA1Final_openssl(unsigned char digest[20], SHA1_CTX *ctx); + +void SHA512Init_openssl(SHA512_CTX *ctx); +void SHA512Update_openssl(SHA512_CTX *ctx, const void *data, unsigned int len); +void SHA512Final_openssl(unsigned char digest[64], SHA1_CTX *ctx); +#else /* for OpenSSL < 3.0 */ #include <openssl/sha.h> typedef SHA_CTX SHA1_CTX; @@ -48,7 +70,7 @@ typedef SHA_CTX SHA1_CTX; #define SHA512Init SHA512_Init #define SHA512Update SHA512_Update #define SHA512Final SHA512_Final - +#endif /* for OpenSSL < 3.0 */ #elif defined(TOMCRYPT_SHA) /* mycrypt.h already included above */ diff --git a/3rd_party/libsrp6a-sha512/t_truerand.c b/3rd_party/libsrp6a-sha512/t_truerand.c index 4a4c3d2..cd27d0d 100644 --- a/3rd_party/libsrp6a-sha512/t_truerand.c +++ b/3rd_party/libsrp6a-sha512/t_truerand.c @@ -54,7 +54,7 @@ #include "t_defines.h" -#ifdef WIN32 +#ifdef _WIN32 # ifdef CRYPTOLIB @@ -69,7 +69,7 @@ raw_truerand() return truerand(); } -# else /* !CRYPTOLIB && WIN32 */ +# else /* !CRYPTOLIB && _WIN32 */ #include <windows.h> #include <wtypes.h> @@ -128,7 +128,7 @@ raw_truerand() { # endif /* CRYPTOLIB */ -#else /* !WIN32 */ +#else /* !_WIN32 */ #include <signal.h> #include <setjmp.h> @@ -227,8 +227,7 @@ raw_truerand() } int -raw_n_truerand(n) -int n; +raw_n_truerand(int n) { int slop, v; @@ -239,4 +238,4 @@ int n; return v % n; } -#endif /* !CRYPTOLIB || !WIN32 */ +#endif /* !CRYPTOLIB || !_WIN32 */ diff --git a/Makefile.am b/Makefile.am index b11de57..f429f2f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,11 +3,11 @@ ACLOCAL_AMFLAGS = -I m4 SUBDIRS = 3rd_party common src include $(CYTHON_SUB) tools docs EXTRA_DIST = \ - docs \ README.md \ git-version-gen dist-hook: + @if ! git diff --quiet; then echo "Uncommitted changes present; not releasing"; exit 1; fi echo $(VERSION) > $(distdir)/.tarball-version docs/html: $(top_builddir)/doxygen.cfg $(top_srcdir)/src/*.c $(top_srcdir)/src/*.h $(top_srcdir)/include/libimobiledevice/*.h @@ -1,3 +1,34 @@ +Version 1.4.0 +~~~~~~~~~~~~~ + +* Development release + - From now on, releases will be made more frequently +* Changes: + - Add support for MbedTLS + - Add Reverse Proxy implementation + - Add support for wireless pairing (AppleTV) + - Embed 3rd party libraries for ed25519 and SRP6a + - Fixes in idevicedebug + - idevicecrashreport: Allow filtering crash reports by filename + - Add idevicedevmodectl tool + - Fixes for idevicebackup2 + - Add property_list_client_get_service_client() and service_get_connection() functions + - Add idevicebtlogger + - Add new idevice_events_subscribe/unsubscribe API + - Move LIBIMOBILEDEVICE_API to public headers + - Add afc_strerror function + - Add libimobiledevice_version() function + - Use libimobiledevice-glue's SHA1 implementation + - Add support for iOS 17+ Personalized Developer Disk image mounting + - Fix compilation on MSVC + - Add idevice_strerror() to interface + - Add new idevice_get_device_version() to interface + - Add os_trace_relay service implementation + - Fixes for idevicesyslog + - afc: Add afc_get_file_info_plist and afc_get_device_info_plist functions + ... and several other internal changes + + Version 1.3.0 ~~~~~~~~~~~~~ @@ -18,7 +18,7 @@ Some key features are: - **Implementation**: Object oriented architecture and service abstraction layer - **Cross-Platform:** Tested on Linux, macOS, Windows and Android platforms - **Utilities**: Provides various command-line utilities for device services -- **SSL**: Allows choosing between OpenSSL or GnuTLS to handle SSL communication +- **SSL**: Allows choosing between OpenSSL, GnuTLS, or MbedTLS to handle SSL communication - **Network**: Supports network connections with "WiFi sync" enabled devices - **Python:** Provides Cython based bindings for Python @@ -66,9 +66,13 @@ sudo apt-get install \ libplist-dev \ libusbmuxd-dev \ libimobiledevice-glue-dev \ + libtatsu-dev \ libssl-dev \ usbmuxd ``` +NOTE: [libtatsu](https://github.com/libimobiledevice/libtatsu) (and thus `libtatsu-dev`) +is a new library that was just published recently, you have to +[build it from source](https://github.com/libimobiledevice/libtatsu?tab=readme-ov-file#building). If you want to optionally build the documentation or Python bindings use: ```shell @@ -144,6 +148,7 @@ The library bundles the following command-line utilities in the tools directory: | `idevicescreenshot` | Gets a screenshot from the connected device | | `idevicesetlocation` | Simulate location on device | | `idevicesyslog` | Relay syslog of a connected device | +| `afcclient` | Interact with device filesystem via AFC/HouseArrest | Please consult the usage information or manual pages of each utility for a documentation of available command line options and usage examples like this: @@ -174,8 +179,8 @@ We are still working on the guidelines so bear with us! ## Links * Homepage: https://libimobiledevice.org/ -* Repository: https://git.libimobiledevice.org/libimobiledevice.git -* Repository (Mirror): https://github.com/libimobiledevice/libimobiledevice.git +* Repository: https://github.com/libimobiledevice/libimobiledevice.git +* Repository (Mirror): https://git.libimobiledevice.org/libimobiledevice.git * Issue Tracker: https://github.com/libimobiledevice/libimobiledevice/issues * Mailing List: https://lists.libimobiledevice.org/mailman/listinfo/libimobiledevice-devel * Twitter: https://twitter.com/libimobiledev @@ -193,4 +198,4 @@ iPadOS, tvOS, watchOS, and macOS are trademarks of Apple Inc. This project is an independent software and has not been authorized, sponsored, or otherwise approved by Apple Inc. -README Updated on: 2022-04-04 +README Updated on: 2024-10-22 diff --git a/common/Makefile.am b/common/Makefile.am index 1a90571..ba7ed9c 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -4,22 +4,18 @@ AM_CPPFLAGS = \ AM_CFLAGS = \ $(GLOBAL_CFLAGS) \ + $(ssl_lib_CFLAGS) \ + $(LFS_CFLAGS) \ $(libusbmuxd_CFLAGS) \ - $(libplist_CFLAGS) \ - $(libgnutls_CFLAGS) \ - $(libtasn1_CFLAGS) \ - $(libgcrypt_CFLAGS) \ - $(openssl_CFLAGS) \ - $(LFS_CFLAGS) + $(limd_glue_CFLAGS) \ + $(libplist_CFLAGS) AM_LDFLAGS = \ + $(ssl_lib_LIBS) \ + ${libpthread_LIBS} \ $(libusbmuxd_LIBS) \ - $(libplist_LIBS) \ - $(libgnutls_LIBS) \ - $(libtasn1_LIBS) \ - $(libgcrypt_LIBS) \ - $(openssl_LIBS) \ - ${libpthread_LIBS} + $(limd_glue_LIBS) \ + $(libplist_LIBS) noinst_LTLIBRARIES = libinternalcommon.la libinternalcommon_la_LIBADD = diff --git a/common/debug.c b/common/debug.c index 6212e71..7a593fc 100644 --- a/common/debug.c +++ b/common/debug.c @@ -30,10 +30,13 @@ #include <stdint.h> #include <stdlib.h> #include <time.h> +#ifndef _WIN32 +#include <sys/time.h> +#endif +#include "src/idevice.h" #include "debug.h" #include "libimobiledevice/libimobiledevice.h" -#include "src/idevice.h" #ifndef STRIP_DEBUG_CODE #include "asprintf.h" @@ -51,27 +54,31 @@ void internal_set_debug_level(int level) #ifndef STRIP_DEBUG_CODE static void debug_print_line(const char *func, const char *file, int line, const char *buffer) { - char *str_time = NULL; - char *header = NULL; + char str_time[24]; +#ifdef _WIN32 + SYSTEMTIME lt; + GetLocalTime(<); + snprintf(str_time, 24, "%02d:%02d:%02d.%03d", lt.wHour, lt.wMinute, lt.wSecond, lt.wMilliseconds); +#else +#ifdef HAVE_GETTIMEOFDAY + struct timeval tv; + struct tm *tp; + gettimeofday(&tv, NULL); +#ifdef HAVE_LOCALTIME_R + struct tm tp_; + tp = localtime_r(&tv.tv_sec, &tp_); +#else + tp = localtime(&tv.tv_sec); +#endif + strftime(str_time, 9, "%H:%M:%S", tp); + snprintf(str_time+8, 10, ".%03d", (int)tv.tv_usec/1000); +#else time_t the_time; - time(&the_time); - str_time = (char*)malloc(255); - strftime(str_time, 254, "%H:%M:%S", localtime (&the_time)); - - /* generate header text */ - (void)asprintf(&header, "%s %s:%d %s()", str_time, file, line, func); - free (str_time); - - /* trim ending newlines */ - - /* print header */ - fprintf(stderr, "%s: ", header); - - /* print actual debug content */ - fprintf(stderr, "%s\n", buffer); - - free (header); + strftime(str_time, 15, "%H:%M:%S", localtime (&the_time)); +#endif +#endif + fprintf(stderr, "%s %s:%d %s(): %s\n", str_time, file, line, func, buffer); } #endif @@ -86,7 +93,7 @@ void debug_info_real(const char *func, const char *file, int line, const char *f /* run the real fprintf */ va_start(args, format); - (void)vasprintf(&buffer, format, args); + if(vasprintf(&buffer, format, args)<0){} va_end(args); debug_print_line(func, file, line, buffer); diff --git a/common/userpref.c b/common/userpref.c index ddd380a..76945e1 100644 --- a/common/userpref.c +++ b/common/userpref.c @@ -29,13 +29,18 @@ #include <stdint.h> #include <stdlib.h> #include <string.h> +#include <errno.h> + #ifdef HAVE_SYS_TYPES_H #include <sys/types.h> #endif -#ifndef WIN32 +#include <dirent.h> +#ifndef _WIN32 #include <pwd.h> -#endif #include <unistd.h> +#include <libgen.h> +#include <sys/stat.h> +#endif #include <usbmuxd.h> #if defined(HAVE_OPENSSL) #include <openssl/bn.h> @@ -64,12 +69,7 @@ #error No supported TLS/SSL library enabled #endif -#include <dirent.h> -#include <libgen.h> -#include <sys/stat.h> -#include <errno.h> - -#ifdef WIN32 +#ifdef _WIN32 #include <shlobj.h> #endif @@ -77,6 +77,7 @@ #define ETIMEDOUT 138 #endif +#include <libimobiledevice/libimobiledevice.h> #include <libimobiledevice-glue/utils.h> #include "userpref.h" @@ -93,7 +94,7 @@ const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = { }; #endif -#ifdef WIN32 +#ifdef _WIN32 #define DIR_SEP '\\' #define DIR_SEP_S "\\" #else @@ -103,7 +104,7 @@ const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = { #define USERPREF_CONFIG_EXTENSION ".plist" -#ifdef WIN32 +#ifdef _WIN32 #define USERPREF_CONFIG_DIR "Apple"DIR_SEP_S"Lockdown" #else #define USERPREF_CONFIG_DIR "lockdown" @@ -113,7 +114,7 @@ const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = { static char *__config_dir = NULL; -#ifdef WIN32 +#ifdef _WIN32 static char *userpref_utf16_to_utf8(wchar_t *unistr, long len, long *items_read, long *items_written) { if (!unistr || (len <= 0)) return NULL; @@ -155,7 +156,7 @@ const char *userpref_get_config_dir() if (__config_dir) return __config_dir; -#ifdef WIN32 +#ifdef _WIN32 wchar_t path[MAX_PATH+1]; HRESULT hr; LPITEMIDLIST pidl = NULL; @@ -338,7 +339,7 @@ userpref_error_t userpref_read_pair_record(const char *udid, plist_t *pair_recor } *pair_record = NULL; - plist_from_memory(record_data, record_size, pair_record); + plist_from_memory(record_data, record_size, pair_record, NULL); free(record_data); if (!*pair_record) { @@ -419,7 +420,7 @@ static int _mbedtls_x509write_crt_set_basic_constraints_critical(mbedtls_x509wri * * @return 1 if keys were successfully generated, 0 otherwise */ -userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_data_t public_key) +userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_data_t public_key, unsigned int device_version) { userpref_error_t ret = USERPREF_E_SSL_ERROR; @@ -435,6 +436,10 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da debug_info("Generating keys and certificates..."); #if defined(HAVE_OPENSSL) +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY* root_pkey = EVP_RSA_gen(2048); + EVP_PKEY* host_pkey = EVP_RSA_gen(2048); +#else BIGNUM *e = BN_new(); RSA* root_keypair = RSA_new(); RSA* host_keypair = RSA_new(); @@ -451,6 +456,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da EVP_PKEY* host_pkey = EVP_PKEY_new(); EVP_PKEY_assign_RSA(host_pkey, host_keypair); +#endif /* generate root certificate */ X509* root_cert = X509_new(); @@ -479,7 +485,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da X509_set_pubkey(root_cert, root_pkey); /* sign root cert with root private key */ - X509_sign(root_cert, root_pkey, EVP_sha1()); + X509_sign(root_cert, root_pkey, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? EVP_sha1() : EVP_sha256()); } /* create host certificate */ @@ -512,7 +518,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da X509_set_pubkey(host_cert, host_pkey); /* sign host cert with root private key */ - X509_sign(host_cert, root_pkey, EVP_sha1()); + X509_sign(host_cert, root_pkey, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? EVP_sha1() : EVP_sha256()); } if (root_cert && root_pkey && host_cert && host_pkey) { @@ -561,12 +567,22 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da } } - RSA *pubkey = NULL; + EVP_PKEY *pubkey = NULL; { BIO *membp = BIO_new_mem_buf(public_key.data, public_key.size); - if (!PEM_read_bio_RSAPublicKey(membp, &pubkey, NULL, NULL)) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (!PEM_read_bio_PUBKEY(membp, &pubkey, NULL, NULL)) { debug_info("WARNING: Could not read public key"); } +#else + RSA *rsa_pubkey = NULL; + if (!PEM_read_bio_RSAPublicKey(membp, &rsa_pubkey, NULL, NULL)) { + debug_info("WARNING: Could not read public key"); + } else { + pubkey = EVP_PKEY_new(); + EVP_PKEY_assign_RSA(pubkey, rsa_pubkey); + } +#endif BIO_free(membp); } @@ -588,16 +604,13 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da X509_set1_notAfter(dev_cert, asn1time); ASN1_TIME_free(asn1time); - EVP_PKEY* pkey = EVP_PKEY_new(); - EVP_PKEY_assign_RSA(pkey, pubkey); - X509_set_pubkey(dev_cert, pkey); - EVP_PKEY_free(pkey); + X509_set_pubkey(dev_cert, pubkey); X509_add_ext_helper(dev_cert, NID_subject_key_identifier, (char*)"hash"); X509_add_ext_helper(dev_cert, NID_key_usage, (char*)"critical,digitalSignature,keyEncipherment"); /* sign device certificate with root private key */ - if (X509_sign(dev_cert, root_pkey, EVP_sha1())) { + if (X509_sign(dev_cert, root_pkey, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? EVP_sha1() : EVP_sha256())) { /* if signing succeeded, export in PEM format */ BIO* membp = BIO_new(BIO_s_mem()); if (PEM_write_bio_X509(membp, dev_cert) > 0) { @@ -615,9 +628,9 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da } } - X509V3_EXT_cleanup(); X509_free(dev_cert); + EVP_PKEY_free(pubkey); EVP_PKEY_free(root_pkey); EVP_PKEY_free(host_pkey); @@ -649,7 +662,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da gnutls_x509_crt_set_ca_status(root_cert, 1); gnutls_x509_crt_set_activation_time(root_cert, time(NULL)); gnutls_x509_crt_set_expiration_time(root_cert, time(NULL) + (60 * 60 * 24 * 365 * 10)); - gnutls_x509_crt_sign2(root_cert, root_cert, root_privkey, GNUTLS_DIG_SHA1, 0); + gnutls_x509_crt_sign2(root_cert, root_cert, root_privkey, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256, 0); gnutls_x509_crt_set_key(host_cert, host_privkey); gnutls_x509_crt_set_serial(host_cert, "\x01", 1); @@ -658,7 +671,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da gnutls_x509_crt_set_key_usage(host_cert, GNUTLS_KEY_KEY_ENCIPHERMENT | GNUTLS_KEY_DIGITAL_SIGNATURE); gnutls_x509_crt_set_activation_time(host_cert, time(NULL)); gnutls_x509_crt_set_expiration_time(host_cert, time(NULL) + (60 * 60 * 24 * 365 * 10)); - gnutls_x509_crt_sign2(host_cert, root_cert, root_privkey, GNUTLS_DIG_SHA1, 0); + gnutls_x509_crt_sign2(host_cert, root_cert, root_privkey, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256, 0); /* export to PEM format */ size_t root_key_export_size = 0; @@ -756,17 +769,17 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da gnutls_x509_crt_set_expiration_time(dev_cert, time(NULL) + (60 * 60 * 24 * 365 * 10)); /* use custom hash generation for compatibility with the "Apple ecosystem" */ - const gnutls_digest_algorithm_t dig_sha1 = GNUTLS_DIG_SHA1; - size_t hash_size = gnutls_hash_get_len(dig_sha1); + const gnutls_digest_algorithm_t dig_sha = (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256; + size_t hash_size = gnutls_hash_get_len(dig_sha); unsigned char hash[hash_size]; - if (gnutls_hash_fast(dig_sha1, der_pub_key.data, der_pub_key.size, (unsigned char*)&hash) < 0) { - debug_info("ERROR: Failed to generate SHA1 for public key"); + if (gnutls_hash_fast(dig_sha, der_pub_key.data, der_pub_key.size, (unsigned char*)&hash) < 0) { + debug_info("ERROR: Failed to generate SHA for public key"); } else { gnutls_x509_crt_set_subject_key_id(dev_cert, hash, hash_size); } gnutls_x509_crt_set_key_usage(dev_cert, GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT); - gnutls_error = gnutls_x509_crt_sign2(dev_cert, root_cert, root_privkey, GNUTLS_DIG_SHA1, 0); + gnutls_error = gnutls_x509_crt_sign2(dev_cert, root_cert, root_privkey, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256, 0); if (GNUTLS_E_SUCCESS == gnutls_error) { /* if everything went well, export in PEM format */ size_t export_size = 0; @@ -860,7 +873,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da /* sign root cert with root private key */ mbedtls_x509write_crt_set_issuer_key(&cert, &root_pkey); - mbedtls_x509write_crt_set_md_alg(&cert, MBEDTLS_MD_SHA1); + mbedtls_x509write_crt_set_md_alg(&cert, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? MBEDTLS_MD_SHA1 : MBEDTLS_MD_SHA256); unsigned char outbuf[16384]; @@ -919,7 +932,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da /* sign host cert with root private key */ mbedtls_x509write_crt_set_issuer_key(&cert, &root_pkey); - mbedtls_x509write_crt_set_md_alg(&cert, MBEDTLS_MD_SHA1); + mbedtls_x509write_crt_set_md_alg(&cert, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? MBEDTLS_MD_SHA1 : MBEDTLS_MD_SHA256); /* write host private key */ mbedtls_pk_write_key_pem(&host_pkey, outbuf, sizeof(outbuf)); @@ -979,7 +992,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da /* sign device certificate with root private key */ mbedtls_x509write_crt_set_issuer_key(&cert, &root_pkey); - mbedtls_x509write_crt_set_md_alg(&cert, MBEDTLS_MD_SHA1); + mbedtls_x509write_crt_set_md_alg(&cert, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? MBEDTLS_MD_SHA1 : MBEDTLS_MD_SHA256); /* write device certificate */ mbedtls_x509write_crt_pem(&cert, outbuf, sizeof(outbuf), mbedtls_ctr_drbg_random, &ctr_drbg); diff --git a/common/userpref.h b/common/userpref.h index 75bb8b7..9a1832c 100644 --- a/common/userpref.h +++ b/common/userpref.h @@ -68,7 +68,7 @@ userpref_error_t userpref_read_pair_record(const char *udid, plist_t *pair_recor userpref_error_t userpref_save_pair_record(const char *udid, uint32_t device_id, plist_t pair_record); userpref_error_t userpref_delete_pair_record(const char *udid); -userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_data_t public_key); +userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_data_t public_key, unsigned int device_version); #if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS) userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const char* name, key_data_t* key); userpref_error_t pair_record_import_crt_with_name(plist_t pair_record, const char* name, key_data_t* cert); diff --git a/configure.ac b/configure.ac index 503051f..055fe04 100644 --- a/configure.ac +++ b/configure.ac @@ -15,7 +15,7 @@ dnl libtool versioning # changes to the signature and the semantic) # ? :+1 : ? == just internal changes # CURRENT : REVISION : AGE -LIBIMOBILEDEVICE_SO_VERSION=6:0:0 +LIBIMOBILEDEVICE_SO_VERSION=7:0:1 AC_SUBST(LIBIMOBILEDEVICE_SO_VERSION) @@ -26,8 +26,9 @@ fi dnl Minimum package versions LIBUSBMUXD_VERSION=2.0.2 -LIBPLIST_VERSION=2.2.0 -LIMD_GLUE_VERSION=1.0.0 +LIBPLIST_VERSION=2.3.0 +LIMD_GLUE_VERSION=1.3.0 +LIBTATSU_VERSION=1.0.3 AC_SUBST(LIBUSBMUXD_VERSION) AC_SUBST(LIBPLIST_VERSION) @@ -43,6 +44,19 @@ LT_INIT PKG_CHECK_MODULES(libusbmuxd, libusbmuxd-2.0 >= $LIBUSBMUXD_VERSION) PKG_CHECK_MODULES(libplist, libplist-2.0 >= $LIBPLIST_VERSION) PKG_CHECK_MODULES(limd_glue, libimobiledevice-glue-1.0 >= $LIMD_GLUE_VERSION) +PKG_CHECK_MODULES(libtatsu, libtatsu-1.0 >= $LIBTATSU_VERSION) +AC_ARG_WITH([readline], + [AS_HELP_STRING([--without-readline], + [build without support for libreadline (default is yes)])], + [check_libreadline=false], + [check_libreadline=true]) +if test "$check_libreadline" = "true"; then + PKG_CHECK_MODULES(readline, readline >= 1.0, have_readline=yes, have_readline=no) + if test "x$have_readline" = "xyes"; then + AC_DEFINE(HAVE_READLINE, 1, [Define if readline library is available]) + fi +fi +AM_CONDITIONAL([HAVE_READLINE],[test "x$have_readline" = "xyes"]) # Checks for header files. AC_CHECK_HEADERS([stdint.h stdlib.h string.h sys/time.h]) @@ -56,7 +70,7 @@ AC_TYPE_UINT32_T AC_TYPE_UINT8_T # Checks for library functions. -AC_CHECK_FUNCS([asprintf strcasecmp strdup strerror strndup stpcpy vasprintf getifaddrs]) +AC_CHECK_FUNCS([asprintf strcasecmp strdup strerror strndup stpcpy vasprintf getifaddrs gettimeofday localtime_r]) AC_CHECK_HEADER(endian.h, [ac_cv_have_endian_h="yes"], [ac_cv_have_endian_h="no"]) if test "x$ac_cv_have_endian_h" = "xno"; then @@ -70,8 +84,24 @@ if test "x$ac_cv_have_endian_h" = "xno"; then fi fi +CACHED_CFLAGS="$CFLAGS" +CFLAGS+=" $libplist_CFLAGS -Werror" + AC_CHECK_DECL([plist_from_json], [AC_DEFINE([HAVE_PLIST_JSON], [1], [Define if libplist has JSON support])], [], [[#include <plist/plist.h>]]) +# check if libplist has plist_new_unix_date() +AC_CACHE_CHECK(for plist_new_unix_date, ac_cv_plist_unix_date, + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include <plist/plist.h> + ]], [[ + return plist_new_unix_date(0) ? 0 : 1 + ]])],[ac_cv_plist_unix_date=yes],[ac_cv_plist_unix_date=no])) +if test "$ac_cv_plist_unix_date" = "yes"; then + AC_DEFINE(HAVE_PLIST_UNIX_DATE, 1, [Define if libplist has new unix date API (>= 2.7.0)]) +fi + +CFLAGS="$CACHED_CFLAGS" + # Check for operating system AC_MSG_CHECKING([for platform-specific build settings]) case ${host_os} in @@ -79,6 +109,7 @@ case ${host_os} in AC_MSG_RESULT([${host_os}]) win32=true AC_DEFINE(WINVER, 0x0501, [minimum Windows version]) + deplibs_check_method='pass_all' ;; darwin*) AC_MSG_RESULT([${host_os}]) @@ -93,24 +124,6 @@ esac AM_CONDITIONAL(WIN32, test x$win32 = xtrue) AM_CONDITIONAL(DARWIN, test x$darwin = xtrue) -# Check if the C compiler supports __attribute__((constructor)) -AC_CACHE_CHECK([wether the C compiler supports constructor/destructor attributes], - ac_cv_attribute_constructor, [ - ac_cv_attribute_constructor=no - AC_COMPILE_IFELSE([AC_LANG_PROGRAM( - [[ - static void __attribute__((constructor)) test_constructor(void) { - } - static void __attribute__((destructor)) test_destructor(void) { - } - ]], [])], - [ac_cv_attribute_constructor=yes] - )] -) -if test "$ac_cv_attribute_constructor" = "yes"; then - AC_DEFINE(HAVE_ATTRIBUTE_CONSTRUCTOR, 1, [Define if the C compiler supports constructor/destructor attributes]) -fi - AC_CHECK_MEMBER(struct dirent.d_type, AC_DEFINE(HAVE_DIRENT_D_TYPE, 1, [define if struct dirent has member d_type]),, [#include <dirent.h>]) # Cython Python Bindings @@ -120,9 +133,9 @@ AC_ARG_WITH([cython], [build_cython=false], [build_cython=true]) if test "$build_cython" = "true"; then - AC_PROG_CYTHON([0.17.0]) + AC_PROG_CYTHON([3.0.0]) if [test "x$CYTHON" != "xfalse"]; then - AM_PATH_PYTHON([2.3], [ + AM_PATH_PYTHON([3.0], [ CYTHON_PYTHON AS_COMPILER_FLAG([-Wno-cast-function-type -Werror], [ CYTHON_CFLAGS+=" -Wno-cast-function-type" @@ -165,7 +178,7 @@ AC_ARG_WITH([mbedtls], [Do not look for mbedtls])], [use_mbedtls=$withval], [use_mbedtls=no]) -if test "x$use_mbedtls" == "xyes"; then +if test "x$use_mbedtls" = "xyes"; then default_openssl=no fi AC_ARG_WITH([gnutls], @@ -173,7 +186,7 @@ AC_ARG_WITH([gnutls], [Do not look for GnuTLS])], [use_gnutls=$withval], [use_gnutls=no]) -if test "x$use_gnutls" == "xyes"; then +if test "x$use_gnutls" = "xyes"; then default_openssl=no fi AC_ARG_WITH([openssl], @@ -182,7 +195,7 @@ AC_ARG_WITH([openssl], [use_openssl=$withval], [use_openssl=$default_openssl]) -if test "x$use_mbedtls" == "xyes"; then +if test "x$use_mbedtls" = "xyes"; then CACHED_CFLAGS="$CFLAGS" conf_mbedtls_CFLAGS="" if test -n "$mbedtls_INCLUDES"; then @@ -209,7 +222,7 @@ if test "x$use_mbedtls" == "xyes"; then ssl_requires="" AC_SUBST(ssl_requires) else - if test "x$use_openssl" == "xyes"; then + if test "x$use_openssl" = "xyes"; then pkg_req_openssl="openssl >= 0.9.8" PKG_CHECK_MODULES(openssl, $pkg_req_openssl, have_openssl=yes, have_openssl=no) if test "x$have_openssl" != "xyes"; then @@ -222,10 +235,40 @@ else AC_SUBST(ssl_lib_LIBS) ssl_provider="OpenSSL"; ssl_requires="$pkg_req_openssl" + # test if we have LibreSSL + CACHED_CFLAGS="$CFLAGS" + CFLAGS="$openssl_CFLAGS" + ac_cv_is_libressl=no + AC_COMPILE_IFELSE([AC_LANG_PROGRAM( + [[ + #include <openssl/opensslv.h> + ]], [ + #ifndef LIBRESSL_VERSION_NUMBER + #error No LibreSSL + #endif + ])], + [ + ac_cv_is_libressl=yes + ], + ) + CFLAGS="$CACHED_CFLAGS" + if test "x$ac_cv_is_libressl" = "xyes"; then + ssl_provider="LibreSSL" + case ${host_os} in + darwin*) + case ${openssl_LIBS} in + *.tbd*) + # using system LibreSSL on Darwin + ssl_requires="" + ;; + esac + ;; + esac + fi AC_SUBST(ssl_requires) fi else - if test "x$use_gnutls" == "xyes"; then + if test "x$use_gnutls" = "xyes"; then pkg_req_gnutls="gnutls >= 2.2.0" pkg_req_libtasn1="libtasn1 >= 1.1" PKG_CHECK_MODULES(libgnutls, $pkg_req_gnutls) @@ -246,9 +289,9 @@ else fi fi fi -AM_CONDITIONAL(HAVE_MBEDTLS, test "x$use_mbedtls" == "xyes") -AM_CONDITIONAL(HAVE_OPENSSL, test "x$use_openssl" == "xyes") -AM_CONDITIONAL(HAVE_GCRYPT, test "x$use_gnutls" == "xyes") +AM_CONDITIONAL(HAVE_MBEDTLS, test "x$use_mbedtls" = "xyes") +AM_CONDITIONAL(HAVE_OPENSSL, test "x$use_openssl" = "xyes") +AM_CONDITIONAL(HAVE_GCRYPT, test "x$use_gnutls" = "xyes") AC_ARG_ENABLE([wireless-pairing], [AS_HELP_STRING([--disable-wireless-pairing], @@ -271,12 +314,12 @@ else fi AS_COMPILER_FLAGS(GLOBAL_CFLAGS, "-Wall -Wextra -Wmissing-declarations -Wredundant-decls -Wshadow -Wpointer-arith -Wwrite-strings -Wswitch-default -Wno-unused-parameter -fsigned-char -fvisibility=hidden") -AC_SUBST(GLOBAL_CFLAGS) -case "$GLOBAL_CFLAGS" in - *-fvisibility=hidden*) - AC_DEFINE([HAVE_FVISIBILITY], [1], [Define if compiled with -fvisibility=hidden]) -esac +if test "x$enable_static" = "xyes" -a "x$enable_shared" = "xno"; then + GLOBAL_CFLAGS+=" -DLIBIMOBILEDEVICE_STATIC" +fi + +AC_SUBST(GLOBAL_CFLAGS) # check for large file support AC_SYS_LARGEFILE diff --git a/cython/Makefile.am b/cython/Makefile.am index 3577c4e..93ea6ed 100644 --- a/cython/Makefile.am +++ b/cython/Makefile.am @@ -3,19 +3,15 @@ AM_CPPFLAGS = \ AM_CFLAGS = \ $(GLOBAL_CFLAGS) \ - $(libgnutls_CFLAGS) \ - $(libtasn1_CFLAGS) \ - $(openssl_CFLAGS) \ - $(libplist_CFLAGS) \ + $(ssl_lib_CFLAGS) \ $(LFS_CFLAGS) \ - $(PTHREAD_CFLAGS) + $(PTHREAD_CFLAGS) \ + $(libplist_CFLAGS) AM_LIBS = \ - $(libgnutls_LIBS) \ - $(libtasn1_LIBS) \ - $(openssl_LIBS) \ - $(libplist_LIBS) \ - $(PTHREAD_LIBS) + $(ssl_lib_LIBS) \ + $(PTHREAD_LIBS) \ + $(libplist_LIBS) if HAVE_CYTHON diff --git a/cython/debugserver.pxi b/cython/debugserver.pxi index a3b7d1e..fb96320 100644 --- a/cython/debugserver.pxi +++ b/cython/debugserver.pxi @@ -43,13 +43,7 @@ cdef class DebugServerError(BaseError): BaseError.__init__(self, *args, **kwargs) -# from http://stackoverflow.com/a/17511714 -# https://github.com/libimobiledevice/libimobiledevice/pull/198 -from cpython cimport PY_MAJOR_VERSION -if PY_MAJOR_VERSION <= 2: - from cpython.string cimport PyString_AsString -else: - from cpython.bytes cimport PyBytes_AsString as PyString_AsString +from cpython.bytes cimport PyBytes_AsString as PyString_AsString cdef char ** to_cstring_array(list_str): if not list_str: return NULL diff --git a/cython/imobiledevice.pxd b/cython/imobiledevice.pxd index b44e444..238df68 100644 --- a/cython/imobiledevice.pxd +++ b/cython/imobiledevice.pxd @@ -1,3 +1,6 @@ +#!python +#cython: language_level=3str + cimport plist from libc.stdint cimport * diff --git a/cython/imobiledevice.pyx b/cython/imobiledevice.pyx index 2a125aa..8da2296 100644 --- a/cython/imobiledevice.pyx +++ b/cython/imobiledevice.pyx @@ -94,7 +94,7 @@ cdef class iDeviceEvent: def __get__(self): return self._c_event.conn_type -cdef void idevice_event_cb(const_idevice_event_t c_event, void *user_data) with gil: +cdef void idevice_event_cb(const_idevice_event_t c_event, void *user_data) noexcept: cdef iDeviceEvent event = iDeviceEvent.__new__(iDeviceEvent) event._c_event = c_event (<object>user_data)(event) diff --git a/cython/installation_proxy.pxi b/cython/installation_proxy.pxi index bf2c1da..1d3e323 100644 --- a/cython/installation_proxy.pxi +++ b/cython/installation_proxy.pxi @@ -27,7 +27,7 @@ cdef extern from "libimobiledevice/installation_proxy.h": instproxy_error_t instproxy_restore(instproxy_client_t client, char *appid, plist.plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) instproxy_error_t instproxy_remove_archive(instproxy_client_t client, char *appid, plist.plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) -cdef void instproxy_notify_cb(plist.plist_t command, plist.plist_t status, void *py_callback) with gil: +cdef void instproxy_notify_cb(plist.plist_t command, plist.plist_t status, void *py_callback) noexcept: (<object>py_callback)(plist.plist_t_to_node(command, False), plist.plist_t_to_node(status, False)) cdef class InstallationProxyError(BaseError): diff --git a/cython/lockdown.pxi b/cython/lockdown.pxi index 1bf7072..25edb4c 100644 --- a/cython/lockdown.pxi +++ b/cython/lockdown.pxi @@ -210,14 +210,23 @@ cdef class LockdownClient(PropertyListService): raise cpdef set_value(self, bytes domain, bytes key, object value): - cdef plist.plist_t c_node = plist.native_to_plist_t(value) + cdef: + plist.plist_t c_node = NULL + char* c_domain = NULL + char* c_key = NULL + + c_node = plist.native_to_plist_t(value) + if domain is not None: + c_domain = domain + if key is not None: + c_key = key try: - self.handle_error(lockdownd_set_value(self._c_client, domain, key, c_node)) + self.handle_error(lockdownd_set_value(self._c_client, c_domain, c_key, c_node)) except BaseError, e: raise finally: if c_node != NULL: - plist.plist_free(c_node) + c_node = NULL cpdef remove_value(self, bytes domain, bytes key): self.handle_error(lockdownd_remove_value(self._c_client, domain, key)) @@ -231,11 +240,12 @@ cdef class LockdownClient(PropertyListService): if issubclass(service, BaseService) and \ service.__service_name__ is not None \ and isinstance(service.__service_name__, (str, bytes)): - c_service_name = <bytes>service.__service_name__ + c_service_name_str = service.__service_name__.encode('utf-8') elif isinstance(service, (str, bytes)): - c_service_name = <bytes>service + c_service_name_str = service.encode('utf-8') else: raise TypeError("LockdownClient.start_service() takes a BaseService or string as its first argument") + c_service_name = c_service_name_str try: self.handle_error(lockdownd_start_service(self._c_client, c_service_name, &c_descriptor)) diff --git a/cython/mobile_image_mounter.pxi b/cython/mobile_image_mounter.pxi index a23a59b..d9d40d5 100644 --- a/cython/mobile_image_mounter.pxi +++ b/cython/mobile_image_mounter.pxi @@ -13,7 +13,9 @@ cdef extern from "libimobiledevice/mobile_image_mounter.h": mobile_image_mounter_error_t mobile_image_mounter_new(idevice_t device, lockdownd_service_descriptor_t descriptor, mobile_image_mounter_client_t *client) mobile_image_mounter_error_t mobile_image_mounter_free(mobile_image_mounter_client_t client) mobile_image_mounter_error_t mobile_image_mounter_lookup_image(mobile_image_mounter_client_t client, char *image_type, plist.plist_t *result) - mobile_image_mounter_error_t mobile_image_mounter_mount_image(mobile_image_mounter_client_t client, char *image_path, char *image_signature, uint16_t signature_length, char *image_type, plist.plist_t *result) + mobile_image_mounter_error_t mobile_image_mounter_mount_image_with_options(mobile_image_mounter_client_t client, char *image_path, const unsigned char *signature, unsigned int signature_length, char *image_type, plist.plist_t options, plist.plist_t *result) + mobile_image_mounter_error_t mobile_image_mounter_mount_image(mobile_image_mounter_client_t client, char *image_path, const unsigned char *signature, unsigned int signature_length, char *image_type, plist.plist_t *result) + mobile_image_mounter_error_t mobile_image_mounter_unmount_image(mobile_image_mounter_client_t client, const char *mount_path); mobile_image_mounter_error_t mobile_image_mounter_hangup(mobile_image_mounter_client_t client) cdef class MobileImageMounterError(BaseError): @@ -57,11 +59,39 @@ cdef class MobileImageMounterClient(PropertyListService): if c_node != NULL: plist.plist_free(c_node) - cpdef plist.Node mount_image(self, bytes image_path, bytes image_signature, bytes image_type): + cpdef plist.Node mount_image_with_options(self, bytes image_path, bytes signature, bytes image_type, object options): cdef: + plist.Node n_options + plist.plist_t c_options + plist.plist_t c_result = NULL + bint free_options = False plist.plist_t c_node = NULL mobile_image_mounter_error_t err - err = mobile_image_mounter_mount_image(self._c_client, image_path, image_signature, len(image_signature), + if isinstance(options, plist.Dict): + n_options = options + c_options = n_options._c_node + elif isinstance(options, dict): + c_options = plist.native_to_plist_t(options) + free_options = True + else: + raise InstallationProxyError(INSTPROXY_E_INVALID_ARG) + err = mobile_image_mounter_mount_image_with_options(self._c_client, image_path, signature, len(signature), + image_type, c_options, &c_node) + if free_options: + plist.plist_free(c_options) + try: + self.handle_error(err) + + return plist.plist_t_to_node(c_node) + except Exception, e: + if c_node != NULL: + plist.plist_free(c_node) + + cpdef plist.Node mount_image(self, bytes image_path, bytes signature, bytes image_type): + cdef: + plist.plist_t c_node = NULL + mobile_image_mounter_error_t err + err = mobile_image_mounter_mount_image(self._c_client, image_path, signature, len(signature), image_type, &c_node) try: @@ -72,6 +102,13 @@ cdef class MobileImageMounterClient(PropertyListService): if c_node != NULL: plist.plist_free(c_node) + cpdef unmount_image(self, bytes mount_path): + cdef: + mobile_image_mounter_error_t err + err = mobile_image_mounter_unmount_image(self._c_client, mount_path) + + self.handle_error(err) + cpdef hangup(self): cdef mobile_image_mounter_error_t err err = mobile_image_mounter_hangup(self._c_client) diff --git a/cython/notification_proxy.pxi b/cython/notification_proxy.pxi index 4ffbf07..261200e 100644 --- a/cython/notification_proxy.pxi +++ b/cython/notification_proxy.pxi @@ -70,7 +70,7 @@ NP_ITDBPREP_DID_END = C_NP_ITDBPREP_DID_END NP_LANGUAGE_CHANGED = C_NP_LANGUAGE_CHANGED NP_ADDRESS_BOOK_PREF_CHANGED = C_NP_ADDRESS_BOOK_PREF_CHANGED -cdef void np_notify_cb(const_char_ptr notification, void *py_callback): +cdef void np_notify_cb(const_char_ptr notification, void *py_callback) noexcept: (<object>py_callback)(notification) cdef class NotificationProxyError(BaseError): diff --git a/docs/Makefile.am b/docs/Makefile.am index 9cdf82e..c9b742f 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -16,9 +16,12 @@ man_MANS = \ idevicecrashreport.1 \ idevicename.1 \ idevicedebug.1 \ + idevicedevmodectl.1 \ idevicenotificationproxy.1 \ - idevicesetlocation.1 + idevicesetlocation.1 \ + afcclient.1 -EXTRA_DIST = $(man_MANS) +EXTRA_DIST = $(man_MANS) \ + doxygen DISTCLEANFILES = html/* html diff --git a/docs/afcclient.1 b/docs/afcclient.1 new file mode 100644 index 0000000..a4eeacb --- /dev/null +++ b/docs/afcclient.1 @@ -0,0 +1,74 @@ +.TH "afcclient" 1 +.SH NAME +afcclient \- Interact with AFC/HouseArrest service on a connected device. +.SH SYNOPSIS +.B afcclient +[OPTIONS] [COMMAND ...] + +.SH DESCRIPTION + +Utility to interact with AFC/HouseArrest service. This allows access to parts +of the filesystem on an iOS device. + +\f[B]afcclient\f[] can be used interactively with a command prompt, or run a single command and exit. + +.SH COMMANDS +.TP +.B devinfo +print device information +.TP +.B info PATH +print file attributes of file at PATH +.TP +.B ls PATH +print directory contents of PATH +.TP +.B mv OLD NEW +rename file OLD to NEW +.TP +.B mkdir PATH +create directory at PATH +.TP +.B ln [-s] FILE [LINK] +Create a (symbolic) link to file named LINKNAME. \f[B]NOTE: This feature has been disabled in newer versions of iOS\f[]. +.TP +.B rm [-rf] PATH +remove item at PATH +.TP +.B get [-rf] PATH [LOCALPATH] +transfer file at PATH from device to LOCALPATH, or current directory if omitted. If LOCALPATH is a directory, the file will be stored inside the directory. +.TP +.B put [-rf] LOCALPATH [PATH] +transfer local file at LOCALPATH to device at PATH, or current directory if omitted. If PATH is a directory, the file will be stored inside the directory. +.TP + +.SH OPTIONS +.TP +.B \-u, \-\-udid UDID +target specific device by UDID +.TP +.B \-n, \-\-network +connect to network device (not recommended, since the connection might be terminated at any time) +.TP +.B \--container <appid> +Access the app container directory of the app with given \f[B]appid\f[] +.TP +.B \--documents <appid> +Access the Documents directory of the app with given \f[B]appid\f[] +.TP +.B \-h, \-\-help +Prints usage information +.TP +.B \-d, \-\-debug +Enable communication debugging +.TP +.B \-v, \-\-version +Prints version information + +.SH AUTHOR +Nikias Bassen + +.SH ON THE WEB +https://libimobiledevice.org + +https://github.com/libimobiledevice/libimobiledevice diff --git a/docs/idevicebackup2.1 b/docs/idevicebackup2.1 index abbe38a..79b6dc4 100644 --- a/docs/idevicebackup2.1 +++ b/docs/idevicebackup2.1 @@ -47,7 +47,7 @@ restore last backup to the device. restore system files, too. .TP .B \t\-\-no\-reboot -reboot the system when done. +do NO reboot the system when done. .TP .B \t\-\-copy create a copy of backup folder before restoring. diff --git a/docs/idevicecrashreport.1 b/docs/idevicecrashreport.1 index 6acd6e9..f117c87 100644 --- a/docs/idevicecrashreport.1 +++ b/docs/idevicecrashreport.1 @@ -16,28 +16,31 @@ the device to the target DIRECTORY. .SH OPTIONS .TP .B \-u, \-\-udid UDID -target specific device by UDID. +Target specific device by UDID. .TP .B \-n, \-\-network -connect to network device. +Connect to network device. .TP .B \-e, \-\-extract -extract raw crash report into separate '.crash' files. +Extract raw crash report into separate '.crash' files. .TP .B \-k, \-\-keep -copy but do not remove crash reports from device. +Copy but do not remove crash reports from device. .TP .B \-d, \-\-debug -enable communication debugging. +Enable communication debugging. .TP .B \-f, \-\-filter NAME -filter crash reports by NAME (case sensitive) +Filter crash reports by NAME (case sensitive) +.TP +.B \-\-remove\-all +Remove all crash log files without copying. Can be used with \f[B]-f\f[] to only remove matching files. .TP .B \-h, \-\-help -prints usage information. +Prints usage information. .TP .B \-v, \-\-version -prints version information. +Prints version information. .SH AUTHOR Martin Szulecki diff --git a/docs/idevicedebugserverproxy.1 b/docs/idevicedebugserverproxy.1 index 248c694..69200ee 100644 --- a/docs/idevicedebugserverproxy.1 +++ b/docs/idevicedebugserverproxy.1 @@ -22,6 +22,9 @@ target specific device by UDID. .B \-n, \-\-network connect to network device. .TP +.B \-l, \-\-lldb +Enable lldb support. +.TP .B \-d, \-\-debug enable communication debugging. .TP diff --git a/docs/idevicedevmodectl.1 b/docs/idevicedevmodectl.1 new file mode 100644 index 0000000..5edaa80 --- /dev/null +++ b/docs/idevicedevmodectl.1 @@ -0,0 +1,58 @@ +.TH "idevicedevmodectl" 1 +.SH NAME +idevicedevmodectl \- Enable Developer Mode on iOS 16+ devices or print the current status. +.SH SYNOPSIS +.B idevicedevmodectl +COMMAND +[OPTIONS] + +.SH DESCRIPTION + +Enable Developer Mode on iOS 16+ devices or print the current status. + +.SH NOTE +Passcode-protected devices will NOT allow enabling of Developer Mode from the command line. It has to be enabled on the device itself under Settings -> Privacy & Security -> Developer Mode. +The \f[B]enable\f[] command will try to enable it, and tell you if that's the case. +If the menu is not shown, you may use the \f[B]reveal\f[] command to reveal it. + +.SH COMMANDS +.TP +.B list +Prints the Developer Mode status of all connected devices, or for a specific one if \f[B]\-\-udid\f[] is given. +.TP +.B enable +Enable Developer Mode (device will reboot), and confirm it after device booted up again. +.TP +.B arm +Arm the Developer Mode (device will reboot) +.TP +.B confirm +Confirm enabling of Developer Mode +.TP +.B reveal +Reveal the Developer Mode menu on the device under Settings -> Privacy & Security + +.SH OPTIONS +.TP +.B \-u, \-\-udid UDID +target specific device by UDID +.TP +.B \-n, \-\-network +connect to network device +.TP +.B \-d, \-\-debug +enable communication debugging +.TP +.B \-h, \-\-help +print usage information +.TP +.B \-v, \-\-version +print version information + +.SH AUTHORS +Nikias Bassen + +.SH ON THE WEB +https://libimobiledevice.org + +https://github.com/libimobiledevice/libimobiledevice diff --git a/docs/ideviceimagemounter.1 b/docs/ideviceimagemounter.1 index 832850a..1fe7e45 100644 --- a/docs/ideviceimagemounter.1 +++ b/docs/ideviceimagemounter.1 @@ -1,13 +1,32 @@ .TH "ideviceimagemounter" 1 .SH NAME -ideviceimagemounter \- Mount disk images on the device. +ideviceimagemounter \- Mount, list, or unmount a disk image on the device. .SH SYNOPSIS .B ideviceimagemounter -[OPTIONS] IMAGE_FILE IMAGE_SIGNATURE_FILE +[OPTIONS] COMMAND [COMMAND OPTIONS] .SH DESCRIPTION -Mounts the specified disk image on the device. +Mount, list, or unmount a disk image on the device. + +.SH COMMANDS +.TP +.B mount PATH +Mount the developer disk image at PATH. +For iOS 17+, PATH is a directory containing a .dmg image, a BuildManifest.plist, +and a Firmware sub-directory. + +For older versions PATH is a .dmg filename with a .dmg.signature file in the same directory, or with +another parameter pointing to a file elsewhere. +.TP +.B list +List mounted disk images. +.TP +.B unmount PATH +Unmount the image mounted at PATH. +.TP +.B devmodestatus +Query the developer mode status (iOS 16+) .SH OPTIONS .TP @@ -20,9 +39,6 @@ connect to network device. .B \-d, \-\-debug enable communication debugging. .TP -.B \-l, \-\-list -list mount information -.TP .B \-t, \-\-imagetype NAME the image type to use, default is 'Developer' .TP @@ -34,12 +50,6 @@ prints usage information .TP .B \-v, \-\-version prints version information. -.TP -.B IMAGE_FILE -the image filename to mount -.TP -.B IMAGE_SIGNATURE_FILE -corresponding signature file for image filename .SH AUTHOR Nikias Bassen diff --git a/docs/idevicenotificationproxy.1 b/docs/idevicenotificationproxy.1 index 56dd0b0..627ee5d 100644 --- a/docs/idevicenotificationproxy.1 +++ b/docs/idevicenotificationproxy.1 @@ -12,19 +12,22 @@ Post or observe notifications on an iOS device from the command line. .SH OPTIONS .TP .B \-u, \-\-udid UDID -target specific device by UDID. +Target specific device by UDID. +.TP +.B \-i, \-\-insecure +Connect to insecure notification proxy (for non-paired devices). .TP .B \-n, \-\-network -connect to network device. +Connect to network device. .TP .B \-d, \-\-debug -enable communication debugging. +Enable communication debugging. .TP .B \-h, \-\-help -prints usage information. +Prints usage information. .TP .B \-v, \-\-version -prints version information. +Prints version information. .SH COMMANDS .TP @@ -38,6 +41,8 @@ observe notification IDs in the foreground until CTRL+C or signal is received. Martin Szulecki +Nikias Bassen + .SH ON THE WEB https://libimobiledevice.org diff --git a/docs/idevicesyslog.1 b/docs/idevicesyslog.1 index b7d4bab..5a677b6 100644 --- a/docs/idevicesyslog.1 +++ b/docs/idevicesyslog.1 @@ -27,17 +27,56 @@ enable communication debugging prints usage information .TP .B \-v, \-\-version -prints version information. +Prints version information. .TP .B \-\-no\-colors disable colored output +.TP +.B \-o, \-\-output FILE +Write to FILE instead of stdout. This will disable writing colored output, but can be re-enabled with \f[B]\-\-colors\f[]. +If FILE already exists, it will be overwritten without warning. +.TP +.B \-\-colors +Force writing colored output, e.g. when using \f[B]\-\-output\f[]. +.TP +.B \-\-syslog\-relay +Use old syslog_relay service instead of os_trace_relay (iOS 9+). + +.SH COMMANDS +.TP +.B pidlist +Print a list with PID and name of all processes currently running on the device. +.TP +.B archive PATH +Request a logarchive from the device. It will be written in tar format to PATH. To pipe to another process use \- as PATH. +Below are some options to restrict the log message data. + +In order to view the logarchive in a compatible log viewer, you can pipe the output data to \f[B]tar\f[] and have it extract into a new directory: + +\f[B]mkdir test.logarchive && tools/idevicesyslog archive - |tar -C test.logarchive -xv\f[] + +This will also print the filenames while they are extracted. +.TP +Further options for \f[B]archive\f[]: +.TP +.B \-\-start\-time VALUE +Start time of the log data as UNIX timestamp. Earlier messages will be dropped. +.TP +.B \-\-age\-limit VALUE +Maximum age of the log data, supposedly number of days. +.TP +.B \-\-size\-limit VALUE +Limit the size of the archive. The unit is currently unknown, so feel free to experiment. +.TP +Keep in mind that the device usually only has a backlog of a few minutes so the options might not have the desired effect. This is not a bug. .SH FILTER OPTIONS .TP .B \-m, \-\-match STRING only print messages that contain STRING - -This option will set a filter to only printed log messages that contain the given string. +.TP +.B \-M, \-\-unmatch STRING +print messages that do not contain STRING .TP .B \-t, \-\-trigger STRING start logging when matching STRING diff --git a/doxygen.cfg.in b/doxygen.cfg.in index b099b42..7bc1160 100644 --- a/doxygen.cfg.in +++ b/doxygen.cfg.in @@ -1,4 +1,4 @@ -# Doxyfile 1.8.16 +# Doxyfile 1.11.0 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -12,6 +12,16 @@ # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). +# +# Note: +# +# Use doxygen to compare the used configuration file with the template +# configuration file: +# doxygen -x [configFile] +# Use doxygen to compare the used configuration file with the template +# configuration file without replacing the environment variables or CMake type +# replacement variables: +# doxygen -x_noenv [configFile] #--------------------------------------------------------------------------- # Project related configuration options @@ -53,6 +63,12 @@ PROJECT_BRIEF = "API Documentation" PROJECT_LOGO = docs/doxygen/logo-vector-clean.svg +# With the PROJECT_ICON tag one can specify an icon that is included in the tabs +# when the HTML document is shown. Doxygen will copy the logo to the output +# directory. + +PROJECT_ICON = + # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If @@ -60,16 +76,28 @@ PROJECT_LOGO = docs/doxygen/logo-vector-clean.svg OUTPUT_DIRECTORY = docs -# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- -# directories (in 2 levels) under the output directory of each output format and -# will distribute the generated files over these directories. Enabling this +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 +# sub-directories (in 2 levels) under the output directory of each output format +# and will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes -# performance problems for the file system. +# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to +# control the number of sub-directories. # The default value is: NO. CREATE_SUBDIRS = NO +# Controls the number of sub-directories that will be created when +# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every +# level increment doubles the number of directories, resulting in 4096 +# directories at level 8 which is the default and also the maximum value. The +# sub-directories are organized in 2 levels, the first level always has a fixed +# number of 16 directories. +# Minimum value: 0, maximum value: 8, default value: 8. +# This tag requires that the tag CREATE_SUBDIRS is set to YES. + +CREATE_SUBDIRS_LEVEL = 8 + # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode @@ -81,14 +109,14 @@ ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. -# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, -# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), -# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, -# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, -# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, -# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, -# Ukrainian and Vietnamese. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, +# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English +# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, +# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with +# English messages), Korean, Korean-en (Korean with English messages), Latvian, +# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, +# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, +# Swedish, Turkish, Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English @@ -209,6 +237,14 @@ QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO +# By default Python docstrings are displayed as preformatted text and doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. @@ -232,16 +268,16 @@ TAB_SIZE = 8 # the documentation. An alias has the form: # name=value # For example adding -# "sideeffect=@par Side Effects:\n" +# "sideeffect=@par Side Effects:^^" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading -# "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines (in the resulting output). You can put ^^ in the value part of an -# alias to insert a newline as if a physical newline was in the original file. -# When you need a literal { or } or , in the value part of an alias you have to -# escape them by means of a backslash (\), this can lead to conflicts with the -# commands \{ and \} for these it is advised to use the version @{ and @} or use -# a double escape (\\{ and \\}) +# "Side Effects:". Note that you cannot put \n's in the value part of an alias +# to insert newlines (in the resulting output). You can put ^^ in the value part +# of an alias to insert a newline as if a physical newline was in the original +# file. When you need a literal { or } or , in the value part of an alias you +# have to escape them by means of a backslash (\), this can lead to conflicts +# with the commands \{ and \} for these it is advised to use the version @{ and +# @} or use a double escape (\\{ and \\}) ALIASES = @@ -285,19 +321,22 @@ OPTIMIZE_OUTPUT_SLICE = YES # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and -# language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, -# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, +# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: # FortranFree, unknown formatted Fortran: Fortran. In the later case the parser # tries to guess whether the code is fixed or free formatted code, this is the -# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat -# .inc files as Fortran files (default is PHP), and .f files as C (default is -# Fortran), use: inc=Fortran f=C. +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise -# the files are not read by doxygen. +# the files are not read by doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. EXTENSION_MAPPING = @@ -315,11 +354,22 @@ MARKDOWN_SUPPORT = YES # to that level are automatically included in the table of contents, even if # they do not have an id attribute. # Note: This feature currently applies only to Markdown headings. -# Minimum value: 0, maximum value: 99, default value: 5. +# Minimum value: 0, maximum value: 99, default value: 6. # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. TOC_INCLUDE_HEADINGS = 5 +# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to +# generate identifiers for the Markdown headings. Note: Every identifier is +# unique. +# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a +# sequence number starting at 0 and GITHUB use the lower case version of title +# with any whitespace replaced by '-' and punctuation characters removed. +# The default value is: DOXYGEN. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +MARKDOWN_ID_STYLE = DOXYGEN + # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or @@ -332,8 +382,8 @@ AUTOLINK_SUPPORT = YES # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); -# versus func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. +# versus func(std::string) {}). This also makes the inheritance and +# collaboration diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = NO @@ -345,9 +395,9 @@ BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen -# will parse them like normal C++ but will assume all classes use public instead -# of private inheritance when no explicit protection keyword is present. +# https://www.riverbankcomputing.com/software) sources only. Doxygen will parse +# them like normal C++ but will assume all classes use public instead of private +# inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO @@ -431,6 +481,27 @@ TYPEDEF_HIDES_STRUCT = YES LOOKUP_CACHE_SIZE = 0 +# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use +# during processing. When set to 0 doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which effectively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 1 + +# If the TIMESTAMP tag is set different from NO then each generated page will +# contain the date or date and time when the page was generated. Setting this to +# NO can help when comparing the output of multiple runs. +# Possible values are: YES, NO, DATETIME and DATE. +# The default value is: NO. + +TIMESTAMP = YES + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- @@ -494,6 +565,13 @@ EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation @@ -505,14 +583,15 @@ HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO, these classes will be included in the various overviews. This option -# has no effect if EXTRACT_ALL is enabled. +# will also hide undocumented C++ concepts if enabled. This option has no effect +# if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# (class|struct|union) declarations. If set to NO, these declarations will be -# included in the documentation. +# declarations. If set to NO, these declarations will be included in the +# documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO @@ -531,12 +610,20 @@ HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO -# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file -# names in lower-case letters. If set to YES, upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# (including Cygwin) ands Mac users are advised to set this option to NO. -# The default value is: system dependent. +# With the correct setting of option CASE_SENSE_NAMES doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and MacOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. +# Possible values are: SYSTEM, NO and YES. +# The default value is: SYSTEM. CASE_SENSE_NAMES = NO @@ -554,6 +641,12 @@ HIDE_SCOPE_NAMES = NO HIDE_COMPOUND_REFERENCE= NO +# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class +# will show which file needs to be included to use the class. +# The default value is: YES. + +SHOW_HEADERFILE = YES + # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. @@ -711,7 +804,8 @@ FILE_VERSION_FILTER = # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml -# will be used as the name of the layout file. +# will be used as the name of the layout file. See also section "Changing the +# layout of pages" for information. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE @@ -757,24 +851,50 @@ WARNINGS = YES WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some parameters -# in a documented function, or documenting parameters that don't exist or using -# markup commands wrongly. +# potential errors in the documentation, such as documenting some parameters in +# a documented function twice, or documenting parameters that don't exist or +# using markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES +# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete +# function parameter documentation. If set to NO, doxygen will accept that some +# parameters have no documentation without warning. +# The default value is: YES. + +WARN_IF_INCOMPLETE_DOC = YES + # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return -# value. If set to NO, doxygen will only warn about wrong or incomplete -# parameter documentation, but not about the absence of documentation. If -# EXTRACT_ALL is set to YES then this flag will automatically be disabled. +# value. If set to NO, doxygen will only warn about wrong parameter +# documentation, but not about the absence of documentation. If EXTRACT_ALL is +# set to YES then this flag will automatically be disabled. See also +# WARN_IF_INCOMPLETE_DOC # The default value is: NO. WARN_NO_PARAMDOC = NO +# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about +# undocumented enumeration values. If set to NO, doxygen will accept +# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: NO. + +WARN_IF_UNDOC_ENUM_VAL = NO + # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when -# a warning is encountered. +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the doxygen process doxygen will return with a non-zero status. +# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then doxygen behaves +# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined doxygen will not +# write the warning messages in between other messages but write them at the end +# of a run, in case a WARN_LOGFILE is defined the warning messages will be +# besides being in the defined file also be shown at the end of a run, unless +# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case +# the behavior will remain as with the setting FAIL_ON_WARNINGS. +# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT. # The default value is: NO. WARN_AS_ERROR = NO @@ -785,13 +905,27 @@ WARN_AS_ERROR = NO # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) +# See also: WARN_LINE_FORMAT # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" +# In the $text part of the WARN_FORMAT command it is possible that a reference +# to a more specific place is given. To make it easier to jump to this place +# (outside of doxygen) the user can define a custom "cut" / "paste" string. +# Example: +# WARN_LINE_FORMAT = "'vi $file +$line'" +# See also: WARN_FORMAT +# The default value is: at line $line of file $file. + +WARN_LINE_FORMAT = "at line $line of file $file" + # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard -# error (stderr). +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). WARN_LOGFILE = @@ -805,19 +939,29 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = \ - include/@PACKAGE@ \ - README.md +INPUT = include/@PACKAGE@ \ + README.md # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: https://www.gnu.org/software/libiconv/) for the list of -# possible encodings. +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# See also: INPUT_FILE_ENCODING # The default value is: UTF-8. INPUT_ENCODING = UTF-8 +# This tag can be used to specify the character encoding of the source files +# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify +# character encoding on a per file pattern basis. Doxygen will compare the file +# name with each pattern and apply the encoding instead of the default +# INPUT_ENCODING) if there is a match. The character encodings are a list of the +# form: pattern=encoding (like *.php=ISO-8859-1). +# See also: INPUT_ENCODING for further information on supported encodings. + +INPUT_FILE_ENCODING = + # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. @@ -826,11 +970,15 @@ INPUT_ENCODING = UTF-8 # need to set EXTENSION_MAPPING for the extension otherwise the files are not # read by doxygen. # -# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, -# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, -# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, -# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, -# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm, +# *.cpp, *.cppm, *.ccm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, +# *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.ixx, *.l, *.cs, *.d, +# *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to +# be provided as doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = @@ -869,12 +1017,9 @@ EXCLUDE_PATTERNS = # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories use the pattern */test/* +# ANamespace::AClass, ANamespace::*Test -EXCLUDE_SYMBOLS = +EXCLUDE_SYMBOLS = LIBIMOBILEDEVICE_API # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include @@ -917,6 +1062,11 @@ IMAGE_PATH = # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. # +# Note that doxygen will use the data processed and written to standard output +# for further processing, therefore nothing else, like debug statements or used +# commands (so in case of a Windows batch file always use @echo OFF), should be +# written to standard output. +# # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. @@ -958,6 +1108,15 @@ FILTER_SOURCE_PATTERNS = USE_MDFILE_AS_MAINPAGE = README.md +# The Fortran standard specifies that for fixed formatted Fortran code all +# characters from position 72 are to be considered as comment. A common +# extension is to allow longer lines before the automatic comment starts. The +# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can +# be processed before the automatic comment starts. +# Minimum value: 7, maximum value: 10000, default value: 72. + +FORTRAN_COMMENT_AFTER = 72 + #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- @@ -972,7 +1131,8 @@ USE_MDFILE_AS_MAINPAGE = README.md SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, -# classes and enums directly into the documentation. +# multi-line macros, enums or list initialized variables directly into the +# documentation. # The default value is: NO. INLINE_SOURCES = NO @@ -1055,10 +1215,11 @@ VERBATIM_HEADERS = NO ALPHABETICAL_INDEX = NO -# In case all classes in a project start with a common prefix, all classes will -# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag -# can be used to specify a prefix (or a list of prefixes) that should be ignored -# while generating the index headers. +# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes) +# that should be ignored while generating the index headers. The IGNORE_PREFIX +# tag works for classes, function and member names. The entity will be placed in +# the alphabetical list under the first letter of the entity name that remains +# after removing the prefix. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = @@ -1137,11 +1298,15 @@ HTML_STYLESHEET = # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance (e.g. the last # style sheet in the list overrules the setting of the previous ones in the -# list). For an example see the documentation. +# list). +# Note: Since the styling of scrollbars can currently not be overruled in +# Webkit/Chromium, the styling will be left out of the default doxygen.css if +# one or more extra stylesheets have been specified. So if scrollbar +# customization is desired it has to be added explicitly. For an example see the +# documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_STYLESHEET = \ - docs/doxygen/custom.css +HTML_EXTRA_STYLESHEET = docs/doxygen/custom.css # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note @@ -1151,15 +1316,27 @@ HTML_EXTRA_STYLESHEET = \ # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_FILES = \ - docs/doxygen/favicon.ico \ - docs/doxygen/folder.png \ - docs/doxygen/folder-open.png \ - docs/doxygen/text-x-generic.png +HTML_EXTRA_FILES = docs/doxygen/favicon.ico \ + docs/doxygen/folder.png \ + docs/doxygen/folder-open.png \ + docs/doxygen/text-x-generic.png + +# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output +# should be rendered with a dark or light theme. +# Possible values are: LIGHT always generates light mode output, DARK always +# generates dark mode output, AUTO_LIGHT automatically sets the mode according +# to the user preference, uses light mode if no preference is set (the default), +# AUTO_DARK automatically sets the mode according to the user preference, uses +# dark mode if no preference is set and TOGGLE allows a user to switch between +# light and dark mode via a button. +# The default value is: AUTO_LIGHT. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE = AUTO_LIGHT # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to -# this color. Hue is specified as an angle on a colorwheel, see +# this color. Hue is specified as an angle on a color-wheel, see # https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. @@ -1169,7 +1346,7 @@ HTML_EXTRA_FILES = \ HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors -# in the HTML output. For a value of 0 the output will use grayscales only. A +# in the HTML output. For a value of 0 the output will use gray-scales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1187,20 +1364,11 @@ HTML_COLORSTYLE_SAT = 100 HTML_COLORSTYLE_GAMMA = 80 -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting this -# to YES can help to show when doxygen was last run and thus if the -# documentation is up to date. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_TIMESTAMP = YES - # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML # documentation will contain a main index with vertical navigation menus that -# are dynamically created via Javascript. If disabled, the navigation index will +# are dynamically created via JavaScript. If disabled, the navigation index will # consists of multiple levels of tabs that are statically embedded in every HTML -# page. Disable this option to support browsers that do not have Javascript, +# page. Disable this option to support browsers that do not have JavaScript, # like the Qt help browser. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1215,6 +1383,33 @@ HTML_DYNAMIC_MENUS = NO HTML_DYNAMIC_SECTIONS = NO +# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be +# dynamically folded and expanded in the generated HTML source code. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_CODE_FOLDING = YES + +# If the HTML_COPY_CLIPBOARD tag is set to YES then doxygen will show an icon in +# the top right corner of code and text fragments that allows the user to copy +# its content to the clipboard. Note this only works if supported by the browser +# and the web page is served via a secure context (see: +# https://www.w3.org/TR/secure-contexts/), i.e. using the https: or file: +# protocol. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COPY_CLIPBOARD = YES + +# Doxygen stores a couple of settings persistently in the browser (via e.g. +# cookies). By default these settings apply to all HTML pages generated by +# doxygen across all projects. The HTML_PROJECT_COOKIE tag can be used to store +# the settings under a project specific key, such that the user preferences will +# be stored separately. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_PROJECT_COOKIE = + # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to @@ -1230,10 +1425,11 @@ HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: https://developer.apple.com/xcode/), introduced with OSX -# 10.5 (Leopard). To create a documentation set, doxygen will generate a -# Makefile in the HTML output directory. Running make will produce the docset in -# that directory and running make install will install the docset in +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy # genXcode/_index.html for more information. @@ -1250,6 +1446,13 @@ GENERATE_DOCSET = NO DOCSET_FEEDNAME = "Doxygen generated docs" +# This tag determines the URL of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDURL = + # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. @@ -1275,8 +1478,12 @@ DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on -# Windows. +# on Windows. In the beginning of 2021 Microsoft took the original page, with +# a.o. the download links, offline the HTML help workshop was already many years +# in maintenance mode). You can download the HTML help workshop from the web +# archives at Installation executable (see: +# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo +# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML @@ -1306,7 +1513,7 @@ CHM_FILE = HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated -# (YES) or that it should be included in the master .chm file (NO). +# (YES) or that it should be included in the main .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. @@ -1333,6 +1540,16 @@ BINARY_TOC = NO TOC_EXPAND = NO +# The SITEMAP_URL tag is used to specify the full URL of the place where the +# generated documentation will be placed on the server by the user during the +# deployment of the documentation. The generated sitemap is called sitemap.xml +# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL +# is specified no sitemap is generated. For information about the sitemap +# protocol see https://www.sitemaps.org +# This tag requires that the tag GENERATE_HTML is set to YES. + +SITEMAP_URL = + # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help @@ -1351,7 +1568,8 @@ QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace -# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1359,8 +1577,8 @@ QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- -# folders). +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1368,16 +1586,16 @@ QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom -# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = @@ -1389,9 +1607,9 @@ QHP_CUST_FILTER_ATTRS = QHP_SECT_FILTER_ATTRS = -# The QHG_LOCATION tag can be used to specify the location of Qt's -# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the -# generated .qhp file. +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to +# run qhelpgenerator on the generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = @@ -1434,16 +1652,28 @@ DISABLE_INDEX = NO # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can -# further fine-tune the look of the index. As an example, the default style -# sheet generated by doxygen has an example that shows how to put an image at -# the root of the tree instead of the PROJECT_NAME. Since the tree basically has -# the same information as the tab index, you could consider setting -# DISABLE_INDEX to YES when enabling this option. +# further fine tune the look of the index (see "Fine-tuning the output"). As an +# example, the default style sheet generated by doxygen has an example that +# shows how to put an image at the root of the tree instead of the PROJECT_NAME. +# Since the tree basically has the same information as the tab index, you could +# consider setting DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NONE +# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the +# FULL_SIDEBAR option determines if the side bar is limited to only the treeview +# area (value NO) or if it should extend to the full height of the window (value +# YES). Setting this to YES gives a layout similar to +# https://docs.readthedocs.io with more room for contents, but less room for the +# project logo, title, and description. If either GENERATE_TREEVIEW or +# DISABLE_INDEX is set to NO, this option has no effect. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FULL_SIDEBAR = NO + # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # @@ -1468,6 +1698,24 @@ TREEVIEW_WIDTH = 250 EXT_LINKS_IN_WINDOW = NO +# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email +# addresses. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +OBFUSCATE_EMAILS = YES + +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML @@ -1477,19 +1725,14 @@ EXT_LINKS_IN_WINDOW = NO FORMULA_FONTSIZE = 10 -# Use the FORMULA_TRANSPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are not -# supported properly for IE 6.0, but are supported on all modern browsers. -# -# Note that when changing this option you need to delete any form_*.png files in -# the HTML output directory before the changes have effect. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. -FORMULA_TRANSPARENT = YES +FORMULA_MACROFILE = # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# https://www.mathjax.org) which uses client side Javascript for the rendering +# https://www.mathjax.org) which uses client side JavaScript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path @@ -1499,11 +1742,29 @@ FORMULA_TRANSPARENT = YES USE_MATHJAX = NO +# With MATHJAX_VERSION it is possible to specify the MathJax version to be used. +# Note that the different versions of MathJax have different requirements with +# regards to the different settings, so it is possible that also other MathJax +# settings have to be changed when switching between the different MathJax +# versions. +# Possible values are: MathJax_2 and MathJax_3. +# The default value is: MathJax_2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_VERSION = MathJax_2 + # When MathJax is enabled you can set the default output format to be used for -# the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/latest/output.html) for more details. +# the MathJax output. For more details about the output format see MathJax +# version 2 (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 +# (see: +# http://docs.mathjax.org/en/latest/web/components/output.html). # Possible values are: HTML-CSS (which is slower, but has the best -# compatibility), NativeMML (i.e. MathML) and SVG. +# compatibility. This is the name for Mathjax version 2, for MathJax version 3 +# this will be translated into chtml), NativeMML (i.e. MathML. Only supported +# for MathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# is the name for Mathjax version 3, for MathJax version 2 this will be +# translated into HTML-CSS) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1516,22 +1777,29 @@ MATHJAX_FORMAT = HTML-CSS # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of -# MathJax from https://www.mathjax.org before deployment. -# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/. +# MathJax from https://www.mathjax.org before deployment. The default value is: +# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 +# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example +# for MathJax version 2 (see +# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions): # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# For example for MathJax version 3 (see +# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): +# MATHJAX_EXTENSIONS = ams # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site -# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1559,7 +1827,7 @@ MATHJAX_CODEFILE = SEARCHENGINE = NO # When the SERVER_BASED_SEARCH tag is enabled the search engine will be -# implemented using a web server instead of a web client using Javascript. There +# implemented using a web server instead of a web client using JavaScript. There # are two flavors of web server based searching depending on the EXTERNAL_SEARCH # setting. When disabled, doxygen will generate a PHP script for searching and # an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing @@ -1578,7 +1846,8 @@ SERVER_BASED_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: https://xapian.org/). +# Xapian (see: +# https://xapian.org/). # # See the section "External Indexing and Searching" for details. # The default value is: NO. @@ -1591,8 +1860,9 @@ EXTERNAL_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: https://xapian.org/). See the section "External Indexing and -# Searching" for details. +# Xapian (see: +# https://xapian.org/). See the section "External Indexing and Searching" for +# details. # This tag requires that the tag SEARCHENGINE is set to YES. SEARCHENGINE_URL = @@ -1701,29 +1971,31 @@ PAPER_TYPE = a4 EXTRA_PACKAGES = -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the -# generated LaTeX document. The header should contain everything until the first -# chapter. If it is left blank doxygen will generate a standard header. See -# section "Doxygen usage" for information on how to let doxygen write the -# default header to a separate file. +# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for +# the generated LaTeX document. The header should contain everything until the +# first chapter. If it is left blank doxygen will generate a standard header. It +# is highly recommended to start with a default header using +# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty +# and then modify the file new_header.tex. See also section "Doxygen usage" for +# information on how to generate the default header that doxygen normally uses. # -# Note: Only use a user-defined header if you know what you are doing! The -# following commands have a special meaning inside the header: $title, -# $datetime, $date, $doxygenversion, $projectname, $projectnumber, -# $projectbrief, $projectlogo. Doxygen will replace $title with the empty -# string, for the replacement values of the other commands the user is referred -# to HTML_HEADER. +# Note: Only use a user-defined header if you know what you are doing! +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. The following +# commands have a special meaning inside the header (and footer): For a +# description of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_HEADER = -# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the -# generated LaTeX document. The footer should contain everything after the last -# chapter. If it is left blank doxygen will generate a standard footer. See +# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for +# the generated LaTeX document. The footer should contain everything after the +# last chapter. If it is left blank doxygen will generate a standard footer. See # LATEX_HEADER for more information on how to generate a default footer and what -# special commands can be used inside the footer. -# -# Note: Only use a user-defined footer if you know what you are doing! +# special commands can be used inside the footer. See also section "Doxygen +# usage" for information on how to generate the default footer that doxygen +# normally uses. Note: Only use a user-defined footer if you know what you are +# doing! # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_FOOTER = @@ -1756,18 +2028,26 @@ LATEX_EXTRA_FILES = PDF_HYPERLINKS = NO -# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate -# the PDF file directly from the LaTeX files. Set this option to YES, to get a -# higher quality PDF documentation. +# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as +# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX +# files. Set this option to YES, to get a higher quality PDF documentation. +# +# See also section LATEX_CMD_NAME for selecting the engine. # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. USE_PDFLATEX = NO -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode -# command to the generated LaTeX files. This will instruct LaTeX to keep running -# if errors occur, instead of asking the user for help. This option is also used -# when generating formulas in HTML. +# The LATEX_BATCHMODE tag signals the behavior of LaTeX in case of an error. +# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch +# mode nothing is printed on the terminal, errors are scrolled as if <return> is +# hit at every error; missing files that TeX tries to input or request from +# keyboard input (\read on a not open input stream) cause the job to abort, +# NON_STOP In nonstop mode the diagnostic message will appear on the terminal, +# but there is no possibility of user interaction just like in batch mode, +# SCROLL In scroll mode, TeX will stop only for missing files to input or if +# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at +# each error, asking for user intervention. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1788,14 +2068,6 @@ LATEX_HIDE_INDICES = NO LATEX_BIB_STYLE = plain -# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated -# page will contain the date and time when the page was generated. Setting this -# to NO can help when comparing the output of multiple runs. -# The default value is: NO. -# This tag requires that the tag GENERATE_LATEX is set to YES. - -LATEX_TIMESTAMP = NO - # The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) # path from which the emoji images will be read. If a relative path is entered, # it will be relative to the LATEX_OUTPUT directory. If left blank the @@ -1860,6 +2132,14 @@ RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = +# The RTF_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the RTF_OUTPUT output directory. +# Note that the files will be copied as-is; there are no commands or markers +# available. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_EXTRA_FILES = + #--------------------------------------------------------------------------- # Configuration options related to the man page output #--------------------------------------------------------------------------- @@ -1961,7 +2241,7 @@ DOCBOOK_OUTPUT = docbook #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an -# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures # the structure of the code including all documentation. Note that this feature # is still experimental and incomplete at the moment. # The default value is: NO. @@ -1969,6 +2249,32 @@ DOCBOOK_OUTPUT = docbook GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- +# Configuration options related to Sqlite3 output +#--------------------------------------------------------------------------- + +# If the GENERATE_SQLITE3 tag is set to YES doxygen will generate a Sqlite3 +# database with symbols found by doxygen stored in tables. +# The default value is: NO. + +GENERATE_SQLITE3 = NO + +# The SQLITE3_OUTPUT tag is used to specify where the Sqlite3 database will be +# put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put +# in front of it. +# The default directory is: sqlite3. +# This tag requires that the tag GENERATE_SQLITE3 is set to YES. + +SQLITE3_OUTPUT = sqlite3 + +# The SQLITE3_RECREATE_DB tag is set to YES, the existing doxygen_sqlite3.db +# database file will be recreated with each doxygen run. If set to NO, doxygen +# will warn if a database file is already found and not modify it. +# The default value is: YES. +# This tag requires that the tag GENERATE_SQLITE3 is set to YES. + +SQLITE3_RECREATE_DB = YES + +#--------------------------------------------------------------------------- # Configuration options related to the Perl module output #--------------------------------------------------------------------------- @@ -2023,7 +2329,7 @@ ENABLE_PREPROCESSING = YES # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -MACRO_EXPANSION = NO +MACRO_EXPANSION = YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then # the macro expansion is limited to the macros specified with the PREDEFINED and @@ -2031,7 +2337,7 @@ MACRO_EXPANSION = NO # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -EXPAND_ONLY_PREDEF = NO +EXPAND_ONLY_PREDEF = YES # If the SEARCH_INCLUDES tag is set to YES, the include files in the # INCLUDE_PATH will be searched if a #include is found. @@ -2042,7 +2348,8 @@ SEARCH_INCLUDES = NO # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by the -# preprocessor. +# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of +# RECURSIVE has no effect here. # This tag requires that the tag SEARCH_INCLUDES is set to YES. INCLUDE_PATH = @@ -2072,7 +2379,7 @@ PREDEFINED = # definition found in the source code. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -EXPAND_AS_DEFINED = +EXPAND_AS_DEFINED = LIBIMOBILEDEVICE_API # If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will # remove all references to function-like macros that are alone on a line, have @@ -2109,15 +2416,15 @@ TAGFILES = GENERATE_TAGFILE = -# If the ALLEXTERNALS tag is set to YES, all external class will be listed in -# the class index. If set to NO, only the inherited external classes will be -# listed. +# If the ALLEXTERNALS tag is set to YES, all external classes and namespaces +# will be listed in the class and namespace index. If set to NO, only the +# inherited external classes will be listed. # The default value is: NO. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will be +# in the topic index. If set to NO, only the current project's groups will be # listed. # The default value is: YES. @@ -2131,25 +2438,9 @@ EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES #--------------------------------------------------------------------------- -# Configuration options related to the dot tool +# Configuration options related to diagram generator tools #--------------------------------------------------------------------------- -# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram -# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to -# NO turns the diagrams off. Note that this option also works with HAVE_DOT -# disabled, but it is recommended to install and use dot, since it yields more -# powerful graphs. -# The default value is: YES. - -CLASS_DIAGRAMS = YES - -# You can include diagrams made with dia in doxygen documentation. Doxygen will -# then run dia to produce the diagram and insert it in the documentation. The -# DIA_PATH tag allows you to specify the directory where the dia binary resides. -# If left empty dia is assumed to be found in the default search path. - -DIA_PATH = - # If set to YES the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. # The default value is: YES. @@ -2158,7 +2449,7 @@ HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz (see: -# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent # Bell Labs. The other options in this section have no effect if this option is # set to NO # The default value is: NO. @@ -2175,49 +2466,77 @@ HAVE_DOT = NO DOT_NUM_THREADS = 0 -# When you want a differently looking font in the dot files that doxygen -# generates you can specify the font name using DOT_FONTNAME. You need to make -# sure dot is able to find the font, which can be done by putting it in a -# standard location or by setting the DOTFONTPATH environment variable or by -# setting DOT_FONTPATH to the directory containing the font. -# The default value is: Helvetica. +# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of +# subgraphs. When you want a differently looking font in the dot files that +# doxygen generates you can specify fontname, fontcolor and fontsize attributes. +# For details please see <a href=https://graphviz.org/doc/info/attrs.html>Node, +# Edge and Graph Attributes specification</a> You need to make sure dot is able +# to find the font, which can be done by putting it in a standard location or by +# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. Default graphviz fontsize is 14. +# The default value is: fontname=Helvetica,fontsize=10. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTNAME = +DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10" -# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of -# dot graphs. -# Minimum value: 4, maximum value: 24, default value: 10. +# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can +# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. <a +# href=https://graphviz.org/doc/info/arrows.html>Complete documentation about +# arrows shapes.</a> +# The default value is: labelfontname=Helvetica,labelfontsize=10. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTSIZE = 10 +DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10" -# By default doxygen will tell dot to use the default font as specified with -# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set -# the path where dot can find it using this tag. +# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes +# around nodes set 'shape=plain' or 'shape=plaintext' <a +# href=https://www.graphviz.org/doc/info/shapes.html>Shapes specification</a> +# The default value is: shape=box,height=0.2,width=0.4. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4" + +# You can set the path where dot can find font specified with fontname in +# DOT_COMMON_ATTR and others dot attributes. # This tag requires that the tag HAVE_DOT is set to YES. DOT_FONTPATH = -# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for -# each documented class showing the direct and indirect inheritance relations. -# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will +# generate a graph for each documented class showing the direct and indirect +# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and +# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case +# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the +# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used. +# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance +# relations will be shown as texts / links. Explicit enabling an inheritance +# graph or choosing a different representation for an inheritance graph of a +# specific class, can be accomplished by means of the command \inheritancegraph. +# Disabling an inheritance graph can be accomplished by means of the command +# \hideinheritancegraph. +# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN. # The default value is: YES. -# This tag requires that the tag HAVE_DOT is set to YES. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a # graph for each documented class showing the direct and indirect implementation # dependencies (inheritance, containment, and class references variables) of the -# class with other documented classes. +# class with other documented classes. Explicit enabling a collaboration graph, +# when COLLABORATION_GRAPH is set to NO, can be accomplished by means of the +# command \collaborationgraph. Disabling a collaboration graph can be +# accomplished by means of the command \hidecollaborationgraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for -# groups, showing the direct groups dependencies. +# groups, showing the direct groups dependencies. Explicit enabling a group +# dependency graph, when GROUP_GRAPHS is set to NO, can be accomplished by means +# of the command \groupgraph. Disabling a directory graph can be accomplished by +# means of the command \hidegroupgraph. See also the chapter Grouping in the +# manual. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2240,10 +2559,32 @@ UML_LOOK = NO # but if the number exceeds 15, the total amount of fields shown is limited to # 10. # Minimum value: 0, maximum value: 100, default value: 10. -# This tag requires that the tag HAVE_DOT is set to YES. +# This tag requires that the tag UML_LOOK is set to YES. UML_LIMIT_NUM_FIELDS = 10 +# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and +# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS +# tag is set to YES, doxygen will add type and arguments for attributes and +# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen +# will not generate fields with class member information in the UML graphs. The +# class diagrams will look similar to the default class diagrams but using UML +# notation for the relationships. +# Possible values are: NO, YES and NONE. +# The default value is: NO. +# This tag requires that the tag UML_LOOK is set to YES. + +DOT_UML_DETAILS = NO + +# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters +# to display on a single line. If the actual line length exceeds this threshold +# significantly it will be wrapped across multiple lines. Some heuristics are +# applied to avoid ugly line breaks. +# Minimum value: 0, maximum value: 1000, default value: 17. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_WRAP_THRESHOLD = 17 + # If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and # collaboration graphs will show the relations between templates and their # instances. @@ -2255,7 +2596,9 @@ TEMPLATE_RELATIONS = NO # If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to # YES then doxygen will generate a graph for each documented file showing the # direct and indirect include dependencies of the file with other documented -# files. +# files. Explicit enabling an include graph, when INCLUDE_GRAPH is is set to NO, +# can be accomplished by means of the command \includegraph. Disabling an +# include graph can be accomplished by means of the command \hideincludegraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2264,7 +2607,10 @@ INCLUDE_GRAPH = YES # If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are # set to YES then doxygen will generate a graph for each documented file showing # the direct and indirect include dependencies of the file with other documented -# files. +# files. Explicit enabling an included by graph, when INCLUDED_BY_GRAPH is set +# to NO, can be accomplished by means of the command \includedbygraph. Disabling +# an included by graph can be accomplished by means of the command +# \hideincludedbygraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2304,16 +2650,26 @@ GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the # dependencies a directory has on other directories in a graphical way. The # dependency relations are determined by the #include relations between the -# files in the directories. +# files in the directories. Explicit enabling a directory graph, when +# DIRECTORY_GRAPH is set to NO, can be accomplished by means of the command +# \directorygraph. Disabling a directory graph can be accomplished by means of +# the command \hidedirectorygraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. DIRECTORY_GRAPH = YES +# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels +# of child directories generated in directory dependency graphs by dot. +# Minimum value: 1, maximum value: 25, default value: 1. +# This tag requires that the tag DIRECTORY_GRAPH is set to YES. + +DIR_GRAPH_MAX_DEPTH = 1 + # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. For an explanation of the image formats see the section # output formats in the documentation of the dot tool (Graphviz (see: -# http://www.graphviz.org/)). +# https://www.graphviz.org/)). # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). @@ -2350,11 +2706,12 @@ DOT_PATH = DOTFILE_DIRS = -# The MSCFILE_DIRS tag can be used to specify one or more directories that -# contain msc files that are included in the documentation (see the \mscfile -# command). +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. -MSCFILE_DIRS = +DIA_PATH = # The DIAFILE_DIRS tag can be used to specify one or more directories that # contain dia files that are included in the documentation (see the \diafile @@ -2363,10 +2720,10 @@ MSCFILE_DIRS = DIAFILE_DIRS = # When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the -# path where java can find the plantuml.jar file. If left blank, it is assumed -# PlantUML is not used or called during a preprocessing step. Doxygen will -# generate a warning when it encounters a \startuml command in this case and -# will not generate output for the diagram. +# path where java can find the plantuml.jar file or to the filename of jar file +# to be used. If left blank, it is assumed PlantUML is not used or called during +# a preprocessing step. Doxygen will generate a warning when it encounters a +# \startuml command in this case and will not generate output for the diagram. PLANTUML_JAR_PATH = @@ -2383,7 +2740,7 @@ PLANTUML_INCLUDE_PATH = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes # that will be shown in the graph. If the number of nodes in a graph becomes # larger than this value, doxygen will truncate the graph, which is visualized -# by representing a node as a red box. Note that doxygen if the number of direct +# by representing a node as a red box. Note that if the number of direct # children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that # the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. @@ -2404,18 +2761,6 @@ DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not seem -# to support this out of the box. -# -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to -# read). -# The default value is: NO. -# This tag requires that the tag HAVE_DOT is set to YES. - -DOT_TRANSPARENT = NO - # Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) support @@ -2428,14 +2773,34 @@ DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page # explaining the meaning of the various boxes and arrows in the dot generated # graphs. +# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal +# graphical representation for inheritance and collaboration diagrams is used. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. GENERATE_LEGEND = YES -# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate # files that are used to generate the various graphs. +# +# Note: This setting is not only used for dot files but also for msc temporary +# files. # The default value is: YES. -# This tag requires that the tag HAVE_DOT is set to YES. DOT_CLEANUP = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. If the MSCGEN_TOOL tag is left empty (the default), then doxygen will +# use a built-in version of mscgen tool to produce the charts. Alternatively, +# the MSCGEN_TOOL tag can also specify the name an external tool. For instance, +# specifying prog as the value, doxygen will call the tool as prog -T +# <outfile_format> -o <outputfile> <inputfile>. The external tool should support +# output file formats "png", "eps", "svg", and "ismap". + +MSCGEN_TOOL = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = diff --git a/git-version-gen b/git-version-gen index 3eb6a42..d868952 100755 --- a/git-version-gen +++ b/git-version-gen @@ -3,7 +3,7 @@ SRCDIR=`dirname $0` if test -n "$1"; then VER=$1 else - if test -d "${SRCDIR}/.git" && test -x "`which git`" ; then + if test -r "${SRCDIR}/.git" && test -x "`which git`" ; then git update-index -q --refresh if ! VER=`git describe --tags --dirty 2>/dev/null`; then COMMIT=`git rev-parse --short HEAD` @@ -16,4 +16,5 @@ else fi fi fi +VER=`printf %s "$VER" | head -n1` printf %s "$VER" diff --git a/include/Makefile.am b/include/Makefile.am index 2abaf49..a41f53d 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -23,9 +23,11 @@ nobase_include_HEADERS = \ libimobiledevice/diagnostics_relay.h \ libimobiledevice/debugserver.h \ libimobiledevice/syslog_relay.h \ + libimobiledevice/ostrace.h \ libimobiledevice/mobileactivation.h \ libimobiledevice/preboard.h \ libimobiledevice/companion_proxy.h \ libimobiledevice/reverse_proxy.h \ + libimobiledevice/bt_packet_logger.h \ libimobiledevice/property_list_service.h \ libimobiledevice/service.h diff --git a/include/libimobiledevice/afc.h b/include/libimobiledevice/afc.h index a2d70d3..3dcb5da 100644 --- a/include/libimobiledevice/afc.h +++ b/include/libimobiledevice/afc.h @@ -107,7 +107,7 @@ typedef afc_client_private *afc_client_t; /**< The client handle. */ * invalid, AFC_E_MUX_ERROR if the connection cannot be established, * or AFC_E_NO_MEM if there is a memory allocation problem. */ -afc_error_t afc_client_new(idevice_t device, lockdownd_service_descriptor_t service, afc_client_t *client); +LIBIMOBILEDEVICE_API afc_error_t afc_client_new(idevice_t device, lockdownd_service_descriptor_t service, afc_client_t *client); /** * Starts a new AFC service on the specified device and connects to it. @@ -120,7 +120,7 @@ afc_error_t afc_client_new(idevice_t device, lockdownd_service_descriptor_t serv * * @return AFC_E_SUCCESS on success, or an AFC_E_* error code otherwise. */ -afc_error_t afc_client_start_service(idevice_t device, afc_client_t* client, const char* label); +LIBIMOBILEDEVICE_API afc_error_t afc_client_start_service(idevice_t device, afc_client_t* client, const char* label); /** * Frees up an AFC client. If the connection was created by the client itself, @@ -128,7 +128,7 @@ afc_error_t afc_client_start_service(idevice_t device, afc_client_t* client, con * * @param client The client to free. */ -afc_error_t afc_client_free(afc_client_t client); +LIBIMOBILEDEVICE_API afc_error_t afc_client_free(afc_client_t client); /** * Get device information for a connected client. The device information @@ -142,7 +142,21 @@ afc_error_t afc_client_free(afc_client_t client); * * @return AFC_E_SUCCESS on success or an AFC_E_* error value. */ -afc_error_t afc_get_device_info(afc_client_t client, char ***device_information); +LIBIMOBILEDEVICE_API afc_error_t afc_get_device_info(afc_client_t client, char ***device_information); + +/** + * Get device information for a connected client. The device information + * returned is the device model as well as the free space, the total capacity + * and blocksize on the accessed disk partition. + * + * @param client The client to get device info for. + * @param device_information A pointer to a plist_t that will be populated + * with key-value pairs (dictionary) representing the device’s + * storage and model information. Free with plist_free(). + * + * @return AFC_E_SUCCESS on success or an AFC_E_* error value. + */ +LIBIMOBILEDEVICE_API afc_error_t afc_get_device_info_plist(afc_client_t client, plist_t *device_information); /** * Gets a directory listing of the directory requested. @@ -155,7 +169,7 @@ afc_error_t afc_get_device_info(afc_client_t client, char ***device_information) * * @return AFC_E_SUCCESS on success or an AFC_E_* error value. */ -afc_error_t afc_read_directory(afc_client_t client, const char *path, char ***directory_information); +LIBIMOBILEDEVICE_API afc_error_t afc_read_directory(afc_client_t client, const char *path, char ***directory_information); /** * Gets information about a specific file. @@ -163,12 +177,25 @@ afc_error_t afc_read_directory(afc_client_t client, const char *path, char ***di * @param client The client to use to get the information of the file. * @param path The fully-qualified path to the file. * @param file_information Pointer to a buffer that will be filled with a - * NULL-terminated list of strings with the file information. Set to NULL + * NULL-terminated list of strings with the file attributes. Set to NULL * before calling this function. Free with afc_dictionary_free(). * * @return AFC_E_SUCCESS on success or an AFC_E_* error value. */ -afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***file_information); +LIBIMOBILEDEVICE_API afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***file_information); + +/** + * Gets information about a specific file. + * + * @param client The client to use to get the information of the file. + * @param path The fully-qualified path to the file. + * @param file_information A pointer to a plist_t that will be populated + * with key-value pairs (dictionary) representing the file attributes. + * Free with plist_free(). + * + * @return AFC_E_SUCCESS on success or an AFC_E_* error value. + */ +LIBIMOBILEDEVICE_API afc_error_t afc_get_file_info_plist(afc_client_t client, const char *path, plist_t *file_information); /** * Opens a file on the device. @@ -180,7 +207,7 @@ afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***fil * * @return AFC_E_SUCCESS on success or an AFC_E_* error value. */ -afc_error_t afc_file_open(afc_client_t client, const char *filename, afc_file_mode_t file_mode, uint64_t *handle); +LIBIMOBILEDEVICE_API afc_error_t afc_file_open(afc_client_t client, const char *filename, afc_file_mode_t file_mode, uint64_t *handle); /** * Closes a file on the device. @@ -188,7 +215,7 @@ afc_error_t afc_file_open(afc_client_t client, const char *filename, afc_file_mo * @param client The client to close the file with. * @param handle File handle of a previously opened file. */ -afc_error_t afc_file_close(afc_client_t client, uint64_t handle); +LIBIMOBILEDEVICE_API afc_error_t afc_file_close(afc_client_t client, uint64_t handle); /** * Locks or unlocks a file on the device. @@ -202,7 +229,7 @@ afc_error_t afc_file_close(afc_client_t client, uint64_t handle); * AFC_LOCK_SH (shared lock), AFC_LOCK_EX (exclusive lock), or * AFC_LOCK_UN (unlock). */ -afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t operation); +LIBIMOBILEDEVICE_API afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t operation); /** * Attempts to the read the given number of bytes from the given file. @@ -215,7 +242,7 @@ afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t op * * @return AFC_E_SUCCESS on success or an AFC_E_* error value. */ -afc_error_t afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length, uint32_t *bytes_read); +LIBIMOBILEDEVICE_API afc_error_t afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length, uint32_t *bytes_read); /** * Writes a given number of bytes to a file. @@ -228,7 +255,7 @@ afc_error_t afc_file_read(afc_client_t client, uint64_t handle, char *data, uint * * @return AFC_E_SUCCESS on success or an AFC_E_* error value. */ -afc_error_t afc_file_write(afc_client_t client, uint64_t handle, const char *data, uint32_t length, uint32_t *bytes_written); +LIBIMOBILEDEVICE_API afc_error_t afc_file_write(afc_client_t client, uint64_t handle, const char *data, uint32_t length, uint32_t *bytes_written); /** * Seeks to a given position of a pre-opened file on the device. @@ -240,7 +267,7 @@ afc_error_t afc_file_write(afc_client_t client, uint64_t handle, const char *dat * * @return AFC_E_SUCCESS on success or an AFC_E_* error value. */ -afc_error_t afc_file_seek(afc_client_t client, uint64_t handle, int64_t offset, int whence); +LIBIMOBILEDEVICE_API afc_error_t afc_file_seek(afc_client_t client, uint64_t handle, int64_t offset, int whence); /** * Returns current position in a pre-opened file on the device. @@ -251,7 +278,7 @@ afc_error_t afc_file_seek(afc_client_t client, uint64_t handle, int64_t offset, * * @return AFC_E_SUCCESS on success or an AFC_E_* error value. */ -afc_error_t afc_file_tell(afc_client_t client, uint64_t handle, uint64_t *position); +LIBIMOBILEDEVICE_API afc_error_t afc_file_tell(afc_client_t client, uint64_t handle, uint64_t *position); /** * Sets the size of a file on the device. @@ -265,7 +292,7 @@ afc_error_t afc_file_tell(afc_client_t client, uint64_t handle, uint64_t *positi * @note This function is more akin to ftruncate than truncate, and truncate * calls would have to open the file before calling this, sadly. */ -afc_error_t afc_file_truncate(afc_client_t client, uint64_t handle, uint64_t newsize); +LIBIMOBILEDEVICE_API afc_error_t afc_file_truncate(afc_client_t client, uint64_t handle, uint64_t newsize); /** * Deletes a file or directory. @@ -275,7 +302,7 @@ afc_error_t afc_file_truncate(afc_client_t client, uint64_t handle, uint64_t new * * @return AFC_E_SUCCESS on success or an AFC_E_* error value. */ -afc_error_t afc_remove_path(afc_client_t client, const char *path); +LIBIMOBILEDEVICE_API afc_error_t afc_remove_path(afc_client_t client, const char *path); /** * Renames a file or directory on the device. @@ -286,7 +313,7 @@ afc_error_t afc_remove_path(afc_client_t client, const char *path); * * @return AFC_E_SUCCESS on success or an AFC_E_* error value. */ -afc_error_t afc_rename_path(afc_client_t client, const char *from, const char *to); +LIBIMOBILEDEVICE_API afc_error_t afc_rename_path(afc_client_t client, const char *from, const char *to); /** * Creates a directory on the device. @@ -297,7 +324,7 @@ afc_error_t afc_rename_path(afc_client_t client, const char *from, const char *t * * @return AFC_E_SUCCESS on success or an AFC_E_* error value. */ -afc_error_t afc_make_directory(afc_client_t client, const char *path); +LIBIMOBILEDEVICE_API afc_error_t afc_make_directory(afc_client_t client, const char *path); /** * Sets the size of a file on the device without prior opening it. @@ -308,7 +335,7 @@ afc_error_t afc_make_directory(afc_client_t client, const char *path); * * @return AFC_E_SUCCESS on success or an AFC_E_* error value. */ -afc_error_t afc_truncate(afc_client_t client, const char *path, uint64_t newsize); +LIBIMOBILEDEVICE_API afc_error_t afc_truncate(afc_client_t client, const char *path, uint64_t newsize); /** * Creates a hard link or symbolic link on the device. @@ -320,7 +347,7 @@ afc_error_t afc_truncate(afc_client_t client, const char *path, uint64_t newsize * * @return AFC_E_SUCCESS on success or an AFC_E_* error value. */ -afc_error_t afc_make_link(afc_client_t client, afc_link_type_t linktype, const char *target, const char *linkname); +LIBIMOBILEDEVICE_API afc_error_t afc_make_link(afc_client_t client, afc_link_type_t linktype, const char *target, const char *linkname); /** * Sets the modification time of a file on the device. @@ -331,7 +358,7 @@ afc_error_t afc_make_link(afc_client_t client, afc_link_type_t linktype, const c * * @return AFC_E_SUCCESS on success or an AFC_E_* error value. */ -afc_error_t afc_set_file_time(afc_client_t client, const char *path, uint64_t mtime); +LIBIMOBILEDEVICE_API afc_error_t afc_set_file_time(afc_client_t client, const char *path, uint64_t mtime); /** * Deletes a file or directory including possible contents. @@ -343,7 +370,7 @@ afc_error_t afc_set_file_time(afc_client_t client, const char *path, uint64_t mt * * @return AFC_E_SUCCESS on success or an AFC_E_* error value. */ -afc_error_t afc_remove_path_and_contents(afc_client_t client, const char *path); +LIBIMOBILEDEVICE_API afc_error_t afc_remove_path_and_contents(afc_client_t client, const char *path); /* Helper functions */ @@ -358,7 +385,7 @@ afc_error_t afc_remove_path_and_contents(afc_client_t client, const char *path); * * @return AFC_E_SUCCESS on success or an AFC_E_* error value. */ -afc_error_t afc_get_device_info_key(afc_client_t client, const char *key, char **value); +LIBIMOBILEDEVICE_API afc_error_t afc_get_device_info_key(afc_client_t client, const char *key, char **value); /** * Frees up a char dictionary as returned by some AFC functions. @@ -367,7 +394,16 @@ afc_error_t afc_get_device_info_key(afc_client_t client, const char *key, char * * * @return AFC_E_SUCCESS on success or an AFC_E_* error value. */ -afc_error_t afc_dictionary_free(char **dictionary); +LIBIMOBILEDEVICE_API afc_error_t afc_dictionary_free(char **dictionary); + +/** + * Gets a readable error string for a given AFC error code. + * + * @param err An AFC error code + * + * @returns A readable error string + */ +LIBIMOBILEDEVICE_API const char* afc_strerror(afc_error_t err); #ifdef __cplusplus } diff --git a/include/libimobiledevice/bt_packet_logger.h b/include/libimobiledevice/bt_packet_logger.h index 230040a..590e5c1 100644 --- a/include/libimobiledevice/bt_packet_logger.h +++ b/include/libimobiledevice/bt_packet_logger.h @@ -70,7 +70,7 @@ typedef void (*bt_packet_logger_receive_cb_t)(uint8_t * data, uint16_t len, void * @return BT_PACKET_LOGGER_E_SUCCESS on success, BT_PACKET_LOGGER_E_INVALID_ARG when * client is NULL, or an BT_PACKET_LOGGER_E_* error code otherwise. */ -bt_packet_logger_error_t bt_packet_logger_client_new(idevice_t device, lockdownd_service_descriptor_t service, bt_packet_logger_client_t * client); +LIBIMOBILEDEVICE_API bt_packet_logger_error_t bt_packet_logger_client_new(idevice_t device, lockdownd_service_descriptor_t service, bt_packet_logger_client_t * client); /** * Starts a new bt_packet_logger service on the specified device and connects to it. @@ -85,7 +85,7 @@ bt_packet_logger_error_t bt_packet_logger_client_new(idevice_t device, lockdownd * @return BT_PACKET_LOGGER_E_SUCCESS on success, or an BT_PACKET_LOGGER_E_* error * code otherwise. */ -bt_packet_logger_error_t bt_packet_logger_client_start_service(idevice_t device, bt_packet_logger_client_t * client, const char* label); +LIBIMOBILEDEVICE_API bt_packet_logger_error_t bt_packet_logger_client_start_service(idevice_t device, bt_packet_logger_client_t * client, const char* label); /** * Disconnects a bt_packet_logger client from the device and frees up the @@ -96,7 +96,7 @@ bt_packet_logger_error_t bt_packet_logger_client_start_service(idevice_t device, * @return BT_PACKET_LOGGER_E_SUCCESS on success, BT_PACKET_LOGGER_E_INVALID_ARG when * client is NULL, or an BT_PACKET_LOGGER_E_* error code otherwise. */ -bt_packet_logger_error_t bt_packet_logger_client_free(bt_packet_logger_client_t client); +LIBIMOBILEDEVICE_API bt_packet_logger_error_t bt_packet_logger_client_free(bt_packet_logger_client_t client); /** @@ -113,7 +113,7 @@ bt_packet_logger_error_t bt_packet_logger_client_free(bt_packet_logger_client_t * invalid or BT_PACKET_LOGGER_E_UNKNOWN_ERROR when an unspecified * error occurs or an hci capture has already been started. */ -bt_packet_logger_error_t bt_packet_logger_start_capture(bt_packet_logger_client_t client, bt_packet_logger_receive_cb_t callback, void* user_data); +LIBIMOBILEDEVICE_API bt_packet_logger_error_t bt_packet_logger_start_capture(bt_packet_logger_client_t client, bt_packet_logger_receive_cb_t callback, void* user_data); /** * Stops capturing the hci interface from the device. @@ -127,7 +127,7 @@ bt_packet_logger_error_t bt_packet_logger_start_capture(bt_packet_logger_client_ * invalid or BT_PACKET_LOGGER_E_UNKNOWN_ERROR when an unspecified * error occurs or an hci capture has already been started. */ -bt_packet_logger_error_t bt_packet_logger_stop_capture(bt_packet_logger_client_t client); +LIBIMOBILEDEVICE_API bt_packet_logger_error_t bt_packet_logger_stop_capture(bt_packet_logger_client_t client); /* Receiving */ @@ -146,7 +146,7 @@ bt_packet_logger_error_t bt_packet_logger_stop_capture(bt_packet_logger_client_t * occurs, or BT_PACKET_LOGGER_E_UNKNOWN_ERROR when an unspecified * error occurs. */ -bt_packet_logger_error_t bt_packet_logger_receive_with_timeout(bt_packet_logger_client_t client, char *data, uint32_t size, uint32_t *received, unsigned int timeout); +LIBIMOBILEDEVICE_API bt_packet_logger_error_t bt_packet_logger_receive_with_timeout(bt_packet_logger_client_t client, char *data, uint32_t size, uint32_t *received, unsigned int timeout); #ifdef __cplusplus diff --git a/include/libimobiledevice/companion_proxy.h b/include/libimobiledevice/companion_proxy.h index d786766..544322a 100644 --- a/include/libimobiledevice/companion_proxy.h +++ b/include/libimobiledevice/companion_proxy.h @@ -67,7 +67,7 @@ typedef void (*companion_proxy_device_event_cb_t) (plist_t event, void* userdata * @return COMPANION_PROXY_E_SUCCESS on success, COMPANION_PROXY_E_INVALID_ARG when * the arguments are invalid, or an COMPANION_PROXY_E_* error code otherwise. */ -companion_proxy_error_t companion_proxy_client_new(idevice_t device, lockdownd_service_descriptor_t service, companion_proxy_client_t* client); +LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_client_new(idevice_t device, lockdownd_service_descriptor_t service, companion_proxy_client_t* client); /** * Starts a new companion_proxy service on the specified device and connects to it. @@ -82,7 +82,7 @@ companion_proxy_error_t companion_proxy_client_new(idevice_t device, lockdownd_s * @return COMPANION_PROXY_E_SUCCESS on success, or an COMPANION_PROXY_E_* error * code otherwise. */ -companion_proxy_error_t companion_proxy_client_start_service(idevice_t device, companion_proxy_client_t* client, const char* label); +LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_client_start_service(idevice_t device, companion_proxy_client_t* client, const char* label); /** * Disconnects a companion_proxy client from the device and frees up the @@ -93,7 +93,7 @@ companion_proxy_error_t companion_proxy_client_start_service(idevice_t device, c * @return COMPANION_PROXY_E_SUCCESS on success, COMPANION_PROXY_E_INVALID_ARG when * client is NULL, or an COMPANION_PROXY_E_* error code otherwise. */ -companion_proxy_error_t companion_proxy_client_free(companion_proxy_client_t client); +LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_client_free(companion_proxy_client_t client); /** * Sends a plist to the service. @@ -104,7 +104,7 @@ companion_proxy_error_t companion_proxy_client_free(companion_proxy_client_t cli * @return COMPANION_PROXY_E_SUCCESS on success, * COMPANION_PROXY_E_INVALID_ARG when client or plist is NULL */ -companion_proxy_error_t companion_proxy_send(companion_proxy_client_t client, plist_t plist); +LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_send(companion_proxy_client_t client, plist_t plist); /** * Receives a plist from the service. @@ -115,7 +115,7 @@ companion_proxy_error_t companion_proxy_send(companion_proxy_client_t client, pl * @return COMPANION_PROXY_E_SUCCESS on success, * COMPANION_PROXY_E_INVALID_ARG when client or plist is NULL */ -companion_proxy_error_t companion_proxy_receive(companion_proxy_client_t client, plist_t * plist); +LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_receive(companion_proxy_client_t client, plist_t * plist); /** * Retrieves a list of paired devices. @@ -129,7 +129,7 @@ companion_proxy_error_t companion_proxy_receive(companion_proxy_client_t client, * COMPANION_PROXY_E_NO_DEVICES if no devices are paired, * or a COMPANION_PROXY_E_* error code otherwise. */ -companion_proxy_error_t companion_proxy_get_device_registry(companion_proxy_client_t client, plist_t* paired_devices); +LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_get_device_registry(companion_proxy_client_t client, plist_t* paired_devices); /** * Starts listening for paired devices. @@ -145,7 +145,7 @@ companion_proxy_error_t companion_proxy_get_device_registry(companion_proxy_clie * @return COMPANION_PROXY_E_SUCCESS on success, * or a COMPANION_PROXY_E_* error code otherwise. */ -companion_proxy_error_t companion_proxy_start_listening_for_devices(companion_proxy_client_t client, companion_proxy_device_event_cb_t callback, void* userdata); +LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_start_listening_for_devices(companion_proxy_client_t client, companion_proxy_device_event_cb_t callback, void* userdata); /** * Stops listening for paired devices @@ -155,7 +155,7 @@ companion_proxy_error_t companion_proxy_start_listening_for_devices(companion_pr * @return COMPANION_PROXY_E_SUCCESS on success, * or a COMPANION_PROXY_E_* error code otherwise. */ -companion_proxy_error_t companion_proxy_stop_listening_for_devices(companion_proxy_client_t client); +LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_stop_listening_for_devices(companion_proxy_client_t client); /** * Returns a value for the given key. @@ -173,7 +173,7 @@ companion_proxy_error_t companion_proxy_stop_listening_for_devices(companion_pro * COMPANION_PROXY_E_UNSUPPORTED_KEY if the companion device doesn't support the given key, * or a COMPANION_PROXY_E_* error code otherwise. */ -companion_proxy_error_t companion_proxy_get_value_from_registry(companion_proxy_client_t client, const char* companion_udid, const char* key, plist_t* value); +LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_get_value_from_registry(companion_proxy_client_t client, const char* companion_udid, const char* key, plist_t* value); /** * Start forwarding a service port on the companion device to a port on the idevice. @@ -190,7 +190,7 @@ companion_proxy_error_t companion_proxy_get_value_from_registry(companion_proxy_ * @return COMPANION_PROXY_E_SUCCESS on success, * or a COMPANION_PROXY_E_* error code otherwise. */ -companion_proxy_error_t companion_proxy_start_forwarding_service_port(companion_proxy_client_t client, uint16_t remote_port, const char* service_name, uint16_t* forward_port, plist_t options); +LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_start_forwarding_service_port(companion_proxy_client_t client, uint16_t remote_port, const char* service_name, uint16_t* forward_port, plist_t options); /** * Stop forwarding a service port between companion device and idevice. @@ -203,7 +203,7 @@ companion_proxy_error_t companion_proxy_start_forwarding_service_port(companion_ * @return COMPANION_PROXY_E_SUCCESS on success, * or a COMPANION_PROXY_E_* error code otherwise. */ -companion_proxy_error_t companion_proxy_stop_forwarding_service_port(companion_proxy_client_t client, uint16_t remote_port); +LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_stop_forwarding_service_port(companion_proxy_client_t client, uint16_t remote_port); #ifdef __cplusplus } diff --git a/include/libimobiledevice/debugserver.h b/include/libimobiledevice/debugserver.h index eaa7c48..809b97f 100644 --- a/include/libimobiledevice/debugserver.h +++ b/include/libimobiledevice/debugserver.h @@ -66,7 +66,7 @@ typedef debugserver_command_private *debugserver_command_t; /**< The command han * @return DEBUGSERVER_E_SUCCESS on success, DEBUGSERVER_E_INVALID_ARG when * client is NULL, or an DEBUGSERVER_E_* error code otherwise. */ -debugserver_error_t debugserver_client_new(idevice_t device, lockdownd_service_descriptor_t service, debugserver_client_t * client); +LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_new(idevice_t device, lockdownd_service_descriptor_t service, debugserver_client_t * client); /** * Starts a new debugserver service on the specified device and connects to it. @@ -81,7 +81,7 @@ debugserver_error_t debugserver_client_new(idevice_t device, lockdownd_service_d * @return DEBUGSERVER_E_SUCCESS on success, or an DEBUGSERVER_E_* error * code otherwise. */ -debugserver_error_t debugserver_client_start_service(idevice_t device, debugserver_client_t * client, const char* label); +LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_start_service(idevice_t device, debugserver_client_t * client, const char* label); /** * Disconnects a debugserver client from the device and frees up the @@ -92,7 +92,7 @@ debugserver_error_t debugserver_client_start_service(idevice_t device, debugserv * @return DEBUGSERVER_E_SUCCESS on success, DEBUGSERVER_E_INVALID_ARG when * client is NULL, or an DEBUGSERVER_E_* error code otherwise. */ -debugserver_error_t debugserver_client_free(debugserver_client_t client); +LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_free(debugserver_client_t client); /** * Sends raw data using the given debugserver service client. @@ -107,7 +107,7 @@ debugserver_error_t debugserver_client_free(debugserver_client_t client); * invalid, or DEBUGSERVER_E_UNKNOWN_ERROR when an unspecified * error occurs. */ -debugserver_error_t debugserver_client_send(debugserver_client_t client, const char* data, uint32_t size, uint32_t *sent); +LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_send(debugserver_client_t client, const char* data, uint32_t size, uint32_t *sent); /** * Receives raw data using the given debugserver client with specified timeout. @@ -125,7 +125,7 @@ debugserver_error_t debugserver_client_send(debugserver_client_t client, const c * or DEBUGSERVER_E_UNKNOWN_ERROR when an unspecified * error occurs. */ -debugserver_error_t debugserver_client_receive_with_timeout(debugserver_client_t client, char *data, uint32_t size, uint32_t *received, unsigned int timeout); +LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive_with_timeout(debugserver_client_t client, char *data, uint32_t size, uint32_t *received, unsigned int timeout); /** * Receives raw data from the debugserver service. @@ -139,7 +139,7 @@ debugserver_error_t debugserver_client_receive_with_timeout(debugserver_client_t * @return DEBUGSERVER_E_SUCCESS on success, * DEBUGSERVER_E_INVALID_ARG when client or plist is NULL */ -debugserver_error_t debugserver_client_receive(debugserver_client_t client, char *data, uint32_t size, uint32_t *received); +LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive(debugserver_client_t client, char *data, uint32_t size, uint32_t *received); /** * Sends a command to the debugserver service. @@ -152,7 +152,7 @@ debugserver_error_t debugserver_client_receive(debugserver_client_t client, char * @return DEBUGSERVER_E_SUCCESS on success, * DEBUGSERVER_E_INVALID_ARG when client or command is NULL */ -debugserver_error_t debugserver_client_send_command(debugserver_client_t client, debugserver_command_t command, char** response, size_t* response_size); +LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_send_command(debugserver_client_t client, debugserver_command_t command, char** response, size_t* response_size); /** * Receives and parses response of debugserver service. @@ -164,7 +164,7 @@ debugserver_error_t debugserver_client_send_command(debugserver_client_t client, * @return DEBUGSERVER_E_SUCCESS on success, * DEBUGSERVER_E_INVALID_ARG when client is NULL */ -debugserver_error_t debugserver_client_receive_response(debugserver_client_t client, char** response, size_t* response_size); +LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive_response(debugserver_client_t client, char** response, size_t* response_size); /** * Controls status of ACK mode when sending commands or receiving responses. @@ -178,7 +178,7 @@ debugserver_error_t debugserver_client_receive_response(debugserver_client_t cli * @return DEBUGSERVER_E_SUCCESS on success, or an DEBUGSERVER_E_* error * code otherwise. */ -debugserver_error_t debugserver_client_set_ack_mode(debugserver_client_t client, int enabled); +LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_ack_mode(debugserver_client_t client, int enabled); /** * Sets behavior when awaiting a response from the server. @@ -197,7 +197,7 @@ debugserver_error_t debugserver_client_set_ack_mode(debugserver_client_t client, * @return DEBUGSERVER_E_SUCCESS on success, or an DEBUGSERVER_E_* error * code otherwise. */ -debugserver_error_t debugserver_client_set_receive_params(debugserver_client_t client, int (*cancel_receive)(), int receive_loop_timeout); +LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_receive_params(debugserver_client_t client, int (*cancel_receive)(), int receive_loop_timeout); /** * Sets the argv which launches an app. @@ -210,7 +210,7 @@ debugserver_error_t debugserver_client_set_receive_params(debugserver_client_t c * @return DEBUGSERVER_E_SUCCESS on success, * DEBUGSERVER_E_INVALID_ARG when client is NULL */ -debugserver_error_t debugserver_client_set_argv(debugserver_client_t client, int argc, char* argv[], char** response); +LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_argv(debugserver_client_t client, int argc, char* argv[], char** response); /** * Adds or sets an environment variable. @@ -222,7 +222,7 @@ debugserver_error_t debugserver_client_set_argv(debugserver_client_t client, int * @return DEBUGSERVER_E_SUCCESS on success, * DEBUGSERVER_E_INVALID_ARG when client is NULL */ -debugserver_error_t debugserver_client_set_environment_hex_encoded(debugserver_client_t client, const char* env, char** response); +LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_environment_hex_encoded(debugserver_client_t client, const char* env, char** response); /** * Creates and initializes a new command object. @@ -235,7 +235,7 @@ debugserver_error_t debugserver_client_set_environment_hex_encoded(debugserver_c * @return DEBUGSERVER_E_SUCCESS on success, * DEBUGSERVER_E_INVALID_ARG when name or command is NULL */ -debugserver_error_t debugserver_command_new(const char* name, int argc, char* argv[], debugserver_command_t* command); +LIBIMOBILEDEVICE_API debugserver_error_t debugserver_command_new(const char* name, int argc, char* argv[], debugserver_command_t* command); /** * Frees memory of command object. @@ -245,7 +245,7 @@ debugserver_error_t debugserver_command_new(const char* name, int argc, char* ar * @return DEBUGSERVER_E_SUCCESS on success, * DEBUGSERVER_E_INVALID_ARG when command is NULL */ -debugserver_error_t debugserver_command_free(debugserver_command_t command); +LIBIMOBILEDEVICE_API debugserver_error_t debugserver_command_free(debugserver_command_t command); /** * Encodes a string into hex notation. @@ -254,7 +254,7 @@ debugserver_error_t debugserver_command_free(debugserver_command_t command); * @param encoded_buffer The buffer receives a hex encoded string * @param encoded_length Length of the hex encoded string */ -void debugserver_encode_string(const char* buffer, char** encoded_buffer, uint32_t* encoded_length); +LIBIMOBILEDEVICE_API void debugserver_encode_string(const char* buffer, char** encoded_buffer, uint32_t* encoded_length); /** * Decodes a hex encoded string. @@ -263,7 +263,7 @@ void debugserver_encode_string(const char* buffer, char** encoded_buffer, uint32 * @param encoded_length Length of the encoded buffer * @param buffer Decoded string to be freed by the caller */ -void debugserver_decode_string(const char *encoded_buffer, size_t encoded_length, char** buffer); +LIBIMOBILEDEVICE_API void debugserver_decode_string(const char *encoded_buffer, size_t encoded_length, char** buffer); #ifdef __cplusplus } diff --git a/include/libimobiledevice/diagnostics_relay.h b/include/libimobiledevice/diagnostics_relay.h index f80a86b..6ab47a9 100644 --- a/include/libimobiledevice/diagnostics_relay.h +++ b/include/libimobiledevice/diagnostics_relay.h @@ -70,7 +70,7 @@ typedef diagnostics_relay_client_private *diagnostics_relay_client_t; /**< The c * DIAGNOSTICS_RELAY_E_INVALID_ARG when one of the parameters is invalid, * or DIAGNOSTICS_RELAY_E_MUX_ERROR when the connection failed. */ -diagnostics_relay_error_t diagnostics_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, diagnostics_relay_client_t *client); +LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, diagnostics_relay_client_t *client); /** * Starts a new diagnostics_relay service on the specified device and connects to it. @@ -85,7 +85,7 @@ diagnostics_relay_error_t diagnostics_relay_client_new(idevice_t device, lockdow * @return DIAGNOSTICS_RELAY_E_SUCCESS on success, or an DIAGNOSTICS_RELAY_E_* error * code otherwise. */ -diagnostics_relay_error_t diagnostics_relay_client_start_service(idevice_t device, diagnostics_relay_client_t* client, const char* label); +LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_client_start_service(idevice_t device, diagnostics_relay_client_t* client, const char* label); /** * Disconnects a diagnostics_relay client from the device and frees up the @@ -98,7 +98,7 @@ diagnostics_relay_error_t diagnostics_relay_client_start_service(idevice_t devic * is invalid, or DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR when the was an * error freeing the parent property_list_service client. */ -diagnostics_relay_error_t diagnostics_relay_client_free(diagnostics_relay_client_t client); +LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_client_free(diagnostics_relay_client_t client); /** @@ -111,7 +111,7 @@ diagnostics_relay_error_t diagnostics_relay_client_free(diagnostics_relay_client * DIAGNOSTICS_RELAY_E_PLIST_ERROR if the device did not acknowledge the * request */ -diagnostics_relay_error_t diagnostics_relay_goodbye(diagnostics_relay_client_t client); +LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_goodbye(diagnostics_relay_client_t client); /** * Puts the device into deep sleep mode and disconnects from host. @@ -123,7 +123,7 @@ diagnostics_relay_error_t diagnostics_relay_goodbye(diagnostics_relay_client_t c * DIAGNOSTICS_RELAY_E_PLIST_ERROR if the device did not acknowledge the * request */ -diagnostics_relay_error_t diagnostics_relay_sleep(diagnostics_relay_client_t client); +LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_sleep(diagnostics_relay_client_t client); /** * Restart the device and optionally show a user notification. @@ -140,7 +140,7 @@ diagnostics_relay_error_t diagnostics_relay_sleep(diagnostics_relay_client_t cli * DIAGNOSTICS_RELAY_E_PLIST_ERROR if the device did not acknowledge the * request */ -diagnostics_relay_error_t diagnostics_relay_restart(diagnostics_relay_client_t client, diagnostics_relay_action_t flags); +LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_restart(diagnostics_relay_client_t client, diagnostics_relay_action_t flags); /** * Shutdown of the device and optionally show a user notification. @@ -157,7 +157,7 @@ diagnostics_relay_error_t diagnostics_relay_restart(diagnostics_relay_client_t c * DIAGNOSTICS_RELAY_E_PLIST_ERROR if the device did not acknowledge the * request */ -diagnostics_relay_error_t diagnostics_relay_shutdown(diagnostics_relay_client_t client, diagnostics_relay_action_t flags); +LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_shutdown(diagnostics_relay_client_t client, diagnostics_relay_action_t flags); /** * Request diagnostics information for a given type. @@ -173,7 +173,7 @@ diagnostics_relay_error_t diagnostics_relay_shutdown(diagnostics_relay_client_t * DIAGNOSTICS_RELAY_E_PLIST_ERROR if the device did not acknowledge the * request */ -diagnostics_relay_error_t diagnostics_relay_request_diagnostics(diagnostics_relay_client_t client, const char* type, plist_t* diagnostics); +LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_request_diagnostics(diagnostics_relay_client_t client, const char* type, plist_t* diagnostics); /** * Query one or multiple MobileGestalt keys. @@ -188,7 +188,7 @@ diagnostics_relay_error_t diagnostics_relay_request_diagnostics(diagnostics_rela * DIAGNOSTICS_RELAY_E_PLIST_ERROR if the device did not acknowledge the * request */ -diagnostics_relay_error_t diagnostics_relay_query_mobilegestalt(diagnostics_relay_client_t client, plist_t keys, plist_t* result); +LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_query_mobilegestalt(diagnostics_relay_client_t client, plist_t keys, plist_t* result); /** * Query an IORegistry entry of a given class. @@ -204,7 +204,7 @@ diagnostics_relay_error_t diagnostics_relay_query_mobilegestalt(diagnostics_rela * DIAGNOSTICS_RELAY_E_PLIST_ERROR if the device did not acknowledge the * request */ -diagnostics_relay_error_t diagnostics_relay_query_ioregistry_entry(diagnostics_relay_client_t client, const char* entry_name, const char* entry_class, plist_t* result); +LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_query_ioregistry_entry(diagnostics_relay_client_t client, const char* entry_name, const char* entry_class, plist_t* result); /** * Query an IORegistry plane. @@ -219,7 +219,7 @@ diagnostics_relay_error_t diagnostics_relay_query_ioregistry_entry(diagnostics_r * DIAGNOSTICS_RELAY_E_PLIST_ERROR if the device did not acknowledge the * request */ -diagnostics_relay_error_t diagnostics_relay_query_ioregistry_plane(diagnostics_relay_client_t client, const char* plane, plist_t* result); +LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_query_ioregistry_plane(diagnostics_relay_client_t client, const char* plane, plist_t* result); #ifdef __cplusplus } diff --git a/include/libimobiledevice/file_relay.h b/include/libimobiledevice/file_relay.h index 6b30e65..00773b8 100644 --- a/include/libimobiledevice/file_relay.h +++ b/include/libimobiledevice/file_relay.h @@ -62,7 +62,7 @@ typedef file_relay_client_private *file_relay_client_t; /**< The client handle. * FILE_RELAY_E_INVALID_ARG when one of the parameters is invalid, * or FILE_RELAY_E_MUX_ERROR when the connection failed. */ -file_relay_error_t file_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, file_relay_client_t *client); +LIBIMOBILEDEVICE_API file_relay_error_t file_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, file_relay_client_t *client); /** * Starts a new file_relay service on the specified device and connects to it. @@ -77,7 +77,7 @@ file_relay_error_t file_relay_client_new(idevice_t device, lockdownd_service_des * @return FILE_RELAY_E_SUCCESS on success, or an FILE_RELAY_E_* error * code otherwise. */ -file_relay_error_t file_relay_client_start_service(idevice_t device, file_relay_client_t* client, const char* label); +LIBIMOBILEDEVICE_API file_relay_error_t file_relay_client_start_service(idevice_t device, file_relay_client_t* client, const char* label); /** * Disconnects a file_relay client from the device and frees up the file_relay @@ -90,7 +90,7 @@ file_relay_error_t file_relay_client_start_service(idevice_t device, file_relay_ * is invalid, or FILE_RELAY_E_UNKNOWN_ERROR when the was an error * freeing the parent property_list_service client. */ -file_relay_error_t file_relay_client_free(file_relay_client_t client); +LIBIMOBILEDEVICE_API file_relay_error_t file_relay_client_free(file_relay_client_t client); /** @@ -123,7 +123,7 @@ file_relay_error_t file_relay_client_free(file_relay_client_t client); * sources are invalid, FILE_RELAY_E_STAGING_EMPTY if no data is available * for the given sources, or FILE_RELAY_E_UNKNOWN_ERROR otherwise. */ -file_relay_error_t file_relay_request_sources(file_relay_client_t client, const char **sources, idevice_connection_t *connection); +LIBIMOBILEDEVICE_API file_relay_error_t file_relay_request_sources(file_relay_client_t client, const char **sources, idevice_connection_t *connection); /** * Request data for the given sources. Calls file_relay_request_sources_timeout() with @@ -157,7 +157,7 @@ file_relay_error_t file_relay_request_sources(file_relay_client_t client, const * sources are invalid, FILE_RELAY_E_STAGING_EMPTY if no data is available * for the given sources, or FILE_RELAY_E_UNKNOWN_ERROR otherwise. */ -file_relay_error_t file_relay_request_sources_timeout(file_relay_client_t client, const char **sources, idevice_connection_t *connection, unsigned int timeout); +LIBIMOBILEDEVICE_API file_relay_error_t file_relay_request_sources_timeout(file_relay_client_t client, const char **sources, idevice_connection_t *connection, unsigned int timeout); #ifdef __cplusplus } diff --git a/include/libimobiledevice/heartbeat.h b/include/libimobiledevice/heartbeat.h index 42b318d..4074b8b 100644 --- a/include/libimobiledevice/heartbeat.h +++ b/include/libimobiledevice/heartbeat.h @@ -60,7 +60,7 @@ typedef heartbeat_client_private *heartbeat_client_t; /**< The client handle. */ * @return HEARTBEAT_E_SUCCESS on success, HEARTBEAT_E_INVALID_ARG when * client is NULL, or an HEARTBEAT_E_* error code otherwise. */ -heartbeat_error_t heartbeat_client_new(idevice_t device, lockdownd_service_descriptor_t service, heartbeat_client_t * client); +LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_client_new(idevice_t device, lockdownd_service_descriptor_t service, heartbeat_client_t * client); /** * Starts a new heartbeat service on the specified device and connects to it. @@ -75,7 +75,7 @@ heartbeat_error_t heartbeat_client_new(idevice_t device, lockdownd_service_descr * @return HEARTBEAT_E_SUCCESS on success, or an HEARTBEAT_E_* error * code otherwise. */ -heartbeat_error_t heartbeat_client_start_service(idevice_t device, heartbeat_client_t * client, const char* label); +LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_client_start_service(idevice_t device, heartbeat_client_t * client, const char* label); /** * Disconnects a heartbeat client from the device and frees up the @@ -86,7 +86,7 @@ heartbeat_error_t heartbeat_client_start_service(idevice_t device, heartbeat_cli * @return HEARTBEAT_E_SUCCESS on success, HEARTBEAT_E_INVALID_ARG when * client is NULL, or an HEARTBEAT_E_* error code otherwise. */ -heartbeat_error_t heartbeat_client_free(heartbeat_client_t client); +LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_client_free(heartbeat_client_t client); /** @@ -98,7 +98,7 @@ heartbeat_error_t heartbeat_client_free(heartbeat_client_t client); * @return HEARTBEAT_E_SUCCESS on success, * HEARTBEAT_E_INVALID_ARG when client or plist is NULL */ -heartbeat_error_t heartbeat_send(heartbeat_client_t client, plist_t plist); +LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_send(heartbeat_client_t client, plist_t plist); /** * Receives a plist from the service. @@ -109,7 +109,7 @@ heartbeat_error_t heartbeat_send(heartbeat_client_t client, plist_t plist); * @return HEARTBEAT_E_SUCCESS on success, * HEARTBEAT_E_INVALID_ARG when client or plist is NULL */ -heartbeat_error_t heartbeat_receive(heartbeat_client_t client, plist_t * plist); +LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_receive(heartbeat_client_t client, plist_t * plist); /** * Receives a plist using the given heartbeat client. @@ -128,7 +128,7 @@ heartbeat_error_t heartbeat_receive(heartbeat_client_t client, plist_t * plist); * communication error occurs, or HEARTBEAT_E_UNKNOWN_ERROR * when an unspecified error occurs. */ -heartbeat_error_t heartbeat_receive_with_timeout(heartbeat_client_t client, plist_t * plist, uint32_t timeout_ms); +LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_receive_with_timeout(heartbeat_client_t client, plist_t * plist, uint32_t timeout_ms); #ifdef __cplusplus } diff --git a/include/libimobiledevice/house_arrest.h b/include/libimobiledevice/house_arrest.h index 3785847..f9ba68a 100644 --- a/include/libimobiledevice/house_arrest.h +++ b/include/libimobiledevice/house_arrest.h @@ -61,7 +61,7 @@ typedef house_arrest_client_private *house_arrest_client_t; /**< The client hand * @return HOUSE_ARREST_E_SUCCESS on success, HOUSE_ARREST_E_INVALID_ARG when * client is NULL, or an HOUSE_ARREST_E_* error code otherwise. */ -house_arrest_error_t house_arrest_client_new(idevice_t device, lockdownd_service_descriptor_t service, house_arrest_client_t *client); +LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_client_new(idevice_t device, lockdownd_service_descriptor_t service, house_arrest_client_t *client); /** * Starts a new house_arrest service on the specified device and connects to it. @@ -76,7 +76,7 @@ house_arrest_error_t house_arrest_client_new(idevice_t device, lockdownd_service * @return HOUSE_ARREST_E_SUCCESS on success, or an HOUSE_ARREST_E_* error * code otherwise. */ -house_arrest_error_t house_arrest_client_start_service(idevice_t device, house_arrest_client_t* client, const char* label); +LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_client_start_service(idevice_t device, house_arrest_client_t* client, const char* label); /** * Disconnects an house_arrest client from the device and frees up the @@ -92,7 +92,7 @@ house_arrest_error_t house_arrest_client_start_service(idevice_t device, house_a * @return HOUSE_ARREST_E_SUCCESS on success, HOUSE_ARREST_E_INVALID_ARG when * client is NULL, or an HOUSE_ARREST_E_* error code otherwise. */ -house_arrest_error_t house_arrest_client_free(house_arrest_client_t client); +LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_client_free(house_arrest_client_t client); /** @@ -112,7 +112,7 @@ house_arrest_error_t house_arrest_client_free(house_arrest_client_t client); * HOUSE_ARREST_E_INVALID_MODE if the client is not in the correct mode, * or HOUSE_ARREST_E_CONN_FAILED if a connection error occurred. */ -house_arrest_error_t house_arrest_send_request(house_arrest_client_t client, plist_t dict); +LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_send_request(house_arrest_client_t client, plist_t dict); /** * Send a command to the connected house_arrest service. @@ -133,7 +133,7 @@ house_arrest_error_t house_arrest_send_request(house_arrest_client_t client, pli * HOUSE_ARREST_E_INVALID_MODE if the client is not in the correct mode, * or HOUSE_ARREST_E_CONN_FAILED if a connection error occurred. */ -house_arrest_error_t house_arrest_send_command(house_arrest_client_t client, const char *command, const char *appid); +LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_send_command(house_arrest_client_t client, const char *command, const char *appid); /** * Retrieves the result of a previously sent house_arrest_request_* request. @@ -149,7 +149,7 @@ house_arrest_error_t house_arrest_send_command(house_arrest_client_t client, con * HOUSE_ARREST_E_INVALID_MODE if the client is not in the correct mode, * or HOUSE_ARREST_E_CONN_FAILED if a connection error occurred. */ -house_arrest_error_t house_arrest_get_result(house_arrest_client_t client, plist_t *dict); +LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_get_result(house_arrest_client_t client, plist_t *dict); /** @@ -171,7 +171,7 @@ house_arrest_error_t house_arrest_get_result(house_arrest_client_t client, plist * an afc client, or an AFC_E_* error code returned by * afc_client_new_with_service_client(). */ -afc_error_t afc_client_new_from_house_arrest_client(house_arrest_client_t client, afc_client_t *afc_client); +LIBIMOBILEDEVICE_API afc_error_t afc_client_new_from_house_arrest_client(house_arrest_client_t client, afc_client_t *afc_client); #ifdef __cplusplus } diff --git a/include/libimobiledevice/installation_proxy.h b/include/libimobiledevice/installation_proxy.h index 87132b9..44331aa 100644 --- a/include/libimobiledevice/installation_proxy.h +++ b/include/libimobiledevice/installation_proxy.h @@ -127,7 +127,7 @@ typedef void (*instproxy_status_cb_t) (plist_t command, plist_t status, void *us * @return INSTPROXY_E_SUCCESS on success, or an INSTPROXY_E_* error value * when an error occurred. */ -instproxy_error_t instproxy_client_new(idevice_t device, lockdownd_service_descriptor_t service, instproxy_client_t *client); +LIBIMOBILEDEVICE_API instproxy_error_t instproxy_client_new(idevice_t device, lockdownd_service_descriptor_t service, instproxy_client_t *client); /** * Starts a new installation_proxy service on the specified device and connects to it. @@ -142,7 +142,7 @@ instproxy_error_t instproxy_client_new(idevice_t device, lockdownd_service_descr * @return INSTPROXY_E_SUCCESS on success, or an INSTPROXY_E_* error * code otherwise. */ -instproxy_error_t instproxy_client_start_service(idevice_t device, instproxy_client_t * client, const char* label); +LIBIMOBILEDEVICE_API instproxy_error_t instproxy_client_start_service(idevice_t device, instproxy_client_t * client, const char* label); /** * Disconnects an installation_proxy client from the device and frees up the @@ -153,7 +153,7 @@ instproxy_error_t instproxy_client_start_service(idevice_t device, instproxy_cli * @return INSTPROXY_E_SUCCESS on success * or INSTPROXY_E_INVALID_ARG if client is NULL. */ -instproxy_error_t instproxy_client_free(instproxy_client_t client); +LIBIMOBILEDEVICE_API instproxy_error_t instproxy_client_free(instproxy_client_t client); /** * List installed applications. This function runs synchronously. @@ -171,7 +171,7 @@ instproxy_error_t instproxy_client_free(instproxy_client_t client); * @return INSTPROXY_E_SUCCESS on success or an INSTPROXY_E_* error value if * an error occurred. */ -instproxy_error_t instproxy_browse(instproxy_client_t client, plist_t client_options, plist_t *result); +LIBIMOBILEDEVICE_API instproxy_error_t instproxy_browse(instproxy_client_t client, plist_t client_options, plist_t *result); /** * List pages of installed applications in a callback. @@ -190,7 +190,7 @@ instproxy_error_t instproxy_browse(instproxy_client_t client, plist_t client_opt * @return INSTPROXY_E_SUCCESS on success or an INSTPROXY_E_* error value if * an error occurred. */ -instproxy_error_t instproxy_browse_with_callback(instproxy_client_t client, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data); +LIBIMOBILEDEVICE_API instproxy_error_t instproxy_browse_with_callback(instproxy_client_t client, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data); /** * Lookup information about specific applications from the device. @@ -206,7 +206,7 @@ instproxy_error_t instproxy_browse_with_callback(instproxy_client_t client, plis * @return INSTPROXY_E_SUCCESS on success or an INSTPROXY_E_* error value if * an error occurred. */ -instproxy_error_t instproxy_lookup(instproxy_client_t client, const char** appids, plist_t client_options, plist_t *result); +LIBIMOBILEDEVICE_API instproxy_error_t instproxy_lookup(instproxy_client_t client, const char** appids, plist_t client_options, plist_t *result); /** * Install an application on the device. @@ -232,7 +232,7 @@ instproxy_error_t instproxy_lookup(instproxy_client_t client, const char** appid * created successfully; any error occurring during the command has to be * handled inside the specified callback function. */ -instproxy_error_t instproxy_install(instproxy_client_t client, const char *pkg_path, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data); +LIBIMOBILEDEVICE_API instproxy_error_t instproxy_install(instproxy_client_t client, const char *pkg_path, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data); /** * Upgrade an application on the device. This function is nearly the same as @@ -260,7 +260,7 @@ instproxy_error_t instproxy_install(instproxy_client_t client, const char *pkg_p * created successfully; any error occurring during the command has to be * handled inside the specified callback function. */ -instproxy_error_t instproxy_upgrade(instproxy_client_t client, const char *pkg_path, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data); +LIBIMOBILEDEVICE_API instproxy_error_t instproxy_upgrade(instproxy_client_t client, const char *pkg_path, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data); /** * Uninstall an application from the device. @@ -281,7 +281,7 @@ instproxy_error_t instproxy_upgrade(instproxy_client_t client, const char *pkg_p * created successfully; any error occurring during the command has to be * handled inside the specified callback function. */ -instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data); +LIBIMOBILEDEVICE_API instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data); /** * List archived applications. This function runs synchronously. @@ -297,7 +297,7 @@ instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *app * @return INSTPROXY_E_SUCCESS on success or an INSTPROXY_E_* error value if * an error occurred. */ -instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist_t client_options, plist_t *result); +LIBIMOBILEDEVICE_API instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist_t client_options, plist_t *result); /** * Archive an application on the device. @@ -323,7 +323,7 @@ instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist_t c * created successfully; any error occurring during the command has to be * handled inside the specified callback function. */ -instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data); +LIBIMOBILEDEVICE_API instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data); /** * Restore a previously archived application on the device. @@ -347,7 +347,7 @@ instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid * created successfully; any error occurring during the command has to be * handled inside the specified callback function. */ -instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data); +LIBIMOBILEDEVICE_API instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data); /** * Removes a previously archived application from the device. @@ -370,7 +370,7 @@ instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid * created successfully; any error occurring during the command has to be * handled inside the specified callback function. */ -instproxy_error_t instproxy_remove_archive(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data); +LIBIMOBILEDEVICE_API instproxy_error_t instproxy_remove_archive(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data); /** * Checks a device for certain capabilities. @@ -386,7 +386,7 @@ instproxy_error_t instproxy_remove_archive(instproxy_client_t client, const char * @return INSTPROXY_E_SUCCESS on success or an INSTPROXY_E_* error value if * an error occurred. */ -instproxy_error_t instproxy_check_capabilities_match(instproxy_client_t client, const char** capabilities, plist_t client_options, plist_t *result); +LIBIMOBILEDEVICE_API instproxy_error_t instproxy_check_capabilities_match(instproxy_client_t client, const char** capabilities, plist_t client_options, plist_t *result); /* Helper */ @@ -396,7 +396,7 @@ instproxy_error_t instproxy_check_capabilities_match(instproxy_client_t client, * @param command The dictionary describing the command. * @param name Pointer to store the name of the command. */ -void instproxy_command_get_name(plist_t command, char** name); +LIBIMOBILEDEVICE_API void instproxy_command_get_name(plist_t command, char** name); /** * Gets the name of a status. @@ -404,7 +404,7 @@ void instproxy_command_get_name(plist_t command, char** name); * @param status The dictionary status response to use. * @param name Pointer to store the name of the status. */ -void instproxy_status_get_name(plist_t status, char **name); +LIBIMOBILEDEVICE_API void instproxy_status_get_name(plist_t status, char **name); /** * Gets error name, code and description from a response if available. @@ -420,7 +420,7 @@ void instproxy_status_get_name(plist_t status, char **name); * @return INSTPROXY_E_SUCCESS if no error is found or an INSTPROXY_E_* error * value matching the error that ẃas found in the status. */ -instproxy_error_t instproxy_status_get_error(plist_t status, char **name, char** description, uint64_t* code); +LIBIMOBILEDEVICE_API instproxy_error_t instproxy_status_get_error(plist_t status, char **name, char** description, uint64_t* code); /** * Gets total and current item information from a browse response if available. @@ -435,7 +435,7 @@ instproxy_error_t instproxy_status_get_error(plist_t status, char **name, char** * If NULL is passed no list will be returned. If NULL is returned no * list was found in the status. */ -void instproxy_status_get_current_list(plist_t status, uint64_t* total, uint64_t* current_index, uint64_t* current_amount, plist_t* list); +LIBIMOBILEDEVICE_API void instproxy_status_get_current_list(plist_t status, uint64_t* total, uint64_t* current_index, uint64_t* current_amount, plist_t* list); /** @@ -445,14 +445,14 @@ void instproxy_status_get_current_list(plist_t status, uint64_t* total, uint64_t * @param percent Pointer to an int to store the progress in percent (0-100) * or -1 if no progress was found in the status. */ -void instproxy_status_get_percent_complete(plist_t status, int *percent); +LIBIMOBILEDEVICE_API void instproxy_status_get_percent_complete(plist_t status, int *percent); /** * Creates a new client_options plist. * * @return A new plist_t of type PLIST_DICT. */ -plist_t instproxy_client_options_new(void); +LIBIMOBILEDEVICE_API plist_t instproxy_client_options_new(void); /** * Adds one or more new key:value pairs to the given client_options. @@ -464,7 +464,7 @@ plist_t instproxy_client_options_new(void); * keys "ApplicationSINF", "iTunesMetadata", "ReturnAttributes" which are * expecting a plist_t node as value and "SkipUninstall" expects int. */ -void instproxy_client_options_add(plist_t client_options, ...); +LIBIMOBILEDEVICE_API void instproxy_client_options_add(plist_t client_options, ...); /** * Adds attributes to the given client_options to filter browse results. @@ -474,7 +474,7 @@ void instproxy_client_options_add(plist_t client_options, ...); * * @note The values passed are expected to be strings. */ -void instproxy_client_options_set_return_attributes(plist_t client_options, ...); +LIBIMOBILEDEVICE_API void instproxy_client_options_set_return_attributes(plist_t client_options, ...); /** * Frees client_options plist. @@ -482,7 +482,7 @@ void instproxy_client_options_set_return_attributes(plist_t client_options, ...) * @param client_options The client options plist to free. Does nothing if NULL * is passed. */ -void instproxy_client_options_free(plist_t client_options); +LIBIMOBILEDEVICE_API void instproxy_client_options_free(plist_t client_options); /** * Queries the device for the path of an application. @@ -496,7 +496,7 @@ void instproxy_client_options_free(plist_t client_options); * the path could not be determined or an INSTPROXY_E_* error * value if an error occurred. */ -instproxy_error_t instproxy_client_get_path_for_bundle_identifier(instproxy_client_t client, const char* bundle_id, char** path); +LIBIMOBILEDEVICE_API instproxy_error_t instproxy_client_get_path_for_bundle_identifier(instproxy_client_t client, const char* bundle_id, char** path); #ifdef __cplusplus } diff --git a/include/libimobiledevice/libimobiledevice.h b/include/libimobiledevice/libimobiledevice.h index 6851145..bc57778 100644 --- a/include/libimobiledevice/libimobiledevice.h +++ b/include/libimobiledevice/libimobiledevice.h @@ -31,10 +31,23 @@ extern "C" { #endif #include <stdint.h> -#include <sys/types.h> -#include <sys/stat.h> #include <plist/plist.h> +#if defined(_MSC_VER) +#include <basetsd.h> +typedef SSIZE_T ssize_t; +#endif + +#ifndef LIBIMOBILEDEVICE_API + #ifdef LIBIMOBILEDEVICE_STATIC + #define LIBIMOBILEDEVICE_API + #elif defined(_WIN32) + #define LIBIMOBILEDEVICE_API __declspec(dllimport) + #else + #define LIBIMOBILEDEVICE_API + #endif +#endif + /** Error Codes */ typedef enum { IDEVICE_E_SUCCESS = 0, @@ -104,7 +117,7 @@ typedef struct idevice_subscription_context* idevice_subscription_context_t; * * @param level Set to 0 for no debug output or 1 to enable debug output. */ -void idevice_set_debug_level(int level); +LIBIMOBILEDEVICE_API void idevice_set_debug_level(int level); /** * Subscribe a callback function that will be called when device add/remove @@ -119,7 +132,7 @@ void idevice_set_debug_level(int level); * * @return IDEVICE_E_SUCCESS on success or an error value when an error occurred. */ -idevice_error_t idevice_events_subscribe(idevice_subscription_context_t *context, idevice_event_cb_t callback, void *user_data); +LIBIMOBILEDEVICE_API idevice_error_t idevice_events_subscribe(idevice_subscription_context_t *context, idevice_event_cb_t callback, void *user_data); /** * Unsubscribe the event callback function that has been registered with @@ -129,7 +142,7 @@ idevice_error_t idevice_events_subscribe(idevice_subscription_context_t *context * * @return IDEVICE_E_SUCCESS on success or an error value when an error occurred. */ -idevice_error_t idevice_events_unsubscribe(idevice_subscription_context_t context); +LIBIMOBILEDEVICE_API idevice_error_t idevice_events_unsubscribe(idevice_subscription_context_t context); /** * (DEPRECATED) Register a callback function that will be called when device add/remove @@ -143,7 +156,7 @@ idevice_error_t idevice_events_unsubscribe(idevice_subscription_context_t contex * * @return IDEVICE_E_SUCCESS on success or an error value when an error occurred. */ -idevice_error_t idevice_event_subscribe(idevice_event_cb_t callback, void *user_data); +LIBIMOBILEDEVICE_API idevice_error_t idevice_event_subscribe(idevice_event_cb_t callback, void *user_data); /** * (DEPRECATED) Release the event callback function that has been registered with @@ -153,7 +166,7 @@ idevice_error_t idevice_event_subscribe(idevice_event_cb_t callback, void *user_ * * @return IDEVICE_E_SUCCESS on success or an error value when an error occurred. */ -idevice_error_t idevice_event_unsubscribe(void); +LIBIMOBILEDEVICE_API idevice_error_t idevice_event_unsubscribe(void); /* discovery (synchronous) */ @@ -170,7 +183,7 @@ idevice_error_t idevice_event_unsubscribe(void); * network devices in the list, use idevice_get_device_list_extended(). * @see idevice_get_device_list_extended */ -idevice_error_t idevice_get_device_list(char ***devices, int *count); +LIBIMOBILEDEVICE_API idevice_error_t idevice_get_device_list(char ***devices, int *count); /** * Free a list of device UDIDs. @@ -179,7 +192,7 @@ idevice_error_t idevice_get_device_list(char ***devices, int *count); * * @return Always returnes IDEVICE_E_SUCCESS. */ -idevice_error_t idevice_device_list_free(char **devices); +LIBIMOBILEDEVICE_API idevice_error_t idevice_device_list_free(char **devices); /** * Get a list of currently available devices @@ -190,7 +203,7 @@ idevice_error_t idevice_device_list_free(char **devices); * * @return IDEVICE_E_SUCCESS on success or an error value when an error occurred. */ -idevice_error_t idevice_get_device_list_extended(idevice_info_t **devices, int *count); +LIBIMOBILEDEVICE_API idevice_error_t idevice_get_device_list_extended(idevice_info_t **devices, int *count); /** * Free an extended device list retrieved through idevice_get_device_list_extended(). @@ -199,7 +212,7 @@ idevice_error_t idevice_get_device_list_extended(idevice_info_t **devices, int * * * @return IDEVICE_E_SUCCESS on success or an error value when an error occurred. */ -idevice_error_t idevice_device_list_extended_free(idevice_info_t *devices); +LIBIMOBILEDEVICE_API idevice_error_t idevice_device_list_extended_free(idevice_info_t *devices); /* device structure creation and destruction */ @@ -220,7 +233,7 @@ idevice_error_t idevice_device_list_extended_free(idevice_info_t *devices); * * @return IDEVICE_E_SUCCESS if ok, otherwise an error code. */ -idevice_error_t idevice_new(idevice_t *device, const char *udid); +LIBIMOBILEDEVICE_API idevice_error_t idevice_new(idevice_t *device, const char *udid); /** * Creates an idevice_t structure for the device specified by UDID, @@ -243,14 +256,14 @@ idevice_error_t idevice_new(idevice_t *device, const char *udid); * * @return IDEVICE_E_SUCCESS if ok, otherwise an error code. */ -idevice_error_t idevice_new_with_options(idevice_t *device, const char *udid, enum idevice_options options); +LIBIMOBILEDEVICE_API idevice_error_t idevice_new_with_options(idevice_t *device, const char *udid, enum idevice_options options); /** * Cleans up an idevice structure, then frees the structure itself. * * @param device idevice_t to free. */ -idevice_error_t idevice_free(idevice_t device); +LIBIMOBILEDEVICE_API idevice_error_t idevice_free(idevice_t device); /* connection/disconnection */ @@ -264,7 +277,7 @@ idevice_error_t idevice_free(idevice_t device); * * @return IDEVICE_E_SUCCESS if ok, otherwise an error code. */ -idevice_error_t idevice_connect(idevice_t device, uint16_t port, idevice_connection_t *connection); +LIBIMOBILEDEVICE_API idevice_error_t idevice_connect(idevice_t device, uint16_t port, idevice_connection_t *connection); /** * Disconnect from the device and clean up the connection structure. @@ -273,7 +286,7 @@ idevice_error_t idevice_connect(idevice_t device, uint16_t port, idevice_connect * * @return IDEVICE_E_SUCCESS if ok, otherwise an error code. */ -idevice_error_t idevice_disconnect(idevice_connection_t connection); +LIBIMOBILEDEVICE_API idevice_error_t idevice_disconnect(idevice_connection_t connection); /* communication */ @@ -288,7 +301,7 @@ idevice_error_t idevice_disconnect(idevice_connection_t connection); * * @return IDEVICE_E_SUCCESS if ok, otherwise an error code. */ -idevice_error_t idevice_connection_send(idevice_connection_t connection, const char *data, uint32_t len, uint32_t *sent_bytes); +LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_send(idevice_connection_t connection, const char *data, uint32_t len, uint32_t *sent_bytes); /** * Receive data from a device via the given connection. @@ -305,7 +318,7 @@ idevice_error_t idevice_connection_send(idevice_connection_t connection, const c * * @return IDEVICE_E_SUCCESS if ok, otherwise an error code. */ -idevice_error_t idevice_connection_receive_timeout(idevice_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout); +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); /** * Receive data from a device via the given connection. @@ -320,7 +333,7 @@ idevice_error_t idevice_connection_receive_timeout(idevice_connection_t connecti * * @return IDEVICE_E_SUCCESS if ok, otherwise an error code. */ -idevice_error_t idevice_connection_receive(idevice_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes); +LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive(idevice_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes); /** * Enables SSL for the given connection. @@ -331,7 +344,7 @@ idevice_error_t idevice_connection_receive(idevice_connection_t connection, char * is NULL or connection->ssl_data is non-NULL, or IDEVICE_E_SSL_ERROR when * SSL initialization, setup, or handshake fails. */ -idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection); +LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection); /** * Disable SSL for the given connection. @@ -342,7 +355,7 @@ idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection); * is NULL. This function also returns IDEVICE_E_SUCCESS when SSL is not * enabled and does no further error checking on cleanup. */ -idevice_error_t idevice_connection_disable_ssl(idevice_connection_t connection); +LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_disable_ssl(idevice_connection_t connection); /** * Disable bypass SSL for the given connection without sending out terminate messages. @@ -355,7 +368,7 @@ idevice_error_t idevice_connection_disable_ssl(idevice_connection_t connection); * is NULL. This function also returns IDEVICE_E_SUCCESS when SSL is not * enabled and does no further error checking on cleanup. */ -idevice_error_t idevice_connection_disable_bypass_ssl(idevice_connection_t connection, uint8_t sslBypass); +LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_disable_bypass_ssl(idevice_connection_t connection, uint8_t sslBypass); /** @@ -366,7 +379,7 @@ idevice_error_t idevice_connection_disable_bypass_ssl(idevice_connection_t conne * * @return IDEVICE_E_SUCCESS if ok, otherwise an error code. */ -idevice_error_t idevice_connection_get_fd(idevice_connection_t connection, int *fd); +LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_get_fd(idevice_connection_t connection, int *fd); /* misc */ @@ -378,7 +391,7 @@ idevice_error_t idevice_connection_get_fd(idevice_connection_t connection, int * * * @return IDEVICE_E_SUCCESS on success, otherwise an error code. */ -idevice_error_t idevice_get_handle(idevice_t device, uint32_t *handle); +LIBIMOBILEDEVICE_API idevice_error_t idevice_get_handle(idevice_t device, uint32_t *handle); /** * Gets the Unique Device ID for the device. @@ -388,7 +401,40 @@ idevice_error_t idevice_get_handle(idevice_t device, uint32_t *handle); * * @return IDEVICE_E_SUCCESS on success, otherwise an error code. */ -idevice_error_t idevice_get_udid(idevice_t device, char **udid); +LIBIMOBILEDEVICE_API idevice_error_t idevice_get_udid(idevice_t device, char **udid); + +/** + * Returns the device ProductVersion in numerical form, where "X.Y.Z" + * will be returned as (X << 16) | (Y << 8) | Z . + * Use IDEVICE_DEVICE_VERSION macro for easy version comparison. + * @see IDEVICE_DEVICE_VERSION + * + * @param client Initialized device client + * + * @return A numerical representation of the X.Y.Z ProductVersion string + * or 0 if the version cannot be retrieved. + */ +LIBIMOBILEDEVICE_API unsigned int idevice_get_device_version(idevice_t device); + +/** + * Gets a readable error string for a given idevice error code. + * + * @param err An idevice error code + * + * @return A readable error string + */ +LIBIMOBILEDEVICE_API const char* idevice_strerror(idevice_error_t err); + +/** + * Returns a static string of the libimobiledevice version. + * + * @return The libimobiledevice version as static ascii string + */ +LIBIMOBILEDEVICE_API const char* libimobiledevice_version(); + +/* macros */ +/** Helper macro to get a numerical representation of a product version tuple */ +#define IDEVICE_DEVICE_VERSION(maj, min, patch) ((((maj) & 0xFF) << 16) | (((min) & 0xFF) << 8) | ((patch) & 0xFF)) #ifdef __cplusplus } diff --git a/include/libimobiledevice/lockdown.h b/include/libimobiledevice/lockdown.h index f22917a..21669ef 100644 --- a/include/libimobiledevice/lockdown.h +++ b/include/libimobiledevice/lockdown.h @@ -31,7 +31,6 @@ extern "C" { #endif #include <libimobiledevice/libimobiledevice.h> -#include <libimobiledevice/lockdown.h> /** Error Codes */ typedef enum { @@ -131,7 +130,7 @@ typedef void (*lockdownd_cu_pairing_cb_t) (lockdownd_cu_pairing_cb_type_t cb_typ * * @return LOCKDOWN_E_SUCCESS on success, LOCKDOWN_E_INVALID_ARG when client is NULL */ -lockdownd_error_t lockdownd_client_new(idevice_t device, lockdownd_client_t *client, const char *label); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_new(idevice_t device, lockdownd_client_t *client, const char *label); /** * Creates a new lockdownd client for the device and starts initial handshake. @@ -150,7 +149,7 @@ lockdownd_error_t lockdownd_client_new(idevice_t device, lockdownd_client_t *cli * @return LOCKDOWN_E_SUCCESS on success, LOCKDOWN_E_INVALID_ARG when client is NULL, * LOCKDOWN_E_INVALID_CONF if configuration data is wrong */ -lockdownd_error_t lockdownd_client_new_with_handshake(idevice_t device, lockdownd_client_t *client, const char *label); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_new_with_handshake(idevice_t device, lockdownd_client_t *client, const char *label); /** * Closes the lockdownd client session if one is running and frees up the @@ -160,7 +159,7 @@ lockdownd_error_t lockdownd_client_new_with_handshake(idevice_t device, lockdown * * @return LOCKDOWN_E_SUCCESS on success, LOCKDOWN_E_INVALID_ARG when client is NULL */ -lockdownd_error_t lockdownd_client_free(lockdownd_client_t client); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_free(lockdownd_client_t client); /** @@ -172,7 +171,7 @@ lockdownd_error_t lockdownd_client_free(lockdownd_client_t client); * * @return LOCKDOWN_E_SUCCESS on success, LOCKDOWN_E_INVALID_ARG when client is NULL */ -lockdownd_error_t lockdownd_query_type(lockdownd_client_t client, char **type); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_query_type(lockdownd_client_t client, char **type); /** * Retrieves a preferences plist using an optional domain and/or key name. @@ -184,7 +183,7 @@ lockdownd_error_t lockdownd_query_type(lockdownd_client_t client, char **type); * * @return LOCKDOWN_E_SUCCESS on success, LOCKDOWN_E_INVALID_ARG when client is NULL */ -lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *domain, const char *key, plist_t *value); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *domain, const char *key, plist_t *value); /** * Sets a preferences value using a plist and optional by domain and/or key name. @@ -197,7 +196,7 @@ lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *dom * @return LOCKDOWN_E_SUCCESS on success, LOCKDOWN_E_INVALID_ARG when client or * value is NULL */ -lockdownd_error_t lockdownd_set_value(lockdownd_client_t client, const char *domain, const char *key, plist_t value); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_set_value(lockdownd_client_t client, const char *domain, const char *key, plist_t value); /** * Removes a preference node by domain and/or key name. @@ -210,7 +209,7 @@ lockdownd_error_t lockdownd_set_value(lockdownd_client_t client, const char *dom * * @return LOCKDOWN_E_SUCCESS on success, LOCKDOWN_E_INVALID_ARG when client is NULL */ -lockdownd_error_t lockdownd_remove_value(lockdownd_client_t client, const char *domain, const char *key); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_remove_value(lockdownd_client_t client, const char *domain, const char *key); /** * Requests to start a service and retrieve it's port on success. @@ -224,7 +223,7 @@ lockdownd_error_t lockdownd_remove_value(lockdownd_client_t client, const char * * by the device, LOCKDOWN_E_START_SERVICE_FAILED if the service could not be * started by the device */ -lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char *identifier, lockdownd_service_descriptor_t *service); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char *identifier, lockdownd_service_descriptor_t *service); /** * Requests to start a service and retrieve it's port on success. @@ -240,7 +239,7 @@ lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char * started by the device, LOCKDOWN_E_INVALID_CONF if the host id or escrow bag are * missing from the device record. */ -lockdownd_error_t lockdownd_start_service_with_escrow_bag(lockdownd_client_t client, const char *identifier, lockdownd_service_descriptor_t *service); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_start_service_with_escrow_bag(lockdownd_client_t client, const char *identifier, lockdownd_service_descriptor_t *service); /** * Opens a session with lockdownd and switches to SSL mode if device wants it. @@ -255,7 +254,7 @@ lockdownd_error_t lockdownd_start_service_with_escrow_bag(lockdownd_client_t cli * LOCKDOWN_E_INVALID_HOST_ID if the device does not know the supplied HostID, * LOCKDOWN_E_SSL_ERROR if enabling SSL communication failed */ -lockdownd_error_t lockdownd_start_session(lockdownd_client_t client, const char *host_id, char **session_id, int *ssl_enabled); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_start_session(lockdownd_client_t client, const char *host_id, char **session_id, int *ssl_enabled); /** * Closes the lockdownd session by sending the StopSession request. @@ -267,7 +266,7 @@ lockdownd_error_t lockdownd_start_session(lockdownd_client_t client, const char * * @return LOCKDOWN_E_SUCCESS on success, LOCKDOWN_E_INVALID_ARG when client is NULL */ -lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client, const char *session_id); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client, const char *session_id); /** * Sends a plist to lockdownd. @@ -281,7 +280,7 @@ lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client, const char * * @return LOCKDOWN_E_SUCCESS on success, LOCKDOWN_E_INVALID_ARG when client or * plist is NULL */ -lockdownd_error_t lockdownd_send(lockdownd_client_t client, plist_t plist); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_send(lockdownd_client_t client, plist_t plist); /** * Receives a plist from lockdownd. @@ -292,7 +291,7 @@ lockdownd_error_t lockdownd_send(lockdownd_client_t client, plist_t plist); * @return LOCKDOWN_E_SUCCESS on success, LOCKDOWN_E_INVALID_ARG when client or * plist is NULL */ -lockdownd_error_t lockdownd_receive(lockdownd_client_t client, plist_t *plist); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_receive(lockdownd_client_t client, plist_t *plist); /** * Pairs the device using the supplied pair record. @@ -308,7 +307,7 @@ lockdownd_error_t lockdownd_receive(lockdownd_client_t client, plist_t *plist); * LOCKDOWN_E_PASSWORD_PROTECTED if the device is password protected, * LOCKDOWN_E_INVALID_HOST_ID if the device does not know the caller's host id */ -lockdownd_error_t lockdownd_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record); /** * Pairs the device using the supplied pair record and passing the given options. @@ -327,7 +326,7 @@ lockdownd_error_t lockdownd_pair(lockdownd_client_t client, lockdownd_pair_recor * LOCKDOWN_E_PASSWORD_PROTECTED if the device is password protected, * LOCKDOWN_E_INVALID_HOST_ID if the device does not know the caller's host id */ -lockdownd_error_t lockdownd_pair_with_options(lockdownd_client_t client, lockdownd_pair_record_t pair_record, plist_t options, plist_t *response); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_pair_with_options(lockdownd_client_t client, lockdownd_pair_record_t pair_record, plist_t options, plist_t *response); /** * Validates if the device is paired with the given HostID. If successful the @@ -346,7 +345,7 @@ lockdownd_error_t lockdownd_pair_with_options(lockdownd_client_t client, lockdow * LOCKDOWN_E_PASSWORD_PROTECTED if the device is password protected, * LOCKDOWN_E_INVALID_HOST_ID if the device does not know the caller's host id */ -lockdownd_error_t lockdownd_validate_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_validate_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record); /** * Unpairs the device with the given HostID and removes the pairing records @@ -362,7 +361,7 @@ lockdownd_error_t lockdownd_validate_pair(lockdownd_client_t client, lockdownd_p * LOCKDOWN_E_PASSWORD_PROTECTED if the device is password protected, * LOCKDOWN_E_INVALID_HOST_ID if the device does not know the caller's host id */ -lockdownd_error_t lockdownd_unpair(lockdownd_client_t client, lockdownd_pair_record_t pair_record); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_unpair(lockdownd_client_t client, lockdownd_pair_record_t pair_record); /** * Activates the device. Only works within an open session. @@ -379,7 +378,7 @@ lockdownd_error_t lockdownd_unpair(lockdownd_client_t client, lockdownd_pair_rec * LOCKDOWN_E_INVALID_ACTIVATION_RECORD if the device reports that the * activation_record is invalid */ -lockdownd_error_t lockdownd_activate(lockdownd_client_t client, plist_t activation_record); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_activate(lockdownd_client_t client, plist_t activation_record); /** * Deactivates the device, returning it to the locked “Activate with iTunes” @@ -391,7 +390,7 @@ lockdownd_error_t lockdownd_activate(lockdownd_client_t client, plist_t activati * LOCKDOWN_E_NO_RUNNING_SESSION if no session is open, * LOCKDOWN_E_PLIST_ERROR if the received plist is broken */ -lockdownd_error_t lockdownd_deactivate(lockdownd_client_t client); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_deactivate(lockdownd_client_t client); /** * Tells the device to immediately enter recovery mode. @@ -400,7 +399,7 @@ lockdownd_error_t lockdownd_deactivate(lockdownd_client_t client); * * @return LOCKDOWN_E_SUCCESS on success, LOCKDOWN_E_INVALID_ARG when client is NULL */ -lockdownd_error_t lockdownd_enter_recovery(lockdownd_client_t client); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_enter_recovery(lockdownd_client_t client); /** * Sends the Goodbye request to lockdownd signaling the end of communication. @@ -411,7 +410,7 @@ lockdownd_error_t lockdownd_enter_recovery(lockdownd_client_t client); * is NULL, LOCKDOWN_E_PLIST_ERROR if the device did not acknowledge the * request */ -lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client); /** * Creates a CU pairing session for the current lockdown client. @@ -440,7 +439,7 @@ lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client); * parameters is invalid, LOCKDOWN_E_PAIRING_FAILED if the pairing failed, * or a LOCKDOWN_E_* error code otherwise. */ -lockdownd_error_t lockdownd_cu_pairing_create(lockdownd_client_t client, lockdownd_cu_pairing_cb_t pairing_callback, void* cb_user_data, plist_t host_info, plist_t acl); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_cu_pairing_create(lockdownd_client_t client, lockdownd_cu_pairing_cb_t pairing_callback, void* cb_user_data, plist_t host_info, plist_t acl); /** * Sends a request via lockdown client with established CU pairing session @@ -460,7 +459,7 @@ lockdownd_error_t lockdownd_cu_pairing_create(lockdownd_client_t client, lockdow * lockdown client does not have an established CU pairing session, * or a LOCKDOWN_E_* error code otherwise. */ -lockdownd_error_t lockdownd_cu_send_request_and_get_reply(lockdownd_client_t client, const char* request, plist_t request_payload, plist_t* reply); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_cu_send_request_and_get_reply(lockdownd_client_t client, const char* request, plist_t request_payload, plist_t* reply); /** * Retrieves a value using an optional domain and/or key name from a lockdown @@ -480,7 +479,7 @@ lockdownd_error_t lockdownd_cu_send_request_and_get_reply(lockdownd_client_t cli * lockdown client does not have an established CU pairing session, * or a LOCKDOWN_E_* error code otherwise. */ -lockdownd_error_t lockdownd_get_value_cu(lockdownd_client_t client, const char* domain, const char* key, plist_t* value); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_value_cu(lockdownd_client_t client, const char* domain, const char* key, plist_t* value); /** * Perform a device pairing with a lockdown client that has an established @@ -493,7 +492,7 @@ lockdownd_error_t lockdownd_get_value_cu(lockdownd_client_t client, const char* * does not have an established CU pairing session, or a LOCKDOWN_E_* error * code otherwise. */ -lockdownd_error_t lockdownd_pair_cu(lockdownd_client_t client); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_pair_cu(lockdownd_client_t client); /* Helper */ @@ -505,7 +504,7 @@ lockdownd_error_t lockdownd_pair_cu(lockdownd_client_t client); * @param label The label to set or NULL to disable sending a label * */ -void lockdownd_client_set_label(lockdownd_client_t client, const char *label); +LIBIMOBILEDEVICE_API void lockdownd_client_set_label(lockdownd_client_t client, const char *label); /** * Returns the unique id of the device from lockdownd. @@ -516,7 +515,7 @@ void lockdownd_client_set_label(lockdownd_client_t client, const char *label); * * @return LOCKDOWN_E_SUCCESS on success */ -lockdownd_error_t lockdownd_get_device_udid(lockdownd_client_t client, char **udid); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_device_udid(lockdownd_client_t client, char **udid); /** * Retrieves the name of the device from lockdownd set by the user. @@ -527,7 +526,7 @@ lockdownd_error_t lockdownd_get_device_udid(lockdownd_client_t client, char **ud * * @return LOCKDOWN_E_SUCCESS on success */ -lockdownd_error_t lockdownd_get_device_name(lockdownd_client_t client, char **device_name); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_device_name(lockdownd_client_t client, char **device_name); /** * Calculates and returns the data classes the device supports from lockdownd. @@ -542,7 +541,7 @@ lockdownd_error_t lockdownd_get_device_name(lockdownd_client_t client, char **de * LOCKDOWN_E_NO_RUNNING_SESSION if no session is open, * LOCKDOWN_E_PLIST_ERROR if the received plist is broken */ -lockdownd_error_t lockdownd_get_sync_data_classes(lockdownd_client_t client, char ***classes, int *count); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_sync_data_classes(lockdownd_client_t client, char ***classes, int *count); /** * Frees memory of an allocated array of data classes as returned by lockdownd_get_sync_data_classes() @@ -551,7 +550,7 @@ lockdownd_error_t lockdownd_get_sync_data_classes(lockdownd_client_t client, cha * * @return LOCKDOWN_E_SUCCESS on success */ -lockdownd_error_t lockdownd_data_classes_free(char **classes); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_data_classes_free(char **classes); /** * Frees memory of a service descriptor as returned by lockdownd_start_service() @@ -560,7 +559,7 @@ lockdownd_error_t lockdownd_data_classes_free(char **classes); * * @return LOCKDOWN_E_SUCCESS on success */ -lockdownd_error_t lockdownd_service_descriptor_free(lockdownd_service_descriptor_t service); +LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_service_descriptor_free(lockdownd_service_descriptor_t service); /** * Gets a readable error string for a given lockdown error code. @@ -569,7 +568,7 @@ lockdownd_error_t lockdownd_service_descriptor_free(lockdownd_service_descriptor * * @returns A readable error string */ -const char* lockdownd_strerror(lockdownd_error_t err); +LIBIMOBILEDEVICE_API const char* lockdownd_strerror(lockdownd_error_t err); #ifdef __cplusplus } diff --git a/include/libimobiledevice/misagent.h b/include/libimobiledevice/misagent.h index 394f5ce..7981a8b 100644 --- a/include/libimobiledevice/misagent.h +++ b/include/libimobiledevice/misagent.h @@ -60,7 +60,7 @@ typedef misagent_client_private *misagent_client_t; /**< The client handle. */ * @return MISAGENT_E_SUCCESS on success, MISAGENT_E_INVALID_ARG when * client is NULL, or an MISAGENT_E_* error code otherwise. */ -misagent_error_t misagent_client_new(idevice_t device, lockdownd_service_descriptor_t service, misagent_client_t *client); +LIBIMOBILEDEVICE_API misagent_error_t misagent_client_new(idevice_t device, lockdownd_service_descriptor_t service, misagent_client_t *client); /** * Starts a new misagent service on the specified device and connects to it. @@ -75,7 +75,7 @@ misagent_error_t misagent_client_new(idevice_t device, lockdownd_service_descrip * @return MISAGENT_E_SUCCESS on success, or an MISAGENT_E_* error * code otherwise. */ -misagent_error_t misagent_client_start_service(idevice_t device, misagent_client_t* client, const char* label); +LIBIMOBILEDEVICE_API misagent_error_t misagent_client_start_service(idevice_t device, misagent_client_t* client, const char* label); /** * Disconnects an misagent client from the device and frees up the @@ -86,7 +86,7 @@ misagent_error_t misagent_client_start_service(idevice_t device, misagent_client * @return MISAGENT_E_SUCCESS on success, MISAGENT_E_INVALID_ARG when * client is NULL, or an MISAGENT_E_* error code otherwise. */ -misagent_error_t misagent_client_free(misagent_client_t client); +LIBIMOBILEDEVICE_API misagent_error_t misagent_client_free(misagent_client_t client); /** @@ -99,7 +99,7 @@ misagent_error_t misagent_client_free(misagent_client_t client); * @return MISAGENT_E_SUCCESS on success, MISAGENT_E_INVALID_ARG when * client is invalid, or an MISAGENT_E_* error code otherwise. */ -misagent_error_t misagent_install(misagent_client_t client, plist_t profile); +LIBIMOBILEDEVICE_API misagent_error_t misagent_install(misagent_client_t client, plist_t profile); /** * Retrieves all installed provisioning profiles (iOS 9.2.1 or below). @@ -118,7 +118,7 @@ misagent_error_t misagent_install(misagent_client_t client, plist_t profile); * still returns MISAGENT_E_SUCCESS and profiles will just point to an * empty array. */ -misagent_error_t misagent_copy(misagent_client_t client, plist_t* profiles); +LIBIMOBILEDEVICE_API misagent_error_t misagent_copy(misagent_client_t client, plist_t* profiles); /** * Retrieves all installed provisioning profiles (iOS 9.3 or higher). @@ -137,7 +137,7 @@ misagent_error_t misagent_copy(misagent_client_t client, plist_t* profiles); * still returns MISAGENT_E_SUCCESS and profiles will just point to an * empty array. */ -misagent_error_t misagent_copy_all(misagent_client_t client, plist_t* profiles); +LIBIMOBILEDEVICE_API misagent_error_t misagent_copy_all(misagent_client_t client, plist_t* profiles); /** * Removes a given provisioning profile. @@ -150,7 +150,7 @@ misagent_error_t misagent_copy_all(misagent_client_t client, plist_t* profiles); * @return MISAGENT_E_SUCCESS on success, MISAGENT_E_INVALID_ARG when * client is invalid, or an MISAGENT_E_* error code otherwise. */ -misagent_error_t misagent_remove(misagent_client_t client, const char* profileID); +LIBIMOBILEDEVICE_API misagent_error_t misagent_remove(misagent_client_t client, const char* profileID); /** * Retrieves the status code from the last operation. @@ -159,7 +159,7 @@ misagent_error_t misagent_remove(misagent_client_t client, const char* profileID * * @return -1 if client is invalid, or the status code from the last operation */ -int misagent_get_status_code(misagent_client_t client); +LIBIMOBILEDEVICE_API int misagent_get_status_code(misagent_client_t client); #ifdef __cplusplus } diff --git a/include/libimobiledevice/mobile_image_mounter.h b/include/libimobiledevice/mobile_image_mounter.h index 891df40..76bb61a 100644 --- a/include/libimobiledevice/mobile_image_mounter.h +++ b/include/libimobiledevice/mobile_image_mounter.h @@ -42,6 +42,7 @@ typedef enum { MOBILE_IMAGE_MOUNTER_E_CONN_FAILED = -3, MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED = -4, MOBILE_IMAGE_MOUNTER_E_DEVICE_LOCKED = -5, + MOBILE_IMAGE_MOUNTER_E_NOT_SUPPORTED = -6, MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR = -256 } mobile_image_mounter_error_t; @@ -66,7 +67,7 @@ typedef ssize_t (*mobile_image_mounter_upload_cb_t) (void* buffer, size_t length * or MOBILE_IMAGE_MOUNTER_E_CONN_FAILED if the connection to the * device could not be established. */ -mobile_image_mounter_error_t mobile_image_mounter_new(idevice_t device, lockdownd_service_descriptor_t service, mobile_image_mounter_client_t *client); +LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_new(idevice_t device, lockdownd_service_descriptor_t service, mobile_image_mounter_client_t *client); /** * Starts a new mobile_image_mounter service on the specified device and connects to it. @@ -81,7 +82,7 @@ mobile_image_mounter_error_t mobile_image_mounter_new(idevice_t device, lockdown * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on success, or an MOBILE_IMAGE_MOUNTER_E_* error * code otherwise. */ -mobile_image_mounter_error_t mobile_image_mounter_start_service(idevice_t device, mobile_image_mounter_client_t* client, const char* label); +LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_start_service(idevice_t device, mobile_image_mounter_client_t* client, const char* label); /** * Disconnects a mobile_image_mounter client from the device and frees up the @@ -92,7 +93,7 @@ mobile_image_mounter_error_t mobile_image_mounter_start_service(idevice_t device * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on success, * or MOBILE_IMAGE_MOUNTER_E_INVALID_ARG if client is NULL. */ -mobile_image_mounter_error_t mobile_image_mounter_free(mobile_image_mounter_client_t client); +LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_free(mobile_image_mounter_client_t client); /** @@ -108,7 +109,7 @@ mobile_image_mounter_error_t mobile_image_mounter_free(mobile_image_mounter_clie * * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on success, or an error code on error */ -mobile_image_mounter_error_t mobile_image_mounter_lookup_image(mobile_image_mounter_client_t client, const char *image_type, plist_t *result); +LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_lookup_image(mobile_image_mounter_client_t client, const char *image_type, plist_t *result); /** * Uploads an image with an optional signature to the device. @@ -127,7 +128,7 @@ mobile_image_mounter_error_t mobile_image_mounter_lookup_image(mobile_image_moun * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on succes, or a * MOBILE_IMAGE_MOUNTER_E_* error code otherwise. */ -mobile_image_mounter_error_t mobile_image_mounter_upload_image(mobile_image_mounter_client_t client, const char *image_type, size_t image_size, const char *signature, uint16_t signature_size, mobile_image_mounter_upload_cb_t upload_cb, void* userdata); +LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_upload_image(mobile_image_mounter_client_t client, const char *image_type, size_t image_size, const unsigned char *signature, unsigned int signature_size, mobile_image_mounter_upload_cb_t upload_cb, void* userdata); /** * Mounts an image on the device. @@ -138,19 +139,50 @@ mobile_image_mounter_error_t mobile_image_mounter_upload_image(mobile_image_moun * @param signature Pointer to a buffer holding the images' signature * @param signature_size Length of the signature image_signature points to * @param image_type Type of image to mount + * @param options A dictionary containing additional key/value pairs to add * @param result Pointer to a plist that will receive the result of the * operation. * * @note This function may return MOBILE_IMAGE_MOUNTER_E_SUCCESS even if the * operation has failed. Check the resulting plist for further information. - * Note that there is no unmounting function. The mount persists until the - * device is rebooted. * * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on success, * MOBILE_IMAGE_MOUNTER_E_INVALID_ARG if on ore more parameters are * invalid, or another error code otherwise. */ -mobile_image_mounter_error_t mobile_image_mounter_mount_image(mobile_image_mounter_client_t client, const char *image_path, const char *signature, uint16_t signature_size, const char *image_type, plist_t *result); +LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_mount_image_with_options(mobile_image_mounter_client_t client, const char *image_path, const unsigned char *signature, unsigned int signature_size, const char *image_type, plist_t options, plist_t *result); + +/** + * Mounts an image on the device. + * + * @param client The connected mobile_image_mounter client. + * @param image_path The absolute path of the image to mount. The image must + * be present before calling this function. + * @param signature Pointer to a buffer holding the images' signature + * @param signature_size Length of the signature image_signature points to + * @param image_type Type of image to mount + * @param result Pointer to a plist that will receive the result of the + * operation. + * + * @note This function may return MOBILE_IMAGE_MOUNTER_E_SUCCESS even if the + * operation has failed. Check the resulting plist for further information. + * + * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on success, + * MOBILE_IMAGE_MOUNTER_E_INVALID_ARG if on ore more parameters are + * invalid, or another error code otherwise. + */ +LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_mount_image(mobile_image_mounter_client_t client, const char *image_path, const unsigned char *signature, unsigned int signature_size, const char *image_type, plist_t *result); + +/** + * Unmount a mounted image at given path on the device. + * + * @param client The connected mobile_image_mounter client. + * @param mount_path The mount path of the mounted image on the device. + * + * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on success, + * or a MOBILE_IMAGE_MOUNTER_E_* error code on error. + */ +LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_unmount_image(mobile_image_mounter_client_t client, const char *mount_path); /** * Hangs up the connection to the mobile_image_mounter service. @@ -163,7 +195,78 @@ mobile_image_mounter_error_t mobile_image_mounter_mount_image(mobile_image_mount * MOBILE_IMAGE_MOUNTER_E_INVALID_ARG if client is invalid, * or another error code otherwise. */ -mobile_image_mounter_error_t mobile_image_mounter_hangup(mobile_image_mounter_client_t client); +LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_hangup(mobile_image_mounter_client_t client); + +/** + * Query the developer mode status of the given device. + * + * @param client The connected mobile_image_mounter client. + * @param result A pointer to a plist_t that will be set to the resulting developer mode status dictionary. + * + * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on success, + * or a MOBILE_IMAGE_MOUNTER_E_* error code on error. + */ +LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_query_developer_mode_status(mobile_image_mounter_client_t client, plist_t *result); + +/** + * Query a personalization nonce for the given image type, used for personalized disk images (iOS 17+). + * This nonce is supposed to be added to the TSS request for the corresponding image. + * + * @param client The connected mobile_image_mounter client. + * @param image_type The image_type to get the personalization nonce for, usually `DeveloperDiskImage`. + * @param nonce Pointer that will be set to an allocated buffer with the nonce value. + * @param nonce_size Pointer to an unsigned int that will receive the size of the nonce value. + * + * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on success, + * or a MOBILE_IMAGE_MOUNTER_E_* error code on error. + */ +LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_query_nonce(mobile_image_mounter_client_t client, const char* image_type, unsigned char** nonce, unsigned int* nonce_size); + +/** + * Query personalization identitifers for the given image_type. + * + * @param client The connected mobile_image_mounter client. + * @param image_type The image_type to get the personalization identifiers for. Can be NULL. + * @param result A pointer to a plist_t that will be set to the resulting identifier dictionary. + * + * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on success, + * or a MOBILE_IMAGE_MOUNTER_E_* error code on error. + */ +LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_query_personalization_identifiers(mobile_image_mounter_client_t client, const char* image_type, plist_t *result); + +/** + * + * @param client The connected mobile_image_mounter client. + * @param image_type The image_type to get the personalization identifiers for. Can be NULL. + * @param signature The signature of the corresponding personalized image. + * @param signature_size The size of signature. + * @param manifest Pointer that will be set to an allocated buffer with the manifest data. + * @param manifest_size Pointer to an unsigned int that will be set to the size of the manifest data. + * + * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on success, + * or a MOBILE_IMAGE_MOUNTER_E_* error code on error. + */ +LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_query_personalization_manifest(mobile_image_mounter_client_t client, const char* image_type, const unsigned char* signature, unsigned int signature_size, unsigned char** manifest, unsigned int* manifest_size); + +/** + * Roll the personalization nonce. + * + * @param client The connected mobile_image_mounter client. + * + * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on success, + * or a MOBILE_IMAGE_MOUNTER_E_* error code on error. + */ +LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_roll_personalization_nonce(mobile_image_mounter_client_t client); + +/** + * Roll the Cryptex nonce. + * + * @param client The connected mobile_image_mounter client. + * + * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on success, + * or a MOBILE_IMAGE_MOUNTER_E_* error code on error. + */ +LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_roll_cryptex_nonce(mobile_image_mounter_client_t client); #ifdef __cplusplus } diff --git a/include/libimobiledevice/mobileactivation.h b/include/libimobiledevice/mobileactivation.h index 774c116..8e036a8 100644 --- a/include/libimobiledevice/mobileactivation.h +++ b/include/libimobiledevice/mobileactivation.h @@ -59,7 +59,7 @@ typedef mobileactivation_client_private *mobileactivation_client_t; /**< The cli * MOBILEACTIVATION_E_INVALID_ARG when one of the parameters is invalid, * or MOBILEACTIVATION_E_MUX_ERROR when the connection failed. */ -mobileactivation_error_t mobileactivation_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobileactivation_client_t *client); +LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobileactivation_client_t *client); /** * Starts a new mobileactivation service on the specified device and connects to it. @@ -74,7 +74,7 @@ mobileactivation_error_t mobileactivation_client_new(idevice_t device, lockdownd * @return MOBILEACTIVATION_E_SUCCESS on success, or an MOBILEACTIVATION_E_* * error code otherwise. */ -mobileactivation_error_t mobileactivation_client_start_service(idevice_t device, mobileactivation_client_t* client, const char* label); +LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_client_start_service(idevice_t device, mobileactivation_client_t* client, const char* label); /** * Disconnects a mobileactivation client from the device and frees up the @@ -87,7 +87,7 @@ mobileactivation_error_t mobileactivation_client_start_service(idevice_t device, * is invalid, or MOBILEACTIVATION_E_UNKNOWN_ERROR when the was an * error freeing the parent property_list_service client. */ -mobileactivation_error_t mobileactivation_client_free(mobileactivation_client_t client); +LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_client_free(mobileactivation_client_t client); /** @@ -102,7 +102,7 @@ mobileactivation_error_t mobileactivation_client_free(mobileactivation_client_t * @return MOBILEACTIVATION_E_SUCCESS on success, or an MOBILEACTIVATION_E_* * error code otherwise. */ -mobileactivation_error_t mobileactivation_get_activation_state(mobileactivation_client_t client, plist_t *state); +LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_get_activation_state(mobileactivation_client_t client, plist_t *state); /** * Retrieves a session blob required for 'drmHandshake' via albert.apple.com. @@ -116,7 +116,7 @@ mobileactivation_error_t mobileactivation_get_activation_state(mobileactivation_ * @return MOBILEACTIVATION_E_SUCCESS on success, or an MOBILEACTIVATION_E_* * error code otherwise. */ -mobileactivation_error_t mobileactivation_create_activation_session_info(mobileactivation_client_t client, plist_t *blob); +LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_create_activation_session_info(mobileactivation_client_t client, plist_t *blob); /** * Retrieves the activation info required for device activation. @@ -130,7 +130,7 @@ mobileactivation_error_t mobileactivation_create_activation_session_info(mobilea * @return MOBILEACTIVATION_E_SUCCESS on success, or an MOBILEACTIVATION_E_* * error code otherwise. */ -mobileactivation_error_t mobileactivation_create_activation_info(mobileactivation_client_t client, plist_t *info); +LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_create_activation_info(mobileactivation_client_t client, plist_t *info); /** * Retrieves the activation info required for device activation in 'session' @@ -148,7 +148,7 @@ mobileactivation_error_t mobileactivation_create_activation_info(mobileactivatio * @return MOBILEACTIVATION_E_SUCCESS on success, or an MOBILEACTIVATION_E_* * error code otherwise. */ -mobileactivation_error_t mobileactivation_create_activation_info_with_session(mobileactivation_client_t client, plist_t handshake_response, plist_t *info); +LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_create_activation_info_with_session(mobileactivation_client_t client, plist_t handshake_response, plist_t *info); /** * Activates the device with the given activation record. @@ -161,7 +161,7 @@ mobileactivation_error_t mobileactivation_create_activation_info_with_session(mo * @return MOBILEACTIVATION_E_SUCCESS on success, or an MOBILEACTIVATION_E_* * error code otherwise. */ -mobileactivation_error_t mobileactivation_activate(mobileactivation_client_t client, plist_t activation_record); +LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_activate(mobileactivation_client_t client, plist_t activation_record); /** * Activates the device with the given activation record in 'session' mode. @@ -176,14 +176,14 @@ mobileactivation_error_t mobileactivation_activate(mobileactivation_client_t cli * @return MOBILEACTIVATION_E_SUCCESS on success, or an MOBILEACTIVATION_E_* * error code otherwise. */ -mobileactivation_error_t mobileactivation_activate_with_session(mobileactivation_client_t client, plist_t activation_record, plist_t headers); +LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_activate_with_session(mobileactivation_client_t client, plist_t activation_record, plist_t headers); /** * Deactivates the device. * * @param client The mobileactivation client */ -mobileactivation_error_t mobileactivation_deactivate(mobileactivation_client_t client); +LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_deactivate(mobileactivation_client_t client); #ifdef __cplusplus } diff --git a/include/libimobiledevice/mobilebackup.h b/include/libimobiledevice/mobilebackup.h index d4c042e..2ecb60c 100644 --- a/include/libimobiledevice/mobilebackup.h +++ b/include/libimobiledevice/mobilebackup.h @@ -69,7 +69,7 @@ typedef enum { * or more parameters are invalid, or DEVICE_LINK_SERVICE_E_BAD_VERSION if * the mobilebackup version on the device is newer. */ -mobilebackup_error_t mobilebackup_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobilebackup_client_t * client); +LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobilebackup_client_t * client); /** * Starts a new mobilebackup service on the specified device and connects to it. @@ -84,7 +84,7 @@ mobilebackup_error_t mobilebackup_client_new(idevice_t device, lockdownd_service * @return MOBILEBACKUP_E_SUCCESS on success, or an MOBILEBACKUP_E_* error * code otherwise. */ -mobilebackup_error_t mobilebackup_client_start_service(idevice_t device, mobilebackup_client_t* client, const char* label); +LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_client_start_service(idevice_t device, mobilebackup_client_t* client, const char* label); /** * Disconnects a mobilebackup client from the device and frees up the @@ -95,7 +95,7 @@ mobilebackup_error_t mobilebackup_client_start_service(idevice_t device, mobileb * @return MOBILEBACKUP_E_SUCCESS on success, or MOBILEBACKUP_E_INVALID_ARG * if client is NULL. */ -mobilebackup_error_t mobilebackup_client_free(mobilebackup_client_t client); +LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_client_free(mobilebackup_client_t client); /** @@ -106,7 +106,7 @@ mobilebackup_error_t mobilebackup_client_free(mobilebackup_client_t client); * * @return an error code */ -mobilebackup_error_t mobilebackup_receive(mobilebackup_client_t client, plist_t *plist); +LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_receive(mobilebackup_client_t client, plist_t *plist); /** * Sends mobilebackup data to the device @@ -119,7 +119,7 @@ mobilebackup_error_t mobilebackup_receive(mobilebackup_client_t client, plist_t * * @return an error code */ -mobilebackup_error_t mobilebackup_send(mobilebackup_client_t client, plist_t plist); +LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_send(mobilebackup_client_t client, plist_t plist); /** * Request a backup from the connected device. @@ -138,7 +138,7 @@ mobilebackup_error_t mobilebackup_send(mobilebackup_client_t client, plist_t pli * backup_manifest is not of type PLIST_DICT, MOBILEBACKUP_E_MUX_ERROR * if a communication error occurs, MOBILEBACKUP_E_REPLY_NOT_OK */ -mobilebackup_error_t mobilebackup_request_backup(mobilebackup_client_t client, plist_t backup_manifest, const char *base_path, const char *proto_version); +LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_request_backup(mobilebackup_client_t client, plist_t backup_manifest, const char *base_path, const char *proto_version); /** * Sends a confirmation to the device that a backup file has been received. @@ -149,7 +149,7 @@ mobilebackup_error_t mobilebackup_request_backup(mobilebackup_client_t client, p * client is invalid, or MOBILEBACKUP_E_MUX_ERROR if a communication error * occurs. */ -mobilebackup_error_t mobilebackup_send_backup_file_received(mobilebackup_client_t client); +LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_send_backup_file_received(mobilebackup_client_t client); /** * Request that a backup should be restored to the connected device. @@ -172,7 +172,7 @@ mobilebackup_error_t mobilebackup_send_backup_file_received(mobilebackup_client_ * if a communication error occurs, or MOBILEBACKUP_E_REPLY_NOT_OK * if the device did not accept the request. */ -mobilebackup_error_t mobilebackup_request_restore(mobilebackup_client_t client, plist_t backup_manifest, mobilebackup_flags_t flags, const char *proto_version); +LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_request_restore(mobilebackup_client_t client, plist_t backup_manifest, mobilebackup_flags_t flags, const char *proto_version); /** * Receive a confirmation from the device that it successfully received @@ -192,7 +192,7 @@ mobilebackup_error_t mobilebackup_request_restore(mobilebackup_client_t client, * message plist, or MOBILEBACKUP_E_MUX_ERROR if a communication error * occurs. */ -mobilebackup_error_t mobilebackup_receive_restore_file_received(mobilebackup_client_t client, plist_t *result); +LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_receive_restore_file_received(mobilebackup_client_t client, plist_t *result); /** * Receive a confirmation from the device that it successfully received @@ -212,7 +212,7 @@ mobilebackup_error_t mobilebackup_receive_restore_file_received(mobilebackup_cli * message plist, or MOBILEBACKUP_E_MUX_ERROR if a communication error * occurs. */ -mobilebackup_error_t mobilebackup_receive_restore_application_received(mobilebackup_client_t client, plist_t *result); +LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_receive_restore_application_received(mobilebackup_client_t client, plist_t *result); /** * Tells the device that the restore process is complete and waits for the @@ -225,7 +225,7 @@ mobilebackup_error_t mobilebackup_receive_restore_application_received(mobilebac * message plist is invalid, or MOBILEBACKUP_E_MUX_ERROR if a communication * error occurs. */ -mobilebackup_error_t mobilebackup_send_restore_complete(mobilebackup_client_t client); +LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_send_restore_complete(mobilebackup_client_t client); /** * Sends a backup error message to the device. @@ -237,7 +237,7 @@ mobilebackup_error_t mobilebackup_send_restore_complete(mobilebackup_client_t cl * one of the parameters is invalid, or MOBILEBACKUP_E_MUX_ERROR if a * communication error occurs. */ -mobilebackup_error_t mobilebackup_send_error(mobilebackup_client_t client, const char *reason); +LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_send_error(mobilebackup_client_t client, const char *reason); #ifdef __cplusplus } diff --git a/include/libimobiledevice/mobilebackup2.h b/include/libimobiledevice/mobilebackup2.h index 1af4141..2e9222d 100644 --- a/include/libimobiledevice/mobilebackup2.h +++ b/include/libimobiledevice/mobilebackup2.h @@ -64,7 +64,7 @@ typedef mobilebackup2_client_private *mobilebackup2_client_t; /**< The client ha * if one or more parameter is invalid, or MOBILEBACKUP2_E_BAD_VERSION * if the mobilebackup2 version on the device is newer. */ -mobilebackup2_error_t mobilebackup2_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobilebackup2_client_t * client); +LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobilebackup2_client_t * client); /** * Starts a new mobilebackup2 service on the specified device and connects to it. @@ -79,7 +79,7 @@ mobilebackup2_error_t mobilebackup2_client_new(idevice_t device, lockdownd_servi * @return MOBILEBACKUP2_E_SUCCESS on success, or an MOBILEBACKUP2_E_* error * code otherwise. */ -mobilebackup2_error_t mobilebackup2_client_start_service(idevice_t device, mobilebackup2_client_t* client, const char* label); +LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_client_start_service(idevice_t device, mobilebackup2_client_t* client, const char* label); /** * Disconnects a mobilebackup2 client from the device and frees up the @@ -90,7 +90,7 @@ mobilebackup2_error_t mobilebackup2_client_start_service(idevice_t device, mobil * @return MOBILEBACKUP2_E_SUCCESS on success, or MOBILEBACKUP2_E_INVALID_ARG * if client is NULL. */ -mobilebackup2_error_t mobilebackup2_client_free(mobilebackup2_client_t client); +LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_client_free(mobilebackup2_client_t client); /** @@ -105,7 +105,7 @@ mobilebackup2_error_t mobilebackup2_client_free(mobilebackup2_client_t client); * will be inserted into this plist before sending it. This parameter * can be NULL if message is not NULL. */ -mobilebackup2_error_t mobilebackup2_send_message(mobilebackup2_client_t client, const char *message, plist_t options); +LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_send_message(mobilebackup2_client_t client, const char *message, plist_t options); /** * Receives a DL* message plist from the device. @@ -125,7 +125,7 @@ mobilebackup2_error_t mobilebackup2_send_message(mobilebackup2_client_t client, * or is not a DL* message plist, or MOBILEBACKUP2_E_MUX_ERROR if * receiving from the device failed. */ -mobilebackup2_error_t mobilebackup2_receive_message(mobilebackup2_client_t client, plist_t *msg_plist, char **dlmessage); +LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_receive_message(mobilebackup2_client_t client, plist_t *msg_plist, char **dlmessage); /** * Send binary data to the device. @@ -143,7 +143,7 @@ mobilebackup2_error_t mobilebackup2_receive_message(mobilebackup2_client_t clien * MOBILEBACKUP2_E_INVALID_ARG if one of the parameters is invalid, * or MOBILEBACKUP2_E_MUX_ERROR if sending of the data failed. */ -mobilebackup2_error_t mobilebackup2_send_raw(mobilebackup2_client_t client, const char *data, uint32_t length, uint32_t *bytes); +LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_send_raw(mobilebackup2_client_t client, const char *data, uint32_t length, uint32_t *bytes); /** * Receive binary from the device. @@ -163,7 +163,7 @@ mobilebackup2_error_t mobilebackup2_send_raw(mobilebackup2_client_t client, cons * MOBILEBACKUP2_E_INVALID_ARG if one of the parameters is invalid, * or MOBILEBACKUP2_E_MUX_ERROR if receiving the data failed. */ -mobilebackup2_error_t mobilebackup2_receive_raw(mobilebackup2_client_t client, char *data, uint32_t length, uint32_t *bytes); +LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_receive_raw(mobilebackup2_client_t client, char *data, uint32_t length, uint32_t *bytes); /** * Performs the mobilebackup2 protocol version exchange. @@ -176,7 +176,7 @@ mobilebackup2_error_t mobilebackup2_receive_raw(mobilebackup2_client_t client, c * @return MOBILEBACKUP2_E_SUCCESS on success, or a MOBILEBACKUP2_E_* error * code otherwise. */ -mobilebackup2_error_t mobilebackup2_version_exchange(mobilebackup2_client_t client, double local_versions[], char count, double *remote_version); +LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_version_exchange(mobilebackup2_client_t client, double local_versions[], char count, double *remote_version); /** * Send a request to the connected mobilebackup2 service. @@ -191,7 +191,7 @@ mobilebackup2_error_t mobilebackup2_version_exchange(mobilebackup2_client_t clie * @return MOBILEBACKUP2_E_SUCCESS if the request was successfully sent, * or a MOBILEBACKUP2_E_* error value otherwise. */ -mobilebackup2_error_t mobilebackup2_send_request(mobilebackup2_client_t client, const char *request, const char *target_identifier, const char *source_identifier, plist_t options); +LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_send_request(mobilebackup2_client_t client, const char *request, const char *target_identifier, const char *source_identifier, plist_t options); /** * Sends a DLMessageStatusResponse to the device. @@ -205,7 +205,7 @@ mobilebackup2_error_t mobilebackup2_send_request(mobilebackup2_client_t client, * @return MOBILEBACKUP2_E_SUCCESS on success, MOBILEBACKUP2_E_INVALID_ARG * if client is invalid, or another MOBILEBACKUP2_E_* otherwise. */ -mobilebackup2_error_t mobilebackup2_send_status_response(mobilebackup2_client_t client, int status_code, const char *status1, plist_t status2); +LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_send_status_response(mobilebackup2_client_t client, int status_code, const char *status1, plist_t status2); #ifdef __cplusplus } diff --git a/include/libimobiledevice/mobilesync.h b/include/libimobiledevice/mobilesync.h index 6b1af18..c3bc53d 100644 --- a/include/libimobiledevice/mobilesync.h +++ b/include/libimobiledevice/mobilesync.h @@ -86,7 +86,7 @@ typedef mobilesync_anchors *mobilesync_anchors_t; * @retval DEVICE_LINK_SERVICE_E_BAD_VERSION if the mobilesync version on * the device is newer. */ -mobilesync_error_t mobilesync_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobilesync_client_t * client); +LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobilesync_client_t * client); /** * Starts a new mobilesync service on the specified device and connects to it. @@ -101,7 +101,7 @@ mobilesync_error_t mobilesync_client_new(idevice_t device, lockdownd_service_des * @return MOBILESYNC_E_SUCCESS on success, or an MOBILESYNC_E_* error * code otherwise. */ -mobilesync_error_t mobilesync_client_start_service(idevice_t device, mobilesync_client_t* client, const char* label); +LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_client_start_service(idevice_t device, mobilesync_client_t* client, const char* label); /** * Disconnects a mobilesync client from the device and frees up the @@ -112,7 +112,7 @@ mobilesync_error_t mobilesync_client_start_service(idevice_t device, mobilesync_ * @retval MOBILESYNC_E_SUCCESS on success * @retval MOBILESYNC_E_INVALID_ARG if \a client is NULL. */ -mobilesync_error_t mobilesync_client_free(mobilesync_client_t client); +LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_client_free(mobilesync_client_t client); /** @@ -123,7 +123,7 @@ mobilesync_error_t mobilesync_client_free(mobilesync_client_t client); * * @return an error code */ -mobilesync_error_t mobilesync_receive(mobilesync_client_t client, plist_t *plist); +LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_receive(mobilesync_client_t client, plist_t *plist); /** * Sends mobilesync data to the device @@ -136,7 +136,7 @@ mobilesync_error_t mobilesync_receive(mobilesync_client_t client, plist_t *plist * * @return an error code */ -mobilesync_error_t mobilesync_send(mobilesync_client_t client, plist_t plist); +LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_send(mobilesync_client_t client, plist_t plist); /** @@ -159,7 +159,7 @@ mobilesync_error_t mobilesync_send(mobilesync_client_t client, plist_t plist); * @retval MOBILESYNC_E_CANCELLED if the device explicitly cancelled the * sync request */ -mobilesync_error_t mobilesync_start(mobilesync_client_t client, const char *data_class, mobilesync_anchors_t anchors, uint64_t computer_data_class_version, mobilesync_sync_type_t *sync_type, uint64_t *device_data_class_version, char** error_description); +LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_start(mobilesync_client_t client, const char *data_class, mobilesync_anchors_t anchors, uint64_t computer_data_class_version, mobilesync_sync_type_t *sync_type, uint64_t *device_data_class_version, char** error_description); /** * Cancels a running synchronization session with a device at any time. @@ -170,7 +170,7 @@ mobilesync_error_t mobilesync_start(mobilesync_client_t client, const char *data * @retval MOBILESYNC_E_SUCCESS on success * @retval MOBILESYNC_E_INVALID_ARG if one of the parameters is invalid */ -mobilesync_error_t mobilesync_cancel(mobilesync_client_t client, const char* reason); +LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_cancel(mobilesync_client_t client, const char* reason); /** * Finish a synchronization session of a data class on the device. @@ -183,7 +183,7 @@ mobilesync_error_t mobilesync_cancel(mobilesync_client_t client, const char* rea * @retval MOBILESYNC_E_PLIST_ERROR if the received plist is not of valid * form */ -mobilesync_error_t mobilesync_finish(mobilesync_client_t client); +LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_finish(mobilesync_client_t client); /** @@ -196,7 +196,7 @@ mobilesync_error_t mobilesync_finish(mobilesync_client_t client); * @retval MOBILESYNC_E_SUCCESS on success * @retval MOBILESYNC_E_INVALID_ARG if one of the parameters is invalid */ -mobilesync_error_t mobilesync_get_all_records_from_device(mobilesync_client_t client); +LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_get_all_records_from_device(mobilesync_client_t client); /** * Requests to receive only changed records of the currently set data class from the device. @@ -208,7 +208,7 @@ mobilesync_error_t mobilesync_get_all_records_from_device(mobilesync_client_t cl * @retval MOBILESYNC_E_SUCCESS on success * @retval MOBILESYNC_E_INVALID_ARG if one of the parameters is invalid */ -mobilesync_error_t mobilesync_get_changes_from_device(mobilesync_client_t client); +LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_get_changes_from_device(mobilesync_client_t client); /** * Requests the device to delete all records of the current data class @@ -221,7 +221,7 @@ mobilesync_error_t mobilesync_get_changes_from_device(mobilesync_client_t client * @retval MOBILESYNC_E_INVALID_ARG if one of the parameters is invalid * @retval MOBILESYNC_E_PLIST_ERROR if the received plist is not of valid form */ -mobilesync_error_t mobilesync_clear_all_records_on_device(mobilesync_client_t client); +LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_clear_all_records_on_device(mobilesync_client_t client); /** @@ -237,7 +237,7 @@ mobilesync_error_t mobilesync_clear_all_records_on_device(mobilesync_client_t cl * @retval MOBILESYNC_E_CANCELLED if the device explicitly cancelled the * session */ -mobilesync_error_t mobilesync_receive_changes(mobilesync_client_t client, plist_t *entities, uint8_t *is_last_record, plist_t *actions); +LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_receive_changes(mobilesync_client_t client, plist_t *entities, uint8_t *is_last_record, plist_t *actions); /** * Acknowledges to the device that the changes have been merged on the computer @@ -247,7 +247,7 @@ mobilesync_error_t mobilesync_receive_changes(mobilesync_client_t client, plist_ * @retval MOBILESYNC_E_SUCCESS on success * @retval MOBILESYNC_E_INVALID_ARG if one of the parameters is invalid */ -mobilesync_error_t mobilesync_acknowledge_changes_from_device(mobilesync_client_t client); +LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_acknowledge_changes_from_device(mobilesync_client_t client); /** @@ -267,7 +267,7 @@ mobilesync_error_t mobilesync_acknowledge_changes_from_device(mobilesync_client_ * @retval MOBILESYNC_E_NOT_READY if the device is not ready to start * receiving any changes */ -mobilesync_error_t mobilesync_ready_to_send_changes_from_computer(mobilesync_client_t client); +LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_ready_to_send_changes_from_computer(mobilesync_client_t client); /** @@ -284,7 +284,7 @@ mobilesync_error_t mobilesync_ready_to_send_changes_from_computer(mobilesync_cli * @retval MOBILESYNC_E_WRONG_DIRECTION if the current sync direction does * not permit this call */ -mobilesync_error_t mobilesync_send_changes(mobilesync_client_t client, plist_t entities, uint8_t is_last_record, plist_t actions); +LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_send_changes(mobilesync_client_t client, plist_t entities, uint8_t is_last_record, plist_t actions); /** * Receives any remapped identifiers reported after the device merged submitted changes. @@ -301,7 +301,7 @@ mobilesync_error_t mobilesync_send_changes(mobilesync_client_t client, plist_t e * @retval MOBILESYNC_E_CANCELLED if the device explicitly cancelled the * session */ -mobilesync_error_t mobilesync_remap_identifiers(mobilesync_client_t client, plist_t *mapping); +LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_remap_identifiers(mobilesync_client_t client, plist_t *mapping); /* Helper */ @@ -314,14 +314,14 @@ mobilesync_error_t mobilesync_remap_identifiers(mobilesync_client_t client, plis * * @return A new #mobilesync_anchors_t struct. Must be freed using mobilesync_anchors_free(). */ -mobilesync_anchors_t mobilesync_anchors_new(const char *device_anchor, const char *computer_anchor); +LIBIMOBILEDEVICE_API mobilesync_anchors_t mobilesync_anchors_new(const char *device_anchor, const char *computer_anchor); /** * Free memory used by anchors. * * @param anchors The anchors to free. */ -void mobilesync_anchors_free(mobilesync_anchors_t anchors); +LIBIMOBILEDEVICE_API void mobilesync_anchors_free(mobilesync_anchors_t anchors); /** @@ -329,7 +329,7 @@ void mobilesync_anchors_free(mobilesync_anchors_t anchors); * * @return A new plist_t of type PLIST_DICT. */ -plist_t mobilesync_actions_new(void); +LIBIMOBILEDEVICE_API plist_t mobilesync_actions_new(void); /** * Add one or more new key:value pairs to the given actions plist. @@ -343,14 +343,14 @@ plist_t mobilesync_actions_new(void); * integer to use as a boolean value indicating that the device should * link submitted changes and report remapped identifiers. */ -void mobilesync_actions_add(plist_t actions, ...); +LIBIMOBILEDEVICE_API void mobilesync_actions_add(plist_t actions, ...); /** * Free actions plist. * * @param actions The actions plist to free. Does nothing if NULL is passed. */ -void mobilesync_actions_free(plist_t actions); +LIBIMOBILEDEVICE_API void mobilesync_actions_free(plist_t actions); #ifdef __cplusplus } diff --git a/include/libimobiledevice/notification_proxy.h b/include/libimobiledevice/notification_proxy.h index 4eccf20..f4f090b 100644 --- a/include/libimobiledevice/notification_proxy.h +++ b/include/libimobiledevice/notification_proxy.h @@ -109,7 +109,7 @@ typedef void (*np_notify_cb_t) (const char *notification, void *user_data); * or NP_E_CONN_FAILED when the connection to the device could not be * established. */ -np_error_t np_client_new(idevice_t device, lockdownd_service_descriptor_t service, np_client_t *client); +LIBIMOBILEDEVICE_API np_error_t np_client_new(idevice_t device, lockdownd_service_descriptor_t service, np_client_t *client); /** * Starts a new notification proxy service on the specified device and connects to it. @@ -124,7 +124,7 @@ np_error_t np_client_new(idevice_t device, lockdownd_service_descriptor_t servic * @return NP_E_SUCCESS on success, or an NP_E_* error * code otherwise. */ -np_error_t np_client_start_service(idevice_t device, np_client_t* client, const char* label); +LIBIMOBILEDEVICE_API np_error_t np_client_start_service(idevice_t device, np_client_t* client, const char* label); /** * Disconnects a notification_proxy client from the device and frees up the @@ -134,7 +134,7 @@ np_error_t np_client_start_service(idevice_t device, np_client_t* client, const * * @return NP_E_SUCCESS on success, or NP_E_INVALID_ARG when client is NULL. */ -np_error_t np_client_free(np_client_t client); +LIBIMOBILEDEVICE_API np_error_t np_client_free(np_client_t client); /** @@ -145,7 +145,7 @@ np_error_t np_client_free(np_client_t client); * * @return NP_E_SUCCESS on success, or an error returned by np_plist_send */ -np_error_t np_post_notification(np_client_t client, const char *notification); +LIBIMOBILEDEVICE_API np_error_t np_post_notification(np_client_t client, const char *notification); /** * Tells the device to send a notification on the specified event. @@ -156,7 +156,7 @@ np_error_t np_post_notification(np_client_t client, const char *notification); * @return NP_E_SUCCESS on success, NP_E_INVALID_ARG when client or * notification are NULL, or an error returned by np_plist_send. */ -np_error_t np_observe_notification(np_client_t client, const char *notification); +LIBIMOBILEDEVICE_API np_error_t np_observe_notification(np_client_t client, const char *notification); /** * Tells the device to send a notification on specified events. @@ -169,7 +169,7 @@ np_error_t np_observe_notification(np_client_t client, const char *notification) * @return NP_E_SUCCESS on success, NP_E_INVALID_ARG when client is null, * or an error returned by np_observe_notification. */ -np_error_t np_observe_notifications(np_client_t client, const char **notification_spec); +LIBIMOBILEDEVICE_API np_error_t np_observe_notifications(np_client_t client, const char **notification_spec); /** * This function allows an application to define a callback function that will @@ -193,7 +193,7 @@ np_error_t np_observe_notifications(np_client_t client, const char **notificatio * NP_E_INVALID_ARG when client is NULL, or NP_E_UNKNOWN_ERROR when * the callback thread could no be created. */ -np_error_t np_set_notify_callback(np_client_t client, np_notify_cb_t notify_cb, void *user_data); +LIBIMOBILEDEVICE_API np_error_t np_set_notify_callback(np_client_t client, np_notify_cb_t notify_cb, void *user_data); #ifdef __cplusplus } diff --git a/include/libimobiledevice/ostrace.h b/include/libimobiledevice/ostrace.h new file mode 100644 index 0000000..f083ba7 --- /dev/null +++ b/include/libimobiledevice/ostrace.h @@ -0,0 +1,198 @@ +/** + * @file libimobiledevice/ostrace.h + * @brief System log and tracing capabilities. + * \internal + * + * 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 + +#ifdef __cplusplus +extern "C" { +#endif + +#include <libimobiledevice/libimobiledevice.h> +#include <libimobiledevice/lockdown.h> + +/** Service identifier passed to lockdownd_start_service() to start the os trace relay service */ +#define OSTRACE_SERVICE_NAME "com.apple.os_trace_relay" + +/** Error Codes */ +typedef enum { + OSTRACE_E_SUCCESS = 0, + OSTRACE_E_INVALID_ARG = -1, + OSTRACE_E_MUX_ERROR = -2, + OSTRACE_E_SSL_ERROR = -3, + OSTRACE_E_NOT_ENOUGH_DATA = -4, + OSTRACE_E_TIMEOUT = -5, + OSTRACE_E_PLIST_ERROR = -6, + OSTRACE_E_REQUEST_FAILED = -7, + OSTRACE_E_UNKNOWN_ERROR = -256 +} ostrace_error_t; + +typedef struct ostrace_client_private ostrace_client_private; /**< \private */ +typedef ostrace_client_private *ostrace_client_t; /**< The client handle. */ + +#pragma pack(push,1) +struct ostrace_packet_header_t { + uint8_t marker; + uint32_t type; + uint32_t header_size; // 0x81 + uint32_t pid; + uint64_t procid; // == pid + unsigned char procuuid[16]; // procuuid + uint16_t procpath_len; // path to process + uint64_t aid; // activity id, usually 0 + uint64_t paid; // (parent?) activity id, usually 0 + uint64_t time_sec; // tv.tv_sec 64 bit + uint32_t time_usec; // tv.usec 32 bit + uint8_t unk06; + uint8_t level; // Notice=0, Info=0x01, Debug=0x02, Error=0x10, Fault=0x11 + uint8_t unk07; + uint8_t unk08; + uint8_t unk09; + uint8_t unk10; + uint8_t unk11; + uint8_t unk12; + uint64_t timestamp; // ? + uint32_t thread_id; + uint32_t unk13; // 0 + unsigned char imageuuid[16]; // framework/dylib uuid + uint16_t imagepath_len; // framework/dylib + uint32_t message_len; // actual log message + uint32_t offset; // offset for like timestamp or sth + uint16_t subsystem_len; // "subsystem" + uint16_t unk14; + uint16_t category_len; // "category" + uint16_t unk15; + uint32_t unk16; // 0 +}; +#pragma pack(pop) + +/** Receives unparsed ostrace data from the ostrace service */ +typedef void (*ostrace_activity_cb_t)(const void* buf, size_t len, void *user_data); + +/** Receives archive data from the ostrace service */ +typedef int (*ostrace_archive_write_cb_t)(const void* buf, size_t len, void *user_data); + +/* Interface */ + +/** + * Connects to the os_trace_relay service on the specified device. + * + * @param device The device to connect to. + * @param service The service descriptor returned by lockdownd_start_service. + * @param client Pointer that will point to a newly allocated + * ostrace_client_t upon successful return. Must be freed using + * ostrace_client_free() after use. + * + * @return OSTRACE_E_SUCCESS on success, OSTRACE_E_INVALID_ARG when + * client is NULL, or an OSTRACE_E_* error code otherwise. + */ +LIBIMOBILEDEVICE_API ostrace_error_t ostrace_client_new(idevice_t device, lockdownd_service_descriptor_t service, ostrace_client_t * client); + +/** + * Starts a new os_trace_relay service on the specified device and connects to it. + * + * @param device The device to connect to. + * @param client Pointer that will point to a newly allocated + * ostrace_client_t upon successful return. Must be freed using + * ostrace_client_free() after use. + * @param label The label to use for communication. Usually the program name. + * Pass NULL to disable sending the label in requests to lockdownd. + * + * @return OSTRACE_E_SUCCESS on success, or an OSTRACE_E_* error code otherwise. + */ +LIBIMOBILEDEVICE_API ostrace_error_t ostrace_client_start_service(idevice_t device, ostrace_client_t * client, const char* label); + +/** + * Disconnects a ostrace client from the device and frees up the + * ostrace client data. + * + * @param client The ostrace client to disconnect and free. + * + * @return OSTRACE_E_SUCCESS on success, OSTRACE_E_INVALID_ARG when + * client is NULL, or an OSTRACE_E_* error code otherwise. + */ +LIBIMOBILEDEVICE_API ostrace_error_t ostrace_client_free(ostrace_client_t client); + +/** + * Starts capturing OS trace activity data of the device using a callback. + * + * Use ostrace_stop_activity() to stop receiving the ostrace. + * + * @param client The ostrace client to use + * @param options Options dictionary to pass to StartActivity request. + * Valid options are MessageFilter (PLIST_INT, default 65535), + * Pid (PLIST_INT, default -1), and StreamFlags (PLIST_INT, default 60) + * @param callback Callback to receive data from ostrace. + * @param user_data Custom pointer passed to the callback function. + * @param user_data_free_func Function pointer that will be called when the + * activity is stopped to release user_data. Can be NULL for none. + * + * @return OSTRACE_E_SUCCESS on success, + * OSTRACE_E_INVALID_ARG when one or more parameters are + * invalid or OSTRACE_E_UNKNOWN_ERROR when an unspecified + * error occurs or an ostrace activity has already been started. + */ +LIBIMOBILEDEVICE_API ostrace_error_t ostrace_start_activity(ostrace_client_t client, plist_t options, ostrace_activity_cb_t callback, void* user_data); + +/** + * Stops the ostrace activity. + * + * Use ostrace_start_activity() to start receiving OS trace data. + * + * @param client The ostrace client to use + * + * @return OSTRACE_E_SUCCESS on success, + * OSTRACE_E_INVALID_ARG when one or more parameters are + * invalid or OSTRACE_E_UNKNOWN_ERROR when an unspecified + * error occurs or an ostrace activity has already been started. + */ +LIBIMOBILEDEVICE_API ostrace_error_t ostrace_stop_activity(ostrace_client_t client); + +/** + * Returns a dictionary with all currently running processes on the device. + * + * @param client The ostrace client to use + * @param list Pointer that will receive an allocated PLIST_DICT structure with the process data + * + * @return OSTRACE_E_SUCCESS on success, or an OSTRACE_E_* error code otherwise + */ +LIBIMOBILEDEVICE_API ostrace_error_t ostrace_get_pid_list(ostrace_client_t client, plist_t* list); + +/** + * Creates a syslog archive. + * + * @note The device will close the connection once the transfer is complete. The client + * is not usable after that anymore and must be disposed with ostrace_client_free. + * + * @param client The ostrace client to use + * @param options A dictionary with options for the request. + * Valid parameters are StartTime (PLIST_UINT), SizeLimit (PLIST_UINT), and AgeLimit (PLIST_UINT). + * + * @return OSTRACE_E_SUCCESS on success, or an OSTRACE_E_* error code otherwise + */ +LIBIMOBILEDEVICE_API ostrace_error_t ostrace_create_archive(ostrace_client_t client, plist_t options, ostrace_archive_write_cb_t callback, void* user_data); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/libimobiledevice/preboard.h b/include/libimobiledevice/preboard.h index 88e9806..0d89eb4 100644 --- a/include/libimobiledevice/preboard.h +++ b/include/libimobiledevice/preboard.h @@ -64,7 +64,7 @@ typedef void (*preboard_status_cb_t) (plist_t message, void *user_data); * @return PREBOARD_E_SUCCESS on success, PREBOARD_E_INVALID_ARG when * client is NULL, or an PREBOARD_E_* error code otherwise. */ -preboard_error_t preboard_client_new(idevice_t device, lockdownd_service_descriptor_t service, preboard_client_t * client); +LIBIMOBILEDEVICE_API preboard_error_t preboard_client_new(idevice_t device, lockdownd_service_descriptor_t service, preboard_client_t * client); /** * Starts a new preboard service on the specified device and connects to it. @@ -79,7 +79,7 @@ preboard_error_t preboard_client_new(idevice_t device, lockdownd_service_descrip * @return PREBOARD_E_SUCCESS on success, or a PREBOARD_E_* error * code otherwise. */ -preboard_error_t preboard_client_start_service(idevice_t device, preboard_client_t * client, const char* label); +LIBIMOBILEDEVICE_API preboard_error_t preboard_client_start_service(idevice_t device, preboard_client_t * client, const char* label); /** * Disconnects a preboard client from the device and frees up the @@ -90,7 +90,7 @@ preboard_error_t preboard_client_start_service(idevice_t device, preboard_client * @return PREBOARD_E_SUCCESS on success, PREBOARD_E_INVALID_ARG when * client is NULL, or a PREBOARD_E_* error code otherwise. */ -preboard_error_t preboard_client_free(preboard_client_t client); +LIBIMOBILEDEVICE_API preboard_error_t preboard_client_free(preboard_client_t client); /** * Sends a plist to the service. @@ -102,7 +102,7 @@ preboard_error_t preboard_client_free(preboard_client_t client); * PREBOARD_E_INVALID_ARG when client or plist is NULL, * or a PREBOARD_E_* error code on error */ -preboard_error_t preboard_send(preboard_client_t client, plist_t plist); +LIBIMOBILEDEVICE_API preboard_error_t preboard_send(preboard_client_t client, plist_t plist); /** * Receives a plist from the service. @@ -115,7 +115,7 @@ preboard_error_t preboard_send(preboard_client_t client, plist_t plist); * PREBOARD_E_TIMEOUT when no data was received after 5 seconds, * or a PREBOARD_E_* error code on error */ -preboard_error_t preboard_receive(preboard_client_t client, plist_t * plist); +LIBIMOBILEDEVICE_API preboard_error_t preboard_receive(preboard_client_t client, plist_t * plist); /** * Receives a plist from the service with the specified timeout. @@ -129,7 +129,7 @@ preboard_error_t preboard_receive(preboard_client_t client, plist_t * plist); * PREBOARD_E_TIMEOUT when no data was received after the given timeout, * or a PREBOARD_E_* error code on error. */ -preboard_error_t preboard_receive_with_timeout(preboard_client_t client, plist_t * plist, uint32_t timeout_ms); +LIBIMOBILEDEVICE_API preboard_error_t preboard_receive_with_timeout(preboard_client_t client, plist_t * plist, uint32_t timeout_ms); /** * Tells the preboard service to create a stashbag. This will make the device @@ -157,7 +157,7 @@ preboard_error_t preboard_receive_with_timeout(preboard_client_t client, plist_t * PREBOARD_E_INVALID_ARG when client is invalid, * or a PREBOARD_E_* error code on error. */ -preboard_error_t preboard_create_stashbag(preboard_client_t client, plist_t manifest, preboard_status_cb_t status_cb, void *user_data); +LIBIMOBILEDEVICE_API preboard_error_t preboard_create_stashbag(preboard_client_t client, plist_t manifest, preboard_status_cb_t status_cb, void *user_data); /** * Instructs the preboard service to commit a previously created stashbag. @@ -178,7 +178,7 @@ preboard_error_t preboard_create_stashbag(preboard_client_t client, plist_t mani * PREBOARD_E_INVALID_ARG when client is invalid, * or a PREBOARD_E_* error code on error. */ -preboard_error_t preboard_commit_stashbag(preboard_client_t client, plist_t manifest, preboard_status_cb_t status_cb, void *user_data); +LIBIMOBILEDEVICE_API preboard_error_t preboard_commit_stashbag(preboard_client_t client, plist_t manifest, preboard_status_cb_t status_cb, void *user_data); #ifdef __cplusplus } diff --git a/include/libimobiledevice/property_list_service.h b/include/libimobiledevice/property_list_service.h index 3f6ebad..e6b26a3 100644 --- a/include/libimobiledevice/property_list_service.h +++ b/include/libimobiledevice/property_list_service.h @@ -60,7 +60,7 @@ typedef property_list_service_private* property_list_service_client_t; /**< The * PROPERTY_LIST_SERVICE_E_INVALID_ARG when one of the arguments is invalid, * or PROPERTY_LIST_SERVICE_E_MUX_ERROR when connecting to the device failed. */ -property_list_service_error_t property_list_service_client_new(idevice_t device, lockdownd_service_descriptor_t service, property_list_service_client_t *client); +LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_client_new(idevice_t device, lockdownd_service_descriptor_t service, property_list_service_client_t *client); /** * Frees a PropertyList service. @@ -71,7 +71,7 @@ property_list_service_error_t property_list_service_client_new(idevice_t device, * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client is invalid, or a * PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when another error occurred. */ -property_list_service_error_t property_list_service_client_free(property_list_service_client_t client); +LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_client_free(property_list_service_client_t client); /** * Sends an XML plist. @@ -84,7 +84,7 @@ property_list_service_error_t property_list_service_client_free(property_list_se * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when dict is not a valid plist, * or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when an unspecified error occurs. */ -property_list_service_error_t property_list_service_send_xml_plist(property_list_service_client_t client, plist_t plist); +LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_send_xml_plist(property_list_service_client_t client, plist_t plist); /** * Sends a binary plist. @@ -97,7 +97,7 @@ property_list_service_error_t property_list_service_send_xml_plist(property_list * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when dict is not a valid plist, * or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when an unspecified error occurs. */ -property_list_service_error_t property_list_service_send_binary_plist(property_list_service_client_t client, plist_t plist); +LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_send_binary_plist(property_list_service_client_t client, plist_t plist); /** * Receives a plist using the given property list service client with specified @@ -116,7 +116,7 @@ property_list_service_error_t property_list_service_send_binary_plist(property_l * communication error occurs, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when * an unspecified error occurs. */ -property_list_service_error_t property_list_service_receive_plist_with_timeout(property_list_service_client_t client, plist_t *plist, unsigned int timeout); +LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_receive_plist_with_timeout(property_list_service_client_t client, plist_t *plist, unsigned int timeout); /** * Receives a plist using the given property list service client. @@ -139,7 +139,7 @@ property_list_service_error_t property_list_service_receive_plist_with_timeout(p * communication error occurs, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when * an unspecified error occurs. */ -property_list_service_error_t property_list_service_receive_plist(property_list_service_client_t client, plist_t *plist); +LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_receive_plist(property_list_service_client_t client, plist_t *plist); /** * Enable SSL for the given property list service client. @@ -152,7 +152,7 @@ property_list_service_error_t property_list_service_receive_plist(property_list_ * PROPERTY_LIST_SERVICE_E_SSL_ERROR when SSL could not be enabled, * or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR otherwise. */ -property_list_service_error_t property_list_service_enable_ssl(property_list_service_client_t client); +LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_enable_ssl(property_list_service_client_t client); /** * Disable SSL for the given property list service client. @@ -164,7 +164,7 @@ property_list_service_error_t property_list_service_enable_ssl(property_list_ser * PROPERTY_LIST_SERVICE_E_INVALID_ARG if one or more of the arguments are invalid, * or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR otherwise. */ -property_list_service_error_t property_list_service_disable_ssl(property_list_service_client_t client); +LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_disable_ssl(property_list_service_client_t client); /** * Return a handle to the parent #service_client_t of the given property list service client. @@ -175,7 +175,7 @@ property_list_service_error_t property_list_service_disable_ssl(property_list_se * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, * PROPERTY_LIST_SERVICE_E_INVALID_ARG if one or more of the arguments are invalid. */ -property_list_service_error_t property_list_service_get_service_client(property_list_service_client_t client, service_client_t *service_client); +LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_get_service_client(property_list_service_client_t client, service_client_t *service_client); #ifdef __cplusplus } diff --git a/include/libimobiledevice/restore.h b/include/libimobiledevice/restore.h index 0017cfd..859dc98 100644 --- a/include/libimobiledevice/restore.h +++ b/include/libimobiledevice/restore.h @@ -56,7 +56,7 @@ typedef restored_client_private *restored_client_t; /**< The client handle. */ * * @return RESTORE_E_SUCCESS on success, RESTORE_E_INVALID_ARG when client is NULL */ -restored_error_t restored_client_new(idevice_t device, restored_client_t *client, const char *label); +LIBIMOBILEDEVICE_API restored_error_t restored_client_new(idevice_t device, restored_client_t *client, const char *label); /** * Closes the restored client session if one is running and frees up the @@ -66,7 +66,7 @@ restored_error_t restored_client_new(idevice_t device, restored_client_t *client * * @return RESTORE_E_SUCCESS on success, RESTORE_E_INVALID_ARG when client is NULL */ -restored_error_t restored_client_free(restored_client_t client); +LIBIMOBILEDEVICE_API restored_error_t restored_client_free(restored_client_t client); /** @@ -79,7 +79,7 @@ restored_error_t restored_client_free(restored_client_t client); * * @return RESTORE_E_SUCCESS on success, RESTORE_E_INVALID_ARG when client is NULL */ -restored_error_t restored_query_type(restored_client_t client, char **type, uint64_t *version); +LIBIMOBILEDEVICE_API restored_error_t restored_query_type(restored_client_t client, char **type, uint64_t *version); /** * Queries a value from the device specified by a key. @@ -90,7 +90,7 @@ restored_error_t restored_query_type(restored_client_t client, char **type, uint * * @return RESTORE_E_SUCCESS on success, RESTORE_E_INVALID_ARG when client is NULL, RESTORE_E_PLIST_ERROR if value for key can't be found */ -restored_error_t restored_query_value(restored_client_t client, const char *key, plist_t *value); +LIBIMOBILEDEVICE_API restored_error_t restored_query_value(restored_client_t client, const char *key, plist_t *value); /** * Retrieves a value from information plist specified by a key. @@ -101,7 +101,7 @@ restored_error_t restored_query_value(restored_client_t client, const char *key, * * @return RESTORE_E_SUCCESS on success, RESTORE_E_INVALID_ARG when client is NULL, RESTORE_E_PLIST_ERROR if value for key can't be found */ -restored_error_t restored_get_value(restored_client_t client, const char *key, plist_t *value) ; +LIBIMOBILEDEVICE_API restored_error_t restored_get_value(restored_client_t client, const char *key, plist_t *value) ; /** * Sends a plist to restored. @@ -115,7 +115,7 @@ restored_error_t restored_get_value(restored_client_t client, const char *key, p * @return RESTORE_E_SUCCESS on success, RESTORE_E_INVALID_ARG when client or * plist is NULL */ -restored_error_t restored_send(restored_client_t client, plist_t plist); +LIBIMOBILEDEVICE_API restored_error_t restored_send(restored_client_t client, plist_t plist); /** * Receives a plist from restored. @@ -126,7 +126,7 @@ restored_error_t restored_send(restored_client_t client, plist_t plist); * @return RESTORE_E_SUCCESS on success, RESTORE_E_INVALID_ARG when client or * plist is NULL */ -restored_error_t restored_receive(restored_client_t client, plist_t *plist); +LIBIMOBILEDEVICE_API restored_error_t restored_receive(restored_client_t client, plist_t *plist); /** * Sends the Goodbye request to restored signaling the end of communication. @@ -136,7 +136,7 @@ restored_error_t restored_receive(restored_client_t client, plist_t *plist); * @return RESTORE_E_SUCCESS on success, RESTORE_E_INVALID_ARG when client is NULL, * RESTORE_E_PLIST_ERROR if the device did not acknowledge the request */ -restored_error_t restored_goodbye(restored_client_t client); +LIBIMOBILEDEVICE_API restored_error_t restored_goodbye(restored_client_t client); /** @@ -149,7 +149,7 @@ restored_error_t restored_goodbye(restored_client_t client); * @return RESTORE_E_SUCCESS on success, RESTORE_E_INVALID_ARG if a parameter * is NULL, RESTORE_E_START_RESTORE_FAILED if the request fails */ -restored_error_t restored_start_restore(restored_client_t client, plist_t options, uint64_t version); +LIBIMOBILEDEVICE_API restored_error_t restored_start_restore(restored_client_t client, plist_t options, uint64_t version); /** * Requests device to reboot. @@ -159,7 +159,7 @@ restored_error_t restored_start_restore(restored_client_t client, plist_t option * @return RESTORE_E_SUCCESS on success, RESTORE_E_INVALID_ARG if a parameter * is NULL */ -restored_error_t restored_reboot(restored_client_t client); +LIBIMOBILEDEVICE_API restored_error_t restored_reboot(restored_client_t client); /* Helper */ @@ -170,7 +170,7 @@ restored_error_t restored_reboot(restored_client_t client); * @param label The label to set or NULL to disable sending a label * */ -void restored_client_set_label(restored_client_t client, const char *label); +LIBIMOBILEDEVICE_API void restored_client_set_label(restored_client_t client, const char *label); #ifdef __cplusplus } diff --git a/include/libimobiledevice/reverse_proxy.h b/include/libimobiledevice/reverse_proxy.h index b7a93ff..5e2f54b 100644 --- a/include/libimobiledevice/reverse_proxy.h +++ b/include/libimobiledevice/reverse_proxy.h @@ -118,7 +118,7 @@ typedef void (*reverse_proxy_status_cb_t) (reverse_proxy_client_t client, revers * @return REVERSE_PROXY_E_SUCCESS on success, * or a REVERSE_PROXY_E_* error code otherwise. */ -reverse_proxy_error_t reverse_proxy_client_create_with_service(idevice_t device, reverse_proxy_client_t* client, const char* label); +LIBIMOBILEDEVICE_API reverse_proxy_error_t reverse_proxy_client_create_with_service(idevice_t device, reverse_proxy_client_t* client, const char* label); /** * Create a reverse proxy client using an open port on the device. This is @@ -136,14 +136,14 @@ reverse_proxy_error_t reverse_proxy_client_create_with_service(idevice_t device, * @return REVERSE_PROXY_E_SUCCESS on success, * or a REVERSE_PROXY_E_* error code otherwise. */ -reverse_proxy_error_t reverse_proxy_client_create_with_port(idevice_t device, reverse_proxy_client_t* client, uint16_t device_port); +LIBIMOBILEDEVICE_API reverse_proxy_error_t reverse_proxy_client_create_with_port(idevice_t device, reverse_proxy_client_t* client, uint16_t device_port); /** * Disconnects a reverse proxy client and frees up the client data. * * @param client The reverse proxy client to disconnect and free. */ -reverse_proxy_error_t reverse_proxy_client_free(reverse_proxy_client_t client); +LIBIMOBILEDEVICE_API reverse_proxy_error_t reverse_proxy_client_free(reverse_proxy_client_t client); /** * Make an initialized reverse proxy client operational, i.e. start the actual proxy. @@ -155,7 +155,7 @@ reverse_proxy_error_t reverse_proxy_client_free(reverse_proxy_client_t client); * @return REVERSE_PROXY_E_SUCCESS on success, * or a REVERSE_PROXY_E_* error code otherwise. */ -reverse_proxy_error_t reverse_proxy_client_start_proxy(reverse_proxy_client_t client, int control_protocol_version); +LIBIMOBILEDEVICE_API reverse_proxy_error_t reverse_proxy_client_start_proxy(reverse_proxy_client_t client, int control_protocol_version); /** * Set a status callback function. This allows to report the status of the @@ -168,7 +168,7 @@ reverse_proxy_error_t reverse_proxy_client_start_proxy(reverse_proxy_client_t cl * when the status of the reverse proxy changes. * @param user_data A pointer that will be passed to the callback function. */ -void reverse_proxy_client_set_status_callback(reverse_proxy_client_t client, reverse_proxy_status_cb_t callback, void* user_data); +LIBIMOBILEDEVICE_API void reverse_proxy_client_set_status_callback(reverse_proxy_client_t client, reverse_proxy_status_cb_t callback, void* user_data); /** * Set a log callback function. Useful for debugging or verbosity. @@ -180,7 +180,7 @@ void reverse_proxy_client_set_status_callback(reverse_proxy_client_t client, rev * when the reverse proxy logs something. * @param user_data A pointer that will be passed to the callback function. */ -void reverse_proxy_client_set_log_callback(reverse_proxy_client_t client, reverse_proxy_log_cb_t callback, void* user_data); +LIBIMOBILEDEVICE_API void reverse_proxy_client_set_log_callback(reverse_proxy_client_t client, reverse_proxy_log_cb_t callback, void* user_data); /** * Set a data callback function. Useful for debugging or extra verbosity. @@ -193,7 +193,7 @@ void reverse_proxy_client_set_log_callback(reverse_proxy_client_t client, revers * @param user_data A pointer that will be passed to the callback function. */ -void reverse_proxy_client_set_data_callback(reverse_proxy_client_t client, reverse_proxy_data_cb_t callback, void* user_data); +LIBIMOBILEDEVICE_API void reverse_proxy_client_set_data_callback(reverse_proxy_client_t client, reverse_proxy_data_cb_t callback, void* user_data); /** * Helper function to return the type of a given reverse proxy client, which @@ -204,7 +204,7 @@ void reverse_proxy_client_set_data_callback(reverse_proxy_client_t client, rever * * @return The type of the rerverse proxy client */ -reverse_proxy_client_type_t reverse_proxy_get_type(reverse_proxy_client_t client); +LIBIMOBILEDEVICE_API reverse_proxy_client_type_t reverse_proxy_get_type(reverse_proxy_client_t client); #ifdef __cplusplus } diff --git a/include/libimobiledevice/sbservices.h b/include/libimobiledevice/sbservices.h index 509d5b9..7435947 100644 --- a/include/libimobiledevice/sbservices.h +++ b/include/libimobiledevice/sbservices.h @@ -68,7 +68,7 @@ typedef sbservices_client_private *sbservices_client_t; /**< The client handle. * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when * client is NULL, or an SBSERVICES_E_* error code otherwise. */ -sbservices_error_t sbservices_client_new(idevice_t device, lockdownd_service_descriptor_t service, sbservices_client_t *client); +LIBIMOBILEDEVICE_API sbservices_error_t sbservices_client_new(idevice_t device, lockdownd_service_descriptor_t service, sbservices_client_t *client); /** * Starts a new sbservices service on the specified device and connects to it. @@ -83,7 +83,7 @@ sbservices_error_t sbservices_client_new(idevice_t device, lockdownd_service_des * @return SBSERVICES_E_SUCCESS on success, or an SBSERVICES_E_* error * code otherwise. */ -sbservices_error_t sbservices_client_start_service(idevice_t device, sbservices_client_t* client, const char* label); +LIBIMOBILEDEVICE_API sbservices_error_t sbservices_client_start_service(idevice_t device, sbservices_client_t* client, const char* label); /** * Disconnects an sbservices client from the device and frees up the @@ -94,7 +94,7 @@ sbservices_error_t sbservices_client_start_service(idevice_t device, sbservices_ * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when * client is NULL, or an SBSERVICES_E_* error code otherwise. */ -sbservices_error_t sbservices_client_free(sbservices_client_t client); +LIBIMOBILEDEVICE_API sbservices_error_t sbservices_client_free(sbservices_client_t client); /** @@ -111,7 +111,7 @@ sbservices_error_t sbservices_client_free(sbservices_client_t client); * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when * client or state is invalid, or an SBSERVICES_E_* error code otherwise. */ -sbservices_error_t sbservices_get_icon_state(sbservices_client_t client, plist_t *state, const char *format_version); +LIBIMOBILEDEVICE_API sbservices_error_t sbservices_get_icon_state(sbservices_client_t client, plist_t *state, const char *format_version); /** * Sets the icon state of the connected device. @@ -122,7 +122,7 @@ sbservices_error_t sbservices_get_icon_state(sbservices_client_t client, plist_t * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when * client or newstate is NULL, or an SBSERVICES_E_* error code otherwise. */ -sbservices_error_t sbservices_set_icon_state(sbservices_client_t client, plist_t newstate); +LIBIMOBILEDEVICE_API sbservices_error_t sbservices_set_icon_state(sbservices_client_t client, plist_t newstate); /** * Get the icon of the specified app as PNG data. @@ -139,7 +139,7 @@ sbservices_error_t sbservices_set_icon_state(sbservices_client_t client, plist_t * client, bundleId, or pngdata are invalid, or an SBSERVICES_E_* error * code otherwise. */ -sbservices_error_t sbservices_get_icon_pngdata(sbservices_client_t client, const char *bundleId, char **pngdata, uint64_t *pngsize); +LIBIMOBILEDEVICE_API sbservices_error_t sbservices_get_icon_pngdata(sbservices_client_t client, const char *bundleId, char **pngdata, uint64_t *pngsize); /** * Gets the interface orientation of the device. @@ -150,7 +150,7 @@ sbservices_error_t sbservices_get_icon_pngdata(sbservices_client_t client, const * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when * client or state is invalid, or an SBSERVICES_E_* error code otherwise. */ -sbservices_error_t sbservices_get_interface_orientation(sbservices_client_t client, sbservices_interface_orientation_t* interface_orientation); +LIBIMOBILEDEVICE_API sbservices_error_t sbservices_get_interface_orientation(sbservices_client_t client, sbservices_interface_orientation_t* interface_orientation); /** * Get the home screen wallpaper as PNG data. @@ -166,7 +166,7 @@ sbservices_error_t sbservices_get_interface_orientation(sbservices_client_t clie * client or pngdata are invalid, or an SBSERVICES_E_* error * code otherwise. */ -sbservices_error_t sbservices_get_home_screen_wallpaper_pngdata(sbservices_client_t client, char **pngdata, uint64_t *pngsize); +LIBIMOBILEDEVICE_API sbservices_error_t sbservices_get_home_screen_wallpaper_pngdata(sbservices_client_t client, char **pngdata, uint64_t *pngsize); #ifdef __cplusplus } diff --git a/include/libimobiledevice/screenshotr.h b/include/libimobiledevice/screenshotr.h index ecbbdbe..db3c969 100644 --- a/include/libimobiledevice/screenshotr.h +++ b/include/libimobiledevice/screenshotr.h @@ -66,7 +66,7 @@ typedef screenshotr_client_private *screenshotr_client_t; /**< The client handle * or more parameters are invalid, or SCREENSHOTR_E_CONN_FAILED if the * connection to the device could not be established. */ -screenshotr_error_t screenshotr_client_new(idevice_t device, lockdownd_service_descriptor_t service, screenshotr_client_t * client); +LIBIMOBILEDEVICE_API screenshotr_error_t screenshotr_client_new(idevice_t device, lockdownd_service_descriptor_t service, screenshotr_client_t * client); /** * Starts a new screenshotr service on the specified device and connects to it. @@ -81,7 +81,7 @@ screenshotr_error_t screenshotr_client_new(idevice_t device, lockdownd_service_d * @return SCREENSHOTR_E_SUCCESS on success, or an SCREENSHOTR_E_* error * code otherwise. */ -screenshotr_error_t screenshotr_client_start_service(idevice_t device, screenshotr_client_t* client, const char* label); +LIBIMOBILEDEVICE_API screenshotr_error_t screenshotr_client_start_service(idevice_t device, screenshotr_client_t* client, const char* label); /** * Disconnects a screenshotr client from the device and frees up the @@ -92,7 +92,7 @@ screenshotr_error_t screenshotr_client_start_service(idevice_t device, screensho * @return SCREENSHOTR_E_SUCCESS on success, or SCREENSHOTR_E_INVALID_ARG * if client is NULL. */ -screenshotr_error_t screenshotr_client_free(screenshotr_client_t client); +LIBIMOBILEDEVICE_API screenshotr_error_t screenshotr_client_free(screenshotr_client_t client); /** @@ -109,7 +109,7 @@ screenshotr_error_t screenshotr_client_free(screenshotr_client_t client); * one or more parameters are invalid, or another error code if an * error occurred. */ -screenshotr_error_t screenshotr_take_screenshot(screenshotr_client_t client, char **imgdata, uint64_t *imgsize); +LIBIMOBILEDEVICE_API screenshotr_error_t screenshotr_take_screenshot(screenshotr_client_t client, char **imgdata, uint64_t *imgsize); #ifdef __cplusplus } diff --git a/include/libimobiledevice/service.h b/include/libimobiledevice/service.h index 28b6db6..f31ada4 100644 --- a/include/libimobiledevice/service.h +++ b/include/libimobiledevice/service.h @@ -62,7 +62,7 @@ typedef service_client_private* service_client_t; /**< The client handle. */ * SERVICE_E_INVALID_ARG when one of the arguments is invalid, * or SERVICE_E_MUX_ERROR when connecting to the device failed. */ -service_error_t service_client_new(idevice_t device, lockdownd_service_descriptor_t service, service_client_t *client); +LIBIMOBILEDEVICE_API service_error_t service_client_new(idevice_t device, lockdownd_service_descriptor_t service, service_client_t *client); /** * Starts a new service on the specified device with given name and @@ -81,7 +81,7 @@ service_error_t service_client_new(idevice_t device, lockdownd_service_descripto * @return SERVICE_E_SUCCESS on success, or a SERVICE_E_* error code * otherwise. */ -service_error_t service_client_factory_start_service(idevice_t device, const char* service_name, void **client, const char* label, int32_t (*constructor_func)(idevice_t, lockdownd_service_descriptor_t, void**), int32_t *error_code); +LIBIMOBILEDEVICE_API service_error_t service_client_factory_start_service(idevice_t device, const char* service_name, void **client, const char* label, int32_t (*constructor_func)(idevice_t, lockdownd_service_descriptor_t, void**), int32_t *error_code); /** * Frees a service instance. @@ -92,7 +92,7 @@ service_error_t service_client_factory_start_service(idevice_t device, const cha * SERVICE_E_INVALID_ARG when client is invalid, or a * SERVICE_E_UNKNOWN_ERROR when another error occurred. */ -service_error_t service_client_free(service_client_t client); +LIBIMOBILEDEVICE_API service_error_t service_client_free(service_client_t client); /** @@ -108,7 +108,7 @@ service_error_t service_client_free(service_client_t client); * invalid, or SERVICE_E_UNKNOWN_ERROR when an unspecified * error occurs. */ -service_error_t service_send(service_client_t client, const char *data, uint32_t size, uint32_t *sent); +LIBIMOBILEDEVICE_API service_error_t service_send(service_client_t client, const char *data, uint32_t size, uint32_t *sent); /** * Receives data using the given service client with specified timeout. @@ -125,7 +125,7 @@ service_error_t service_send(service_client_t client, const char *data, uint32_t * occurs, or SERVICE_E_UNKNOWN_ERROR when an unspecified * error occurs. */ -service_error_t service_receive_with_timeout(service_client_t client, char *data, uint32_t size, uint32_t *received, unsigned int timeout); +LIBIMOBILEDEVICE_API service_error_t service_receive_with_timeout(service_client_t client, char *data, uint32_t size, uint32_t *received, unsigned int timeout); /** * Receives data using the given service client. @@ -143,7 +143,7 @@ service_error_t service_receive_with_timeout(service_client_t client, char *data * occurs, or SERVICE_E_UNKNOWN_ERROR when an unspecified * error occurs. */ -service_error_t service_receive(service_client_t client, char *data, uint32_t size, uint32_t *received); +LIBIMOBILEDEVICE_API service_error_t service_receive(service_client_t client, char *data, uint32_t size, uint32_t *received); /** @@ -158,7 +158,7 @@ service_error_t service_receive(service_client_t client, char *data, uint32_t si * SERVICE_E_SSL_ERROR when SSL could not be enabled, * or SERVICE_E_UNKNOWN_ERROR otherwise. */ -service_error_t service_enable_ssl(service_client_t client); +LIBIMOBILEDEVICE_API service_error_t service_enable_ssl(service_client_t client); /** * Disable SSL for the given service client. @@ -169,7 +169,7 @@ service_error_t service_enable_ssl(service_client_t client); * SERVICE_E_INVALID_ARG if client or client->connection is * NULL, or SERVICE_E_UNKNOWN_ERROR otherwise. */ -service_error_t service_disable_ssl(service_client_t client); +LIBIMOBILEDEVICE_API service_error_t service_disable_ssl(service_client_t client); /** * Disable SSL for the given service client, optionally without sending SSL terminate messages. @@ -182,7 +182,7 @@ service_error_t service_disable_ssl(service_client_t client); * SERVICE_E_INVALID_ARG if client or client->connection is * NULL, or SERVICE_E_UNKNOWN_ERROR otherwise. */ -service_error_t service_disable_bypass_ssl(service_client_t client, uint8_t sslBypass); +LIBIMOBILEDEVICE_API service_error_t service_disable_bypass_ssl(service_client_t client, uint8_t sslBypass); /** * Return a handle to the parent #idevice_connection_t of the given service client. @@ -193,7 +193,8 @@ service_error_t service_disable_bypass_ssl(service_client_t client, uint8_t sslB * @return SERVICE_E_SUCCESS on success, * SERVICE_E_INVALID_ARG if one or more of the arguments are invalid. */ -service_error_t service_get_connection(service_client_t client, idevice_connection_t *connection); +LIBIMOBILEDEVICE_API service_error_t service_get_connection(service_client_t client, idevice_connection_t *connection); + #ifdef __cplusplus } #endif diff --git a/include/libimobiledevice/syslog_relay.h b/include/libimobiledevice/syslog_relay.h index aae5d11..0f6487a 100644 --- a/include/libimobiledevice/syslog_relay.h +++ b/include/libimobiledevice/syslog_relay.h @@ -65,7 +65,7 @@ typedef void (*syslog_relay_receive_cb_t)(char c, void *user_data); * @return SYSLOG_RELAY_E_SUCCESS on success, SYSLOG_RELAY_E_INVALID_ARG when * client is NULL, or an SYSLOG_RELAY_E_* error code otherwise. */ -syslog_relay_error_t syslog_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, syslog_relay_client_t * client); +LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, syslog_relay_client_t * client); /** * Starts a new syslog_relay service on the specified device and connects to it. @@ -80,7 +80,7 @@ syslog_relay_error_t syslog_relay_client_new(idevice_t device, lockdownd_service * @return SYSLOG_RELAY_E_SUCCESS on success, or an SYSLOG_RELAY_E_* error * code otherwise. */ -syslog_relay_error_t syslog_relay_client_start_service(idevice_t device, syslog_relay_client_t * client, const char* label); +LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_client_start_service(idevice_t device, syslog_relay_client_t * client, const char* label); /** * Disconnects a syslog_relay client from the device and frees up the @@ -91,7 +91,7 @@ syslog_relay_error_t syslog_relay_client_start_service(idevice_t device, syslog_ * @return SYSLOG_RELAY_E_SUCCESS on success, SYSLOG_RELAY_E_INVALID_ARG when * client is NULL, or an SYSLOG_RELAY_E_* error code otherwise. */ -syslog_relay_error_t syslog_relay_client_free(syslog_relay_client_t client); +LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_client_free(syslog_relay_client_t client); /** @@ -108,7 +108,7 @@ syslog_relay_error_t syslog_relay_client_free(syslog_relay_client_t client); * invalid or SYSLOG_RELAY_E_UNKNOWN_ERROR when an unspecified * error occurs or a syslog capture has already been started. */ -syslog_relay_error_t syslog_relay_start_capture(syslog_relay_client_t client, syslog_relay_receive_cb_t callback, void* user_data); +LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_start_capture(syslog_relay_client_t client, syslog_relay_receive_cb_t callback, void* user_data); /** * Starts capturing the *raw* syslog of the device using a callback. @@ -129,7 +129,7 @@ syslog_relay_error_t syslog_relay_start_capture(syslog_relay_client_t client, sy * invalid or SYSLOG_RELAY_E_UNKNOWN_ERROR when an unspecified * error occurs or a syslog capture has already been started. */ -syslog_relay_error_t syslog_relay_start_capture_raw(syslog_relay_client_t client, syslog_relay_receive_cb_t callback, void* user_data); +LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_start_capture_raw(syslog_relay_client_t client, syslog_relay_receive_cb_t callback, void* user_data); /** * Stops capturing the syslog of the device. @@ -143,7 +143,7 @@ syslog_relay_error_t syslog_relay_start_capture_raw(syslog_relay_client_t client * invalid or SYSLOG_RELAY_E_UNKNOWN_ERROR when an unspecified * error occurs or a syslog capture has already been started. */ -syslog_relay_error_t syslog_relay_stop_capture(syslog_relay_client_t client); +LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_stop_capture(syslog_relay_client_t client); /* Receiving */ @@ -162,7 +162,7 @@ syslog_relay_error_t syslog_relay_stop_capture(syslog_relay_client_t client); * occurs, or SYSLOG_RELAY_E_UNKNOWN_ERROR when an unspecified * error occurs. */ -syslog_relay_error_t syslog_relay_receive_with_timeout(syslog_relay_client_t client, char *data, uint32_t size, uint32_t *received, unsigned int timeout); +LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_receive_with_timeout(syslog_relay_client_t client, char *data, uint32_t size, uint32_t *received, unsigned int timeout); /** * Receives data from the service. @@ -175,7 +175,7 @@ syslog_relay_error_t syslog_relay_receive_with_timeout(syslog_relay_client_t cli * @return SYSLOG_RELAY_E_SUCCESS on success, * SYSLOG_RELAY_E_INVALID_ARG when client or plist is NULL */ -syslog_relay_error_t syslog_relay_receive(syslog_relay_client_t client, char *data, uint32_t size, uint32_t *received); +LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_receive(syslog_relay_client_t client, char *data, uint32_t size, uint32_t *received); #ifdef __cplusplus } diff --git a/include/libimobiledevice/webinspector.h b/include/libimobiledevice/webinspector.h index 064ba91..16d2ca2 100644 --- a/include/libimobiledevice/webinspector.h +++ b/include/libimobiledevice/webinspector.h @@ -62,7 +62,7 @@ typedef webinspector_client_private *webinspector_client_t; /**< The client hand * @return WEBINSPECTOR_E_SUCCESS on success, WEBINSPECTOR_E_INVALID_ARG when * client is NULL, or an WEBINSPECTOR_E_* error code otherwise. */ -webinspector_error_t webinspector_client_new(idevice_t device, lockdownd_service_descriptor_t service, webinspector_client_t * client); +LIBIMOBILEDEVICE_API webinspector_error_t webinspector_client_new(idevice_t device, lockdownd_service_descriptor_t service, webinspector_client_t * client); /** * Starts a new webinspector service on the specified device and connects to it. @@ -77,7 +77,7 @@ webinspector_error_t webinspector_client_new(idevice_t device, lockdownd_service * @return WEBINSPECTOR_E_SUCCESS on success, or an WEBINSPECTOR_E_* error * code otherwise. */ -webinspector_error_t webinspector_client_start_service(idevice_t device, webinspector_client_t * client, const char* label); +LIBIMOBILEDEVICE_API webinspector_error_t webinspector_client_start_service(idevice_t device, webinspector_client_t * client, const char* label); /** * Disconnects a webinspector client from the device and frees up the @@ -88,7 +88,7 @@ webinspector_error_t webinspector_client_start_service(idevice_t device, webinsp * @return WEBINSPECTOR_E_SUCCESS on success, WEBINSPECTOR_E_INVALID_ARG when * client is NULL, or an WEBINSPECTOR_E_* error code otherwise. */ -webinspector_error_t webinspector_client_free(webinspector_client_t client); +LIBIMOBILEDEVICE_API webinspector_error_t webinspector_client_free(webinspector_client_t client); /** @@ -100,7 +100,7 @@ webinspector_error_t webinspector_client_free(webinspector_client_t client); * @return DIAGNOSTICS_RELAY_E_SUCCESS on success, * DIAGNOSTICS_RELAY_E_INVALID_ARG when client or plist is NULL */ -webinspector_error_t webinspector_send(webinspector_client_t client, plist_t plist); +LIBIMOBILEDEVICE_API webinspector_error_t webinspector_send(webinspector_client_t client, plist_t plist); /** * Receives a plist from the service. @@ -111,7 +111,7 @@ webinspector_error_t webinspector_send(webinspector_client_t client, plist_t pli * @return DIAGNOSTICS_RELAY_E_SUCCESS on success, * DIAGNOSTICS_RELAY_E_INVALID_ARG when client or plist is NULL */ -webinspector_error_t webinspector_receive(webinspector_client_t client, plist_t * plist); +LIBIMOBILEDEVICE_API webinspector_error_t webinspector_receive(webinspector_client_t client, plist_t * plist); /** * Receives a plist using the given webinspector client. @@ -128,7 +128,7 @@ webinspector_error_t webinspector_receive(webinspector_client_t client, plist_t * communication error occurs, or WEBINSPECTOR_E_UNKNOWN_ERROR * when an unspecified error occurs. */ -webinspector_error_t webinspector_receive_with_timeout(webinspector_client_t client, plist_t * plist, uint32_t timeout_ms); +LIBIMOBILEDEVICE_API webinspector_error_t webinspector_receive_with_timeout(webinspector_client_t client, plist_t * plist, uint32_t timeout_ms); #ifdef __cplusplus } diff --git a/m4/ax_python_devel.m4 b/m4/ax_python_devel.m4 index 44dbd83..935056c 100644 --- a/m4/ax_python_devel.m4 +++ b/m4/ax_python_devel.m4 @@ -4,7 +4,7 @@ # # SYNOPSIS # -# AX_PYTHON_DEVEL([version]) +# AX_PYTHON_DEVEL([version[,optional]]) # # DESCRIPTION # @@ -23,6 +23,11 @@ # version number. Don't use "PYTHON_VERSION" for this: that environment # variable is declared as precious and thus reserved for the end-user. # +# By default this will fail if it does not detect a development version of +# python. If you want it to continue, set optional to true, like +# AX_PYTHON_DEVEL([], [true]). The ax_python_devel_found variable will be +# "no" if it fails. +# # This macro should work for all versions of Python >= 2.1.0. As an end # user, you can disable the check for the python version by setting the # PYTHON_NOVERSIONCHECK environment variable to something else than the @@ -67,10 +72,18 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 21 +#serial 37 AU_ALIAS([AC_PYTHON_DEVEL], [AX_PYTHON_DEVEL]) AC_DEFUN([AX_PYTHON_DEVEL],[ + # Get whether it's optional + if test -z "$2"; then + ax_python_devel_optional=false + else + ax_python_devel_optional=$2 + fi + ax_python_devel_found=yes + # # Allow the use of a (user set) custom python version # @@ -81,21 +94,26 @@ AC_DEFUN([AX_PYTHON_DEVEL],[ AC_PATH_PROG([PYTHON],[python[$PYTHON_VERSION]]) if test -z "$PYTHON"; then - AC_MSG_ERROR([Cannot find python$PYTHON_VERSION in your system path]) + AC_MSG_WARN([Cannot find python$PYTHON_VERSION in your system path]) + if ! $ax_python_devel_optional; then + AC_MSG_ERROR([Giving up, python development not available]) + fi + ax_python_devel_found=no PYTHON_VERSION="" fi - # - # Check for a version of Python >= 2.1.0 - # - AC_MSG_CHECKING([for a version of Python >= '2.1.0']) - ac_supports_python_ver=`$PYTHON -c "import sys; \ + if test $ax_python_devel_found = yes; then + # + # Check for a version of Python >= 2.1.0 + # + AC_MSG_CHECKING([for a version of Python >= '2.1.0']) + ac_supports_python_ver=`$PYTHON -c "import sys; \ ver = sys.version.split ()[[0]]; \ print (ver >= '2.1.0')"` - if test "$ac_supports_python_ver" != "True"; then + if test "$ac_supports_python_ver" != "True"; then if test -z "$PYTHON_NOVERSIONCHECK"; then AC_MSG_RESULT([no]) - AC_MSG_FAILURE([ + AC_MSG_WARN([ This version of the AC@&t@_PYTHON_DEVEL macro doesn't work properly with versions of Python before 2.1.0. You may need to re-run configure, setting the @@ -104,58 +122,119 @@ PYTHON_EXTRA_LIBS and PYTHON_EXTRA_LDFLAGS by hand. Moreover, to disable this check, set PYTHON_NOVERSIONCHECK to something else than an empty string. ]) + if ! $ax_python_devel_optional; then + AC_MSG_FAILURE([Giving up]) + fi + ax_python_devel_found=no + PYTHON_VERSION="" else AC_MSG_RESULT([skip at user request]) fi - else + else AC_MSG_RESULT([yes]) + fi fi - # - # if the macro parameter ``version'' is set, honour it - # - if test -n "$1"; then + if test $ax_python_devel_found = yes; then + # + # If the macro parameter ``version'' is set, honour it. + # A Python shim class, VPy, is used to implement correct version comparisons via + # string expressions, since e.g. a naive textual ">= 2.7.3" won't work for + # Python 2.7.10 (the ".1" being evaluated as less than ".3"). + # + if test -n "$1"; then AC_MSG_CHECKING([for a version of Python $1]) - ac_supports_python_ver=`$PYTHON -c "import sys; \ - ver = sys.version.split ()[[0]]; \ + cat << EOF > ax_python_devel_vpy.py +class VPy: + def vtup(self, s): + return tuple(map(int, s.strip().replace("rc", ".").split("."))) + def __init__(self): + import sys + self.vpy = tuple(sys.version_info)[[:3]] + def __eq__(self, s): + return self.vpy == self.vtup(s) + def __ne__(self, s): + return self.vpy != self.vtup(s) + def __lt__(self, s): + return self.vpy < self.vtup(s) + def __gt__(self, s): + return self.vpy > self.vtup(s) + def __le__(self, s): + return self.vpy <= self.vtup(s) + def __ge__(self, s): + return self.vpy >= self.vtup(s) +EOF + ac_supports_python_ver=`$PYTHON -c "import ax_python_devel_vpy; \ + ver = ax_python_devel_vpy.VPy(); \ print (ver $1)"` + rm -rf ax_python_devel_vpy*.py* __pycache__/ax_python_devel_vpy*.py* if test "$ac_supports_python_ver" = "True"; then - AC_MSG_RESULT([yes]) + AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) - AC_MSG_ERROR([this package requires Python $1. + AC_MSG_WARN([this package requires Python $1. If you have it installed, but it isn't the default Python interpreter in your system path, please pass the PYTHON_VERSION variable to configure. See ``configure --help'' for reference. ]) + if ! $ax_python_devel_optional; then + AC_MSG_ERROR([Giving up]) + fi + ax_python_devel_found=no PYTHON_VERSION="" fi + fi fi - # - # Check if you have distutils, else fail - # - AC_MSG_CHECKING([for the distutils Python package]) - ac_distutils_result=`$PYTHON -c "import distutils" 2>&1` - if test $? -eq 0; then + if test $ax_python_devel_found = yes; then + # + # Check if you have distutils, else fail + # + AC_MSG_CHECKING([for the sysconfig Python package]) + ac_sysconfig_result=`$PYTHON -c "import sysconfig" 2>&1` + if test $? -eq 0; then AC_MSG_RESULT([yes]) - else + IMPORT_SYSCONFIG="import sysconfig" + else AC_MSG_RESULT([no]) - AC_MSG_ERROR([cannot import Python module "distutils". + + AC_MSG_CHECKING([for the distutils Python package]) + ac_sysconfig_result=`$PYTHON -c "from distutils import sysconfig" 2>&1` + if test $? -eq 0; then + AC_MSG_RESULT([yes]) + IMPORT_SYSCONFIG="from distutils import sysconfig" + else + AC_MSG_WARN([cannot import Python module "distutils". Please check your Python installation. The error was: -$ac_distutils_result]) - PYTHON_VERSION="" +$ac_sysconfig_result]) + if ! $ax_python_devel_optional; then + AC_MSG_ERROR([Giving up]) + fi + ax_python_devel_found=no + PYTHON_VERSION="" + fi + fi fi - # - # Check for Python include path - # - AC_MSG_CHECKING([for Python include path]) - if test -z "$PYTHON_CPPFLAGS"; then - python_path=`$PYTHON -c "import distutils.sysconfig; \ - print (distutils.sysconfig.get_python_inc ());"` - plat_python_path=`$PYTHON -c "import distutils.sysconfig; \ - print (distutils.sysconfig.get_python_inc (plat_specific=1));"` + if test $ax_python_devel_found = yes; then + # + # Check for Python include path + # + AC_MSG_CHECKING([for Python include path]) + if test -z "$PYTHON_CPPFLAGS"; then + if test "$IMPORT_SYSCONFIG" = "import sysconfig"; then + # sysconfig module has different functions + python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \ + print (sysconfig.get_path ('include'));"` + plat_python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \ + print (sysconfig.get_path ('platinclude'));"` + else + # old distutils way + python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \ + print (sysconfig.get_python_inc ());"` + plat_python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \ + print (sysconfig.get_python_inc (plat_specific=1));"` + fi if test -n "${python_path}"; then if test "${plat_python_path}" != "${python_path}"; then python_path="-I$python_path -I$plat_python_path" @@ -164,22 +243,22 @@ $ac_distutils_result]) fi fi PYTHON_CPPFLAGS=$python_path - fi - AC_MSG_RESULT([$PYTHON_CPPFLAGS]) - AC_SUBST([PYTHON_CPPFLAGS]) + fi + AC_MSG_RESULT([$PYTHON_CPPFLAGS]) + AC_SUBST([PYTHON_CPPFLAGS]) - # - # Check for Python library path - # - AC_MSG_CHECKING([for Python library path]) - if test -z "$PYTHON_LIBS"; then + # + # Check for Python library path + # + AC_MSG_CHECKING([for Python library path]) + if test -z "$PYTHON_LIBS"; then # (makes two attempts to ensure we've got a version number # from the interpreter) ac_python_version=`cat<<EOD | $PYTHON - # join all versioning strings, on some systems # major/minor numbers could be in different list elements -from distutils.sysconfig import * +from sysconfig import * e = get_config_var('VERSION') if e is not None: print(e) @@ -190,7 +269,7 @@ EOD` ac_python_version=$PYTHON_VERSION else ac_python_version=`$PYTHON -c "import sys; \ - print (sys.version[[:3]])"` + print ("%d.%d" % sys.version_info[[:2]])"` fi fi @@ -202,8 +281,8 @@ EOD` ac_python_libdir=`cat<<EOD | $PYTHON - # There should be only one -import distutils.sysconfig -e = distutils.sysconfig.get_config_var('LIBDIR') +$IMPORT_SYSCONFIG +e = sysconfig.get_config_var('LIBDIR') if e is not None: print (e) EOD` @@ -211,8 +290,8 @@ EOD` # Now, for the library: ac_python_library=`cat<<EOD | $PYTHON - -import distutils.sysconfig -c = distutils.sysconfig.get_config_vars() +$IMPORT_SYSCONFIG +c = sysconfig.get_config_vars() if 'LDVERSION' in c: print ('python'+c[['LDVERSION']]) else: @@ -231,83 +310,140 @@ EOD` else # old way: use libpython from python_configdir ac_python_libdir=`$PYTHON -c \ - "from distutils.sysconfig import get_python_lib as f; \ + "from sysconfig import get_python_lib as f; \ import os; \ print (os.path.join(f(plat_specific=1, standard_lib=1), 'config'));"` PYTHON_LIBS="-L$ac_python_libdir -lpython$ac_python_version" fi - if test -z "PYTHON_LIBS"; then - AC_MSG_ERROR([ + if test -z "$PYTHON_LIBS"; then + AC_MSG_WARN([ Cannot determine location of your Python DSO. Please check it was installed with dynamic libraries enabled, or try setting PYTHON_LIBS by hand. ]) + if ! $ax_python_devel_optional; then + AC_MSG_ERROR([Giving up]) + fi + ax_python_devel_found=no + PYTHON_VERSION="" fi + fi fi - AC_MSG_RESULT([$PYTHON_LIBS]) - AC_SUBST([PYTHON_LIBS]) - # - # Check for site packages - # - AC_MSG_CHECKING([for Python site-packages path]) - if test -z "$PYTHON_SITE_PKG"; then - PYTHON_SITE_PKG=`$PYTHON -c "import distutils.sysconfig; \ - print (distutils.sysconfig.get_python_lib(0,0));"` - fi - AC_MSG_RESULT([$PYTHON_SITE_PKG]) - AC_SUBST([PYTHON_SITE_PKG]) + if test $ax_python_devel_found = yes; then + AC_MSG_RESULT([$PYTHON_LIBS]) + AC_SUBST([PYTHON_LIBS]) - # - # libraries which must be linked in when embedding - # - AC_MSG_CHECKING(python extra libraries) - if test -z "$PYTHON_EXTRA_LIBS"; then - PYTHON_EXTRA_LIBS=`$PYTHON -c "import distutils.sysconfig; \ - conf = distutils.sysconfig.get_config_var; \ + # + # Check for site packages + # + AC_MSG_CHECKING([for Python site-packages path]) + if test -z "$PYTHON_SITE_PKG"; then + if test "$IMPORT_SYSCONFIG" = "import sysconfig"; then + PYTHON_SITE_PKG=`$PYTHON -c " +$IMPORT_SYSCONFIG; +if hasattr(sysconfig, 'get_default_scheme'): + scheme = sysconfig.get_default_scheme() +else: + scheme = sysconfig._get_default_scheme() +if scheme == 'posix_local': + # Debian's default scheme installs to /usr/local/ but we want to find headers in /usr/ + scheme = 'posix_prefix' +prefix = '$prefix' +if prefix == 'NONE': + prefix = '$ac_default_prefix' +sitedir = sysconfig.get_path('purelib', scheme, vars={'base': prefix}) +print(sitedir)"` + else + # distutils.sysconfig way + PYTHON_SITE_PKG=`$PYTHON -c "$IMPORT_SYSCONFIG; \ + print (sysconfig.get_python_lib(0,0));"` + fi + fi + AC_MSG_RESULT([$PYTHON_SITE_PKG]) + AC_SUBST([PYTHON_SITE_PKG]) + + # + # Check for platform-specific site packages + # + AC_MSG_CHECKING([for Python platform specific site-packages path]) + if test -z "$PYTHON_PLATFORM_SITE_PKG"; then + if test "$IMPORT_SYSCONFIG" = "import sysconfig"; then + PYTHON_PLATFORM_SITE_PKG=`$PYTHON -c " +$IMPORT_SYSCONFIG; +if hasattr(sysconfig, 'get_default_scheme'): + scheme = sysconfig.get_default_scheme() +else: + scheme = sysconfig._get_default_scheme() +if scheme == 'posix_local': + # Debian's default scheme installs to /usr/local/ but we want to find headers in /usr/ + scheme = 'posix_prefix' +prefix = '$prefix' +if prefix == 'NONE': + prefix = '$ac_default_prefix' +sitedir = sysconfig.get_path('platlib', scheme, vars={'platbase': prefix}) +print(sitedir)"` + else + # distutils.sysconfig way + PYTHON_PLATFORM_SITE_PKG=`$PYTHON -c "$IMPORT_SYSCONFIG; \ + print (sysconfig.get_python_lib(1,0));"` + fi + fi + AC_MSG_RESULT([$PYTHON_PLATFORM_SITE_PKG]) + AC_SUBST([PYTHON_PLATFORM_SITE_PKG]) + + # + # libraries which must be linked in when embedding + # + AC_MSG_CHECKING(python extra libraries) + if test -z "$PYTHON_EXTRA_LIBS"; then + PYTHON_EXTRA_LIBS=`$PYTHON -c "$IMPORT_SYSCONFIG; \ + conf = sysconfig.get_config_var; \ print (conf('LIBS') + ' ' + conf('SYSLIBS'))"` - fi - AC_MSG_RESULT([$PYTHON_EXTRA_LIBS]) - AC_SUBST(PYTHON_EXTRA_LIBS) + fi + AC_MSG_RESULT([$PYTHON_EXTRA_LIBS]) + AC_SUBST(PYTHON_EXTRA_LIBS) - # - # linking flags needed when embedding - # - AC_MSG_CHECKING(python extra linking flags) - if test -z "$PYTHON_EXTRA_LDFLAGS"; then - PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "import distutils.sysconfig; \ - conf = distutils.sysconfig.get_config_var; \ + # + # linking flags needed when embedding + # + AC_MSG_CHECKING(python extra linking flags) + if test -z "$PYTHON_EXTRA_LDFLAGS"; then + PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "$IMPORT_SYSCONFIG; \ + conf = sysconfig.get_config_var; \ print (conf('LINKFORSHARED'))"` - fi - AC_MSG_RESULT([$PYTHON_EXTRA_LDFLAGS]) - AC_SUBST(PYTHON_EXTRA_LDFLAGS) + # Hack for macos, it sticks this in here. + PYTHON_EXTRA_LDFLAGS=`echo $PYTHON_EXTRA_LDFLAGS | sed 's/CoreFoundation.*$/CoreFoundation/'` + fi + AC_MSG_RESULT([$PYTHON_EXTRA_LDFLAGS]) + AC_SUBST(PYTHON_EXTRA_LDFLAGS) - # - # final check to see if everything compiles alright - # - AC_MSG_CHECKING([consistency of all components of python development environment]) - # save current global flags - ac_save_LIBS="$LIBS" - ac_save_LDFLAGS="$LDFLAGS" - ac_save_CPPFLAGS="$CPPFLAGS" - LIBS="$ac_save_LIBS $PYTHON_LIBS $PYTHON_EXTRA_LIBS $PYTHON_EXTRA_LIBS" - LDFLAGS="$ac_save_LDFLAGS $PYTHON_EXTRA_LDFLAGS" - CPPFLAGS="$ac_save_CPPFLAGS $PYTHON_CPPFLAGS" - AC_LANG_PUSH([C]) - AC_LINK_IFELSE([ + # + # final check to see if everything compiles alright + # + AC_MSG_CHECKING([consistency of all components of python development environment]) + # save current global flags + ac_save_LIBS="$LIBS" + ac_save_LDFLAGS="$LDFLAGS" + ac_save_CPPFLAGS="$CPPFLAGS" + LIBS="$ac_save_LIBS $PYTHON_LIBS $PYTHON_EXTRA_LIBS" + LDFLAGS="$ac_save_LDFLAGS $PYTHON_EXTRA_LDFLAGS" + CPPFLAGS="$ac_save_CPPFLAGS $PYTHON_CPPFLAGS" + AC_LANG_PUSH([C]) + AC_LINK_IFELSE([ AC_LANG_PROGRAM([[#include <Python.h>]], [[Py_Initialize();]]) ],[pythonexists=yes],[pythonexists=no]) - AC_LANG_POP([C]) - # turn back to default flags - CPPFLAGS="$ac_save_CPPFLAGS" - LIBS="$ac_save_LIBS" - LDFLAGS="$ac_save_LDFLAGS" + AC_LANG_POP([C]) + # turn back to default flags + CPPFLAGS="$ac_save_CPPFLAGS" + LIBS="$ac_save_LIBS" + LDFLAGS="$ac_save_LDFLAGS" - AC_MSG_RESULT([$pythonexists]) + AC_MSG_RESULT([$pythonexists]) - if test ! "x$pythonexists" = "xyes"; then - AC_MSG_FAILURE([ + if test ! "x$pythonexists" = "xyes"; then + AC_MSG_WARN([ Could not link test program to Python. Maybe the main Python library has been installed in some non-standard library path. If so, pass it to configure, via the LIBS environment variable. @@ -317,8 +453,13 @@ EOD` You probably have to install the development version of the Python package for your distribution. The exact name of this package varies among them. ============================================================================ - ]) - PYTHON_VERSION="" + ]) + if ! $ax_python_devel_optional; then + AC_MSG_ERROR([Giving up]) + fi + ax_python_devel_found=no + PYTHON_VERSION="" + fi fi # diff --git a/src/Makefile.am b/src/Makefile.am index 1c80ed6..1ee9be8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,19 +6,19 @@ AM_CPPFLAGS = \ AM_CFLAGS = \ $(GLOBAL_CFLAGS) \ - $(libusbmuxd_CFLAGS) \ - $(libplist_CFLAGS) \ - $(limd_glue_CFLAGS) \ $(ssl_lib_CFLAGS) \ $(LFS_CFLAGS) \ - $(PTHREAD_CFLAGS) + $(PTHREAD_CFLAGS) \ + $(libusbmuxd_CFLAGS) \ + $(libplist_CFLAGS) \ + $(limd_glue_CFLAGS) AM_LDFLAGS = \ + $(ssl_lib_LIBS) \ + $(PTHREAD_LIBS) \ $(libusbmuxd_LIBS) \ $(libplist_LIBS) \ - $(limd_glue_LIBS) \ - $(ssl_lib_LIBS) \ - $(PTHREAD_LIBS) + $(limd_glue_LIBS) lib_LTLIBRARIES = libimobiledevice-1.0.la libimobiledevice_1_0_la_LIBADD = $(top_builddir)/common/libinternalcommon.la @@ -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 @@ -26,11 +26,14 @@ #endif #include <stdio.h> #include <stdlib.h> -#include <unistd.h> #include <string.h> -#include "afc.h" +#ifndef _MSC_VER +#include <unistd.h> +#endif + #include "idevice.h" +#include "afc.h" #include "common/debug.h" #include "endianness.h" @@ -68,7 +71,7 @@ static void afc_unlock(afc_client_t client) * invalid, or AFC_E_NO_MEM if there is a memory allocation problem. */ -LIBIMOBILEDEVICE_API afc_error_t afc_client_new_with_service_client(service_client_t service_client, afc_client_t *client) +afc_error_t afc_client_new_with_service_client(service_client_t service_client, afc_client_t *client) { if (!service_client) return AFC_E_INVALID_ARG; @@ -94,7 +97,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_client_new_with_service_client(service_clie return AFC_E_SUCCESS; } -LIBIMOBILEDEVICE_API afc_error_t afc_client_new(idevice_t device, lockdownd_service_descriptor_t service, afc_client_t * client) +afc_error_t afc_client_new(idevice_t device, lockdownd_service_descriptor_t service, afc_client_t * client) { if (!device || !service || service->port == 0) return AFC_E_INVALID_ARG; @@ -113,14 +116,14 @@ LIBIMOBILEDEVICE_API afc_error_t afc_client_new(idevice_t device, lockdownd_serv return err; } -LIBIMOBILEDEVICE_API afc_error_t afc_client_start_service(idevice_t device, afc_client_t * client, const char* label) +afc_error_t afc_client_start_service(idevice_t device, afc_client_t * client, const char* label) { - afc_error_t err = AFC_E_UNKNOWN_ERROR; + 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; } -LIBIMOBILEDEVICE_API afc_error_t afc_client_free(afc_client_t client) +afc_error_t afc_client_free(afc_client_t client) { if (!client || !client->afc_packet) return AFC_E_INVALID_ARG; @@ -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) { @@ -414,7 +461,7 @@ static int _afc_check_packet_buffer(afc_client_t client, uint32_t data_len) #define AFC_PACKET_DATA_PTR ((char*)client->afc_packet + sizeof(AFCPacket)) -LIBIMOBILEDEVICE_API afc_error_t afc_read_directory(afc_client_t client, const char *path, char ***directory_information) +afc_error_t afc_read_directory(afc_client_t client, const char *path, char ***directory_information) { uint32_t bytes = 0; char *data = NULL, **list_loc = NULL; @@ -458,7 +505,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_read_directory(afc_client_t client, const c return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_get_device_info(afc_client_t client, char ***device_information) +afc_error_t afc_get_device_info(afc_client_t client, char ***device_information) { uint32_t bytes = 0; char *data = NULL, **list = NULL; @@ -495,7 +542,41 @@ LIBIMOBILEDEVICE_API afc_error_t afc_get_device_info(afc_client_t client, char * return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_get_device_info_key(afc_client_t client, const char *key, char **value) +afc_error_t afc_get_device_info_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; char **kvps, **ptr; @@ -522,7 +603,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_get_device_info_key(afc_client_t client, co return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_remove_path(afc_client_t client, const char *path) +afc_error_t afc_remove_path(afc_client_t client, const char *path) { uint32_t bytes = 0; afc_error_t ret = AFC_E_UNKNOWN_ERROR; @@ -558,7 +639,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_remove_path(afc_client_t client, const char return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_rename_path(afc_client_t client, const char *from, const char *to) +afc_error_t afc_rename_path(afc_client_t client, const char *from, const char *to) { if (!client || !from || !to || !client->afc_packet || !client->parent) return AFC_E_INVALID_ARG; @@ -594,7 +675,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_rename_path(afc_client_t client, const char return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_make_directory(afc_client_t client, const char *path) +afc_error_t afc_make_directory(afc_client_t client, const char *path) { uint32_t bytes = 0; afc_error_t ret = AFC_E_UNKNOWN_ERROR; @@ -626,7 +707,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_make_directory(afc_client_t client, const c return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***file_information) +afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***file_information) { char *received = NULL; uint32_t bytes = 0; @@ -644,8 +725,6 @@ LIBIMOBILEDEVICE_API afc_error_t afc_get_file_info(afc_client_t client, const ch 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,7 +745,45 @@ LIBIMOBILEDEVICE_API afc_error_t afc_get_file_info(afc_client_t client, const ch return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_file_open(afc_client_t client, const char *filename, afc_file_mode_t file_mode, uint64_t *handle) +afc_error_t afc_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) return AFC_E_INVALID_ARG; @@ -718,7 +835,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_open(afc_client_t client, const char * return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length, uint32_t *bytes_read) +afc_error_t afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length, uint32_t *bytes_read) { char *input = NULL; uint32_t current_count = 0, bytes_loc = 0; @@ -774,7 +891,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_read(afc_client_t client, uint64_t han return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_file_write(afc_client_t client, uint64_t handle, const char *data, uint32_t length, uint32_t *bytes_written) +afc_error_t afc_file_write(afc_client_t client, uint64_t handle, const char *data, uint32_t length, uint32_t *bytes_written) { uint32_t current_count = 0; uint32_t bytes_loc = 0; @@ -809,7 +926,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_write(afc_client_t client, uint64_t ha return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_file_close(afc_client_t client, uint64_t handle) +afc_error_t afc_file_close(afc_client_t client, uint64_t handle) { uint32_t bytes = 0; afc_error_t ret = AFC_E_UNKNOWN_ERROR; @@ -840,7 +957,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_close(afc_client_t client, uint64_t ha return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t operation) +afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t operation) { uint32_t bytes = 0; struct lockinfo { @@ -874,7 +991,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_lock(afc_client_t client, uint64_t han return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_file_seek(afc_client_t client, uint64_t handle, int64_t offset, int whence) +afc_error_t afc_file_seek(afc_client_t client, uint64_t handle, int64_t offset, int whence) { uint32_t bytes = 0; struct seekinfo { @@ -908,7 +1025,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_seek(afc_client_t client, uint64_t han return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_file_tell(afc_client_t client, uint64_t handle, uint64_t *position) +afc_error_t afc_file_tell(afc_client_t client, uint64_t handle, uint64_t *position) { char *buffer = NULL; uint32_t bytes = 0; @@ -943,7 +1060,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_tell(afc_client_t client, uint64_t han return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_file_truncate(afc_client_t client, uint64_t handle, uint64_t newsize) +afc_error_t afc_file_truncate(afc_client_t client, uint64_t handle, uint64_t newsize) { uint32_t bytes = 0; struct truncinfo { @@ -975,7 +1092,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_truncate(afc_client_t client, uint64_t return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_truncate(afc_client_t client, const char *path, uint64_t newsize) +afc_error_t afc_truncate(afc_client_t client, const char *path, uint64_t newsize) { if (!client || !path || !client->afc_packet || !client->parent) return AFC_E_INVALID_ARG; @@ -1008,7 +1125,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_truncate(afc_client_t client, const char *p return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_make_link(afc_client_t client, afc_link_type_t linktype, const char *target, const char *linkname) +afc_error_t afc_make_link(afc_client_t client, afc_link_type_t linktype, const char *target, const char *linkname) { if (!client || !target || !linkname || !client->afc_packet || !client->parent) return AFC_E_INVALID_ARG; @@ -1049,7 +1166,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_make_link(afc_client_t client, afc_link_typ return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_set_file_time(afc_client_t client, const char *path, uint64_t mtime) +afc_error_t afc_set_file_time(afc_client_t client, const char *path, uint64_t mtime) { if (!client || !path || !client->afc_packet || !client->parent) return AFC_E_INVALID_ARG; @@ -1082,7 +1199,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_set_file_time(afc_client_t client, const ch return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_remove_path_and_contents(afc_client_t client, const char *path) +afc_error_t afc_remove_path_and_contents(afc_client_t client, const char *path) { uint32_t bytes = 0; afc_error_t ret = AFC_E_UNKNOWN_ERROR; @@ -1114,7 +1231,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_remove_path_and_contents(afc_client_t clien return ret; } -LIBIMOBILEDEVICE_API afc_error_t afc_dictionary_free(char **dictionary) +afc_error_t afc_dictionary_free(char **dictionary) { int i = 0; @@ -1128,3 +1245,70 @@ LIBIMOBILEDEVICE_API afc_error_t afc_dictionary_free(char **dictionary) return AFC_E_SUCCESS; } + +const char* afc_strerror(afc_error_t err) +{ + switch (err) { + case AFC_E_SUCCESS: + return "Success"; + case AFC_E_UNKNOWN_ERROR: + return "Unknown Error"; + case AFC_E_OP_HEADER_INVALID: + return "Operation header invalid"; + case AFC_E_NO_RESOURCES: + return "No resources"; + case AFC_E_READ_ERROR: + return "Read error"; + case AFC_E_WRITE_ERROR: + return "Write error"; + case AFC_E_UNKNOWN_PACKET_TYPE: + return "Unknown packet type"; + case AFC_E_INVALID_ARG: + return "Invalid argument"; + case AFC_E_OBJECT_NOT_FOUND: + return "Not found"; + case AFC_E_OBJECT_IS_DIR: + return "Object is a directory"; + case AFC_E_PERM_DENIED: + return "Permission denied"; + case AFC_E_SERVICE_NOT_CONNECTED: + return "Service not connected"; + case AFC_E_OP_TIMEOUT: + return "Timeout"; + case AFC_E_TOO_MUCH_DATA: + return "Too much data"; + case AFC_E_END_OF_DATA: + return "End of data"; + case AFC_E_OP_NOT_SUPPORTED: + return "Operation not supported"; + case AFC_E_OBJECT_EXISTS: + return "Object exists"; + case AFC_E_OBJECT_BUSY: + return "Object busy"; + case AFC_E_NO_SPACE_LEFT: + return "No space left on device"; + case AFC_E_OP_WOULD_BLOCK: + return "Operation would block"; + case AFC_E_IO_ERROR: + return "I/O error"; + case AFC_E_OP_INTERRUPTED: + return "Operation interrupted"; + case AFC_E_OP_IN_PROGRESS: + return "Operation on progress"; + case AFC_E_INTERNAL_ERROR: + return "Internal error"; + case AFC_E_MUX_ERROR: + return "MUX error"; + case AFC_E_NO_MEM: + return "Out of memory"; + case AFC_E_NOT_ENOUGH_DATA: + return "Not enough data"; + case AFC_E_DIR_NOT_EMPTY: + return "Directory not empty"; + case AFC_E_FORCE_SIGNED_TYPE: + return "Force signed type"; + default: + break; + } + return "Unknown Error"; +} diff --git a/src/bt_packet_logger.c b/src/bt_packet_logger.c index 5f7bdeb..937747c 100644 --- a/src/bt_packet_logger.c +++ b/src/bt_packet_logger.c @@ -69,7 +69,7 @@ static bt_packet_logger_error_t bt_packet_logger_error(service_error_t err) return BT_PACKET_LOGGER_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API bt_packet_logger_error_t bt_packet_logger_client_new(idevice_t device, lockdownd_service_descriptor_t service, bt_packet_logger_client_t * client) +bt_packet_logger_error_t bt_packet_logger_client_new(idevice_t device, lockdownd_service_descriptor_t service, bt_packet_logger_client_t * client) { if (!device || !service || service->port == 0 || !client || *client) { debug_info("Incorrect parameter passed to bt_packet_logger_client_new."); @@ -95,14 +95,14 @@ LIBIMOBILEDEVICE_API bt_packet_logger_error_t bt_packet_logger_client_new(idevic return 0; } -LIBIMOBILEDEVICE_API bt_packet_logger_error_t bt_packet_logger_client_start_service(idevice_t device, bt_packet_logger_client_t * client, const char* label) +bt_packet_logger_error_t bt_packet_logger_client_start_service(idevice_t device, bt_packet_logger_client_t * client, const char* label) { bt_packet_logger_error_t err = BT_PACKET_LOGGER_E_UNKNOWN_ERROR; service_client_factory_start_service(device, BT_PACKETLOGGER_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(bt_packet_logger_client_new), &err); return err; } -LIBIMOBILEDEVICE_API bt_packet_logger_error_t bt_packet_logger_client_free(bt_packet_logger_client_t client) +bt_packet_logger_error_t bt_packet_logger_client_free(bt_packet_logger_client_t client) { if (!client) return BT_PACKET_LOGGER_E_INVALID_ARG; @@ -113,7 +113,7 @@ LIBIMOBILEDEVICE_API bt_packet_logger_error_t bt_packet_logger_client_free(bt_pa return err; } -LIBIMOBILEDEVICE_API bt_packet_logger_error_t bt_packet_logger_receive_with_timeout(bt_packet_logger_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout) +bt_packet_logger_error_t bt_packet_logger_receive_with_timeout(bt_packet_logger_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout) { bt_packet_logger_error_t res = BT_PACKET_LOGGER_E_UNKNOWN_ERROR; int bytes = 0; @@ -186,7 +186,7 @@ void *bt_packet_logger_worker(void *arg) return NULL; } -LIBIMOBILEDEVICE_API bt_packet_logger_error_t bt_packet_logger_start_capture(bt_packet_logger_client_t client, bt_packet_logger_receive_cb_t callback, void* user_data) +bt_packet_logger_error_t bt_packet_logger_start_capture(bt_packet_logger_client_t client, bt_packet_logger_receive_cb_t callback, void* user_data) { if (!client || !callback) return BT_PACKET_LOGGER_E_INVALID_ARG; @@ -214,7 +214,7 @@ LIBIMOBILEDEVICE_API bt_packet_logger_error_t bt_packet_logger_start_capture(bt_ } -LIBIMOBILEDEVICE_API bt_packet_logger_error_t bt_packet_logger_stop_capture(bt_packet_logger_client_t client) +bt_packet_logger_error_t bt_packet_logger_stop_capture(bt_packet_logger_client_t client) { if (client->worker) { /* notify thread to finish */ diff --git a/src/bt_packet_logger.h b/src/bt_packet_logger.h index 95990d5..620555e 100644 --- a/src/bt_packet_logger.h +++ b/src/bt_packet_logger.h @@ -22,6 +22,7 @@ #ifndef _BR_PACKET_LOGGER_H #define _BR_PACKET_LOGGER_H +#include "idevice.h" #include "libimobiledevice/bt_packet_logger.h" #include "service.h" #include <libimobiledevice-glue/thread.h> diff --git a/src/companion_proxy.c b/src/companion_proxy.c index 5852904..421fa9a 100644 --- a/src/companion_proxy.c +++ b/src/companion_proxy.c @@ -62,7 +62,7 @@ static companion_proxy_error_t companion_proxy_error(property_list_service_error return COMPANION_PROXY_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_client_new(idevice_t device, lockdownd_service_descriptor_t service, companion_proxy_client_t * client) +companion_proxy_error_t companion_proxy_client_new(idevice_t device, lockdownd_service_descriptor_t service, companion_proxy_client_t * client) { *client = NULL; @@ -90,14 +90,14 @@ LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_client_new(idevice_ return COMPANION_PROXY_E_SUCCESS; } -LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_client_start_service(idevice_t device, companion_proxy_client_t * client, const char* label) +companion_proxy_error_t companion_proxy_client_start_service(idevice_t device, companion_proxy_client_t * client, const char* label) { companion_proxy_error_t err = COMPANION_PROXY_E_UNKNOWN_ERROR; service_client_factory_start_service(device, COMPANION_PROXY_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(companion_proxy_client_new), &err); return err; } -LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_client_free(companion_proxy_client_t client) +companion_proxy_error_t companion_proxy_client_free(companion_proxy_client_t client) { if (!client) return COMPANION_PROXY_E_INVALID_ARG; @@ -116,7 +116,7 @@ LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_client_free(compani return err; } -LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_send(companion_proxy_client_t client, plist_t plist) +companion_proxy_error_t companion_proxy_send(companion_proxy_client_t client, plist_t plist) { companion_proxy_error_t res = COMPANION_PROXY_E_UNKNOWN_ERROR; @@ -129,7 +129,7 @@ LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_send(companion_prox return res; } -LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_receive(companion_proxy_client_t client, plist_t * plist) +companion_proxy_error_t companion_proxy_receive(companion_proxy_client_t client, plist_t * plist) { companion_proxy_error_t res = COMPANION_PROXY_E_UNKNOWN_ERROR; plist_t outplist = NULL; @@ -143,7 +143,7 @@ LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_receive(companion_p return res; } -LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_get_device_registry(companion_proxy_client_t client, plist_t* paired_devices) +companion_proxy_error_t companion_proxy_get_device_registry(companion_proxy_client_t client, plist_t* paired_devices) { if (!client || !paired_devices) { return COMPANION_PROXY_E_INVALID_ARG; @@ -226,7 +226,7 @@ static void* companion_proxy_event_thread(void* arg) return NULL; } -LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_start_listening_for_devices(companion_proxy_client_t client, companion_proxy_device_event_cb_t callback, void* userdata) +companion_proxy_error_t companion_proxy_start_listening_for_devices(companion_proxy_client_t client, companion_proxy_device_event_cb_t callback, void* userdata) { if (!client || !client->parent || !callback) { return COMPANION_PROXY_E_INVALID_ARG; @@ -252,7 +252,7 @@ LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_start_listening_for return res; } -LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_stop_listening_for_devices(companion_proxy_client_t client) +companion_proxy_error_t companion_proxy_stop_listening_for_devices(companion_proxy_client_t client) { property_list_service_client_t parent = client->parent; client->parent = NULL; @@ -266,7 +266,7 @@ LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_stop_listening_for_ return COMPANION_PROXY_E_SUCCESS; } -LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_get_value_from_registry(companion_proxy_client_t client, const char* companion_udid, const char* key, plist_t* value) +companion_proxy_error_t companion_proxy_get_value_from_registry(companion_proxy_client_t client, const char* companion_udid, const char* key, plist_t* value) { if (!client || !companion_udid || !key || !value) { return COMPANION_PROXY_E_INVALID_ARG; @@ -310,7 +310,7 @@ LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_get_value_from_regi return res; } -LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_start_forwarding_service_port(companion_proxy_client_t client, uint16_t remote_port, const char* service_name, uint16_t* forward_port, plist_t options) +companion_proxy_error_t companion_proxy_start_forwarding_service_port(companion_proxy_client_t client, uint16_t remote_port, const char* service_name, uint16_t* forward_port, plist_t options) { if (!client) { return COMPANION_PROXY_E_INVALID_ARG; @@ -353,7 +353,7 @@ LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_start_forwarding_se return res; } -LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_stop_forwarding_service_port(companion_proxy_client_t client, uint16_t remote_port) +companion_proxy_error_t companion_proxy_stop_forwarding_service_port(companion_proxy_client_t client, uint16_t remote_port) { if (!client) { return COMPANION_PROXY_E_INVALID_ARG; diff --git a/src/companion_proxy.h b/src/companion_proxy.h index 0226640..e36932a 100644 --- a/src/companion_proxy.h +++ b/src/companion_proxy.h @@ -22,6 +22,7 @@ #ifndef __COMPANION_PROXY_H #define __COMPANION_PROXY_H +#include "idevice.h" #include "libimobiledevice/companion_proxy.h" #include "property_list_service.h" #include <libimobiledevice-glue/thread.h> diff --git a/src/debugserver.c b/src/debugserver.c index 39c1bdc..74ade8a 100644 --- a/src/debugserver.c +++ b/src/debugserver.c @@ -64,7 +64,7 @@ static debugserver_error_t debugserver_error(service_error_t err) return DEBUGSERVER_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_new(idevice_t device, lockdownd_service_descriptor_t service, debugserver_client_t* client) +debugserver_error_t debugserver_client_new(idevice_t device, lockdownd_service_descriptor_t service, debugserver_client_t* client) { *client = NULL; @@ -98,7 +98,7 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_new(idevice_t device return DEBUGSERVER_E_SUCCESS; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_start_service(idevice_t device, debugserver_client_t * client, const char* label) +debugserver_error_t debugserver_client_start_service(idevice_t device, debugserver_client_t * client, const char* label) { debugserver_error_t err = DEBUGSERVER_E_UNKNOWN_ERROR; service_client_factory_start_service(device, DEBUGSERVER_SECURE_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(debugserver_client_new), &err); @@ -109,7 +109,7 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_start_service(idevic return err; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_free(debugserver_client_t client) +debugserver_error_t debugserver_client_free(debugserver_client_t client) { if (!client) return DEBUGSERVER_E_INVALID_ARG; @@ -121,7 +121,7 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_free(debugserver_cli return err; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_send(debugserver_client_t client, const char* data, uint32_t size, uint32_t *sent) +debugserver_error_t debugserver_client_send(debugserver_client_t client, const char* data, uint32_t size, uint32_t *sent) { debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR; int bytes = 0; @@ -142,7 +142,7 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_send(debugserver_cli return res; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive_with_timeout(debugserver_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout) +debugserver_error_t debugserver_client_receive_with_timeout(debugserver_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout) { debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR; int bytes = 0; @@ -162,7 +162,7 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive_with_timeout return (bytes > 0) ? DEBUGSERVER_E_SUCCESS : res; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive(debugserver_client_t client, char* data, uint32_t size, uint32_t *received) +debugserver_error_t debugserver_client_receive(debugserver_client_t client, char* data, uint32_t size, uint32_t *received) { debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR; do { @@ -172,7 +172,7 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive(debugserver_ return res; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_command_new(const char* name, int argc, char* argv[], debugserver_command_t* command) +debugserver_error_t debugserver_command_new(const char* name, int argc, char* argv[], debugserver_command_t* command) { int i; debugserver_command_t tmp = (debugserver_command_t) malloc(sizeof(struct debugserver_command_private)); @@ -197,7 +197,7 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_command_new(const char* nam return DEBUGSERVER_E_SUCCESS; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_command_free(debugserver_command_t command) +debugserver_error_t debugserver_command_free(debugserver_command_t command) { int i; debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR; @@ -275,7 +275,7 @@ static int debugserver_response_is_checksum_valid(const char* response, uint32_t return 1; } -LIBIMOBILEDEVICE_API void debugserver_encode_string(const char* buffer, char** encoded_buffer, uint32_t* encoded_length) +void debugserver_encode_string(const char* buffer, char** encoded_buffer, uint32_t* encoded_length) { uint32_t position; uint32_t index; @@ -291,7 +291,7 @@ LIBIMOBILEDEVICE_API void debugserver_encode_string(const char* buffer, char** e } } -LIBIMOBILEDEVICE_API void debugserver_decode_string(const char *encoded_buffer, size_t encoded_length, char** buffer) +void debugserver_decode_string(const char *encoded_buffer, size_t encoded_length, char** buffer) { *buffer = malloc(sizeof(char) * ((encoded_length / 2)+1)); char* t = *buffer; @@ -350,7 +350,7 @@ static debugserver_error_t debugserver_client_send_noack(debugserver_client_t cl return debugserver_client_send(client, "-", sizeof(char), NULL); } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_ack_mode(debugserver_client_t client, int enabled) +debugserver_error_t debugserver_client_set_ack_mode(debugserver_client_t client, int enabled) { if (!client) return DEBUGSERVER_E_INVALID_ARG; @@ -362,7 +362,7 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_ack_mode(debugse return DEBUGSERVER_E_SUCCESS; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_receive_params(debugserver_client_t client, int (*cancel_receive)(), int receive_loop_timeout) +debugserver_error_t debugserver_client_set_receive_params(debugserver_client_t client, int (*cancel_receive)(), int receive_loop_timeout) { if (!client) return DEBUGSERVER_E_INVALID_ARG; @@ -392,7 +392,7 @@ static debugserver_error_t debugserver_client_receive_internal_char(debugserver_ return res; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive_response(debugserver_client_t client, char** response, size_t* response_size) +debugserver_error_t debugserver_client_receive_response(debugserver_client_t client, char** response, size_t* response_size) { debugserver_error_t res = DEBUGSERVER_E_SUCCESS; @@ -503,7 +503,7 @@ cleanup: return res; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_send_command(debugserver_client_t client, debugserver_command_t command, char** response, size_t* response_size) +debugserver_error_t debugserver_client_send_command(debugserver_client_t client, debugserver_command_t command, char** response, size_t* response_size) { debugserver_error_t res = DEBUGSERVER_E_SUCCESS; int i; @@ -559,7 +559,7 @@ cleanup: return res; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_environment_hex_encoded(debugserver_client_t client, const char* env, char** response) +debugserver_error_t debugserver_client_set_environment_hex_encoded(debugserver_client_t client, const char* env, char** response) { if (!client || !env) return DEBUGSERVER_E_INVALID_ARG; @@ -578,7 +578,7 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_environment_hex_ return result; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_argv(debugserver_client_t client, int argc, char* argv[], char** response) +debugserver_error_t debugserver_client_set_argv(debugserver_client_t client, int argc, char* argv[], char** response) { if (!client || !argc) return DEBUGSERVER_E_INVALID_ARG; diff --git a/src/debugserver.h b/src/debugserver.h index ee3ba62..ce9c255 100644 --- a/src/debugserver.h +++ b/src/debugserver.h @@ -22,6 +22,7 @@ #ifndef _DEBUGSERVER_H #define _DEBUGSERVER_H +#include "idevice.h" #include "libimobiledevice/debugserver.h" #include "service.h" diff --git a/src/device_link_service.h b/src/device_link_service.h index eae912a..0255b21 100644 --- a/src/device_link_service.h +++ b/src/device_link_service.h @@ -22,6 +22,7 @@ #ifndef __DEVICE_LINK_SERVICE_H #define __DEVICE_LINK_SERVICE_H +#include "idevice.h" #include "property_list_service.h" /* Error Codes */ diff --git a/src/diagnostics_relay.c b/src/diagnostics_relay.c index 5444fcc..6ee3150 100644 --- a/src/diagnostics_relay.c +++ b/src/diagnostics_relay.c @@ -73,7 +73,7 @@ static int diagnostics_relay_check_result(plist_t dict) return ret; } -LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, diagnostics_relay_client_t *client) +diagnostics_relay_error_t diagnostics_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, diagnostics_relay_client_t *client) { if (!device || !service || service->port == 0 || !client || *client) { return DIAGNOSTICS_RELAY_E_INVALID_ARG; @@ -93,14 +93,14 @@ LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_client_new(idev return DIAGNOSTICS_RELAY_E_SUCCESS; } -LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_client_start_service(idevice_t device, diagnostics_relay_client_t * client, const char* label) +diagnostics_relay_error_t diagnostics_relay_client_start_service(idevice_t device, diagnostics_relay_client_t * client, const char* label) { diagnostics_relay_error_t err = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR; service_client_factory_start_service(device, DIAGNOSTICS_RELAY_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(diagnostics_relay_client_new), &err); return err; } -LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_client_free(diagnostics_relay_client_t client) +diagnostics_relay_error_t diagnostics_relay_client_free(diagnostics_relay_client_t client) { if (!client) return DIAGNOSTICS_RELAY_E_INVALID_ARG; @@ -167,7 +167,7 @@ static diagnostics_relay_error_t diagnostics_relay_send(diagnostics_relay_client return ret; } -LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_goodbye(diagnostics_relay_client_t client) +diagnostics_relay_error_t diagnostics_relay_goodbye(diagnostics_relay_client_t client) { if (!client) return DIAGNOSTICS_RELAY_E_INVALID_ARG; @@ -201,7 +201,7 @@ LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_goodbye(diagnos return ret; } -LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_sleep(diagnostics_relay_client_t client) +diagnostics_relay_error_t diagnostics_relay_sleep(diagnostics_relay_client_t client) { if (!client) return DIAGNOSTICS_RELAY_E_INVALID_ARG; @@ -277,17 +277,17 @@ static diagnostics_relay_error_t internal_diagnostics_relay_action(diagnostics_r return ret; } -LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_restart(diagnostics_relay_client_t client, diagnostics_relay_action_t flags) +diagnostics_relay_error_t diagnostics_relay_restart(diagnostics_relay_client_t client, diagnostics_relay_action_t flags) { return internal_diagnostics_relay_action(client, "Restart", flags); } -LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_shutdown(diagnostics_relay_client_t client, diagnostics_relay_action_t flags) +diagnostics_relay_error_t diagnostics_relay_shutdown(diagnostics_relay_client_t client, diagnostics_relay_action_t flags) { return internal_diagnostics_relay_action(client, "Shutdown", flags); } -LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_request_diagnostics(diagnostics_relay_client_t client, const char* type, plist_t* diagnostics) +diagnostics_relay_error_t diagnostics_relay_request_diagnostics(diagnostics_relay_client_t client, const char* type, plist_t* diagnostics) { if (!client || diagnostics == NULL) return DIAGNOSTICS_RELAY_E_INVALID_ARG; @@ -331,7 +331,7 @@ LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_request_diagnos return ret; } -LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_query_mobilegestalt(diagnostics_relay_client_t client, plist_t keys, plist_t* result) +diagnostics_relay_error_t diagnostics_relay_query_mobilegestalt(diagnostics_relay_client_t client, plist_t keys, plist_t* result) { if (!client || plist_get_node_type(keys) != PLIST_ARRAY || result == NULL) return DIAGNOSTICS_RELAY_E_INVALID_ARG; @@ -376,7 +376,7 @@ LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_query_mobileges return ret; } -LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_query_ioregistry_entry(diagnostics_relay_client_t client, const char* entry_name, const char* entry_class, plist_t* result) +diagnostics_relay_error_t diagnostics_relay_query_ioregistry_entry(diagnostics_relay_client_t client, const char* entry_name, const char* entry_class, plist_t* result) { if (!client || (entry_name == NULL && entry_class == NULL) || result == NULL) return DIAGNOSTICS_RELAY_E_INVALID_ARG; @@ -424,7 +424,7 @@ LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_query_ioregistr return ret; } -LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_query_ioregistry_plane(diagnostics_relay_client_t client, const char* plane, plist_t* result) +diagnostics_relay_error_t diagnostics_relay_query_ioregistry_plane(diagnostics_relay_client_t client, const char* plane, plist_t* result) { if (!client || plane == NULL || result == NULL) return DIAGNOSTICS_RELAY_E_INVALID_ARG; diff --git a/src/diagnostics_relay.h b/src/diagnostics_relay.h index 6d11ea1..3bb543a 100644 --- a/src/diagnostics_relay.h +++ b/src/diagnostics_relay.h @@ -22,6 +22,7 @@ #ifndef __DIAGNOSTICS_RELAY_H #define __DIAGNOSTICS_RELAY_H +#include "idevice.h" #include "libimobiledevice/diagnostics_relay.h" #include "property_list_service.h" diff --git a/src/file_relay.c b/src/file_relay.c index aa77ae6..fbe7cbf 100644 --- a/src/file_relay.c +++ b/src/file_relay.c @@ -28,7 +28,7 @@ #include "property_list_service.h" #include "common/debug.h" -LIBIMOBILEDEVICE_API file_relay_error_t file_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, file_relay_client_t *client) +file_relay_error_t file_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, file_relay_client_t *client) { if (!device || !service || service->port == 0 || !client || *client) { return FILE_RELAY_E_INVALID_ARG; @@ -48,14 +48,14 @@ LIBIMOBILEDEVICE_API file_relay_error_t file_relay_client_new(idevice_t device, return FILE_RELAY_E_SUCCESS; } -LIBIMOBILEDEVICE_API file_relay_error_t file_relay_client_start_service(idevice_t device, file_relay_client_t * client, const char* label) +file_relay_error_t file_relay_client_start_service(idevice_t device, file_relay_client_t * client, const char* label) { file_relay_error_t err = FILE_RELAY_E_UNKNOWN_ERROR; service_client_factory_start_service(device, FILE_RELAY_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(file_relay_client_new), &err); return err; } -LIBIMOBILEDEVICE_API file_relay_error_t file_relay_client_free(file_relay_client_t client) +file_relay_error_t file_relay_client_free(file_relay_client_t client) { if (!client) return FILE_RELAY_E_INVALID_ARG; @@ -67,7 +67,7 @@ LIBIMOBILEDEVICE_API file_relay_error_t file_relay_client_free(file_relay_client return FILE_RELAY_E_SUCCESS; } -LIBIMOBILEDEVICE_API file_relay_error_t file_relay_request_sources_timeout(file_relay_client_t client, const char **sources, idevice_connection_t *connection, unsigned int timeout) +file_relay_error_t file_relay_request_sources_timeout(file_relay_client_t client, const char **sources, idevice_connection_t *connection, unsigned int timeout) { if (!client || !client->parent || !sources || !sources[0]) { return FILE_RELAY_E_INVALID_ARG; @@ -159,7 +159,7 @@ leave: return err; } -LIBIMOBILEDEVICE_API file_relay_error_t file_relay_request_sources(file_relay_client_t client, const char **sources, idevice_connection_t *connection) +file_relay_error_t file_relay_request_sources(file_relay_client_t client, const char **sources, idevice_connection_t *connection) { return file_relay_request_sources_timeout(client, sources, connection, 60000); } diff --git a/src/file_relay.h b/src/file_relay.h index 626fab8..65bf460 100644 --- a/src/file_relay.h +++ b/src/file_relay.h @@ -22,6 +22,7 @@ #ifndef __FILE_RELAY_H #define __FILE_RELAY_H +#include "idevice.h" #include "libimobiledevice/file_relay.h" #include "property_list_service.h" diff --git a/src/heartbeat.c b/src/heartbeat.c index 9a527cc..3945d73 100644 --- a/src/heartbeat.c +++ b/src/heartbeat.c @@ -62,7 +62,7 @@ static heartbeat_error_t heartbeat_error(property_list_service_error_t err) return HEARTBEAT_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_client_new(idevice_t device, lockdownd_service_descriptor_t service, heartbeat_client_t * client) +heartbeat_error_t heartbeat_client_new(idevice_t device, lockdownd_service_descriptor_t service, heartbeat_client_t * client) { *client = NULL; @@ -89,14 +89,14 @@ LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_client_new(idevice_t device, lo return 0; } -LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_client_start_service(idevice_t device, heartbeat_client_t * client, const char* label) +heartbeat_error_t heartbeat_client_start_service(idevice_t device, heartbeat_client_t * client, const char* label) { heartbeat_error_t err = HEARTBEAT_E_UNKNOWN_ERROR; service_client_factory_start_service(device, HEARTBEAT_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(heartbeat_client_new), &err); return err; } -LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_client_free(heartbeat_client_t client) +heartbeat_error_t heartbeat_client_free(heartbeat_client_t client) { if (!client) return HEARTBEAT_E_INVALID_ARG; @@ -107,7 +107,7 @@ LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_client_free(heartbeat_client_t return err; } -LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_send(heartbeat_client_t client, plist_t plist) +heartbeat_error_t heartbeat_send(heartbeat_client_t client, plist_t plist) { heartbeat_error_t res = HEARTBEAT_E_UNKNOWN_ERROR; @@ -122,12 +122,12 @@ LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_send(heartbeat_client_t client, return res; } -LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_receive(heartbeat_client_t client, plist_t * plist) +heartbeat_error_t heartbeat_receive(heartbeat_client_t client, plist_t * plist) { return heartbeat_receive_with_timeout(client, plist, 1000); } -LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_receive_with_timeout(heartbeat_client_t client, plist_t * plist, uint32_t timeout_ms) +heartbeat_error_t heartbeat_receive_with_timeout(heartbeat_client_t client, plist_t * plist, uint32_t timeout_ms) { heartbeat_error_t res = HEARTBEAT_E_UNKNOWN_ERROR; plist_t outplist = NULL; diff --git a/src/heartbeat.h b/src/heartbeat.h index f648681..379ecc1 100644 --- a/src/heartbeat.h +++ b/src/heartbeat.h @@ -22,6 +22,7 @@ #ifndef __HEARTBEAT_H #define __HEARTBEAT_H +#include "idevice.h" #include "libimobiledevice/heartbeat.h" #include "property_list_service.h" diff --git a/src/house_arrest.c b/src/house_arrest.c index ac92130..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" @@ -58,7 +62,7 @@ static house_arrest_error_t house_arrest_error(property_list_service_error_t err return HOUSE_ARREST_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_client_new(idevice_t device, lockdownd_service_descriptor_t service, house_arrest_client_t *client) +house_arrest_error_t house_arrest_client_new(idevice_t device, lockdownd_service_descriptor_t service, house_arrest_client_t *client) { property_list_service_client_t plistclient = NULL; house_arrest_error_t err = house_arrest_error(property_list_service_client_new(device, service, &plistclient)); @@ -74,14 +78,14 @@ LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_client_new(idevice_t devi return HOUSE_ARREST_E_SUCCESS; } -LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_client_start_service(idevice_t device, house_arrest_client_t * client, const char* label) +house_arrest_error_t house_arrest_client_start_service(idevice_t device, house_arrest_client_t * client, const char* label) { house_arrest_error_t err = HOUSE_ARREST_E_UNKNOWN_ERROR; service_client_factory_start_service(device, HOUSE_ARREST_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(house_arrest_client_new), &err); return err; } -LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_client_free(house_arrest_client_t client) +house_arrest_error_t house_arrest_client_free(house_arrest_client_t client) { if (!client) return HOUSE_ARREST_E_INVALID_ARG; @@ -96,7 +100,7 @@ LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_client_free(house_arrest_ return err; } -LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_send_request(house_arrest_client_t client, plist_t dict) +house_arrest_error_t house_arrest_send_request(house_arrest_client_t client, plist_t dict) { if (!client || !client->parent || !dict) return HOUSE_ARREST_E_INVALID_ARG; @@ -112,7 +116,7 @@ LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_send_request(house_arrest return res; } -LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_send_command(house_arrest_client_t client, const char *command, const char *appid) +house_arrest_error_t house_arrest_send_command(house_arrest_client_t client, const char *command, const char *appid) { if (!client || !client->parent || !command || !appid) return HOUSE_ARREST_E_INVALID_ARG; @@ -132,7 +136,7 @@ LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_send_command(house_arrest return res; } -LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_get_result(house_arrest_client_t client, plist_t *dict) +house_arrest_error_t house_arrest_get_result(house_arrest_client_t client, plist_t *dict) { if (!client || !client->parent) return HOUSE_ARREST_E_INVALID_ARG; @@ -150,7 +154,7 @@ LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_get_result(house_arrest_c return res; } -LIBIMOBILEDEVICE_API afc_error_t afc_client_new_from_house_arrest_client(house_arrest_client_t client, afc_client_t *afc_client) +afc_error_t afc_client_new_from_house_arrest_client(house_arrest_client_t client, afc_client_t *afc_client) { if (!client || !client->parent || (client->mode == HOUSE_ARREST_CLIENT_MODE_AFC)) { return AFC_E_INVALID_ARG; diff --git a/src/house_arrest.h b/src/house_arrest.h index 387594f..5612a29 100644 --- a/src/house_arrest.h +++ b/src/house_arrest.h @@ -22,6 +22,7 @@ #ifndef __HOUSE_ARREST_H #define __HOUSE_ARREST_H +#include "idevice.h" #include "libimobiledevice/house_arrest.h" #include "property_list_service.h" diff --git a/src/idevice.c b/src/idevice.c index 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"; +} diff --git a/src/idevice.h b/src/idevice.h index 2509e48..e05338e 100644 --- a/src/idevice.h +++ b/src/idevice.h @@ -37,21 +37,21 @@ #include <mbedtls/ctr_drbg.h> #endif -#ifdef WIN32 -#define LIBIMOBILEDEVICE_API __declspec( dllexport ) +#ifdef LIBIMOBILEDEVICE_STATIC + #define LIBIMOBILEDEVICE_API +#elif defined(_WIN32) + #define LIBIMOBILEDEVICE_API __declspec( dllexport ) #else -#ifdef HAVE_FVISIBILITY -#define LIBIMOBILEDEVICE_API __attribute__((visibility("default"))) -#else -#define LIBIMOBILEDEVICE_API -#endif + #if __GNUC__ >= 4 + #define LIBIMOBILEDEVICE_API __attribute__((visibility("default"))) + #else + #define LIBIMOBILEDEVICE_API + #endif #endif #include "common/userpref.h" #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 b13abf9..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" @@ -232,7 +236,7 @@ static instproxy_error_t instproxy_error(property_list_service_error_t err) return INSTPROXY_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_client_new(idevice_t device, lockdownd_service_descriptor_t service, instproxy_client_t *client) +instproxy_error_t instproxy_client_new(idevice_t device, lockdownd_service_descriptor_t service, instproxy_client_t *client) { property_list_service_client_t plistclient = NULL; instproxy_error_t err = instproxy_error(property_list_service_client_new(device, service, &plistclient)); @@ -249,14 +253,14 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_client_new(idevice_t device, lo return INSTPROXY_E_SUCCESS; } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_client_start_service(idevice_t device, instproxy_client_t * client, const char* label) +instproxy_error_t instproxy_client_start_service(idevice_t device, instproxy_client_t * client, const char* label) { - instproxy_error_t err = INSTPROXY_E_UNKNOWN_ERROR; + 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; } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_client_free(instproxy_client_t client) +instproxy_error_t instproxy_client_free(instproxy_client_t client) { if (!client) return INSTPROXY_E_INVALID_ARG; @@ -525,7 +529,7 @@ static instproxy_error_t instproxy_perform_command(instproxy_client_t client, pl return res; } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_browse_with_callback(instproxy_client_t client, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) +instproxy_error_t instproxy_browse_with_callback(instproxy_client_t client, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) { if (!client || !client->parent || !status_cb) return INSTPROXY_E_INVALID_ARG; @@ -566,7 +570,7 @@ static void instproxy_append_current_list_to_result_cb(plist_t command, plist_t plist_free(current_list); } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_browse(instproxy_client_t client, plist_t client_options, plist_t *result) +instproxy_error_t instproxy_browse(instproxy_client_t client, plist_t client_options, plist_t *result) { if (!client || !client->parent || !result) return INSTPROXY_E_INVALID_ARG; @@ -603,7 +607,7 @@ static void instproxy_copy_lookup_result_cb(plist_t command, plist_t status, voi } } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_lookup(instproxy_client_t client, const char** appids, plist_t client_options, plist_t *result) +instproxy_error_t instproxy_lookup(instproxy_client_t client, const char** appids, plist_t client_options, plist_t *result) { instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; int i = 0; @@ -650,7 +654,7 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_lookup(instproxy_client_t clien return res; } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_install(instproxy_client_t client, const char *pkg_path, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) +instproxy_error_t instproxy_install(instproxy_client_t client, const char *pkg_path, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) { instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; @@ -667,7 +671,7 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_install(instproxy_client_t clie return res; } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_upgrade(instproxy_client_t client, const char *pkg_path, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) +instproxy_error_t instproxy_upgrade(instproxy_client_t client, const char *pkg_path, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) { instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; @@ -684,7 +688,7 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_upgrade(instproxy_client_t clie return res; } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) +instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) { instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; @@ -701,7 +705,7 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_uninstall(instproxy_client_t cl return res; } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist_t client_options, plist_t *result) +instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist_t client_options, plist_t *result) { instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; @@ -717,7 +721,7 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_lookup_archives(instproxy_clien return res; } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) +instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) { instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; @@ -734,7 +738,7 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_archive(instproxy_client_t clie return res; } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) +instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) { instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; @@ -751,7 +755,7 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_restore(instproxy_client_t clie return res; } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_remove_archive(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) +instproxy_error_t instproxy_remove_archive(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) { instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; @@ -768,7 +772,7 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_remove_archive(instproxy_client return res; } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_check_capabilities_match(instproxy_client_t client, const char** capabilities, plist_t client_options, plist_t *result) +instproxy_error_t instproxy_check_capabilities_match(instproxy_client_t client, const char** capabilities, plist_t client_options, plist_t *result) { if (!client || !capabilities || !result) return INSTPROXY_E_INVALID_ARG; @@ -805,7 +809,7 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_check_capabilities_match(instpr return res; } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_status_get_error(plist_t status, char **name, char** description, uint64_t* code) +instproxy_error_t instproxy_status_get_error(plist_t status, char **name, char** description, uint64_t* code) { instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; @@ -843,7 +847,7 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_status_get_error(plist_t status return res; } -LIBIMOBILEDEVICE_API void instproxy_status_get_name(plist_t status, char **name) +void instproxy_status_get_name(plist_t status, char **name) { if (name) { plist_t node = plist_dict_get_item(status, "Status"); @@ -855,7 +859,7 @@ LIBIMOBILEDEVICE_API void instproxy_status_get_name(plist_t status, char **name) } } -LIBIMOBILEDEVICE_API void instproxy_status_get_percent_complete(plist_t status, int *percent) +void instproxy_status_get_percent_complete(plist_t status, int *percent) { uint64_t val = 0; if (percent) { @@ -867,7 +871,7 @@ LIBIMOBILEDEVICE_API void instproxy_status_get_percent_complete(plist_t status, } } -LIBIMOBILEDEVICE_API void instproxy_status_get_current_list(plist_t status, uint64_t* total, uint64_t* current_index, uint64_t* current_amount, plist_t* list) +void instproxy_status_get_current_list(plist_t status, uint64_t* total, uint64_t* current_index, uint64_t* current_amount, plist_t* list) { plist_t node = NULL; @@ -904,7 +908,7 @@ LIBIMOBILEDEVICE_API void instproxy_status_get_current_list(plist_t status, uint } } -LIBIMOBILEDEVICE_API void instproxy_command_get_name(plist_t command, char** name) +void instproxy_command_get_name(plist_t command, char** name) { if (name) { plist_t node = plist_dict_get_item(command, "Command"); @@ -916,12 +920,12 @@ LIBIMOBILEDEVICE_API void instproxy_command_get_name(plist_t command, char** nam } } -LIBIMOBILEDEVICE_API plist_t instproxy_client_options_new(void) +plist_t instproxy_client_options_new(void) { return plist_new_dict(); } -LIBIMOBILEDEVICE_API void instproxy_client_options_add(plist_t client_options, ...) +void instproxy_client_options_add(plist_t client_options, ...) { if (!client_options) return; @@ -934,7 +938,7 @@ LIBIMOBILEDEVICE_API void instproxy_client_options_add(plist_t client_options, . if (!strcmp(key, "SkipUninstall")) { int intval = va_arg(args, int); plist_dict_set_item(client_options, key, plist_new_bool(intval)); - } else if (!strcmp(key, "ApplicationSINF") || !strcmp(key, "iTunesMetadata") || !strcmp(key, "ReturnAttributes")) { + } else if (!strcmp(key, "ApplicationSINF") || !strcmp(key, "iTunesMetadata") || !strcmp(key, "ReturnAttributes") || !strcmp(key, "BundleIDs")) { plist_t plistval = va_arg(args, plist_t); if (!plistval) { free(key); @@ -955,7 +959,7 @@ LIBIMOBILEDEVICE_API void instproxy_client_options_add(plist_t client_options, . va_end(args); } -LIBIMOBILEDEVICE_API void instproxy_client_options_set_return_attributes(plist_t client_options, ...) +void instproxy_client_options_set_return_attributes(plist_t client_options, ...) { if (!client_options) return; @@ -976,14 +980,14 @@ LIBIMOBILEDEVICE_API void instproxy_client_options_set_return_attributes(plist_t plist_dict_set_item(client_options, "ReturnAttributes", return_attributes); } -LIBIMOBILEDEVICE_API void instproxy_client_options_free(plist_t client_options) +void instproxy_client_options_free(plist_t client_options) { if (client_options) { plist_free(client_options); } } -LIBIMOBILEDEVICE_API instproxy_error_t instproxy_client_get_path_for_bundle_identifier(instproxy_client_t client, const char* bundle_id, char** path) +instproxy_error_t instproxy_client_get_path_for_bundle_identifier(instproxy_client_t client, const char* bundle_id, char** path) { if (!client || !client->parent || !bundle_id) return INSTPROXY_E_INVALID_ARG; diff --git a/src/installation_proxy.h b/src/installation_proxy.h index 033bdef..5bdbb71 100644 --- a/src/installation_proxy.h +++ b/src/installation_proxy.h @@ -23,6 +23,7 @@ #ifndef __INSTALLATION_PROXY_H #define __INSTALLATION_PROXY_H +#include "idevice.h" #include "libimobiledevice/installation_proxy.h" #include "property_list_service.h" #include <libimobiledevice-glue/thread.h> diff --git a/src/lockdown-cu.c b/src/lockdown-cu.c index cdaf02c..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" @@ -62,6 +66,7 @@ #include <sys/sysctl.h> #include <SystemConfiguration/SystemConfiguration.h> #include <CoreFoundation/CoreFoundation.h> +#include <TargetConditionals.h> #endif #include "property_list_service.h" @@ -293,7 +298,7 @@ poly1305_update_with_pad16(poly1305_state *poly1305, static void chacha20_poly1305_encrypt_96(unsigned char* key, unsigned char* nonce, unsigned char* ad, size_t ad_len, unsigned char* in, size_t in_len, unsigned char* out, size_t* out_len) { #if defined(HAVE_OPENSSL) -#if defined(LIBRESSL_VERSION_NUMBER) +#if defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x3050000fL) #if (LIBRESSL_VERSION_NUMBER >= 0x2040000fL) const EVP_AEAD *aead = EVP_aead_chacha20_poly1305(); EVP_AEAD_CTX ctx; @@ -377,7 +382,7 @@ static void chacha20_poly1305_encrypt_64(unsigned char* key, unsigned char* nonc static void chacha20_poly1305_decrypt_96(unsigned char* key, unsigned char* nonce, unsigned char* ad, size_t ad_len, unsigned char* in, size_t in_len, unsigned char* out, size_t* out_len) { #if defined(HAVE_OPENSSL) -#if defined(LIBRESSL_VERSION_NUMBER) +#if defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x3050000fL) #if (LIBRESSL_VERSION_NUMBER >= 0x2040000fL) const EVP_AEAD *aead = EVP_aead_chacha20_poly1305(); EVP_AEAD_CTX ctx; @@ -489,7 +494,7 @@ static void chacha20_poly1305_decrypt_64(unsigned char* key, unsigned char* nonc #endif /* HAVE_WIRELESS_PAIRING */ -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_cu_pairing_create(lockdownd_client_t client, lockdownd_cu_pairing_cb_t pairing_callback, void* cb_user_data, plist_t host_info, plist_t acl) +lockdownd_error_t lockdownd_cu_pairing_create(lockdownd_client_t client, lockdownd_cu_pairing_cb_t pairing_callback, void* cb_user_data, plist_t host_info, plist_t acl) { #ifdef HAVE_WIRELESS_PAIRING if (!client || !pairing_callback || (host_info && plist_get_node_type(host_info) != PLIST_DICT) || (acl && plist_get_node_type(acl) != PLIST_DICT)) @@ -504,7 +509,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_cu_pairing_create(lockdownd_cli 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); } @@ -647,12 +652,12 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_cu_pairing_create(lockdownd_cli /* HOST INFORMATION */ char hostname[256]; -#ifdef __APPLE__ +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) CFStringRef cname = SCDynamicStoreCopyComputerName(NULL, NULL); CFStringGetCString(cname, hostname, sizeof(hostname), kCFStringEncodingUTF8); CFRelease(cname); #else -#ifdef WIN32 +#ifdef _WIN32 DWORD hostname_len = sizeof(hostname); GetComputerName(hostname, &hostname_len); #else @@ -931,7 +936,7 @@ debug_buffer(data, data_len); #endif } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_cu_send_request_and_get_reply(lockdownd_client_t client, const char* request, plist_t request_payload, plist_t* reply) +lockdownd_error_t lockdownd_cu_send_request_and_get_reply(lockdownd_client_t client, const char* request, plist_t request_payload, plist_t* reply) { #ifdef HAVE_WIRELESS_PAIRING if (!client || !request) @@ -956,12 +961,12 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_cu_send_request_and_get_reply(l 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 } @@ -1031,7 +1036,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_cu_send_request_and_get_reply(l plist_free(dict); dict = NULL; - plist_from_memory((const char*)decrypted, decrypted_len, &dict); + plist_from_memory((const char*)decrypted, decrypted_len, &dict, NULL); if (!dict) { ret = LOCKDOWN_E_PLIST_ERROR; debug_info("Failed to parse PLIST from decrypted payload:"); @@ -1056,7 +1061,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_cu_send_request_and_get_reply(l #endif } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_value_cu(lockdownd_client_t client, const char* domain, const char* key, plist_t* value) +lockdownd_error_t lockdownd_get_value_cu(lockdownd_client_t client, const char* domain, const char* key, plist_t* value) { #ifdef HAVE_WIRELESS_PAIRING if (!client) @@ -1096,7 +1101,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_value_cu(lockdownd_client_t #endif } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_pair_cu(lockdownd_client_t client) +lockdownd_error_t lockdownd_pair_cu(lockdownd_client_t client) { #ifdef HAVE_WIRELESS_PAIRING if (!client) @@ -1127,7 +1132,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_pair_cu(lockdownd_client_t clie 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 505b13e..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 @@ -165,51 +169,38 @@ lockdownd_error_t lockdown_check_result(plist_t dict, const char *query_match) return ret; } - char *query_value = NULL; - - plist_get_string_val(query_node, &query_value); + const char *query_value = plist_get_string_ptr(query_node, NULL); if (!query_value) { return ret; } if (query_match && (strcmp(query_value, query_match) != 0)) { - free(query_value); return ret; } - free(query_value); - - plist_t result_node = plist_dict_get_item(dict, "Result"); - if (!result_node) { - /* iOS 5: the 'Result' key is not present anymore. - But we need to check for the 'Error' key. */ - plist_t err_node = plist_dict_get_item(dict, "Error"); - if (err_node) { - if (plist_get_node_type(err_node) == PLIST_STRING) { - char *err_value = NULL; - - plist_get_string_val(err_node, &err_value); - if (err_value) { - debug_info("ERROR: %s", err_value); - ret = lockdownd_strtoerr(err_value); - free(err_value); - } else { - debug_info("ERROR: unknown error occurred"); - } + /* Check for 'Error' in reply */ + plist_t err_node = plist_dict_get_item(dict, "Error"); + if (err_node) { + if (plist_get_node_type(err_node) == PLIST_STRING) { + const char *err_value = plist_get_string_ptr(err_node, NULL); + if (err_value) { + debug_info("ERROR: %s", err_value); + ret = lockdownd_strtoerr(err_value); + } else { + debug_info("ERROR: unknown error occurred"); } - return ret; } - - ret = LOCKDOWN_E_SUCCESS; - return ret; } - plist_type result_type = plist_get_node_type(result_node); - if (result_type == PLIST_STRING) { - char *result_value = NULL; - - plist_get_string_val(result_node, &result_value); + plist_t result_node = plist_dict_get_item(dict, "Result"); + if (!result_node) { + /* With iOS 5+ 'Result' is not present anymore. + If there is no 'Error', we can just assume success. */ + return LOCKDOWN_E_SUCCESS; + } + if (plist_get_node_type(result_node) == PLIST_STRING) { + const char *result_value = plist_get_string_ptr(result_node, NULL); if (result_value) { if (!strcmp(result_value, "Success")) { ret = LOCKDOWN_E_SUCCESS; @@ -219,9 +210,6 @@ lockdownd_error_t lockdown_check_result(plist_t dict, const char *query_match) debug_info("ERROR: unknown result value '%s'", result_value); } } - - if (result_value) - free(result_value); } return ret; @@ -242,7 +230,7 @@ static void plist_dict_add_label(plist_t plist, const char *label) } } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client, const char *session_id) +lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client, const char *session_id) { if (!client) return LOCKDOWN_E_INVALID_ARG; @@ -325,7 +313,7 @@ static lockdownd_error_t lockdownd_client_free_simple(lockdownd_client_t client) return ret; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_free(lockdownd_client_t client) +lockdownd_error_t lockdownd_client_free(lockdownd_client_t client) { if (!client) return LOCKDOWN_E_INVALID_ARG; @@ -341,7 +329,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_free(lockdownd_client_t return ret; } -LIBIMOBILEDEVICE_API void lockdownd_client_set_label(lockdownd_client_t client, const char *label) +void lockdownd_client_set_label(lockdownd_client_t client, const char *label) { if (client) { if (client->label) @@ -351,7 +339,7 @@ LIBIMOBILEDEVICE_API void lockdownd_client_set_label(lockdownd_client_t client, } } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_receive(lockdownd_client_t client, plist_t *plist) +lockdownd_error_t lockdownd_receive(lockdownd_client_t client, plist_t *plist) { if (!client || !plist || (plist && *plist)) return LOCKDOWN_E_INVALID_ARG; @@ -359,7 +347,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_receive(lockdownd_client_t clie return lockdownd_error(property_list_service_receive_plist(client->parent, plist)); } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_send(lockdownd_client_t client, plist_t plist) +lockdownd_error_t lockdownd_send(lockdownd_client_t client, plist_t plist) { if (!client || !plist) return LOCKDOWN_E_INVALID_ARG; @@ -367,7 +355,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_send(lockdownd_client_t client, return lockdownd_error(property_list_service_send_xml_plist(client->parent, plist)); } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_query_type(lockdownd_client_t client, char **type) +lockdownd_error_t lockdownd_query_type(lockdownd_client_t client, char **type) { if (!client) return LOCKDOWN_E_INVALID_ARG; @@ -412,7 +400,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_query_type(lockdownd_client_t c return ret; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *domain, const char *key, plist_t *value) +lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *domain, const char *key, plist_t *value) { if (!client) return LOCKDOWN_E_INVALID_ARG; @@ -466,7 +454,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_value(lockdownd_client_t cl return ret; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_set_value(lockdownd_client_t client, const char *domain, const char *key, plist_t value) +lockdownd_error_t lockdownd_set_value(lockdownd_client_t client, const char *domain, const char *key, plist_t value) { if (!client || !value) return LOCKDOWN_E_INVALID_ARG; @@ -514,7 +502,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_set_value(lockdownd_client_t cl return ret; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_remove_value(lockdownd_client_t client, const char *domain, const char *key) +lockdownd_error_t lockdownd_remove_value(lockdownd_client_t client, const char *domain, const char *key) { if (!client) return LOCKDOWN_E_INVALID_ARG; @@ -561,7 +549,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_remove_value(lockdownd_client_t return ret; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_device_udid(lockdownd_client_t client, char **udid) +lockdownd_error_t lockdownd_get_device_udid(lockdownd_client_t client, char **udid) { lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; plist_t value = NULL; @@ -607,7 +595,7 @@ static lockdownd_error_t lockdownd_get_device_public_key_as_key_data(lockdownd_c return ret; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_device_name(lockdownd_client_t client, char **device_name) +lockdownd_error_t lockdownd_get_device_name(lockdownd_client_t client, char **device_name) { lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; plist_t value = NULL; @@ -624,7 +612,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_device_name(lockdownd_clien return ret; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_new(idevice_t device, lockdownd_client_t *client, const char *label) +lockdownd_error_t lockdownd_client_new(idevice_t device, lockdownd_client_t *client, const char *label) { if (!device || !client) return LOCKDOWN_E_INVALID_ARG; @@ -633,6 +621,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_new(idevice_t device, lo .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) { @@ -654,51 +643,32 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_new(idevice_t device, lo client_loc->label = label ? strdup(label) : NULL; - *client = client_loc; - - return LOCKDOWN_E_SUCCESS; -} - -LIBIMOBILEDEVICE_API 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; @@ -723,6 +693,26 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_new_with_handshake(idevi 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); @@ -746,7 +736,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_new_with_handshake(idevi 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); @@ -852,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; @@ -862,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; } @@ -1072,7 +1063,7 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_ return ret; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record) +lockdownd_error_t lockdownd_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record) { plist_t options = plist_new_dict(); @@ -1085,22 +1076,22 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_pair(lockdownd_client_t client, return ret; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_pair_with_options(lockdownd_client_t client, lockdownd_pair_record_t pair_record, plist_t options, plist_t *response) +lockdownd_error_t lockdownd_pair_with_options(lockdownd_client_t client, lockdownd_pair_record_t pair_record, plist_t options, plist_t *response) { return lockdownd_do_pair(client, pair_record, "Pair", options, response); } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_validate_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record) +lockdownd_error_t lockdownd_validate_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record) { return lockdownd_do_pair(client, pair_record, "ValidatePair", NULL, NULL); } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_unpair(lockdownd_client_t client, lockdownd_pair_record_t pair_record) +lockdownd_error_t lockdownd_unpair(lockdownd_client_t client, lockdownd_pair_record_t pair_record) { return lockdownd_do_pair(client, pair_record, "Unpair", NULL, NULL); } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_enter_recovery(lockdownd_client_t client) +lockdownd_error_t lockdownd_enter_recovery(lockdownd_client_t client) { if (!client) return LOCKDOWN_E_INVALID_ARG; @@ -1130,7 +1121,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_enter_recovery(lockdownd_client return ret; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client) +lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client) { if (!client) return LOCKDOWN_E_INVALID_ARG; @@ -1164,7 +1155,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_goodbye(lockdownd_client_t clie return ret; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_start_session(lockdownd_client_t client, const char *host_id, char **session_id, int *ssl_enabled) +lockdownd_error_t lockdownd_start_session(lockdownd_client_t client, const char *host_id, char **session_id, int *ssl_enabled) { lockdownd_error_t ret = LOCKDOWN_E_SUCCESS; plist_t dict = NULL; @@ -1408,17 +1399,17 @@ static lockdownd_error_t lockdownd_do_start_service(lockdownd_client_t client, c return ret; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char *identifier, lockdownd_service_descriptor_t *service) +lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char *identifier, lockdownd_service_descriptor_t *service) { return lockdownd_do_start_service(client, identifier, 0, service); } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_start_service_with_escrow_bag(lockdownd_client_t client, const char *identifier, lockdownd_service_descriptor_t *service) +lockdownd_error_t lockdownd_start_service_with_escrow_bag(lockdownd_client_t client, const char *identifier, lockdownd_service_descriptor_t *service) { return lockdownd_do_start_service(client, identifier, 1, service); } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_activate(lockdownd_client_t client, plist_t activation_record) +lockdownd_error_t lockdownd_activate(lockdownd_client_t client, plist_t activation_record) { if (!client) return LOCKDOWN_E_INVALID_ARG; @@ -1457,7 +1448,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_activate(lockdownd_client_t cli return ret; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_deactivate(lockdownd_client_t client) +lockdownd_error_t lockdownd_deactivate(lockdownd_client_t client) { if (!client) return LOCKDOWN_E_INVALID_ARG; @@ -1504,7 +1495,7 @@ static void str_remove_spaces(char *source) *dest = 0; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_sync_data_classes(lockdownd_client_t client, char ***classes, int *count) +lockdownd_error_t lockdownd_get_sync_data_classes(lockdownd_client_t client, char ***classes, int *count) { if (!client) return LOCKDOWN_E_INVALID_ARG; @@ -1559,7 +1550,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_sync_data_classes(lockdownd return LOCKDOWN_E_SUCCESS; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_data_classes_free(char **classes) +lockdownd_error_t lockdownd_data_classes_free(char **classes) { if (classes) { int i = 0; @@ -1571,7 +1562,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_data_classes_free(char **classe return LOCKDOWN_E_SUCCESS; } -LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_service_descriptor_free(lockdownd_service_descriptor_t service) +lockdownd_error_t lockdownd_service_descriptor_free(lockdownd_service_descriptor_t service) { if (service) { free(service->identifier); @@ -1581,7 +1572,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_service_descriptor_free(lockdow return LOCKDOWN_E_SUCCESS; } -LIBIMOBILEDEVICE_API const char* lockdownd_strerror(lockdownd_error_t err) +const char* lockdownd_strerror(lockdownd_error_t err) { switch (err) { case LOCKDOWN_E_SUCCESS: diff --git a/src/lockdown.h b/src/lockdown.h index bcd4717..ba291ec 100644 --- a/src/lockdown.h +++ b/src/lockdown.h @@ -23,6 +23,7 @@ #ifndef __LOCKDOWND_H #define __LOCKDOWND_H +#include "idevice.h" #include "libimobiledevice/lockdown.h" #include "property_list_service.h" diff --git a/src/misagent.c b/src/misagent.c index af925f9..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" @@ -89,7 +93,7 @@ static misagent_error_t misagent_check_result(plist_t response, int* status_code return MISAGENT_E_REQUEST_FAILED; } -LIBIMOBILEDEVICE_API misagent_error_t misagent_client_new(idevice_t device, lockdownd_service_descriptor_t service, misagent_client_t *client) +misagent_error_t misagent_client_new(idevice_t device, lockdownd_service_descriptor_t service, misagent_client_t *client) { property_list_service_client_t plistclient = NULL; misagent_error_t err = misagent_error(property_list_service_client_new(device, service, &plistclient)); @@ -105,14 +109,14 @@ LIBIMOBILEDEVICE_API misagent_error_t misagent_client_new(idevice_t device, lock return MISAGENT_E_SUCCESS; } -LIBIMOBILEDEVICE_API misagent_error_t misagent_client_start_service(idevice_t device, misagent_client_t * client, const char* label) +misagent_error_t misagent_client_start_service(idevice_t device, misagent_client_t * client, const char* label) { misagent_error_t err = MISAGENT_E_UNKNOWN_ERROR; service_client_factory_start_service(device, MISAGENT_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(misagent_client_new), &err); return err; } -LIBIMOBILEDEVICE_API misagent_error_t misagent_client_free(misagent_client_t client) +misagent_error_t misagent_client_free(misagent_client_t client) { if (!client) return MISAGENT_E_INVALID_ARG; @@ -127,7 +131,7 @@ LIBIMOBILEDEVICE_API misagent_error_t misagent_client_free(misagent_client_t cli return err; } -LIBIMOBILEDEVICE_API misagent_error_t misagent_install(misagent_client_t client, plist_t profile) +misagent_error_t misagent_install(misagent_client_t client, plist_t profile) { if (!client || !client->parent || !profile || (plist_get_node_type(profile) != PLIST_DATA)) return MISAGENT_E_INVALID_ARG; @@ -164,7 +168,7 @@ LIBIMOBILEDEVICE_API misagent_error_t misagent_install(misagent_client_t client, return res; } -LIBIMOBILEDEVICE_API misagent_error_t misagent_copy(misagent_client_t client, plist_t* profiles) +misagent_error_t misagent_copy(misagent_client_t client, plist_t* profiles) { if (!client || !client->parent || !profiles) return MISAGENT_E_INVALID_ARG; @@ -204,7 +208,7 @@ LIBIMOBILEDEVICE_API misagent_error_t misagent_copy(misagent_client_t client, pl } -LIBIMOBILEDEVICE_API misagent_error_t misagent_copy_all(misagent_client_t client, plist_t* profiles) +misagent_error_t misagent_copy_all(misagent_client_t client, plist_t* profiles) { if (!client || !client->parent || !profiles) return MISAGENT_E_INVALID_ARG; @@ -244,7 +248,7 @@ LIBIMOBILEDEVICE_API misagent_error_t misagent_copy_all(misagent_client_t client } -LIBIMOBILEDEVICE_API misagent_error_t misagent_remove(misagent_client_t client, const char* profileID) +misagent_error_t misagent_remove(misagent_client_t client, const char* profileID) { if (!client || !client->parent || !profileID) return MISAGENT_E_INVALID_ARG; @@ -281,7 +285,7 @@ LIBIMOBILEDEVICE_API misagent_error_t misagent_remove(misagent_client_t client, return res; } -LIBIMOBILEDEVICE_API int misagent_get_status_code(misagent_client_t client) +int misagent_get_status_code(misagent_client_t client) { if (!client) { return -1; diff --git a/src/misagent.h b/src/misagent.h index 08ad063..e394087 100644 --- a/src/misagent.h +++ b/src/misagent.h @@ -22,6 +22,7 @@ #ifndef __MISAGENT_H #define __MISAGENT_H +#include "idevice.h" #include "libimobiledevice/misagent.h" #include "property_list_service.h" diff --git a/src/mobile_image_mounter.c b/src/mobile_image_mounter.c index 9ccfd85..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" @@ -78,7 +82,7 @@ static mobile_image_mounter_error_t mobile_image_mounter_error(property_list_ser return MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_new(idevice_t device, lockdownd_service_descriptor_t service, mobile_image_mounter_client_t *client) +mobile_image_mounter_error_t mobile_image_mounter_new(idevice_t device, lockdownd_service_descriptor_t service, mobile_image_mounter_client_t *client) { property_list_service_client_t plistclient = NULL; mobile_image_mounter_error_t err = mobile_image_mounter_error(property_list_service_client_new(device, service, &plistclient)); @@ -95,14 +99,14 @@ LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_new(idevi return MOBILE_IMAGE_MOUNTER_E_SUCCESS; } -LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_start_service(idevice_t device, mobile_image_mounter_client_t * client, const char* label) +mobile_image_mounter_error_t mobile_image_mounter_start_service(idevice_t device, mobile_image_mounter_client_t * client, const char* label) { mobile_image_mounter_error_t err = MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR; service_client_factory_start_service(device, MOBILE_IMAGE_MOUNTER_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(mobile_image_mounter_new), &err); return err; } -LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_free(mobile_image_mounter_client_t client) +mobile_image_mounter_error_t mobile_image_mounter_free(mobile_image_mounter_client_t client) { if (!client) return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; @@ -115,7 +119,7 @@ LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_free(mobi return MOBILE_IMAGE_MOUNTER_E_SUCCESS; } -LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_lookup_image(mobile_image_mounter_client_t client, const char *image_type, plist_t *result) +mobile_image_mounter_error_t mobile_image_mounter_lookup_image(mobile_image_mounter_client_t client, const char *image_type, plist_t *result) { if (!client || !image_type || !result) { return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; @@ -181,7 +185,7 @@ static mobile_image_mounter_error_t process_result(plist_t result, const char *e return res; } -LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_upload_image(mobile_image_mounter_client_t client, const char *image_type, size_t image_size, const char *signature, uint16_t signature_size, mobile_image_mounter_upload_cb_t upload_cb, void* userdata) +mobile_image_mounter_error_t mobile_image_mounter_upload_image(mobile_image_mounter_client_t client, const char *image_type, size_t image_size, const unsigned char *signature, unsigned int signature_size, mobile_image_mounter_upload_cb_t upload_cb, void* userdata) { if (!client || !image_type || (image_size == 0) || !upload_cb) { return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; @@ -192,7 +196,7 @@ LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_upload_im plist_t dict = plist_new_dict(); plist_dict_set_item(dict, "Command", plist_new_string("ReceiveBytes")); if (signature && signature_size != 0) - plist_dict_set_item(dict, "ImageSignature", plist_new_data(signature, signature_size)); + plist_dict_set_item(dict, "ImageSignature", plist_new_data((char*)signature, signature_size)); plist_dict_set_item(dict, "ImageSize", plist_new_uint(image_size)); plist_dict_set_item(dict, "ImageType", plist_new_string(image_type)); @@ -241,6 +245,7 @@ LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_upload_im free(buf); if (tx < image_size) { debug_info("Error: failed to upload image"); + res = MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED; goto leave_unlock; } debug_info("image uploaded"); @@ -260,7 +265,7 @@ leave_unlock: } -LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_mount_image(mobile_image_mounter_client_t client, const char *image_path, const char *signature, uint16_t signature_size, const char *image_type, plist_t *result) +mobile_image_mounter_error_t mobile_image_mounter_mount_image_with_options(mobile_image_mounter_client_t client, const char *image_path, const unsigned char *signature, unsigned int signature_size, const char *image_type, plist_t options, plist_t *result) { if (!client || !image_path || !image_type || !result) { return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; @@ -271,8 +276,11 @@ LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_mount_ima plist_dict_set_item(dict, "Command", plist_new_string("MountImage")); plist_dict_set_item(dict, "ImagePath", plist_new_string(image_path)); if (signature && signature_size != 0) - plist_dict_set_item(dict, "ImageSignature", plist_new_data(signature, signature_size)); + plist_dict_set_item(dict, "ImageSignature", plist_new_data((char*)signature, signature_size)); plist_dict_set_item(dict, "ImageType", plist_new_string(image_type)); + if (PLIST_IS_DICT(options)) { + plist_dict_merge(&dict, options); + } mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); plist_free(dict); @@ -292,7 +300,57 @@ leave_unlock: return res; } -LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_hangup(mobile_image_mounter_client_t client) +mobile_image_mounter_error_t mobile_image_mounter_mount_image(mobile_image_mounter_client_t client, const char *image_path, const unsigned char *signature, unsigned int signature_size, const char *image_type, plist_t *result) +{ + return mobile_image_mounter_mount_image_with_options(client, image_path, signature, signature_size, image_type, NULL, result); +} + +mobile_image_mounter_error_t mobile_image_mounter_unmount_image(mobile_image_mounter_client_t client, const char *mount_path) +{ + if (!client || !mount_path) { + return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; + } + mobile_image_mounter_lock(client); + + plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "Command", plist_new_string("UnmountImage")); + plist_dict_set_item(dict, "MountPath", plist_new_string(mount_path)); + mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); + plist_free(dict); + + if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { + debug_info("%s: Error sending XML plist to device!", __func__); + goto leave_unlock; + } + + plist_t result = NULL; + res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, &result)); + if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { + debug_info("%s: Error receiving response from device!", __func__); + } else { + plist_t p_error = plist_dict_get_item(result, "Error"); + if (p_error) { + plist_t p_detailed = plist_dict_get_item(result, "DetailedError"); + const char* detailederr = (p_detailed) ? plist_get_string_ptr(p_detailed, NULL) : ""; + const char* errstr = plist_get_string_ptr(p_error, NULL); + if (errstr && !strcmp(errstr, "UnknownCommand")) { + res = MOBILE_IMAGE_MOUNTER_E_NOT_SUPPORTED; + } else if (errstr && !strcmp(errstr, "DeviceLocked")) { + res = MOBILE_IMAGE_MOUNTER_E_DEVICE_LOCKED; + } else if (strstr(detailederr, "no matching entry")) { + res = MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED; + } else { + res = MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR; + } + } + } + +leave_unlock: + mobile_image_mounter_unlock(client); + return res; +} + +mobile_image_mounter_error_t mobile_image_mounter_hangup(mobile_image_mounter_client_t client) { if (!client) { return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; @@ -324,3 +382,215 @@ leave_unlock: mobile_image_mounter_unlock(client); return res; } + +mobile_image_mounter_error_t mobile_image_mounter_query_developer_mode_status(mobile_image_mounter_client_t client, plist_t *result) +{ + if (!client || !result) { + return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; + } + mobile_image_mounter_lock(client); + + plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "Command", plist_new_string("QueryDeveloperModeStatus")); + mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); + plist_free(dict); + + if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { + debug_info("%s: Error sending XML plist to device!", __func__); + goto leave_unlock; + } + + res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, result)); + if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { + debug_info("%s: Error receiving response from device!", __func__); + } + +leave_unlock: + mobile_image_mounter_unlock(client); + return res; +} + +mobile_image_mounter_error_t mobile_image_mounter_query_nonce(mobile_image_mounter_client_t client, const char* image_type, unsigned char** nonce, unsigned int* nonce_size) +{ + if (!client || !nonce || !nonce_size) { + return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; + } + mobile_image_mounter_lock(client); + + plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "Command", plist_new_string("QueryNonce")); + if (image_type) { + plist_dict_set_item(dict, "PersonalizedImageType", plist_new_string(image_type)); + } + mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); + plist_free(dict); + + if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { + debug_info("%s: Error sending XML plist to device!", __func__); + goto leave_unlock; + } + + plist_t result = NULL; + res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, &result)); + if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { + debug_info("%s: Error receiving response from device!", __func__); + } else { + plist_t p_nonce = plist_dict_get_item(result, "PersonalizationNonce"); + if (!p_nonce) { + res = MOBILE_IMAGE_MOUNTER_E_NOT_SUPPORTED; + } else { + uint64_t nonce_size_ = 0; + plist_get_data_val(p_nonce, (char**)nonce, &nonce_size_); + if (*nonce) { + *nonce_size = (unsigned int)nonce_size_; + } else { + res = MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED; + } + } + } + plist_free(result); + +leave_unlock: + mobile_image_mounter_unlock(client); + return res; +} + +mobile_image_mounter_error_t mobile_image_mounter_query_personalization_identifiers(mobile_image_mounter_client_t client, const char* image_type, plist_t *result) +{ + if (!client || !result) { + return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; + } + mobile_image_mounter_lock(client); + + plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "Command", plist_new_string("QueryPersonalizationIdentifiers")); + if (image_type) { + plist_dict_set_item(dict, "PersonalizedImageType", plist_new_string(image_type)); + } + mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); + plist_free(dict); + + if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { + debug_info("%s: Error sending XML plist to device!", __func__); + goto leave_unlock; + } + + plist_t _result = NULL; + res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, &_result)); + if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { + debug_info("%s: Error receiving response from device!", __func__); + } + *result = plist_copy(plist_dict_get_item(_result, "PersonalizationIdentifiers")); + if (!*result) { + debug_info("%s: Response did not contain PersonalizationIdentifiers!", __func__); + res = MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED; + } + +leave_unlock: + mobile_image_mounter_unlock(client); + return res; +} + +mobile_image_mounter_error_t mobile_image_mounter_query_personalization_manifest(mobile_image_mounter_client_t client, const char* image_type, const unsigned char* signature, unsigned int signature_size, unsigned char** manifest, unsigned int* manifest_size) +{ + if (!client || !image_type || !signature || !signature_size || !manifest || !manifest_size) { + return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; + } + mobile_image_mounter_lock(client); + + plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "Command", plist_new_string("QueryPersonalizationManifest")); + plist_dict_set_item(dict, "PersonalizedImageType", plist_new_string(image_type)); + plist_dict_set_item(dict, "ImageType", plist_new_string(image_type)); + plist_dict_set_item(dict, "ImageSignature", plist_new_data((char*)signature, signature_size)); + + mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); + plist_free(dict); + + if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { + debug_info("%s: Error sending XML plist to device!", __func__); + goto leave_unlock; + } + + plist_t result = NULL; + res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, &result)); + if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { + debug_info("%s: Error receiving response from device!", __func__); + } else { + plist_t p_manifest = plist_dict_get_item(result, "ImageSignature"); + if (!p_manifest) { + res = MOBILE_IMAGE_MOUNTER_E_NOT_SUPPORTED; + } else { + uint64_t manifest_size_ = 0; + plist_get_data_val(p_manifest, (char**)manifest, &manifest_size_); + if (*manifest) { + *manifest_size = (unsigned int)manifest_size_; + } else { + res = MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED; + } + } + } + plist_free(result); + +leave_unlock: + mobile_image_mounter_unlock(client); + return res; +} + +mobile_image_mounter_error_t mobile_image_mounter_roll_personalization_nonce(mobile_image_mounter_client_t client) +{ + if (!client) { + return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; + } + mobile_image_mounter_lock(client); + + plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "Command", plist_new_string("RollPersonalizationNonce")); + mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); + plist_free(dict); + + if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { + debug_info("%s: Error sending XML plist to device!", __func__); + goto leave_unlock; + } + + plist_t result = NULL; + res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, &result)); + if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { + debug_info("%s: Error receiving response from device!", __func__); + } + plist_free(result); + +leave_unlock: + mobile_image_mounter_unlock(client); + return res; +} + +mobile_image_mounter_error_t mobile_image_mounter_roll_cryptex_nonce(mobile_image_mounter_client_t client) +{ + if (!client) { + return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; + } + mobile_image_mounter_lock(client); + + plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "Command", plist_new_string("RollCryptexNonce")); + mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); + plist_free(dict); + + if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { + debug_info("%s: Error sending XML plist to device!", __func__); + goto leave_unlock; + } + + plist_t result = NULL; + res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, &result)); + if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { + debug_info("%s: Error receiving response from device!", __func__); + } + plist_free(result); + +leave_unlock: + mobile_image_mounter_unlock(client); + return res; +} diff --git a/src/mobile_image_mounter.h b/src/mobile_image_mounter.h index 55c9cf2..9a8fcdd 100644 --- a/src/mobile_image_mounter.h +++ b/src/mobile_image_mounter.h @@ -22,6 +22,7 @@ #ifndef __MOBILE_IMAGE_MOUNTER_H #define __MOBILE_IMAGE_MOUNTER_H +#include "idevice.h" #include "libimobiledevice/mobile_image_mounter.h" #include "property_list_service.h" #include <libimobiledevice-glue/thread.h> diff --git a/src/mobileactivation.c b/src/mobileactivation.c index 79c7003..fce5f16 100644 --- a/src/mobileactivation.c +++ b/src/mobileactivation.c @@ -54,7 +54,7 @@ static mobileactivation_error_t mobileactivation_error(property_list_service_err return MOBILEACTIVATION_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobileactivation_client_t *client) +mobileactivation_error_t mobileactivation_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobileactivation_client_t *client) { if (!device || !service || service->port == 0 || !client || *client) { return MOBILEACTIVATION_E_INVALID_ARG; @@ -74,14 +74,14 @@ LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_client_new(idevic return MOBILEACTIVATION_E_SUCCESS; } -LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_client_start_service(idevice_t device, mobileactivation_client_t * client, const char* label) +mobileactivation_error_t mobileactivation_client_start_service(idevice_t device, mobileactivation_client_t * client, const char* label) { mobileactivation_error_t err = MOBILEACTIVATION_E_UNKNOWN_ERROR; service_client_factory_start_service(device, MOBILEACTIVATION_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(mobileactivation_client_new), &err); return err; } -LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_client_free(mobileactivation_client_t client) +mobileactivation_error_t mobileactivation_client_free(mobileactivation_client_t client) { if (!client) return MOBILEACTIVATION_E_INVALID_ARG; @@ -176,7 +176,7 @@ static mobileactivation_error_t mobileactivation_send_command(mobileactivation_c return ret; } -LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_get_activation_state(mobileactivation_client_t client, plist_t *state) +mobileactivation_error_t mobileactivation_get_activation_state(mobileactivation_client_t client, plist_t *state) { if (!client || !state) return MOBILEACTIVATION_E_INVALID_ARG; @@ -198,7 +198,7 @@ LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_get_activation_st return ret; } -LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_create_activation_session_info(mobileactivation_client_t client, plist_t *blob) +mobileactivation_error_t mobileactivation_create_activation_session_info(mobileactivation_client_t client, plist_t *blob) { if (!client || !blob) return MOBILEACTIVATION_E_INVALID_ARG; @@ -218,7 +218,7 @@ LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_create_activation return ret; } -LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_create_activation_info(mobileactivation_client_t client, plist_t *info) +mobileactivation_error_t mobileactivation_create_activation_info(mobileactivation_client_t client, plist_t *info) { if (!client || !info) return MOBILEACTIVATION_E_INVALID_ARG; @@ -240,7 +240,7 @@ LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_create_activation return ret; } -LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_create_activation_info_with_session(mobileactivation_client_t client, plist_t handshake_response, plist_t *info) +mobileactivation_error_t mobileactivation_create_activation_info_with_session(mobileactivation_client_t client, plist_t handshake_response, plist_t *info) { if (!client || !info) return MOBILEACTIVATION_E_INVALID_ARG; @@ -264,7 +264,7 @@ LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_create_activation return ret; } -LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_activate(mobileactivation_client_t client, plist_t activation_record) +mobileactivation_error_t mobileactivation_activate(mobileactivation_client_t client, plist_t activation_record) { if (!client || !activation_record) return MOBILEACTIVATION_E_INVALID_ARG; @@ -277,7 +277,7 @@ LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_activate(mobileac return ret; } -LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_activate_with_session(mobileactivation_client_t client, plist_t activation_record, plist_t headers) +mobileactivation_error_t mobileactivation_activate_with_session(mobileactivation_client_t client, plist_t activation_record, plist_t headers) { if (!client || !activation_record) return MOBILEACTIVATION_E_INVALID_ARG; @@ -300,7 +300,7 @@ LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_activate_with_ses } -LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_deactivate(mobileactivation_client_t client) +mobileactivation_error_t mobileactivation_deactivate(mobileactivation_client_t client) { if (!client) return MOBILEACTIVATION_E_INVALID_ARG; diff --git a/src/mobileactivation.h b/src/mobileactivation.h index 49b9ebc..a8dff5d 100644 --- a/src/mobileactivation.h +++ b/src/mobileactivation.h @@ -22,6 +22,7 @@ #ifndef __MOBILEACTIVATION_H #define __MOBILEACTIVATION_H +#include "idevice.h" #include "libimobiledevice/mobileactivation.h" #include "property_list_service.h" diff --git a/src/mobilebackup.c b/src/mobilebackup.c index aa29277..36986a4 100644 --- a/src/mobilebackup.c +++ b/src/mobilebackup.c @@ -26,6 +26,7 @@ #include <plist/plist.h> #include <string.h> #include <stdlib.h> +#include <stdio.h> #include "mobilebackup.h" #include "device_link_service.h" @@ -68,7 +69,7 @@ static mobilebackup_error_t mobilebackup_error(device_link_service_error_t err) return MOBILEBACKUP_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobilebackup_client_t * client) +mobilebackup_error_t mobilebackup_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobilebackup_client_t * client) { if (!device || !service || service->port == 0 || !client || *client) return MOBILEBACKUP_E_INVALID_ARG; @@ -95,14 +96,14 @@ LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_client_new(idevice_t devi return ret; } -LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_client_start_service(idevice_t device, mobilebackup_client_t * client, const char* label) +mobilebackup_error_t mobilebackup_client_start_service(idevice_t device, mobilebackup_client_t * client, const char* label) { mobilebackup_error_t err = MOBILEBACKUP_E_UNKNOWN_ERROR; service_client_factory_start_service(device, MOBILEBACKUP_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(mobilebackup_client_new), &err); return err; } -LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_client_free(mobilebackup_client_t client) +mobilebackup_error_t mobilebackup_client_free(mobilebackup_client_t client) { if (!client) return MOBILEBACKUP_E_INVALID_ARG; @@ -115,7 +116,7 @@ LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_client_free(mobilebackup_ return err; } -LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_receive(mobilebackup_client_t client, plist_t * plist) +mobilebackup_error_t mobilebackup_receive(mobilebackup_client_t client, plist_t * plist) { if (!client) return MOBILEBACKUP_E_INVALID_ARG; @@ -123,7 +124,7 @@ LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_receive(mobilebackup_clie return ret; } -LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_send(mobilebackup_client_t client, plist_t plist) +mobilebackup_error_t mobilebackup_send(mobilebackup_client_t client, plist_t plist) { if (!client || !plist) return MOBILEBACKUP_E_INVALID_ARG; @@ -240,7 +241,7 @@ leave: return err; } -LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_request_backup(mobilebackup_client_t client, plist_t backup_manifest, const char *base_path, const char *proto_version) +mobilebackup_error_t mobilebackup_request_backup(mobilebackup_client_t client, plist_t backup_manifest, const char *base_path, const char *proto_version) { if (!client || !client->parent || !base_path || !proto_version) return MOBILEBACKUP_E_INVALID_ARG; @@ -279,7 +280,15 @@ LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_request_backup(mobileback char *str = NULL; plist_get_string_val(node, &str); if (str) { - if (strcmp(str, proto_version) != 0) { + int maj = 0; + int min = 0; + sscanf(str, "%u.%u", &maj, &min); + uint32_t this_ver = ((maj & 0xFF) << 8) | (min & 0xFF); + maj = 0; + min = 0; + sscanf(proto_version, "%u.%u", &maj, &min); + uint32_t proto_ver = ((maj & 0xFF) << 8) | (min & 0xFF); + if (this_ver > proto_ver) { err = MOBILEBACKUP_E_BAD_VERSION; } free(str); @@ -300,12 +309,12 @@ leave: return err; } -LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_send_backup_file_received(mobilebackup_client_t client) +mobilebackup_error_t mobilebackup_send_backup_file_received(mobilebackup_client_t client) { return mobilebackup_send_message(client, "kBackupMessageBackupFileReceived", NULL); } -LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_request_restore(mobilebackup_client_t client, plist_t backup_manifest, mobilebackup_flags_t flags, const char *proto_version) +mobilebackup_error_t mobilebackup_request_restore(mobilebackup_client_t client, plist_t backup_manifest, mobilebackup_flags_t flags, const char *proto_version) { if (!client || !client->parent || !backup_manifest || !proto_version) return MOBILEBACKUP_E_INVALID_ARG; @@ -346,7 +355,15 @@ LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_request_restore(mobilebac char *str = NULL; plist_get_string_val(node, &str); if (str) { - if (strcmp(str, proto_version) != 0) { + int maj = 0; + int min = 0; + sscanf(str, "%u.%u", &maj, &min); + uint32_t this_ver = ((maj & 0xFF) << 8) | (min & 0xFF); + maj = 0; + min = 0; + sscanf(proto_version, "%u.%u", &maj, &min); + uint32_t proto_ver = ((maj & 0xFF) << 8) | (min & 0xFF); + if (this_ver > proto_ver) { err = MOBILEBACKUP_E_BAD_VERSION; } free(str); @@ -359,17 +376,17 @@ leave: return err; } -LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_receive_restore_file_received(mobilebackup_client_t client, plist_t *result) +mobilebackup_error_t mobilebackup_receive_restore_file_received(mobilebackup_client_t client, plist_t *result) { return mobilebackup_receive_message(client, "BackupMessageRestoreFileReceived", result); } -LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_receive_restore_application_received(mobilebackup_client_t client, plist_t *result) +mobilebackup_error_t mobilebackup_receive_restore_application_received(mobilebackup_client_t client, plist_t *result) { return mobilebackup_receive_message(client, "BackupMessageRestoreApplicationReceived", result); } -LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_send_restore_complete(mobilebackup_client_t client) +mobilebackup_error_t mobilebackup_send_restore_complete(mobilebackup_client_t client) { mobilebackup_error_t err = mobilebackup_send_message(client, "BackupMessageRestoreComplete", NULL); if (err != MOBILEBACKUP_E_SUCCESS) { @@ -414,7 +431,7 @@ LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_send_restore_complete(mob return err; } -LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_send_error(mobilebackup_client_t client, const char *reason) +mobilebackup_error_t mobilebackup_send_error(mobilebackup_client_t client, const char *reason) { if (!client || !client->parent || !reason) return MOBILEBACKUP_E_INVALID_ARG; diff --git a/src/mobilebackup.h b/src/mobilebackup.h index edda70f..04ec479 100644 --- a/src/mobilebackup.h +++ b/src/mobilebackup.h @@ -23,6 +23,7 @@ #ifndef __MOBILEBACKUP_H #define __MOBILEBACKUP_H +#include "idevice.h" #include "libimobiledevice/mobilebackup.h" #include "device_link_service.h" diff --git a/src/mobilebackup2.c b/src/mobilebackup2.c index 3726065..a8d673f 100644 --- a/src/mobilebackup2.c +++ b/src/mobilebackup2.c @@ -68,7 +68,7 @@ static mobilebackup2_error_t mobilebackup2_error(device_link_service_error_t err return MOBILEBACKUP2_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_client_new(idevice_t device, lockdownd_service_descriptor_t service, +mobilebackup2_error_t mobilebackup2_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobilebackup2_client_t * client) { if (!device || !service || service->port == 0 || !client || *client) @@ -96,14 +96,14 @@ LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_client_new(idevice_t de return ret; } -LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_client_start_service(idevice_t device, mobilebackup2_client_t * client, const char* label) +mobilebackup2_error_t mobilebackup2_client_start_service(idevice_t device, mobilebackup2_client_t * client, const char* label) { mobilebackup2_error_t err = MOBILEBACKUP2_E_UNKNOWN_ERROR; service_client_factory_start_service(device, MOBILEBACKUP2_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(mobilebackup2_client_new), &err); return err; } -LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_client_free(mobilebackup2_client_t client) +mobilebackup2_error_t mobilebackup2_client_free(mobilebackup2_client_t client) { if (!client) return MOBILEBACKUP2_E_INVALID_ARG; @@ -116,7 +116,7 @@ LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_client_free(mobilebacku return err; } -LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_send_message(mobilebackup2_client_t client, const char *message, plist_t options) +mobilebackup2_error_t mobilebackup2_send_message(mobilebackup2_client_t client, const char *message, plist_t options) { if (!client || !client->parent || (!message && !options)) return MOBILEBACKUP2_E_INVALID_ARG; @@ -214,12 +214,12 @@ leave: return err; } -LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_receive_message(mobilebackup2_client_t client, plist_t *msg_plist, char **dlmessage) +mobilebackup2_error_t mobilebackup2_receive_message(mobilebackup2_client_t client, plist_t *msg_plist, char **dlmessage) { return mobilebackup2_error(device_link_service_receive_message(client->parent, msg_plist, dlmessage)); } -LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_send_raw(mobilebackup2_client_t client, const char *data, uint32_t length, uint32_t *bytes) +mobilebackup2_error_t mobilebackup2_send_raw(mobilebackup2_client_t client, const char *data, uint32_t length, uint32_t *bytes) { if (!client || !client->parent || !data || (length == 0) || !bytes) return MOBILEBACKUP2_E_INVALID_ARG; @@ -244,7 +244,7 @@ LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_send_raw(mobilebackup2_ return MOBILEBACKUP2_E_MUX_ERROR; } -LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_receive_raw(mobilebackup2_client_t client, char *data, uint32_t length, uint32_t *bytes) +mobilebackup2_error_t mobilebackup2_receive_raw(mobilebackup2_client_t client, char *data, uint32_t length, uint32_t *bytes) { if (!client || !client->parent || !data || (length == 0) || !bytes) return MOBILEBACKUP2_E_INVALID_ARG; @@ -271,7 +271,7 @@ LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_receive_raw(mobilebacku return MOBILEBACKUP2_E_MUX_ERROR; } -LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_version_exchange(mobilebackup2_client_t client, double local_versions[], char count, double *remote_version) +mobilebackup2_error_t mobilebackup2_version_exchange(mobilebackup2_client_t client, double local_versions[], char count, double *remote_version) { int i; @@ -329,7 +329,7 @@ leave: return err; } -LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_send_request(mobilebackup2_client_t client, const char *request, const char *target_identifier, const char *source_identifier, plist_t options) +mobilebackup2_error_t mobilebackup2_send_request(mobilebackup2_client_t client, const char *request, const char *target_identifier, const char *source_identifier, plist_t options) { if (!client || !client->parent || !request || !target_identifier) return MOBILEBACKUP2_E_INVALID_ARG; @@ -360,7 +360,7 @@ LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_send_request(mobileback return err; } -LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_send_status_response(mobilebackup2_client_t client, int status_code, const char *status1, plist_t status2) +mobilebackup2_error_t mobilebackup2_send_status_response(mobilebackup2_client_t client, int status_code, const char *status1, plist_t status2) { if (!client || !client->parent) return MOBILEBACKUP2_E_INVALID_ARG; diff --git a/src/mobilebackup2.h b/src/mobilebackup2.h index 025b6bf..e232b97 100644 --- a/src/mobilebackup2.h +++ b/src/mobilebackup2.h @@ -22,6 +22,7 @@ #ifndef __MOBILEBACKUP2_H #define __MOBILEBACKUP2_H +#include "idevice.h" #include "libimobiledevice/mobilebackup2.h" #include "device_link_service.h" diff --git a/src/mobilesync.c b/src/mobilesync.c index e50226c..9b81a49 100644 --- a/src/mobilesync.c +++ b/src/mobilesync.c @@ -71,7 +71,7 @@ static mobilesync_error_t mobilesync_error(device_link_service_error_t err) return MOBILESYNC_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_client_new(idevice_t device, lockdownd_service_descriptor_t service, +mobilesync_error_t mobilesync_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobilesync_client_t * client) { if (!device || !service || service->port == 0 || !client || *client) @@ -101,14 +101,14 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_client_new(idevice_t device, return ret; } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_client_start_service(idevice_t device, mobilesync_client_t * client, const char* label) +mobilesync_error_t mobilesync_client_start_service(idevice_t device, mobilesync_client_t * client, const char* label) { mobilesync_error_t err = MOBILESYNC_E_UNKNOWN_ERROR; service_client_factory_start_service(device, MOBILESYNC_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(mobilesync_client_new), &err); return err; } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_client_free(mobilesync_client_t client) +mobilesync_error_t mobilesync_client_free(mobilesync_client_t client) { if (!client) return MOBILESYNC_E_INVALID_ARG; @@ -118,7 +118,7 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_client_free(mobilesync_client return err; } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_receive(mobilesync_client_t client, plist_t * plist) +mobilesync_error_t mobilesync_receive(mobilesync_client_t client, plist_t * plist) { if (!client) return MOBILESYNC_E_INVALID_ARG; @@ -126,14 +126,14 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_receive(mobilesync_client_t c return ret; } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_send(mobilesync_client_t client, plist_t plist) +mobilesync_error_t mobilesync_send(mobilesync_client_t client, plist_t plist) { if (!client || !plist) return MOBILESYNC_E_INVALID_ARG; return mobilesync_error(device_link_service_send(client->parent, plist)); } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_start(mobilesync_client_t client, const char *data_class, mobilesync_anchors_t anchors, uint64_t computer_data_class_version, mobilesync_sync_type_t *sync_type, uint64_t *device_data_class_version, char** error_description) +mobilesync_error_t mobilesync_start(mobilesync_client_t client, const char *data_class, mobilesync_anchors_t anchors, uint64_t computer_data_class_version, mobilesync_sync_type_t *sync_type, uint64_t *device_data_class_version, char** error_description) { if (!client || client->data_class || !data_class || !anchors || !anchors->computer_anchor) { @@ -259,7 +259,7 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_start(mobilesync_client_t cli return err; } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_finish(mobilesync_client_t client) +mobilesync_error_t mobilesync_finish(mobilesync_client_t client) { if (!client || !client->data_class) { return MOBILESYNC_E_INVALID_ARG; @@ -344,17 +344,17 @@ static mobilesync_error_t mobilesync_get_records(mobilesync_client_t client, con return err; } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_get_all_records_from_device(mobilesync_client_t client) +mobilesync_error_t mobilesync_get_all_records_from_device(mobilesync_client_t client) { return mobilesync_get_records(client, "SDMessageGetAllRecordsFromDevice"); } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_get_changes_from_device(mobilesync_client_t client) +mobilesync_error_t mobilesync_get_changes_from_device(mobilesync_client_t client) { return mobilesync_get_records(client, "SDMessageGetChangesFromDevice"); } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_receive_changes(mobilesync_client_t client, plist_t *entities, uint8_t *is_last_record, plist_t *actions) +mobilesync_error_t mobilesync_receive_changes(mobilesync_client_t client, plist_t *entities, uint8_t *is_last_record, plist_t *actions) { if (!client || !client->data_class) { return MOBILESYNC_E_INVALID_ARG; @@ -421,7 +421,7 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_receive_changes(mobilesync_cl return err; } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_clear_all_records_on_device(mobilesync_client_t client) +mobilesync_error_t mobilesync_clear_all_records_on_device(mobilesync_client_t client) { if (!client || !client->data_class) { return MOBILESYNC_E_INVALID_ARG; @@ -490,7 +490,7 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_clear_all_records_on_device(m return err; } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_acknowledge_changes_from_device(mobilesync_client_t client) +mobilesync_error_t mobilesync_acknowledge_changes_from_device(mobilesync_client_t client) { if (!client || !client->data_class) { return MOBILESYNC_E_INVALID_ARG; @@ -524,7 +524,7 @@ static plist_t create_process_changes_message(const char *data_class, plist_t en return msg; } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_ready_to_send_changes_from_computer(mobilesync_client_t client) +mobilesync_error_t mobilesync_ready_to_send_changes_from_computer(mobilesync_client_t client) { if (!client || !client->data_class) { return MOBILESYNC_E_INVALID_ARG; @@ -591,7 +591,7 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_ready_to_send_changes_from_co return err; } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_send_changes(mobilesync_client_t client, plist_t entities, uint8_t is_last_record, plist_t actions) +mobilesync_error_t mobilesync_send_changes(mobilesync_client_t client, plist_t entities, uint8_t is_last_record, plist_t actions) { if (!client || !client->data_class || !entities) { return MOBILESYNC_E_INVALID_ARG; @@ -619,7 +619,7 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_send_changes(mobilesync_clien return err; } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_remap_identifiers(mobilesync_client_t client, plist_t *mapping) +mobilesync_error_t mobilesync_remap_identifiers(mobilesync_client_t client, plist_t *mapping) { if (!client || !client->data_class) { return MOBILESYNC_E_INVALID_ARG; @@ -688,7 +688,7 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_remap_identifiers(mobilesync_ return err; } -LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_cancel(mobilesync_client_t client, const char* reason) +mobilesync_error_t mobilesync_cancel(mobilesync_client_t client, const char* reason) { if (!client || !client->data_class || !reason) { return MOBILESYNC_E_INVALID_ARG; @@ -714,7 +714,7 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_cancel(mobilesync_client_t cl return err; } -LIBIMOBILEDEVICE_API mobilesync_anchors_t mobilesync_anchors_new(const char *device_anchor, const char *computer_anchor) +mobilesync_anchors_t mobilesync_anchors_new(const char *device_anchor, const char *computer_anchor) { mobilesync_anchors_t anchors = (mobilesync_anchors_t) malloc(sizeof(mobilesync_anchors)); if (device_anchor != NULL) { @@ -731,7 +731,7 @@ LIBIMOBILEDEVICE_API mobilesync_anchors_t mobilesync_anchors_new(const char *dev return anchors; } -LIBIMOBILEDEVICE_API void mobilesync_anchors_free(mobilesync_anchors_t anchors) +void mobilesync_anchors_free(mobilesync_anchors_t anchors) { if (anchors->device_anchor != NULL) { free(anchors->device_anchor); @@ -745,12 +745,12 @@ LIBIMOBILEDEVICE_API void mobilesync_anchors_free(mobilesync_anchors_t anchors) anchors = NULL; } -LIBIMOBILEDEVICE_API plist_t mobilesync_actions_new(void) +plist_t mobilesync_actions_new(void) { return plist_new_dict(); } -LIBIMOBILEDEVICE_API void mobilesync_actions_add(plist_t actions, ...) +void mobilesync_actions_add(plist_t actions, ...) { if (!actions) return; @@ -782,7 +782,7 @@ LIBIMOBILEDEVICE_API void mobilesync_actions_add(plist_t actions, ...) va_end(args); } -LIBIMOBILEDEVICE_API void mobilesync_actions_free(plist_t actions) +void mobilesync_actions_free(plist_t actions) { if (actions) { plist_free(actions); diff --git a/src/mobilesync.h b/src/mobilesync.h index f672252..3b5ece9 100644 --- a/src/mobilesync.h +++ b/src/mobilesync.h @@ -23,6 +23,7 @@ #ifndef __MOBILESYNC_H #define __MOBILESYNC_H +#include "idevice.h" #include "libimobiledevice/mobilesync.h" #include "device_link_service.h" diff --git a/src/notification_proxy.c b/src/notification_proxy.c index e17e2fe..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 @@ -89,7 +94,7 @@ static np_error_t np_error(property_list_service_error_t err) return NP_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API np_error_t np_client_new(idevice_t device, lockdownd_service_descriptor_t service, np_client_t *client) +np_error_t np_client_new(idevice_t device, lockdownd_service_descriptor_t service, np_client_t *client) { property_list_service_client_t plistclient = NULL; np_error_t err = np_error(property_list_service_client_new(device, service, &plistclient)); @@ -107,14 +112,14 @@ LIBIMOBILEDEVICE_API np_error_t np_client_new(idevice_t device, lockdownd_servic return NP_E_SUCCESS; } -LIBIMOBILEDEVICE_API np_error_t np_client_start_service(idevice_t device, np_client_t* client, const char* label) +np_error_t np_client_start_service(idevice_t device, np_client_t* client, const char* label) { - np_error_t err = NP_E_UNKNOWN_ERROR; + 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; } -LIBIMOBILEDEVICE_API np_error_t np_client_free(np_client_t client) +np_error_t np_client_free(np_client_t client) { plist_t dict; property_list_service_client_t parent; @@ -168,7 +173,7 @@ LIBIMOBILEDEVICE_API np_error_t np_client_free(np_client_t client) return NP_E_SUCCESS; } -LIBIMOBILEDEVICE_API np_error_t np_post_notification(np_client_t client, const char *notification) +np_error_t np_post_notification(np_client_t client, const char *notification) { if (!client || !notification) { return NP_E_INVALID_ARG; @@ -204,7 +209,7 @@ static np_error_t internal_np_observe_notification(np_client_t client, const cha return res; } -LIBIMOBILEDEVICE_API np_error_t np_observe_notification( np_client_t client, const char *notification ) +np_error_t np_observe_notification( np_client_t client, const char *notification ) { if (!client || !notification) { return NP_E_INVALID_ARG; @@ -215,7 +220,7 @@ LIBIMOBILEDEVICE_API np_error_t np_observe_notification( np_client_t client, con return res; } -LIBIMOBILEDEVICE_API np_error_t np_observe_notifications(np_client_t client, const char **notification_spec) +np_error_t np_observe_notifications(np_client_t client, const char **notification_spec) { int i = 0; np_error_t res = NP_E_UNKNOWN_ERROR; @@ -346,7 +351,7 @@ void* np_notifier( void* arg ) return NULL; } -LIBIMOBILEDEVICE_API np_error_t np_set_notify_callback( np_client_t client, np_notify_cb_t notify_cb, void *user_data ) +np_error_t np_set_notify_callback( np_client_t client, np_notify_cb_t notify_cb, void *user_data ) { if (!client) return NP_E_INVALID_ARG; diff --git a/src/notification_proxy.h b/src/notification_proxy.h index ea85149..595cb01 100644 --- a/src/notification_proxy.h +++ b/src/notification_proxy.h @@ -22,6 +22,7 @@ #ifndef __NOTIFICATION_PROXY_H #define __NOTIFICATION_PROXY_H +#include "idevice.h" #include "libimobiledevice/notification_proxy.h" #include "property_list_service.h" #include <libimobiledevice-glue/thread.h> diff --git a/src/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/preboard.c b/src/preboard.c index 4b3b444..c3eff02 100644 --- a/src/preboard.c +++ b/src/preboard.c @@ -62,7 +62,7 @@ static preboard_error_t preboard_error(property_list_service_error_t err) return PREBOARD_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API preboard_error_t preboard_client_new(idevice_t device, lockdownd_service_descriptor_t service, preboard_client_t * client) +preboard_error_t preboard_client_new(idevice_t device, lockdownd_service_descriptor_t service, preboard_client_t * client) { *client = NULL; @@ -90,14 +90,14 @@ LIBIMOBILEDEVICE_API preboard_error_t preboard_client_new(idevice_t device, lock return 0; } -LIBIMOBILEDEVICE_API preboard_error_t preboard_client_start_service(idevice_t device, preboard_client_t * client, const char* label) +preboard_error_t preboard_client_start_service(idevice_t device, preboard_client_t * client, const char* label) { preboard_error_t err = PREBOARD_E_UNKNOWN_ERROR; service_client_factory_start_service(device, PREBOARD_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(preboard_client_new), &err); return err; } -LIBIMOBILEDEVICE_API preboard_error_t preboard_client_free(preboard_client_t client) +preboard_error_t preboard_client_free(preboard_client_t client) { if (!client) return PREBOARD_E_INVALID_ARG; @@ -116,7 +116,7 @@ LIBIMOBILEDEVICE_API preboard_error_t preboard_client_free(preboard_client_t cli return err; } -LIBIMOBILEDEVICE_API preboard_error_t preboard_send(preboard_client_t client, plist_t plist) +preboard_error_t preboard_send(preboard_client_t client, plist_t plist) { preboard_error_t res = PREBOARD_E_UNKNOWN_ERROR; res = preboard_error(property_list_service_send_binary_plist(client->parent, plist)); @@ -127,7 +127,7 @@ LIBIMOBILEDEVICE_API preboard_error_t preboard_send(preboard_client_t client, pl return res; } -LIBIMOBILEDEVICE_API preboard_error_t preboard_receive_with_timeout(preboard_client_t client, plist_t * plist, uint32_t timeout_ms) +preboard_error_t preboard_receive_with_timeout(preboard_client_t client, plist_t * plist, uint32_t timeout_ms) { preboard_error_t res = PREBOARD_E_UNKNOWN_ERROR; plist_t outplist = NULL; @@ -141,7 +141,7 @@ LIBIMOBILEDEVICE_API preboard_error_t preboard_receive_with_timeout(preboard_cli return res; } -LIBIMOBILEDEVICE_API preboard_error_t preboard_receive(preboard_client_t client, plist_t * plist) +preboard_error_t preboard_receive(preboard_client_t client, plist_t * plist) { return preboard_receive_with_timeout(client, plist, 5000); } @@ -209,7 +209,7 @@ static preboard_error_t preboard_receive_status_loop_with_callback(preboard_clie return res; } -LIBIMOBILEDEVICE_API preboard_error_t preboard_create_stashbag(preboard_client_t client, plist_t manifest, preboard_status_cb_t status_cb, void *user_data) +preboard_error_t preboard_create_stashbag(preboard_client_t client, plist_t manifest, preboard_status_cb_t status_cb, void *user_data) { if (!client) { return PREBOARD_E_INVALID_ARG; @@ -232,7 +232,7 @@ LIBIMOBILEDEVICE_API preboard_error_t preboard_create_stashbag(preboard_client_t return preboard_receive_status_loop_with_callback(client, status_cb, user_data); } -LIBIMOBILEDEVICE_API preboard_error_t preboard_commit_stashbag(preboard_client_t client, plist_t manifest, preboard_status_cb_t status_cb, void *user_data) +preboard_error_t preboard_commit_stashbag(preboard_client_t client, plist_t manifest, preboard_status_cb_t status_cb, void *user_data) { if (!client) { return PREBOARD_E_INVALID_ARG; diff --git a/src/preboard.h b/src/preboard.h index 61263fc..f8164eb 100644 --- a/src/preboard.h +++ b/src/preboard.h @@ -22,6 +22,7 @@ #ifndef __PREBOARD_H #define __PREBOARD_H +#include "idevice.h" #include "libimobiledevice/preboard.h" #include "property_list_service.h" #include <libimobiledevice-glue/thread.h> diff --git a/src/property_list_service.c b/src/property_list_service.c index 4654b6e..2fca4e7 100644 --- a/src/property_list_service.c +++ b/src/property_list_service.c @@ -58,7 +58,7 @@ static property_list_service_error_t service_to_property_list_service_error(serv return PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_client_new(idevice_t device, lockdownd_service_descriptor_t service, property_list_service_client_t *client) +property_list_service_error_t property_list_service_client_new(idevice_t device, lockdownd_service_descriptor_t service, property_list_service_client_t *client) { if (!device || !service || service->port == 0 || !client || *client) return PROPERTY_LIST_SERVICE_E_INVALID_ARG; @@ -78,7 +78,7 @@ LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_client_ return PROPERTY_LIST_SERVICE_E_SUCCESS; } -LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_client_free(property_list_service_client_t client) +property_list_service_error_t property_list_service_client_free(property_list_service_client_t client) { if (!client) return PROPERTY_LIST_SERVICE_E_INVALID_ARG; @@ -152,12 +152,12 @@ static property_list_service_error_t internal_plist_send(property_list_service_c return res; } -LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_send_xml_plist(property_list_service_client_t client, plist_t plist) +property_list_service_error_t property_list_service_send_xml_plist(property_list_service_client_t client, plist_t plist) { return internal_plist_send(client, plist, 0); } -LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_send_binary_plist(property_list_service_client_t client, plist_t plist) +property_list_service_error_t property_list_service_send_binary_plist(property_list_service_client_t client, plist_t plist) { return internal_plist_send(client, plist, 1); } @@ -262,31 +262,31 @@ static property_list_service_error_t internal_plist_receive_timeout(property_lis return res; } -LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_receive_plist_with_timeout(property_list_service_client_t client, plist_t *plist, unsigned int timeout) +property_list_service_error_t property_list_service_receive_plist_with_timeout(property_list_service_client_t client, plist_t *plist, unsigned int timeout) { return internal_plist_receive_timeout(client, plist, timeout); } -LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_receive_plist(property_list_service_client_t client, plist_t *plist) +property_list_service_error_t property_list_service_receive_plist(property_list_service_client_t client, plist_t *plist) { return internal_plist_receive_timeout(client, plist, 30000); } -LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_enable_ssl(property_list_service_client_t client) +property_list_service_error_t property_list_service_enable_ssl(property_list_service_client_t client) { if (!client || !client->parent) return PROPERTY_LIST_SERVICE_E_INVALID_ARG; return service_to_property_list_service_error(service_enable_ssl(client->parent)); } -LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_disable_ssl(property_list_service_client_t client) +property_list_service_error_t property_list_service_disable_ssl(property_list_service_client_t client) { if (!client || !client->parent) return PROPERTY_LIST_SERVICE_E_INVALID_ARG; return service_to_property_list_service_error(service_disable_ssl(client->parent)); } -LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_get_service_client(property_list_service_client_t client, service_client_t *service_client) +property_list_service_error_t property_list_service_get_service_client(property_list_service_client_t client, service_client_t *service_client) { if (!client || !client->parent || !service_client) return PROPERTY_LIST_SERVICE_E_INVALID_ARG; diff --git a/src/property_list_service.h b/src/property_list_service.h index 3c9e14d..0e9e948 100644 --- a/src/property_list_service.h +++ b/src/property_list_service.h @@ -22,6 +22,7 @@ #ifndef __PROPERTY_LIST_SERVICE_H #define __PROPERTY_LIST_SERVICE_H +#include "idevice.h" #include "libimobiledevice/property_list_service.h" #include "service.h" diff --git a/src/restore.c b/src/restore.c index 591fd16..d13a28a 100644 --- a/src/restore.c +++ b/src/restore.c @@ -111,7 +111,7 @@ static restored_error_t restored_error(property_list_service_error_t err) return RESTORE_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API restored_error_t restored_client_free(restored_client_t client) +restored_error_t restored_client_free(restored_client_t client) { if (!client) return RESTORE_E_INVALID_ARG; @@ -139,7 +139,7 @@ LIBIMOBILEDEVICE_API restored_error_t restored_client_free(restored_client_t cli return ret; } -LIBIMOBILEDEVICE_API void restored_client_set_label(restored_client_t client, const char *label) +void restored_client_set_label(restored_client_t client, const char *label) { if (client) { if (client->label) @@ -149,7 +149,7 @@ LIBIMOBILEDEVICE_API void restored_client_set_label(restored_client_t client, co } } -LIBIMOBILEDEVICE_API restored_error_t restored_receive(restored_client_t client, plist_t *plist) +restored_error_t restored_receive(restored_client_t client, plist_t *plist) { if (!client || !plist || (plist && *plist)) return RESTORE_E_INVALID_ARG; @@ -157,7 +157,7 @@ LIBIMOBILEDEVICE_API restored_error_t restored_receive(restored_client_t client, return restored_error(property_list_service_receive_plist(client->parent, plist)); } -LIBIMOBILEDEVICE_API restored_error_t restored_send(restored_client_t client, plist_t plist) +restored_error_t restored_send(restored_client_t client, plist_t plist) { if (!client || !plist) return RESTORE_E_INVALID_ARG; @@ -165,7 +165,7 @@ LIBIMOBILEDEVICE_API restored_error_t restored_send(restored_client_t client, pl return restored_error(property_list_service_send_xml_plist(client->parent, plist)); } -LIBIMOBILEDEVICE_API restored_error_t restored_query_type(restored_client_t client, char **type, uint64_t *version) +restored_error_t restored_query_type(restored_client_t client, char **type, uint64_t *version) { if (!client) return RESTORE_E_INVALID_ARG; @@ -224,7 +224,7 @@ LIBIMOBILEDEVICE_API restored_error_t restored_query_type(restored_client_t clie return ret; } -LIBIMOBILEDEVICE_API restored_error_t restored_query_value(restored_client_t client, const char *key, plist_t *value) +restored_error_t restored_query_value(restored_client_t client, const char *key, plist_t *value) { if (!client || !key) return RESTORE_E_INVALID_ARG; @@ -266,7 +266,7 @@ LIBIMOBILEDEVICE_API restored_error_t restored_query_value(restored_client_t cli return ret; } -LIBIMOBILEDEVICE_API restored_error_t restored_get_value(restored_client_t client, const char *key, plist_t *value) +restored_error_t restored_get_value(restored_client_t client, const char *key, plist_t *value) { plist_t item; @@ -287,11 +287,11 @@ LIBIMOBILEDEVICE_API restored_error_t restored_get_value(restored_client_t clien } *value = plist_copy(item); - free(item); + return RESTORE_E_SUCCESS; } -LIBIMOBILEDEVICE_API restored_error_t restored_client_new(idevice_t device, restored_client_t *client, const char *label) +restored_error_t restored_client_new(idevice_t device, restored_client_t *client, const char *label) { if (!client) return RESTORE_E_INVALID_ARG; @@ -335,7 +335,7 @@ LIBIMOBILEDEVICE_API restored_error_t restored_client_new(idevice_t device, rest return ret; } -LIBIMOBILEDEVICE_API restored_error_t restored_goodbye(restored_client_t client) +restored_error_t restored_goodbye(restored_client_t client) { if (!client) return RESTORE_E_INVALID_ARG; @@ -367,7 +367,7 @@ LIBIMOBILEDEVICE_API restored_error_t restored_goodbye(restored_client_t client) return ret; } -LIBIMOBILEDEVICE_API restored_error_t restored_start_restore(restored_client_t client, plist_t options, uint64_t version) +restored_error_t restored_start_restore(restored_client_t client, plist_t options, uint64_t version) { if (!client) return RESTORE_E_INVALID_ARG; @@ -391,7 +391,7 @@ LIBIMOBILEDEVICE_API restored_error_t restored_start_restore(restored_client_t c return ret; } -LIBIMOBILEDEVICE_API restored_error_t restored_reboot(restored_client_t client) +restored_error_t restored_reboot(restored_client_t client) { if (!client) return RESTORE_E_INVALID_ARG; diff --git a/src/restore.h b/src/restore.h index 646d1d1..ec6fa04 100644 --- a/src/restore.h +++ b/src/restore.h @@ -24,6 +24,7 @@ #include <string.h> +#include "idevice.h" #include "libimobiledevice/restore.h" #include "property_list_service.h" diff --git a/src/reverse_proxy.c b/src/reverse_proxy.c index 3f0a839..2fcfdd1 100644 --- a/src/reverse_proxy.c +++ b/src/reverse_proxy.c @@ -25,6 +25,9 @@ #endif #include <string.h> #include <stdlib.h> +#define _GNU_SOURCE 1 +#define __USE_GNU 1 +#include <stdio.h> #include <errno.h> #include <plist/plist.h> @@ -91,7 +94,7 @@ static void _reverse_proxy_log(reverse_proxy_client_t client, const char* format va_list args; va_start(args, format); char* buffer = NULL; - (void)vasprintf(&buffer, format, args); + if(vasprintf(&buffer, format, args)<0){} va_end(args); client->log_cb(client, buffer, client->log_cb_user_data); free(buffer); @@ -113,7 +116,7 @@ static void _reverse_proxy_status(reverse_proxy_client_t client, int status, con va_list args; va_start(args, format); char* buffer = NULL; - (void)vasprintf(&buffer, format, args); + if(vasprintf(&buffer, format, args)<0){} va_end(args); client->status_cb(client, status, buffer, client->status_cb_user_data); free(buffer); @@ -186,10 +189,10 @@ static int _reverse_proxy_handle_proxy_cmd(reverse_proxy_client_t client) /* else wait for messages and forward them */ int sockfd = socket_connect(host, port); - free(host); if (sockfd < 0) { free(buf); _reverse_proxy_log(client, "ERROR: Connection to %s:%u failed: %s", host, port, strerror(errno)); + free(host); return -1; } @@ -259,6 +262,7 @@ static int _reverse_proxy_handle_proxy_cmd(reverse_proxy_client_t client) } } socket_close(sockfd); + free(host); free(buf); _reverse_proxy_status(client, RP_STATUS_DISCONNECTED, "Disconnected (out: %u / in: %u)", sent_total, recv_total); @@ -524,7 +528,7 @@ static void* _reverse_proxy_control_thread(void *cdata) return NULL; } -LIBIMOBILEDEVICE_API reverse_proxy_error_t reverse_proxy_client_start_proxy(reverse_proxy_client_t client, int control_protocol_version) +reverse_proxy_error_t reverse_proxy_client_start_proxy(reverse_proxy_client_t client, int control_protocol_version) { char buf[16] = {0, }; uint32_t bytes = 0; @@ -603,7 +607,7 @@ LIBIMOBILEDEVICE_API reverse_proxy_error_t reverse_proxy_client_start_proxy(reve return err; } -LIBIMOBILEDEVICE_API reverse_proxy_error_t reverse_proxy_client_create_with_service(idevice_t device, reverse_proxy_client_t* client, const char* label) +reverse_proxy_error_t reverse_proxy_client_create_with_service(idevice_t device, reverse_proxy_client_t* client, const char* label) { reverse_proxy_error_t err = REVERSE_PROXY_E_UNKNOWN_ERROR; service_client_factory_start_service(device, "com.apple.PurpleReverseProxy.Ctrl", (void**)client, label, SERVICE_CONSTRUCTOR(reverse_proxy_client_new), &err); @@ -616,7 +620,7 @@ LIBIMOBILEDEVICE_API reverse_proxy_error_t reverse_proxy_client_create_with_serv return REVERSE_PROXY_E_SUCCESS; } -LIBIMOBILEDEVICE_API reverse_proxy_error_t reverse_proxy_client_create_with_port(idevice_t device, reverse_proxy_client_t* client, uint16_t device_port) +reverse_proxy_error_t reverse_proxy_client_create_with_port(idevice_t device, reverse_proxy_client_t* client, uint16_t device_port) { reverse_proxy_client_t client_loc = NULL; reverse_proxy_error_t err; @@ -637,7 +641,7 @@ LIBIMOBILEDEVICE_API reverse_proxy_error_t reverse_proxy_client_create_with_port return REVERSE_PROXY_E_SUCCESS; } -LIBIMOBILEDEVICE_API reverse_proxy_error_t reverse_proxy_client_free(reverse_proxy_client_t client) +reverse_proxy_error_t reverse_proxy_client_free(reverse_proxy_client_t client) { if (!client) return REVERSE_PROXY_E_INVALID_ARG; @@ -656,14 +660,14 @@ LIBIMOBILEDEVICE_API reverse_proxy_error_t reverse_proxy_client_free(reverse_pro return err; } -LIBIMOBILEDEVICE_API reverse_proxy_client_type_t reverse_proxy_get_type(reverse_proxy_client_t client) +reverse_proxy_client_type_t reverse_proxy_get_type(reverse_proxy_client_t client) { if (!client) return 0; return client->type; } -LIBIMOBILEDEVICE_API void reverse_proxy_client_set_status_callback(reverse_proxy_client_t client, reverse_proxy_status_cb_t status_callback, void* user_data) +void reverse_proxy_client_set_status_callback(reverse_proxy_client_t client, reverse_proxy_status_cb_t status_callback, void* user_data) { if (!client) { return; @@ -672,7 +676,7 @@ LIBIMOBILEDEVICE_API void reverse_proxy_client_set_status_callback(reverse_proxy client->status_cb_user_data = user_data; } -LIBIMOBILEDEVICE_API void reverse_proxy_client_set_log_callback(reverse_proxy_client_t client, reverse_proxy_log_cb_t log_callback, void* user_data) +void reverse_proxy_client_set_log_callback(reverse_proxy_client_t client, reverse_proxy_log_cb_t log_callback, void* user_data) { if (!client) { return; @@ -681,7 +685,7 @@ LIBIMOBILEDEVICE_API void reverse_proxy_client_set_log_callback(reverse_proxy_cl client->log_cb_user_data = user_data; } -LIBIMOBILEDEVICE_API void reverse_proxy_client_set_data_callback(reverse_proxy_client_t client, reverse_proxy_data_cb_t data_callback, void* user_data) +void reverse_proxy_client_set_data_callback(reverse_proxy_client_t client, reverse_proxy_data_cb_t data_callback, void* user_data) { if (!client) { return; diff --git a/src/reverse_proxy.h b/src/reverse_proxy.h index 17eabac..7f441bd 100644 --- a/src/reverse_proxy.h +++ b/src/reverse_proxy.h @@ -22,6 +22,7 @@ #ifndef __REVERSE_PROXY_H #define __REVERSE_PROXY_H +#include "idevice.h" #include "libimobiledevice/reverse_proxy.h" #include "service.h" diff --git a/src/sbservices.c b/src/sbservices.c index ccb7c4b..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" @@ -79,7 +83,7 @@ static sbservices_error_t sbservices_error(property_list_service_error_t err) return SBSERVICES_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API sbservices_error_t sbservices_client_new(idevice_t device, lockdownd_service_descriptor_t service, sbservices_client_t *client) +sbservices_error_t sbservices_client_new(idevice_t device, lockdownd_service_descriptor_t service, sbservices_client_t *client) { property_list_service_client_t plistclient = NULL; sbservices_error_t err = sbservices_error(property_list_service_client_new(device, service, &plistclient)); @@ -95,14 +99,14 @@ LIBIMOBILEDEVICE_API sbservices_error_t sbservices_client_new(idevice_t device, return SBSERVICES_E_SUCCESS; } -LIBIMOBILEDEVICE_API sbservices_error_t sbservices_client_start_service(idevice_t device, sbservices_client_t * client, const char* label) +sbservices_error_t sbservices_client_start_service(idevice_t device, sbservices_client_t * client, const char* label) { sbservices_error_t err = SBSERVICES_E_UNKNOWN_ERROR; service_client_factory_start_service(device, SBSERVICES_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(sbservices_client_new), &err); return err; } -LIBIMOBILEDEVICE_API sbservices_error_t sbservices_client_free(sbservices_client_t client) +sbservices_error_t sbservices_client_free(sbservices_client_t client) { if (!client) return SBSERVICES_E_INVALID_ARG; @@ -115,7 +119,7 @@ LIBIMOBILEDEVICE_API sbservices_error_t sbservices_client_free(sbservices_client return err; } -LIBIMOBILEDEVICE_API sbservices_error_t sbservices_get_icon_state(sbservices_client_t client, plist_t *state, const char *format_version) +sbservices_error_t sbservices_get_icon_state(sbservices_client_t client, plist_t *state, const char *format_version) { if (!client || !client->parent || !state) return SBSERVICES_E_INVALID_ARG; @@ -155,7 +159,7 @@ leave_unlock: return res; } -LIBIMOBILEDEVICE_API sbservices_error_t sbservices_set_icon_state(sbservices_client_t client, plist_t newstate) +sbservices_error_t sbservices_set_icon_state(sbservices_client_t client, plist_t newstate) { if (!client || !client->parent || !newstate) return SBSERVICES_E_INVALID_ARG; @@ -172,7 +176,10 @@ LIBIMOBILEDEVICE_API sbservices_error_t sbservices_set_icon_state(sbservices_cli if (res != SBSERVICES_E_SUCCESS) { debug_info("could not send plist, error %d", res); } - /* NO RESPONSE */ + + uint32_t bytes = 0; + service_receive_with_timeout(client->parent->parent, malloc(4), 4, &bytes, 2000); + debug_info("setIconState response: %u", bytes); if (dict) { plist_free(dict); @@ -181,7 +188,7 @@ LIBIMOBILEDEVICE_API sbservices_error_t sbservices_set_icon_state(sbservices_cli return res; } -LIBIMOBILEDEVICE_API sbservices_error_t sbservices_get_icon_pngdata(sbservices_client_t client, const char *bundleId, char **pngdata, uint64_t *pngsize) +sbservices_error_t sbservices_get_icon_pngdata(sbservices_client_t client, const char *bundleId, char **pngdata, uint64_t *pngsize) { if (!client || !client->parent || !bundleId || !pngdata) return SBSERVICES_E_INVALID_ARG; @@ -218,7 +225,7 @@ leave_unlock: return res; } -LIBIMOBILEDEVICE_API sbservices_error_t sbservices_get_interface_orientation(sbservices_client_t client, sbservices_interface_orientation_t* interface_orientation) +sbservices_error_t sbservices_get_interface_orientation(sbservices_client_t client, sbservices_interface_orientation_t* interface_orientation) { if (!client || !client->parent || !interface_orientation) return SBSERVICES_E_INVALID_ARG; @@ -256,7 +263,7 @@ leave_unlock: return res; } -LIBIMOBILEDEVICE_API sbservices_error_t sbservices_get_home_screen_wallpaper_pngdata(sbservices_client_t client, char **pngdata, uint64_t *pngsize) +sbservices_error_t sbservices_get_home_screen_wallpaper_pngdata(sbservices_client_t client, char **pngdata, uint64_t *pngsize) { if (!client || !client->parent || !pngdata) return SBSERVICES_E_INVALID_ARG; diff --git a/src/sbservices.h b/src/sbservices.h index 39d822c..b67281e 100644 --- a/src/sbservices.h +++ b/src/sbservices.h @@ -22,6 +22,7 @@ #ifndef __SBSERVICES_H #define __SBSERVICES_H +#include "idevice.h" #include "libimobiledevice/sbservices.h" #include "property_list_service.h" #include <libimobiledevice-glue/thread.h> diff --git a/src/screenshotr.c b/src/screenshotr.c index 77835da..c3cc9ba 100644 --- a/src/screenshotr.c +++ b/src/screenshotr.c @@ -65,7 +65,7 @@ static screenshotr_error_t screenshotr_error(device_link_service_error_t err) return SCREENSHOTR_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API screenshotr_error_t screenshotr_client_new(idevice_t device, lockdownd_service_descriptor_t service, +screenshotr_error_t screenshotr_client_new(idevice_t device, lockdownd_service_descriptor_t service, screenshotr_client_t * client) { if (!device || !service || service->port == 0 || !client || *client) @@ -93,14 +93,14 @@ LIBIMOBILEDEVICE_API screenshotr_error_t screenshotr_client_new(idevice_t device return ret; } -LIBIMOBILEDEVICE_API screenshotr_error_t screenshotr_client_start_service(idevice_t device, screenshotr_client_t * client, const char* label) +screenshotr_error_t screenshotr_client_start_service(idevice_t device, screenshotr_client_t * client, const char* label) { screenshotr_error_t err = SCREENSHOTR_E_UNKNOWN_ERROR; service_client_factory_start_service(device, SCREENSHOTR_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(screenshotr_client_new), &err); return err; } -LIBIMOBILEDEVICE_API screenshotr_error_t screenshotr_client_free(screenshotr_client_t client) +screenshotr_error_t screenshotr_client_free(screenshotr_client_t client) { if (!client) return SCREENSHOTR_E_INVALID_ARG; @@ -110,7 +110,7 @@ LIBIMOBILEDEVICE_API screenshotr_error_t screenshotr_client_free(screenshotr_cli return err; } -LIBIMOBILEDEVICE_API screenshotr_error_t screenshotr_take_screenshot(screenshotr_client_t client, char **imgdata, uint64_t *imgsize) +screenshotr_error_t screenshotr_take_screenshot(screenshotr_client_t client, char **imgdata, uint64_t *imgsize) { if (!client || !client->parent || !imgdata) return SCREENSHOTR_E_INVALID_ARG; diff --git a/src/screenshotr.h b/src/screenshotr.h index 47d4e42..1319ec0 100644 --- a/src/screenshotr.h +++ b/src/screenshotr.h @@ -22,6 +22,7 @@ #ifndef __SCREENSHOTR_H #define __SCREENSHOTR_H +#include "idevice.h" #include "libimobiledevice/screenshotr.h" #include "device_link_service.h" diff --git a/src/service.c b/src/service.c index 6c9d109..9474021 100644 --- a/src/service.c +++ b/src/service.c @@ -56,7 +56,7 @@ static service_error_t idevice_to_service_error(idevice_error_t err) return SERVICE_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API service_error_t service_client_new(idevice_t device, lockdownd_service_descriptor_t service, service_client_t *client) +service_error_t service_client_new(idevice_t device, lockdownd_service_descriptor_t service, service_client_t *client) { if (!device || !service || service->port == 0 || !client || *client) return SERVICE_E_INVALID_ARG; @@ -80,7 +80,7 @@ LIBIMOBILEDEVICE_API service_error_t service_client_new(idevice_t device, lockdo return SERVICE_E_SUCCESS; } -LIBIMOBILEDEVICE_API service_error_t service_client_factory_start_service(idevice_t device, const char* service_name, void **client, const char* label, int32_t (*constructor_func)(idevice_t, lockdownd_service_descriptor_t, void**), int32_t *error_code) +service_error_t service_client_factory_start_service(idevice_t device, const char* service_name, void **client, const char* label, int32_t (*constructor_func)(idevice_t, lockdownd_service_descriptor_t, void**), int32_t *error_code) { *client = NULL; @@ -119,7 +119,7 @@ LIBIMOBILEDEVICE_API service_error_t service_client_factory_start_service(idevic return (ec == SERVICE_E_SUCCESS) ? SERVICE_E_SUCCESS : SERVICE_E_START_SERVICE_ERROR; } -LIBIMOBILEDEVICE_API service_error_t service_client_free(service_client_t client) +service_error_t service_client_free(service_client_t client) { if (!client) return SERVICE_E_INVALID_ARG; @@ -132,7 +132,7 @@ LIBIMOBILEDEVICE_API service_error_t service_client_free(service_client_t client return err; } -LIBIMOBILEDEVICE_API service_error_t service_send(service_client_t client, const char* data, uint32_t size, uint32_t *sent) +service_error_t service_send(service_client_t client, const char* data, uint32_t size, uint32_t *sent) { service_error_t res = SERVICE_E_UNKNOWN_ERROR; uint32_t bytes = 0; @@ -153,7 +153,7 @@ LIBIMOBILEDEVICE_API service_error_t service_send(service_client_t client, const return res; } -LIBIMOBILEDEVICE_API service_error_t service_receive_with_timeout(service_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout) +service_error_t service_receive_with_timeout(service_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout) { service_error_t res = SERVICE_E_UNKNOWN_ERROR; uint32_t bytes = 0; @@ -174,31 +174,31 @@ LIBIMOBILEDEVICE_API service_error_t service_receive_with_timeout(service_client return res; } -LIBIMOBILEDEVICE_API service_error_t service_receive(service_client_t client, char* data, uint32_t size, uint32_t *received) +service_error_t service_receive(service_client_t client, char* data, uint32_t size, uint32_t *received) { return service_receive_with_timeout(client, data, size, received, 30000); } -LIBIMOBILEDEVICE_API service_error_t service_enable_ssl(service_client_t client) +service_error_t service_enable_ssl(service_client_t client) { if (!client || !client->connection) return SERVICE_E_INVALID_ARG; return idevice_to_service_error(idevice_connection_enable_ssl(client->connection)); } -LIBIMOBILEDEVICE_API service_error_t service_disable_ssl(service_client_t client) +service_error_t service_disable_ssl(service_client_t client) { return service_disable_bypass_ssl(client, 0); } -LIBIMOBILEDEVICE_API service_error_t service_disable_bypass_ssl(service_client_t client, uint8_t sslBypass) +service_error_t service_disable_bypass_ssl(service_client_t client, uint8_t sslBypass) { if (!client || !client->connection) return SERVICE_E_INVALID_ARG; return idevice_to_service_error(idevice_connection_disable_bypass_ssl(client->connection, sslBypass)); } -LIBIMOBILEDEVICE_API service_error_t service_get_connection(service_client_t client, idevice_connection_t *connection) +service_error_t service_get_connection(service_client_t client, idevice_connection_t *connection) { if (!client || !client->connection || !connection) return SERVICE_E_INVALID_ARG; diff --git a/src/service.h b/src/service.h index 3fc3077..071fe3f 100644 --- a/src/service.h +++ b/src/service.h @@ -21,9 +21,9 @@ #ifndef SERVICE_H #define SERVICE_H +#include "idevice.h" #include "libimobiledevice/service.h" #include "libimobiledevice/lockdown.h" -#include "idevice.h" struct service_client_private { idevice_connection_t connection; diff --git a/src/syslog_relay.c b/src/syslog_relay.c index ec9eca5..9f4296e 100644 --- a/src/syslog_relay.c +++ b/src/syslog_relay.c @@ -67,7 +67,7 @@ static syslog_relay_error_t syslog_relay_error(service_error_t err) return SYSLOG_RELAY_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, syslog_relay_client_t * client) +syslog_relay_error_t syslog_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, syslog_relay_client_t * client) { *client = NULL; @@ -95,14 +95,14 @@ LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_client_new(idevice_t devi return 0; } -LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_client_start_service(idevice_t device, syslog_relay_client_t * client, const char* label) +syslog_relay_error_t syslog_relay_client_start_service(idevice_t device, syslog_relay_client_t * client, const char* label) { syslog_relay_error_t err = SYSLOG_RELAY_E_UNKNOWN_ERROR; service_client_factory_start_service(device, SYSLOG_RELAY_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(syslog_relay_client_new), &err); return err; } -LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_client_free(syslog_relay_client_t client) +syslog_relay_error_t syslog_relay_client_free(syslog_relay_client_t client) { if (!client) return SYSLOG_RELAY_E_INVALID_ARG; @@ -113,12 +113,12 @@ LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_client_free(syslog_relay_ return err; } -LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_receive(syslog_relay_client_t client, char* data, uint32_t size, uint32_t *received) +syslog_relay_error_t syslog_relay_receive(syslog_relay_client_t client, char* data, uint32_t size, uint32_t *received) { return syslog_relay_receive_with_timeout(client, data, size, received, 1000); } -LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_receive_with_timeout(syslog_relay_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout) +syslog_relay_error_t syslog_relay_receive_with_timeout(syslog_relay_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout) { syslog_relay_error_t res = SYSLOG_RELAY_E_UNKNOWN_ERROR; int bytes = 0; @@ -175,7 +175,7 @@ void *syslog_relay_worker(void *arg) return NULL; } -LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_start_capture(syslog_relay_client_t client, syslog_relay_receive_cb_t callback, void* user_data) +syslog_relay_error_t syslog_relay_start_capture(syslog_relay_client_t client, syslog_relay_receive_cb_t callback, void* user_data) { if (!client || !callback) return SYSLOG_RELAY_E_INVALID_ARG; @@ -203,7 +203,7 @@ LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_start_capture(syslog_rela return res; } -LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_start_capture_raw(syslog_relay_client_t client, syslog_relay_receive_cb_t callback, void* user_data) +syslog_relay_error_t syslog_relay_start_capture_raw(syslog_relay_client_t client, syslog_relay_receive_cb_t callback, void* user_data) { if (!client || !callback) return SYSLOG_RELAY_E_INVALID_ARG; @@ -231,7 +231,7 @@ LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_start_capture_raw(syslog_ return res; } -LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_stop_capture(syslog_relay_client_t client) +syslog_relay_error_t syslog_relay_stop_capture(syslog_relay_client_t client) { if (client->worker) { /* notify thread to finish */ diff --git a/src/syslog_relay.h b/src/syslog_relay.h index 86d798e..d5263e2 100644 --- a/src/syslog_relay.h +++ b/src/syslog_relay.h @@ -22,6 +22,7 @@ #ifndef _SYSLOG_RELAY_H #define _SYSLOG_RELAY_H +#include "idevice.h" #include "libimobiledevice/syslog_relay.h" #include "service.h" #include <libimobiledevice-glue/thread.h> diff --git a/src/webinspector.c b/src/webinspector.c index 3360597..f960fcc 100644 --- a/src/webinspector.c +++ b/src/webinspector.c @@ -62,7 +62,7 @@ static webinspector_error_t webinspector_error(property_list_service_error_t err return WEBINSPECTOR_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API webinspector_error_t webinspector_client_new(idevice_t device, lockdownd_service_descriptor_t service, webinspector_client_t * client) +webinspector_error_t webinspector_client_new(idevice_t device, lockdownd_service_descriptor_t service, webinspector_client_t * client) { *client = NULL; @@ -89,14 +89,14 @@ LIBIMOBILEDEVICE_API webinspector_error_t webinspector_client_new(idevice_t devi return 0; } -LIBIMOBILEDEVICE_API webinspector_error_t webinspector_client_start_service(idevice_t device, webinspector_client_t * client, const char* label) +webinspector_error_t webinspector_client_start_service(idevice_t device, webinspector_client_t * client, const char* label) { webinspector_error_t err = WEBINSPECTOR_E_UNKNOWN_ERROR; service_client_factory_start_service(device, WEBINSPECTOR_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(webinspector_client_new), &err); return err; } -LIBIMOBILEDEVICE_API webinspector_error_t webinspector_client_free(webinspector_client_t client) +webinspector_error_t webinspector_client_free(webinspector_client_t client) { if (!client) return WEBINSPECTOR_E_INVALID_ARG; @@ -107,7 +107,7 @@ LIBIMOBILEDEVICE_API webinspector_error_t webinspector_client_free(webinspector_ return err; } -LIBIMOBILEDEVICE_API webinspector_error_t webinspector_send(webinspector_client_t client, plist_t plist) +webinspector_error_t webinspector_send(webinspector_client_t client, plist_t plist) { webinspector_error_t res = WEBINSPECTOR_E_UNKNOWN_ERROR; @@ -164,12 +164,12 @@ LIBIMOBILEDEVICE_API webinspector_error_t webinspector_send(webinspector_client_ return res; } -LIBIMOBILEDEVICE_API webinspector_error_t webinspector_receive(webinspector_client_t client, plist_t * plist) +webinspector_error_t webinspector_receive(webinspector_client_t client, plist_t * plist) { return webinspector_receive_with_timeout(client, plist, 5000); } -LIBIMOBILEDEVICE_API webinspector_error_t webinspector_receive_with_timeout(webinspector_client_t client, plist_t * plist, uint32_t timeout_ms) +webinspector_error_t webinspector_receive_with_timeout(webinspector_client_t client, plist_t * plist, uint32_t timeout_ms) { webinspector_error_t res = WEBINSPECTOR_E_UNKNOWN_ERROR; plist_t message = NULL; diff --git a/src/webinspector.h b/src/webinspector.h index 67421bc..d249c58 100644 --- a/src/webinspector.h +++ b/src/webinspector.h @@ -22,6 +22,7 @@ #ifndef __WEBINSPECTOR_H #define __WEBINSPECTOR_H +#include "idevice.h" #include "libimobiledevice/webinspector.h" #include "property_list_service.h" diff --git a/tools/Makefile.am b/tools/Makefile.am index e8ef3ab..24cfc66 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -4,6 +4,7 @@ AM_CPPFLAGS = \ AM_CFLAGS = \ $(GLOBAL_CFLAGS) \ + $(ssl_lib_CFLAGS) \ $(libplist_CFLAGS) \ $(LFS_CFLAGS) @@ -27,12 +28,14 @@ bin_PROGRAMS = \ idevicedebugserverproxy \ idevicediagnostics \ idevicedebug \ + idevicedevmodectl \ idevicenotificationproxy \ idevicecrashreport \ - idevicesetlocation + idevicesetlocation \ + afcclient idevicebtlogger_SOURCES = idevicebtlogger.c -iidevicebtlogger_CFLAGS = $(AM_CFLAGS) +idevicebtlogger_CFLAGS = $(AM_CFLAGS) idevicebtlogger_LDFLAGS = $(top_builddir)/common/libinternalcommon.la $(AM_LDFLAGS) idevicebtlogger_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la @@ -47,9 +50,9 @@ idevicename_LDFLAGS = $(AM_LDFLAGS) idevicename_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la idevicepair_SOURCES = idevicepair.c -idevicepair_CFLAGS = $(AM_CFLAGS) $(ssl_lib_CFLAGS) -idevicepair_LDFLAGS = $(AM_LDFLAGS) $(libusbmuxd_LIBS) $(ssl_lib_LIBS) -idevicepair_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la $(top_builddir)/common/libinternalcommon.la $(limd_glue_LIBS) +idevicepair_CFLAGS = $(AM_CFLAGS) +idevicepair_LDFLAGS = $(AM_LDFLAGS) $(libusbmuxd_LIBS) +idevicepair_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la $(top_builddir)/common/libinternalcommon.la $(limd_glue_LIBS) $(ssl_lib_LIBS) idevicesyslog_SOURCES = idevicesyslog.c idevicesyslog_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS) @@ -62,8 +65,8 @@ idevice_id_LDFLAGS = $(AM_LDFLAGS) idevice_id_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la idevicebackup_SOURCES = idevicebackup.c -idevicebackup_CFLAGS = $(AM_CFLAGS) $(ssl_lib_CFLAGS) $(limd_glue_CFLAGS) -idevicebackup_LDFLAGS = $(AM_LDFLAGS) $(ssl_lib_LIBS) $(limd_glue_LIBS) +idevicebackup_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS) +idevicebackup_LDFLAGS = $(AM_LDFLAGS) $(limd_glue_LIBS) idevicebackup_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la idevicebackup2_SOURCES = idevicebackup2.c @@ -72,8 +75,8 @@ idevicebackup2_LDFLAGS = $(AM_LDFLAGS) $(limd_glue_LIBS) idevicebackup2_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la ideviceimagemounter_SOURCES = ideviceimagemounter.c -ideviceimagemounter_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS) -ideviceimagemounter_LDFLAGS = $(AM_LDFLAGS) $(limd_glue_LIBS) +ideviceimagemounter_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS) $(libtatsu_CFLAGS) +ideviceimagemounter_LDFLAGS = $(AM_LDFLAGS) $(limd_glue_LIBS) $(libtatsu_LIBS) ideviceimagemounter_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la idevicescreenshot_SOURCES = idevicescreenshot.c @@ -111,6 +114,11 @@ idevicedebug_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS) idevicedebug_LDFLAGS = $(AM_LDFLAGS) $(limd_glue_LIBS) idevicedebug_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la $(top_builddir)/common/libinternalcommon.la +idevicedevmodectl_SOURCES = idevicedevmodectl.c +idevicedevmodectl_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS) +idevicedevmodectl_LDFLAGS = $(AM_LDFLAGS) $(limd_glue_LIBS) +idevicedevmodectl_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la $(top_builddir)/common/libinternalcommon.la + idevicenotificationproxy_SOURCES = idevicenotificationproxy.c idevicenotificationproxy_CFLAGS = $(AM_CFLAGS) idevicenotificationproxy_LDFLAGS = $(AM_LDFLAGS) @@ -125,3 +133,12 @@ idevicesetlocation_SOURCES = idevicesetlocation.c idevicesetlocation_CFLAGS = $(AM_CFLAGS) idevicesetlocation_LDFLAGS = $(AM_LDFLAGS) idevicesetlocation_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la + +afcclient_SOURCES = afcclient.c +afcclient_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS) +afcclient_LDFLAGS = $(AM_LDFLAGS) $(limd_glue_LIBS) +if HAVE_READLINE + afcclient_CFLAGS += $(readline_CFLAGS) + afcclient_LDFLAGS += $(readline_LIBS) +endif +afcclient_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la $(limd_glue_LIBS) diff --git a/tools/afcclient.c b/tools/afcclient.c new file mode 100644 index 0000000..a958c23 --- /dev/null +++ b/tools/afcclient.c @@ -0,0 +1,1630 @@ +/* + * afcclient.c + * Utility to interact with AFC/HoustArrest service on the device + * + * Inspired by https://github.com/emonti/afcclient + * But entirely rewritten from scratch. + * + * Copyright (c) 2023 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 + +#define TOOL_NAME "afcclient" + +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> +#include <getopt.h> +#include <signal.h> +#include <ctype.h> +#include <unistd.h> +#include <dirent.h> +#include <time.h> +#include <sys/stat.h> + +#ifdef _WIN32 +#include <windows.h> +#include <sys/time.h> +#include <conio.h> +#define sleep(x) Sleep(x*1000) +#define S_IFMT 0170000 /* [XSI] type of file mask */ +#define S_IFIFO 0010000 /* [XSI] named pipe (fifo) */ +#define S_IFCHR 0020000 /* [XSI] character special */ +#define S_IFBLK 0060000 /* [XSI] block special */ +#define S_IFLNK 0120000 /* [XSI] symbolic link */ +#define S_IFSOCK 0140000 /* [XSI] socket */ +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) /* block special */ +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) /* char special */ +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) /* fifo or socket */ +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) /* symbolic link */ +#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) /* socket */ +#else +#include <sys/time.h> +#include <termios.h> +#endif + +#ifdef HAVE_READLINE +#include <readline/readline.h> +#include <readline/history.h> +#endif + +#include <libimobiledevice/libimobiledevice.h> +#include <libimobiledevice/lockdown.h> +#include <libimobiledevice/house_arrest.h> +#include <libimobiledevice/afc.h> +#include <plist/plist.h> + +#include <libimobiledevice-glue/termcolors.h> +#include <libimobiledevice-glue/utils.h> + +#undef st_mtime +#undef st_birthtime +struct afc_file_stat { + uint16_t st_mode; + uint16_t st_nlink; + uint64_t st_size; + uint64_t st_mtime; + uint64_t st_birthtime; + uint32_t st_blocks; +}; + +static char* udid = NULL; +static int connected = 0; +static int use_network = 0; +static idevice_subscription_context_t context = NULL; +static char* curdir = NULL; +static size_t curdir_len = 0; + +static int file_exists(const char* path) +{ + struct stat tst; +#ifdef _WIN32 + return (stat(path, &tst) == 0); +#else + return (lstat(path, &tst) == 0); +#endif +} + +static int is_directory(const char* path) +{ + struct stat tst; +#ifdef _WIN32 + return (stat(path, &tst) == 0) && S_ISDIR(tst.st_mode); +#else + return (lstat(path, &tst) == 0) && S_ISDIR(tst.st_mode); +#endif +} + +static void print_usage(int argc, char **argv, int is_error) +{ + char *name = strrchr(argv[0], '/'); + fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS]\n", (name ? name + 1: argv[0])); + fprintf(is_error ? stderr : stdout, + "\n" + "Interact with AFC/HouseArrest service on a connected device.\n" + "\n" + "OPTIONS:\n" + " -u, --udid UDID target specific device by UDID\n" + " -n, --network connect to network device (not recommended!)\n" + " --container <appid> Access container of given app\n" + " --documents <appid> Access Documents directory of given app\n" + " -h, --help prints usage information\n" \ + " -d, --debug enable communication debugging\n" \ + " -v, --version prints version information\n" \ + "\n" + ); + fprintf(is_error ? stderr : stdout, + "\n" \ + "Homepage: <" PACKAGE_URL ">\n" + "Bug Reports: <" PACKAGE_BUGREPORT ">\n" + ); +} + +#ifndef HAVE_READLINE +#ifdef _WIN32 +#define BS_CC '\b' +#else +#define BS_CC 0x7f +#define getch getchar +#endif +static void get_input(char *buf, int maxlen) +{ + int len = 0; + int c; + + while ((c = getch())) { + if ((c == '\r') || (c == '\n')) { + break; + } + if (isprint(c)) { + if (len < maxlen-1) + buf[len++] = c; + } else if (c == BS_CC) { + if (len > 0) { + fputs("\b \b", stdout); + len--; + } + } + } + buf[len] = 0; +} +#endif + +#define OPT_DOCUMENTS 1 +#define OPT_CONTAINER 2 + +int stop_requested = 0; + +static void handle_signal(int sig) +{ + stop_requested++; +#ifdef _WIN32 + GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); +#else + kill(getpid(), SIGINT); +#endif +} + +static void handle_help(afc_client_t afc, int argc, char** argv) +{ + printf("Available commands:\n"); + printf("help - print list of available commands\n"); + printf("devinfo - print device information\n"); + printf("info PATH - print file attributes of file at PATH\n"); + printf("ls [-l] PATH - print directory contents of PATH\n"); + printf("mv OLD NEW - rename file OLD to NEW\n"); + printf("mkdir PATH - create directory at PATH\n"); + printf("ln [-s] FILE [LINK] - create a (symbolic) link to file named LINKNAME\n"); + printf(" NOTE: This feature has been disabled in newer versions of iOS.\n"); + printf("rm PATH - remove item at PATH\n"); + printf("get [-rf] PATH [LOCALPATH] - transfer file at PATH from device to LOCALPATH\n"); + printf("put [-rf] LOCALPATH [PATH] - transfer local file at LOCALPATH to device at PATH\n"); + printf("\n"); +} + +static const char* path_get_basename(const char* path) +{ + const char *p = strrchr(path, '/'); + return p ? p + 1 : path; +} + +static int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y) +{ + /* Perform the carry for the later subtraction by updating y. */ + if (x->tv_usec < y->tv_usec) { + int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; + y->tv_usec -= 1000000 * nsec; + y->tv_sec += nsec; + } + if (x->tv_usec - y->tv_usec > 1000000) { + int nsec = (x->tv_usec - y->tv_usec) / 1000000; + y->tv_usec += 1000000 * nsec; + y->tv_sec -= nsec; + } + /* Compute the time remaining to wait. + tv_usec is certainly positive. */ + result->tv_sec = x->tv_sec - y->tv_sec; + result->tv_usec = x->tv_usec - y->tv_usec; + /* Return 1 if result is negative. */ + return x->tv_sec < y->tv_sec; +} + +struct str_item { + size_t len; + char* str; +}; + +static char* get_absolute_path(const char *path) +{ + if (*path == '/') { + return strdup(path); + } else { + size_t len = curdir_len + 1 + strlen(path) + 1; + char* result = (char*)malloc(len); + if (!strcmp(curdir, "/")) { + snprintf(result, len, "/%s", path); + } else { + snprintf(result, len, "%s/%s", curdir, path); + } + return result; + } +} + +static char* get_realpath(const char* path) +{ + if (!path) return NULL; + + int is_absolute = 0; + if (*path == '/') { + is_absolute = 1; + } + + const char* p = path; + if (is_absolute) { + while (*p == '/') p++; + } + if (*p == '\0') { + return strdup("/"); + } + + int c_count = 1; + const char* start = p; + const char* end = p; + struct str_item* comps = NULL; + + while (*p) { + if (*p == '/') { + p++; + end = p-1; + while (*p == '/') p++; + if (*p == '\0') break; + struct str_item* newcomps = (struct str_item*)realloc(comps, sizeof(struct str_item)*c_count); + if (!newcomps) { + free(comps); + printf("%s: out of memory?!\n", __func__); + return NULL; + } + comps = newcomps; + char *comp = (char*)malloc(end-start+1); + strncpy(comp, start, end-start); + comp[end-start] = '\0'; + comps[c_count-1].len = end-start; + comps[c_count-1].str = comp; + c_count++; + start = p; + end = p; + } + p++; + } + if (p > start) { + if (start == end) { + end = p; + } + struct str_item* newcomps = (struct str_item*)realloc(comps, sizeof(struct str_item)*c_count); + if (!newcomps) { + free(comps); + printf("%s: out of memory?!\n", __func__); + return NULL; + } + comps = newcomps; + char *comp = (char*)malloc(end-start+1); + strncpy(comp, start, end-start); + comp[end-start] = '\0'; + comps[c_count-1].len = end-start; + comps[c_count-1].str = comp; + } + + struct str_item* comps_final = (struct str_item*)malloc(sizeof(struct str_item)*(c_count+1)); + int o = 1; + if (is_absolute) { + comps_final[0].len = 1; + comps_final[0].str = (char*)"/"; + } else { + comps_final[0].len = curdir_len; + comps_final[0].str = curdir; + } + size_t o_len = comps_final[0].len; + + for (int i = 0; i < c_count; i++) { + if (!strcmp(comps[i].str, "..")) { + o--; + continue; + } else if (!strcmp(comps[i].str, ".")) { + continue; + } + o_len += comps[i].len; + comps_final[o].str = comps[i].str; + comps_final[o].len = comps[i].len; + o++; + } + + o_len += o; + char* result = (char*)malloc(o_len); + char* presult = result; + for (int i = 0; i < o; i++) { + if (i > 0 && strcmp(comps_final[i-1].str, "/") != 0) { + *presult = '/'; + presult++; + } + strncpy(presult, comps_final[i].str, comps_final[i].len); + presult+=comps_final[i].len; + *presult = '\0'; + } + if (presult == result) { + *presult = '/'; + presult++; + *presult = 0; + } + + for (int i = 0; i < c_count; i++) { + free(comps[i].str); + } + free(comps); + free(comps_final); + + return result; +} + +static void handle_devinfo(afc_client_t afc, int argc, char** argv) +{ + plist_t info = NULL; + afc_error_t err = afc_get_device_info_plist(afc, &info); + if (err == AFC_E_SUCCESS && info) { + if (argc > 0 && !strcmp(argv[0], "--plain")) { + plist_write_to_stream(info, stdout, PLIST_FORMAT_LIMD, PLIST_OPT_NONE); + } else { + plist_write_to_stream(info, stdout, PLIST_FORMAT_JSON, PLIST_OPT_NONE); + } + } else { + printf("Error: Failed to get device info: %s (%d)\n", afc_strerror(err), err); + } + plist_free(info); +} + +static int get_file_info_stat(afc_client_t afc, const char* path, struct afc_file_stat *stbuf) +{ + plist_t info = NULL; + afc_error_t ret = afc_get_file_info_plist(afc, path, &info); + memset(stbuf, 0, sizeof(struct afc_file_stat)); + if (ret != AFC_E_SUCCESS) { + return -1; + } else if (!info) { + return -1; + } + stbuf->st_size = plist_dict_get_uint(info, "st_size"); + stbuf->st_blocks = plist_dict_get_uint(info, "st_blocks"); + const char* s_ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL); + if (s_ifmt) { + if (!strcmp(s_ifmt, "S_IFREG")) { + stbuf->st_mode = S_IFREG; + } else if (!strcmp(s_ifmt, "S_IFDIR")) { + stbuf->st_mode = S_IFDIR; + } else if (!strcmp(s_ifmt, "S_IFLNK")) { + stbuf->st_mode = S_IFLNK; + } else if (!strcmp(s_ifmt, "S_IFBLK")) { + stbuf->st_mode = S_IFBLK; + } else if (!strcmp(s_ifmt, "S_IFCHR")) { + stbuf->st_mode = S_IFCHR; + } else if (!strcmp(s_ifmt, "S_IFIFO")) { + stbuf->st_mode = S_IFIFO; + } else if (!strcmp(s_ifmt, "S_IFSOCK")) { + stbuf->st_mode = S_IFSOCK; + } + } + stbuf->st_nlink = plist_dict_get_uint(info, "st_nlink"); + stbuf->st_mtime = (time_t)(plist_dict_get_uint(info, "st_mtime") / 1000000000); + /* available on iOS 7+ */ + stbuf->st_birthtime = (time_t)(plist_dict_get_uint(info, "st_birthtime") / 1000000000); + plist_free(info); + return 0; +} + +static void handle_file_info(afc_client_t afc, int argc, char** argv) +{ + if (argc < 1) { + printf("Error: Missing PATH.\n"); + return; + } + + plist_t info = NULL; + char* abspath = get_absolute_path(argv[0]); + if (!abspath) { + printf("Error: Invalid argument\n"); + return; + } + afc_error_t err = afc_get_file_info_plist(afc, abspath, &info); + if (err == AFC_E_SUCCESS && info) { + if (argc > 1 && !strcmp(argv[1], "--plain")) { + plist_write_to_stream(info, stdout, PLIST_FORMAT_LIMD, PLIST_OPT_NONE); + } else { + plist_write_to_stream(info, stdout, PLIST_FORMAT_JSON, PLIST_OPT_NONE); + } + } else { + printf("Error: Failed to get file info for %s: %s (%d)\n", argv[0], afc_strerror(err), err); + } + plist_free(info); + free(abspath); +} + +static void print_file_info(afc_client_t afc, const char* path, int list_verbose) +{ + struct afc_file_stat st; + get_file_info_stat(afc, path, &st); + if (list_verbose) { + char timebuf[64]; + time_t t = st.st_mtime; + if (S_ISDIR(st.st_mode)) { + printf("drwxr-xr-x"); + } else if (S_ISLNK(st.st_mode)) { + printf("lrwxrwxrwx"); + } else { + if (S_ISFIFO(st.st_mode)) { + printf("f"); + } else if (S_ISBLK(st.st_mode)) { + printf("b"); + } else if (S_ISCHR(st.st_mode)) { + printf("c"); + } else if (S_ISSOCK(st.st_mode)) { + printf("s"); + } else { + printf("-"); + } + printf("rw-r--r--"); + } + printf(" "); + printf("%4d", st.st_nlink); + printf(" "); + printf("mobile"); + printf(" "); + printf("mobile"); + printf(" "); + printf("%10lld", (long long)st.st_size); + printf(" "); +#ifdef _WIN32 + strftime(timebuf, 64, "%d %b %Y %H:%M:%S", localtime(&t)); +#else + strftime(timebuf, 64, "%d %h %Y %H:%M:%S", localtime(&t)); +#endif + printf("%s", timebuf); + printf(" "); + } + if (S_ISDIR(st.st_mode)) { + cprintf(FG_CYAN); + } else if (S_ISLNK(st.st_mode)) { + cprintf(FG_MAGENTA); + } else if (S_ISREG(st.st_mode)) { + cprintf(FG_DEFAULT); + } else { + cprintf(FG_YELLOW); + } + cprintf("%s" COLOR_RESET "\n", path_get_basename(path)); +} + +static void handle_list(afc_client_t afc, int argc, char** argv) +{ + const char* path = NULL; + int list_verbose = 0; + if (argc < 1) { + path = curdir; + } else { + if (!strcmp(argv[0], "-l")) { + list_verbose = 1; + if (argc == 2) { + path = argv[1]; + } else { + path = curdir; + } + } else { + path = argv[0]; + } + } + char* abspath = get_absolute_path(path); + if (!abspath) { + printf("Error: Invalid argument\n"); + return; + } + int abspath_is_root = strcmp(abspath, "/") == 0; + size_t abspath_len = (abspath_is_root) ? 0 : strlen(abspath); + char** entries = NULL; + afc_error_t err = afc_read_directory(afc, abspath, &entries); + if (err == AFC_E_READ_ERROR) { + print_file_info(afc, abspath, list_verbose); + return; + } else if (err != AFC_E_SUCCESS) { + printf("Error: Failed to list '%s': %s (%d)\n", path, afc_strerror(err), err); + free(abspath); + return; + } + + char** p = entries; + while (p && *p) { + if (strcmp(".", *p) == 0 || strcmp("..", *p) == 0) { + p++; + continue; + } + size_t len = abspath_len + 1 + strlen(*p) + 1; + char* testpath = (char*)malloc(len); + if (abspath_is_root) { + snprintf(testpath, len, "/%s", *p); + } else { + snprintf(testpath, len, "%s/%s", abspath, *p); + } + print_file_info(afc, testpath, list_verbose); + free(testpath); + p++; + } + afc_dictionary_free(entries); + free(abspath); +} + +static void handle_rename(afc_client_t afc, int argc, char** argv) +{ + if (argc != 2) { + printf("Error: Invalid number of arguments\n"); + return; + } + char* srcpath = get_absolute_path(argv[0]); + if (!srcpath) { + printf("Error: Invalid argument\n"); + return; + } + char* dstpath = get_absolute_path(argv[1]); + if (!dstpath) { + free(srcpath); + printf("Error: Invalid argument\n"); + return; + } + afc_error_t err = afc_rename_path(afc, srcpath, dstpath); + if (err != AFC_E_SUCCESS) { + printf("Error: Failed to rename '%s' -> '%s': %s (%d)\n", argv[0], argv[1], afc_strerror(err), err); + } + free(srcpath); + free(dstpath); +} + +static void handle_mkdir(afc_client_t afc, int argc, char** argv) +{ + for (int i = 0; i < argc; i++) { + char* abspath = get_absolute_path(argv[i]); + if (!abspath) { + printf("Error: Invalid argument '%s'\n", argv[i]); + continue; + } + afc_error_t err = afc_make_directory(afc, abspath); + if (err != AFC_E_SUCCESS) { + printf("Error: Failed to create directory '%s': %s (%d)\n", argv[i], afc_strerror(err), err); + } + free(abspath); + } +} + +static void handle_link(afc_client_t afc, int argc, char** argv) +{ + if (argc < 2) { + printf("Error: Invalid number of arguments\n"); + return; + } + afc_link_type_t link_type = AFC_HARDLINK; + if (!strcmp(argv[0], "-s")) { + argc--; + argv++; + link_type = AFC_SYMLINK; + } + if (argc < 1 || argc > 2) { + printf("Error: Invalid number of arguments\n"); + return; + } + const char *link_name = (argc == 1) ? path_get_basename(argv[0]) : argv[1]; + char* abs_link_name = get_absolute_path(link_name); + if (!abs_link_name) { + printf("Error: Invalid argument\n"); + return; + } + afc_error_t err = afc_make_link(afc, link_type, argv[0], link_name); + if (err != AFC_E_SUCCESS) { + printf("Error: Failed to create %s link for '%s' at '%s': %s (%d)\n", (link_type == AFC_HARDLINK) ? "hard" : "symbolic", argv[0], link_name, afc_strerror(err), err); + } +} + +static int ask_yesno(const char* prompt) +{ + int ret = 0; +#ifdef HAVE_READLINE + char* result = readline(prompt); + if (result && result[0] == 'y') { + ret = 1; + } +#else + char cmdbuf[2] = {0, }; + printf("%s", prompt); + fflush(stdout); + get_input(cmdbuf, sizeof(cmdbuf)); + if (cmdbuf[0] == 'y') { + ret = 1; + } +#endif +#ifdef HAVE_READLINE + free(result); +#endif + return ret; +} + +static void handle_remove(afc_client_t afc, int argc, char** argv) +{ + int recursive = 0; + int force = 0; + int i = 0; + for (i = 0; i < argc; i++) { + if (!strcmp(argv[i], "--")) { + i++; + break; + } else if (!strcmp(argv[i], "-r")) { + recursive = 1; + } else if (!strcmp(argv[i], "-f")) { + force = 1; + } else if (!strcmp(argv[i], "-rf") || !strcmp(argv[i], "-fr")) { + recursive = 1; + force = 1; + } else { + break; + } + } + if (recursive && !force) { + if (!ask_yesno("WARNING: This operation will remove all contents of the given path(s). Continue? [y/N] ")) { + printf("Aborted.\n"); + return; + } + } + for ( ; i < argc; i++) { + char* abspath = get_absolute_path(argv[i]); + if (!abspath) { + printf("Error: Invalid argument '%s'\n", argv[i]); + continue; + } + afc_error_t err; + if (recursive) { + err = afc_remove_path_and_contents(afc, abspath); + } else { + err = afc_remove_path(afc, abspath); + } + if (err != AFC_E_SUCCESS) { + printf("Error: Failed to remove '%s': %s (%d)\n", argv[i], afc_strerror(err), err); + } + free(abspath); + } +} + +static uint8_t get_single_file(afc_client_t afc, const char *srcpath, const char *dstpath, uint64_t file_size, uint8_t force_overwrite) +{ + uint64_t fh = 0; + afc_error_t err = afc_file_open(afc, srcpath, AFC_FOPEN_RDONLY, &fh); + if (err != AFC_E_SUCCESS) { + printf("Error: Failed to open file '%s': %s (%d)\n", srcpath, afc_strerror(err), err); + return 0; + } + if (file_exists(dstpath) && !force_overwrite) { + printf("Error: Failed to overwrite existing file without '-f' option: %s\n", dstpath); + return 0; + } + FILE *f = fopen(dstpath, "wb"); + if (!f) { + printf("Error: Failed to open local file '%s': %s\n", dstpath, strerror(errno)); + return 0; + } + struct timeval t1; + struct timeval t2; + struct timeval tdiff; + size_t bufsize = 0x100000; + char *buf = malloc(bufsize); + size_t total = 0; + int progress = 0; + int lastprog = 0; + if (file_size > 0x400000) { + progress = 1; + gettimeofday(&t1, NULL); + } + uint8_t succeed = 1; + while (err == AFC_E_SUCCESS) { + uint32_t bytes_read = 0; + size_t chunk = 0; + err = afc_file_read(afc, fh, buf, bufsize, &bytes_read); + if (bytes_read == 0) { + break; + } + while (chunk < bytes_read) { + size_t wr = fwrite(buf + chunk, 1, bytes_read - chunk, f); + if (wr == 0) { + if (progress) { + printf("\n"); + } + printf("Error: Failed to write to local file\n"); + succeed = 0; + break; + } + chunk += wr; + } + total += chunk; + if (progress) { + int prog = (int) ((double) total / (double) file_size * 100.0f); + if (prog > lastprog) { + gettimeofday(&t2, NULL); + timeval_subtract(&tdiff, &t2, &t1); + double time_in_sec = (double) tdiff.tv_sec + (double) tdiff.tv_usec / 1000000; + printf("\r%d%% (%0.1f MB/s) ", prog, (double) total / 1048576.0f / time_in_sec); + fflush(stdout); + lastprog = prog; + } + } + } + if (progress) { + printf("\n"); + } + if (err != AFC_E_SUCCESS) { + printf("Error: Failed to read from file '%s': %s (%d)\n", srcpath, afc_strerror(err), err); + succeed = 0; + } + free(buf); + fclose(f); + afc_file_close(afc, fh); + return succeed; +} + +static int __mkdir(const char* path) +{ +#ifdef _WIN32 + return mkdir(path); +#else + return mkdir(path, 0755); +#endif +} + +static uint8_t get_file(afc_client_t afc, const char *srcpath, const char *dstpath, uint8_t force_overwrite, uint8_t recursive_get) +{ + plist_t info = NULL; + uint64_t file_size = 0; + afc_error_t err = afc_get_file_info_plist(afc, srcpath, &info); + if (err == AFC_E_OBJECT_NOT_FOUND) { + printf("Error: Failed to read from file '%s': %s (%d)\n", srcpath, afc_strerror(err), err); + return 0; + } + uint8_t is_dir = 0; + if (info) { + file_size = plist_dict_get_uint(info, "st_size"); + const char* ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL); + is_dir = (ifmt && !strcmp(ifmt, "S_IFDIR")); + plist_free(info); + } + uint8_t succeed = 1; + if (is_dir) { + if (!recursive_get) { + printf("Error: Failed to get a directory without '-r' option: %s\n", srcpath); + return 0; + } + char **entries = NULL; + err = afc_read_directory(afc, srcpath, &entries); + if (err != AFC_E_SUCCESS) { + printf("Error: Failed to list '%s': %s (%d)\n", srcpath, afc_strerror(err), err); + return 0; + } + char **p = entries; + size_t srcpath_len = strlen(srcpath); + uint8_t srcpath_is_root = strcmp(srcpath, "/") == 0; + // if directory exists, check force_overwrite flag + if (is_directory(dstpath)) { + if (!force_overwrite) { + printf("Error: Failed to write into existing directory without '-f': %s\n", dstpath); + return 0; + } + } else if (__mkdir(dstpath) != 0) { + printf("Error: Failed to create directory '%s': %s\n", dstpath, strerror(errno)); + afc_dictionary_free(entries); + return 0; + } + while (p && *p) { + if (strcmp(".", *p) == 0 || strcmp("..", *p) == 0) { + p++; + continue; + } + size_t len = srcpath_is_root ? (strlen(*p) + 2) : (srcpath_len + 1 + strlen(*p) + 1); + char *testpath = (char *) malloc(len); + if (srcpath_is_root) { + snprintf(testpath, len, "/%s", *p); + } else { + snprintf(testpath, len, "%s/%s", srcpath, *p); + } + uint8_t dst_is_root = strcmp(srcpath, "/") == 0; + size_t dst_len = dst_is_root ? (strlen(*p) + 2) : (strlen(dstpath) + 1 + strlen(*p) + 1); + char *newdst = (char *) malloc(dst_len); + if (dst_is_root) { + snprintf(newdst, dst_len, "/%s", *p); + } else { + snprintf(newdst, dst_len, "%s/%s", dstpath, *p); + } + if (!get_file(afc, testpath, newdst, force_overwrite, recursive_get)) { + succeed = 0; + break; + } + free(testpath); + free(newdst); + p++; + } + afc_dictionary_free(entries); + } else { + succeed = get_single_file(afc, srcpath, dstpath, file_size, force_overwrite); + } + return succeed; +} + +static void handle_get(afc_client_t afc, int argc, char **argv) +{ + if (argc < 1) { + printf("Error: Invalid number of arguments\n"); + return; + } + uint8_t force_overwrite = 0, recursive_get = 0; + char *srcpath = NULL; + char *dstpath = NULL; + int i = 0; + for ( ; i < argc; i++) { + if (!strcmp(argv[i], "--")) { + i++; + break; + } else if (!strcmp(argv[i], "-r")) { + recursive_get = 1; + } else if (!strcmp(argv[i], "-f")) { + force_overwrite = 1; + } else if (!strcmp(argv[i], "-rf") || !strcmp(argv[i], "-fr")) { + recursive_get = 1; + force_overwrite = 1; + } else { + break; + } + } + if (argc - i == 1) { + char *tmp = strdup(argv[i]); + size_t src_len = strlen(tmp); + if (src_len > 1 && tmp[src_len - 1] == '/') { + tmp[src_len - 1] = '\0'; + } + srcpath = get_absolute_path(tmp); + dstpath = strdup(path_get_basename(tmp)); + free(tmp); + } else if (argc - i == 2) { + char *tmp = strdup(argv[i]); + size_t src_len = strlen(tmp); + if (src_len > 1 && tmp[src_len - 1] == '/') { + tmp[src_len - 1] = '\0'; + } + srcpath = get_absolute_path(tmp); + dstpath = strdup(argv[i + 1]); + size_t dst_len = strlen(dstpath); + if (dst_len > 1 && dstpath[dst_len - 1] == '/') { + dstpath[dst_len - 1] = '\0'; + } + free(tmp); + } else { + printf("Error: Invalid number of arguments\n"); + return; + } + + // target is a directory, put file under this target + if (is_directory(dstpath)) { + const char *basen = path_get_basename(srcpath); + uint8_t dst_is_root = strcmp(dstpath, "/") == 0; + size_t len = dst_is_root ? (strlen(basen) + 2) : (strlen(dstpath) + 1 + strlen(basen) + 1); + char *newdst = (char *) malloc(len); + if (dst_is_root) { + snprintf(newdst, len, "/%s", basen); + } else { + snprintf(newdst, len, "%s/%s", dstpath, basen); + } + get_file(afc, srcpath, newdst, force_overwrite, recursive_get); + free(srcpath); + free(newdst); + free(dstpath); + } else { + // target is not a dir or does not exist, just try to create or rewrite it + get_file(afc, srcpath, dstpath, force_overwrite, recursive_get); + free(srcpath); + free(dstpath); + } +} + +static uint8_t put_single_file(afc_client_t afc, const char *srcpath, const char *dstpath, uint8_t force_overwrite) +{ + plist_t info = NULL; + afc_error_t ret = afc_get_file_info_plist(afc, dstpath, &info); + // file exists, only overwrite with '-f' option was set + if (ret == AFC_E_SUCCESS && info) { + plist_free(info); + if (!force_overwrite) { + printf("Error: Failed to write into existing file without '-f' option: %s\n", dstpath); + return 0; + } + } + FILE *f = fopen(srcpath, "rb"); + if (!f) { + printf("Error: Failed to open local file '%s': %s\n", srcpath, strerror(errno)); + return 0; + } + struct timeval t1; + struct timeval t2; + struct timeval tdiff; + struct stat fst; + int progress = 0; + size_t bufsize = 0x100000; + char *buf = malloc(bufsize); + + fstat(fileno(f), &fst); + if (fst.st_size >= 0x400000) { + progress = 1; + gettimeofday(&t1, NULL); + } + size_t total = 0; + int lastprog = 0; + uint64_t fh = 0; + afc_error_t err = afc_file_open(afc, dstpath, AFC_FOPEN_RW, &fh); + uint8_t succeed = 1; + while (err == AFC_E_SUCCESS) { + uint32_t bytes_read = fread(buf, 1, bufsize, f); + if (bytes_read == 0) { + if (!feof(f)) { + if (progress) { + printf("\n"); + } + printf("Error: Failed to read from local file\n"); + succeed = 0; + } + break; + } + uint32_t chunk = 0; + while (chunk < bytes_read) { + uint32_t bytes_written = 0; + err = afc_file_write(afc, fh, buf + chunk, bytes_read - chunk, &bytes_written); + if (err != AFC_E_SUCCESS) { + if (progress) { + printf("\n"); + } + printf("Error: Failed to write to device file\n"); + succeed = 0; + break; + } + chunk += bytes_written; + } + total += chunk; + if (progress) { + int prog = (int) ((double) total / (double) fst.st_size * 100.0f); + if (prog > lastprog) { + gettimeofday(&t2, NULL); + timeval_subtract(&tdiff, &t2, &t1); + double time_in_sec = (double) tdiff.tv_sec + (double) tdiff.tv_usec / 1000000; + printf("\r%d%% (%0.1f MB/s) ", prog, (double) total / 1048576.0f / time_in_sec); + fflush(stdout); + lastprog = prog; + } + } + } + free(buf); + afc_file_close(afc, fh); + fclose(f); + return succeed; +} + +static uint8_t put_file(afc_client_t afc, const char *srcpath, const char *dstpath, uint8_t force_overwrite, uint8_t recursive_put) +{ + if (is_directory(srcpath)) { + if (!recursive_put) { + printf("Error: Failed to put directory without '-r' option: %s\n", srcpath); + return 0; + } + plist_t info = NULL; + afc_error_t err = afc_get_file_info_plist(afc, dstpath, &info); + //create if target directory does not exist + plist_free(info); + info = NULL; + if (err == AFC_E_OBJECT_NOT_FOUND) { + err = afc_make_directory(afc, dstpath); + if (err != AFC_E_SUCCESS) { + printf("Error: Failed to create directory '%s': %s (%d)\n", dstpath, afc_strerror(err), err); + return 0; + } + } else if (!force_overwrite) { + printf("Error: Failed to put existing directory without '-f' option: %s\n", dstpath); + return 0; + } + afc_get_file_info_plist(afc, dstpath, &info); + uint8_t is_dir = 0; + if (info) { + const char* ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL); + is_dir = (ifmt && !strcmp(ifmt, "S_IFDIR")); + plist_free(info); + } + if (!is_dir) { + printf("Error: Failed to create or access directory: '%s'\n", dstpath); + return 0; + } + + // walk dir recursively to put files + DIR *cur_dir = opendir(srcpath); + if (cur_dir) { + struct dirent *ep; + while ((ep = readdir(cur_dir))) { + if ((strcmp(ep->d_name, ".") == 0) || (strcmp(ep->d_name, "..") == 0)) { + continue; + } + char *fpath = string_build_path(srcpath, ep->d_name, NULL); + if (fpath) { + uint8_t dst_is_root = strcmp(dstpath, "/") == 0; + size_t len = dst_is_root ? (strlen(ep->d_name) + 2) : (strlen(dstpath) + 1 + strlen(ep->d_name) + 1); + char *newdst = (char *) malloc(len); + if (dst_is_root) { + snprintf(newdst, len, "/%s", ep->d_name); + } else { + snprintf(newdst, len, "%s/%s", dstpath, ep->d_name); + } + if (!put_file(afc, fpath, newdst, force_overwrite, recursive_put)) { + free(newdst); + free(fpath); + return 0; + } + free(newdst); + free(fpath); + } + } + closedir(cur_dir); + } else { + printf("Error: Failed to visit directory: '%s': %s\n", srcpath, strerror(errno)); + return 0; + } + } else { + return put_single_file(afc, srcpath, dstpath, force_overwrite); + } + return 1; +} + +static void handle_put(afc_client_t afc, int argc, char **argv) +{ + if (argc < 1) { + printf("Error: Invalid number of arguments\n"); + return; + } + int i = 0; + uint8_t force_overwrite = 0, recursive_put = 0; + for ( ; i < argc; i++) { + if (!strcmp(argv[i], "--")) { + i++; + break; + } else if (!strcmp(argv[i], "-r")) { + recursive_put = 1; + } else if (!strcmp(argv[i], "-f")) { + force_overwrite = 1; + } else if (!strcmp(argv[i], "-rf") || !strcmp(argv[i], "-fr")) { + recursive_put = 1; + force_overwrite = 1; + } else { + break; + } + } + if (i >= argc) { + printf("Error: Invalid number of arguments\n"); + return; + } + char *srcpath = strdup(argv[i]); + size_t src_len = strlen(srcpath); + if (src_len > 1 && srcpath[src_len - 1] == '/') { + srcpath[src_len - 1] = '\0'; + } + char *dstpath = NULL; + if (argc - i == 1) { + dstpath = get_absolute_path(path_get_basename(srcpath)); + } else if (argc - i == 2) { + char *tmp = strdup(argv[i + 1]); + size_t dst_len = strlen(tmp); + if (dst_len > 1 && tmp[dst_len - 1] == '/') { + tmp[dst_len - 1] = '\0'; + } + dstpath = get_absolute_path(tmp); + free(tmp); + } else { + printf("Error: Invalid number of arguments\n"); + return; + } + plist_t info = NULL; + afc_error_t err = afc_get_file_info_plist(afc, dstpath, &info); + // target does not exist, put directly + if (err == AFC_E_OBJECT_NOT_FOUND) { + put_file(afc, srcpath, dstpath, force_overwrite, recursive_put); + free(srcpath); + free(dstpath); + } else { + uint8_t is_dir = 0; + if (info) { + const char* ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL); + is_dir = (ifmt && !strcmp(ifmt, "S_IFDIR")); + plist_free(info); + } + // target is a directory, try to put under this directory + if (is_dir) { + const char *basen = path_get_basename(srcpath); + uint8_t dst_is_root = strcmp(dstpath, "/") == 0; + size_t len = dst_is_root ? (strlen(basen) + 2) : (strlen(dstpath) + 1 + strlen(basen) + 1); + char *newdst = (char *) malloc(len); + if (dst_is_root) { + snprintf(newdst, len, "/%s", basen); + } else { + snprintf(newdst, len, "%s/%s", dstpath, basen); + } + free(dstpath); + dstpath = get_absolute_path(newdst); + free(newdst); + put_file(afc, srcpath, dstpath, force_overwrite, recursive_put); + } else { + //target is common file, rewrite it + put_file(afc, srcpath, dstpath, force_overwrite, recursive_put); + } + free(srcpath); + free(dstpath); + } +} + +static void handle_pwd(afc_client_t afc, int argc, char** argv) +{ + printf("%s\n", curdir); +} + +static void handle_cd(afc_client_t afc, int argc, char** argv) +{ + if (argc != 1) { + printf("Error: Invalid number of arguments\n"); + return; + } + + if (!strcmp(argv[0], ".")) { + return; + } + + if (!strcmp(argv[0], "..")) { + if (!strcmp(curdir, "/")) { + return; + } + char *p = strrchr(curdir, '/'); + if (!p) { + strcpy(curdir, "/"); + return; + } + if (p == curdir) { + *(p+1) = '\0'; + } else { + *p = '\0'; + } + return; + } + + char* path = get_realpath(argv[0]); + int is_dir = 0; + plist_t info = NULL; + afc_error_t err = afc_get_file_info_plist(afc, path, &info); + if (err == AFC_E_SUCCESS && info) { + const char* ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL); + is_dir = (ifmt && !strcmp(ifmt, "S_IFDIR")); + plist_free(info); + } else { + printf("Error: Failed to get file info for %s: %s (%d)\n", path, afc_strerror(err), err); + free(path); + return; + } + + if (!is_dir) { + printf("Error: '%s' is not a valid directory\n", path); + free(path); + return; + } + + free(curdir); + curdir = path; + curdir_len = strlen(curdir); +} + +static void parse_cmdline(int* p_argc, char*** p_argv, const char* cmdline) +{ + char **argv = NULL; + int argc = 0; + size_t maxlen = strlen(cmdline); + const char* pos = cmdline; + const char* qpos = NULL; + char *tmpbuf = NULL; + int tmplen = 0; + int is_error = 0; + + /* skip initial whitespace */ + while (isspace(*pos)) pos++; + maxlen -= (pos - cmdline); + + tmpbuf = (char*)malloc(maxlen+1); + + while (!is_error) { + if (*pos == '\\') { + pos++; + switch (*pos) { + case '"': + case '\'': + case '\\': + case ' ': + tmpbuf[tmplen++] = *pos; + pos++; + break; + default: + printf("Error: Invalid escape sequence\n"); + is_error++; + break; + } + } else if (*pos == '"' || *pos == '\'') { + if (!qpos) { + qpos = pos; + } else { + qpos = NULL; + } + pos++; + } else if (*pos == '\0' || (!qpos && isspace(*pos))) { + tmpbuf[tmplen] = '\0'; + if (*pos == '\0' && qpos) { + printf("Error: Unmatched `%c`\n", *qpos); + is_error++; + break; + } + char** new_argv = (char**)realloc(argv, (argc+1)*sizeof(char*)); + if (new_argv == NULL) { + printf("Error: Out of memory?!\n"); + is_error++; + break; + } + argv = new_argv; + /* shrink buffer to actual argument size */ + argv[argc] = (char*)realloc(tmpbuf, tmplen+1); + if (!argv[argc]) { + printf("Error: Out of memory?!\n"); + is_error++; + break; + } + argc++; + tmpbuf = NULL; + if (*pos == '\0') { + break; + } + maxlen -= tmplen; + tmpbuf = (char*)malloc(maxlen+1); + tmplen = 0; + while (isspace(*pos)) pos++; + } else { + tmpbuf[tmplen++] = *pos; + pos++; + } + } + if (tmpbuf) { + free(tmpbuf); + } + if (is_error) { + int i; + for (i = 0; argv && i < argc; i++) free(argv[i]); + free(argv); + return; + } + + *p_argv = argv; + *p_argc = argc; +} + +static int process_args(afc_client_t afc, int argc, char** argv) +{ + if (!strcmp(argv[0], "q") || !strcmp(argv[0], "quit") || !strcmp(argv[0], "exit")) { + return -1; + } + else if (!strcmp(argv[0], "help")) { + handle_help(afc, argc, argv); + } + else if (!strcmp(argv[0], "devinfo") || !strcmp(argv[0], "deviceinfo")) { + handle_devinfo(afc, argc-1, argv+1); + } + else if (!strcmp(argv[0], "info")) { + handle_file_info(afc, argc-1, argv+1); + } + else if (!strcmp(argv[0], "ls") || !strcmp(argv[0], "list")) { + handle_list(afc, argc-1, argv+1); + } + else if (!strcmp(argv[0], "mv") || !strcmp(argv[0], "rename")) { + handle_rename(afc, argc-1, argv+1); + } + else if (!strcmp(argv[0], "mkdir")) { + handle_mkdir(afc, argc-1, argv+1); + } + else if (!strcmp(argv[0], "ln")) { + handle_link(afc, argc-1, argv+1); + } + else if (!strcmp(argv[0], "rm") || !strcmp(argv[0], "remove")) { + handle_remove(afc, argc-1, argv+1); + } + else if (!strcmp(argv[0], "get")) { + handle_get(afc, argc-1, argv+1); + } + else if (!strcmp(argv[0], "put")) { + handle_put(afc, argc-1, argv+1); + } + else if (!strcmp(argv[0], "pwd")) { + handle_pwd(afc, argc-1, argv+1); + } + else if (!strcmp(argv[0], "cd")) { + handle_cd(afc, argc-1, argv+1); + } + else { + printf("Unknown command '%s'. Type 'help' to get a list of available commands.\n", argv[0]); + } + return 0; +} + +static void start_cmdline(afc_client_t afc) +{ + while (!stop_requested) { + int argc = 0; + char **argv = NULL; + char prompt[128]; + int plen = curdir_len; + char *ppath = curdir; + int plim = (int)(sizeof(prompt)/2)-8; + if (plen > plim) { + ppath = curdir + (plen - plim); + plen = plim; + } + snprintf(prompt, 128, FG_BLACK BG_LIGHT_GRAY "afc:" COLOR_RESET FG_BRIGHT_YELLOW BG_BLUE "%.*s" COLOR_RESET " > ", plen, ppath); +#ifdef HAVE_READLINE + char* cmd = readline(prompt); + if (!cmd || !*cmd) { + free(cmd); + continue; + } + add_history(cmd); + parse_cmdline(&argc, &argv, cmd); +#else + char cmdbuf[4096]; + printf("%s", prompt); + fflush(stdout); + get_input(cmdbuf, sizeof(cmdbuf)); + parse_cmdline(&argc, &argv, cmdbuf); +#endif +#ifdef HAVE_READLINE + free(cmd); +#endif + /* process arguments */ + if (argv && argv[0]) { + if (process_args(afc, argc, argv) < 0) { + break; + } + } + } +} + +static void device_event_cb(const idevice_event_t* event, void* userdata) +{ + if (use_network && event->conn_type != CONNECTION_NETWORK) { + return; + } else if (!use_network && event->conn_type != CONNECTION_USBMUXD) { + return; + } + if (event->event == IDEVICE_DEVICE_ADD) { + if (!udid) { + udid = strdup(event->udid); + } + if (strcmp(udid, event->udid) == 0) { + connected = 1; + } + } else if (event->event == IDEVICE_DEVICE_REMOVE) { + if (strcmp(udid, event->udid) == 0) { + connected = 0; + printf("\n[disconnected]\n"); + handle_signal(SIGINT); + } + } +} + +int main(int argc, char** argv) +{ + const char* appid = NULL; + int ret = 0; + idevice_t device = NULL; + lockdownd_client_t lockdown = NULL; + lockdownd_error_t ldret = LOCKDOWN_E_UNKNOWN_ERROR; + lockdownd_service_descriptor_t service = NULL; + afc_client_t afc = NULL; + house_arrest_client_t house_arrest = NULL; + const char* service_name = AFC_SERVICE_NAME; + int use_container = 0; + + int c = 0; + const struct option longopts[] = { + { "udid", required_argument, NULL, 'u' }, + { "network", no_argument, NULL, 'n' }, + { "help", no_argument, NULL, 'h' }, + { "debug", no_argument, NULL, 'd' }, + { "version", no_argument, NULL, 'v' }, + { "documents", required_argument, NULL, OPT_DOCUMENTS }, + { "container", required_argument, NULL, OPT_CONTAINER }, + { NULL, 0, NULL, 0} + }; + + signal(SIGTERM, handle_signal); +#ifndef _WIN32 + signal(SIGQUIT, handle_signal); + signal(SIGPIPE, SIG_IGN); +#endif + + while ((c = getopt_long(argc, argv, "du:nhv", longopts, NULL)) != -1) { + switch (c) { + case 'd': + idevice_set_debug_level(1); + break; + case 'u': + if (!*optarg) { + fprintf(stderr, "ERROR: UDID must not be empty!\n"); + print_usage(argc, argv, 1); + return 2; + } + udid = strdup(optarg); + break; + case 'n': + use_network = 1; + break; + case 'h': + print_usage(argc, argv, 0); + return 0; + case 'v': + printf("%s %s", TOOL_NAME, PACKAGE_VERSION); +#ifdef HAVE_READLINE + printf(" (readline)"); +#endif + printf("\n"); + return 0; + case OPT_DOCUMENTS: + if (!*optarg) { + fprintf(stderr, "ERROR: '--documents' requires a non-empty app ID!\n"); + print_usage(argc, argv, 1); + return 2; + } + appid = optarg; + use_container = 0; + break; + case OPT_CONTAINER: + if (!*optarg) { + fprintf(stderr, "ERROR: '--container' requires a not-empty app ID!\n"); + print_usage(argc, argv, 1); + return 2; + } + appid = optarg; + use_container = 1; + break; + default: + print_usage(argc, argv, 1); + return 2; + } + } + + argc -= optind; + argv += optind; + + int num = 0; + idevice_info_t *devices = NULL; + idevice_get_device_list_extended(&devices, &num); + int count = 0; + for (int i = 0; i < num; i++) { + if (devices[i]->conn_type == CONNECTION_NETWORK && use_network) { + count++; + } else if (devices[i]->conn_type == CONNECTION_USBMUXD) { + count++; + } + } + idevice_device_list_extended_free(devices); + if (count == 0) { + fprintf(stderr, "No device found. Plug in a device or pass UDID with -u to wait for device to be available.\n"); + return 1; + } + + idevice_events_subscribe(&context, device_event_cb, NULL); + + while (!connected && !stop_requested) { +#ifdef _WIN32 + Sleep(100); +#else + usleep(100000); +#endif + } + if (stop_requested) { + return 0; + } + + ret = idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX); + if (ret != IDEVICE_E_SUCCESS) { + if (udid) { + fprintf(stderr, "ERROR: Device %s not found!\n", udid); + } else { + fprintf(stderr, "ERROR: No device found!\n"); + } + return 1; + } + + do { + if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME))) { + fprintf(stderr, "ERROR: Could not connect to lockdownd: %s (%d)\n", lockdownd_strerror(ldret), ldret); + ret = 1; + break; + } + + if (appid) { + service_name = HOUSE_ARREST_SERVICE_NAME; + } + + ldret = lockdownd_start_service(lockdown, service_name, &service); + if (ldret != LOCKDOWN_E_SUCCESS) { + fprintf(stderr, "ERROR: Failed to start service %s: %s (%d)\n", service_name, lockdownd_strerror(ldret), ldret); + ret = 1; + break; + } + + if (appid) { + house_arrest_client_new(device, service, &house_arrest); + if (!house_arrest) { + fprintf(stderr, "Could not start document sharing service!\n"); + ret = 1; + break; + } + + if (house_arrest_send_command(house_arrest, use_container ? "VendContainer": "VendDocuments", appid) != HOUSE_ARREST_E_SUCCESS) { + fprintf(stderr, "Could not send house_arrest command!\n"); + ret = 1; + break; + } + + plist_t dict = NULL; + if (house_arrest_get_result(house_arrest, &dict) != HOUSE_ARREST_E_SUCCESS) { + fprintf(stderr, "Could not get result from document sharing service!\n"); + break; + } + plist_t node = plist_dict_get_item(dict, "Error"); + if (node) { + char *str = NULL; + plist_get_string_val(node, &str); + fprintf(stderr, "ERROR: %s\n", str); + if (str && !strcmp(str, "InstallationLookupFailed")) { + fprintf(stderr, "The App '%s' is either not present on the device, or the 'UIFileSharingEnabled' key is not set in its Info.plist. Starting with iOS 8.3 this key is mandatory to allow access to an app's Documents folder.\n", appid); + } + free(str); + plist_free(dict); + break; + } + plist_free(dict); + afc_client_new_from_house_arrest_client(house_arrest, &afc); + } else { + afc_client_new(device, service, &afc); + } + lockdownd_service_descriptor_free(service); + lockdownd_client_free(lockdown); + lockdown = NULL; + + curdir = strdup("/"); + curdir_len = 1; + + if (argc > 0) { + // command line mode + process_args(afc, argc, argv); + } else { + // interactive mode + start_cmdline(afc); + } + + } while (0); + + if (afc) { + afc_client_free(afc); + } + if (lockdown) { + lockdownd_client_free(lockdown); + } + idevice_free(device); + + return ret; +} diff --git a/tools/idevicebackup.c b/tools/idevicebackup.c index 2856fda..363abad 100644 --- a/tools/idevicebackup.c +++ b/tools/idevicebackup.c @@ -32,31 +32,19 @@ #include <stdlib.h> #include <signal.h> #include <getopt.h> -#if defined(HAVE_OPENSSL) -#include <openssl/sha.h> -#elif defined(HAVE_GNUTLS) -#include <gcrypt.h> -#elif defined(HAVE_MBEDTLS) -#include <mbedtls/sha1.h> -#if MBEDTLS_VERSION_NUMBER < 0x03000000 -#define mbedtls_sha1 mbedtls_sha1_ret -#define mbedtls_sha1_starts mbedtls_sha1_starts_ret -#define mbedtls_sha1_update mbedtls_sha1_update_ret -#define mbedtls_sha1_finish mbedtls_sha1_finish_ret -#endif -#else -#error No supported crypto library enabled -#endif #include <unistd.h> #include <ctype.h> #include <time.h> +#include <sys/stat.h> #include <libimobiledevice/libimobiledevice.h> #include <libimobiledevice/lockdown.h> #include <libimobiledevice/mobilebackup.h> #include <libimobiledevice/notification_proxy.h> #include <libimobiledevice/afc.h> +#include <libimobiledevice-glue/sha.h> #include <libimobiledevice-glue/utils.h> +#include <plist/plist.h> #define MOBILEBACKUP_SERVICE_NAME "com.apple.mobilebackup" #define NP_SERVICE_NAME "com.apple.mobile.notification_proxy" @@ -64,7 +52,7 @@ #define LOCK_ATTEMPTS 50 #define LOCK_WAIT 200000 -#ifdef WIN32 +#ifdef _WIN32 #include <windows.h> #define sleep(x) Sleep(x*1000) #endif @@ -87,17 +75,6 @@ enum device_link_file_status_t { DEVICE_LINK_FILE_STATUS_LAST_HUNK }; -static void sha1_of_data(const char *input, uint32_t size, unsigned char *hash_out) -{ -#if defined(HAVE_OPENSSL) - SHA1((const unsigned char*)input, size, hash_out); -#elif defined(HAVE_GNUTLS) - gcry_md_hash_buffer(GCRY_MD_SHA1, hash_out, input, size); -#elif defined(HAVE_MBEDTLS) - mbedtls_sha1((unsigned char*)input, size, hash_out); -#endif -} - static int compare_hash(const unsigned char *hash1, const unsigned char *hash2, int hash_len) { int i; @@ -109,89 +86,49 @@ static int compare_hash(const unsigned char *hash1, const unsigned char *hash2, return 1; } -static void _sha1_update(void* context, const char* data, size_t len) -{ -#if defined(HAVE_OPENSSL) - SHA1_Update(context, data, len); -#elif defined(HAVE_GNUTLS) - gcry_md_write(context, data, len); -#elif defined(HAVE_MBEDTLS) - mbedtls_sha1_update(context, (const unsigned char*)data, len); -#endif -} - static void compute_datahash(const char *path, const char *destpath, uint8_t greylist, const char *domain, const char *appid, const char *version, unsigned char *hash_out) { -#if defined(HAVE_OPENSSL) - SHA_CTX sha1; - SHA1_Init(&sha1); - void* psha1 = &sha1; -#elif defined(HAVE_GNUTLS) - gcry_md_hd_t hd = NULL; - gcry_md_open(&hd, GCRY_MD_SHA1, 0); - if (!hd) { - printf("ERROR: Could not initialize libgcrypt/SHA1\n"); - return; - } - gcry_md_reset(hd); - void* psha1 = hd; -#elif defined(HAVE_MBEDTLS) - mbedtls_sha1_context sha1; - mbedtls_sha1_init(&sha1); - mbedtls_sha1_starts(&sha1); - void* psha1 = &sha1; -#endif + sha1_context sha1; + sha1_init(&sha1); FILE *f = fopen(path, "rb"); if (f) { unsigned char buf[16384]; size_t len; while ((len = fread(buf, 1, 16384, f)) > 0) { - _sha1_update(psha1, (const char*)buf, len); + sha1_update(&sha1, buf, len); } fclose(f); - _sha1_update(psha1, destpath, strlen(destpath)); - _sha1_update(psha1, ";", 1); + sha1_update(&sha1, destpath, strlen(destpath)); + sha1_update(&sha1, ";", 1); if (greylist == 1) { - _sha1_update(psha1, "true", 4); + sha1_update(&sha1, "true", 4); } else { - _sha1_update(psha1, "false", 5); + sha1_update(&sha1, "false", 5); } - _sha1_update(psha1, ";", 1); + sha1_update(&sha1, ";", 1); if (domain) { - _sha1_update(psha1, domain, strlen(domain)); + sha1_update(&sha1, domain, strlen(domain)); } else { - _sha1_update(psha1, "(null)", 6); + sha1_update(&sha1, "(null)", 6); } - _sha1_update(psha1, ";", 1); + sha1_update(&sha1, ";", 1); if (appid) { - _sha1_update(psha1, appid, strlen(appid)); + sha1_update(&sha1, appid, strlen(appid)); } else { - _sha1_update(psha1, "(null)", 6); + sha1_update(&sha1, "(null)", 6); } - _sha1_update(psha1, ";", 1); + sha1_update(&sha1, ";", 1); if (version) { - _sha1_update(psha1, version, strlen(version)); + sha1_update(&sha1, version, strlen(version)); } else { - _sha1_update(psha1, "(null)", 6); + sha1_update(&sha1, "(null)", 6); } -#if defined(HAVE_OPENSSL) - SHA1_Final(hash_out, &sha1); -#elif defined(HAVE_GNUTLS) - unsigned char *newhash = gcry_md_read(hd, GCRY_MD_SHA1); - memcpy(hash_out, newhash, 20); -#elif defined(HAVE_MBEDTLS) - mbedtls_sha1_finish(&sha1, hash_out); -#endif + sha1_final(&sha1, hash_out); } -#if defined(HAVE_GNUTLS) - gcry_md_close(hd); -#elif defined(HAVE_MBEDTLS) - mbedtls_sha1_free(&sha1); -#endif } static void print_hash(const unsigned char *hash, int len) @@ -239,7 +176,13 @@ static plist_t mobilebackup_factory_info_plist_new(const char* udid) if (value_node) plist_dict_set_item(ret, "IMEI", plist_copy(value_node)); - plist_dict_set_item(ret, "Last Backup Date", plist_new_date(time(NULL) - MAC_EPOCH, 0)); + plist_dict_set_item(ret, "Last Backup Date", +#ifdef HAVE_PLIST_UNIX_DATE + plist_new_unix_date(time(NULL)) +#else + plist_new_date(time(NULL) - MAC_EPOCH, 0) +#endif + ); value_node = plist_dict_get_item(root_node, "ProductType"); plist_dict_set_item(ret, "Product Type", plist_copy(value_node)); @@ -276,7 +219,11 @@ static void mobilebackup_info_update_last_backup_date(plist_t info_plist) return; node = plist_dict_get_item(info_plist, "Last Backup Date"); +#ifdef HAVE_PLIST_UNIX_DATE + plist_set_unix_date_val(node, time(NULL)); +#else plist_set_date_val(node, time(NULL) - MAC_EPOCH, 0); +#endif node = NULL; } @@ -317,7 +264,7 @@ static void mobilebackup_write_status(const char *path, int status) if (stat(file_path, &st) == 0) remove(file_path); - plist_write_to_filename(status_plist, file_path, PLIST_FORMAT_XML); + plist_write_to_file(status_plist, file_path, PLIST_FORMAT_XML, 0); plist_free(status_plist); status_plist = NULL; @@ -331,7 +278,7 @@ static int mobilebackup_read_status(const char *path) plist_t status_plist = NULL; char *file_path = mobilebackup_build_path(path, "Status", ".plist"); - plist_read_from_filename(&status_plist, file_path); + plist_read_from_file(file_path, &status_plist, NULL); free(file_path); if (!status_plist) { printf("Could not read Status.plist!\n"); @@ -454,7 +401,7 @@ static int mobilebackup_check_file_integrity(const char *backup_directory, const } infopath = mobilebackup_build_path(backup_directory, hash, ".mdinfo"); - plist_read_from_filename(&mdinfo, infopath); + plist_read_from_file(infopath, &mdinfo, NULL); free(infopath); if (!mdinfo) { printf("\r\n"); @@ -528,7 +475,7 @@ static int mobilebackup_check_file_integrity(const char *backup_directory, const unsigned char fnhash[20]; char fnamehash[41]; char *p = fnamehash; - sha1_of_data(fnstr, strlen(fnstr), fnhash); + sha1((const unsigned char*)fnstr, strlen(fnstr), fnhash); free(fnstr); int i; for ( i = 0; i < 20; i++, p += 2 ) { @@ -706,7 +653,7 @@ int main(int argc, char *argv[]) /* we need to exit cleanly on running backups and restores or we cause havok */ signal(SIGINT, clean_exit); signal(SIGTERM, clean_exit); -#ifndef WIN32 +#ifndef _WIN32 signal(SIGQUIT, clean_exit); signal(SIGPIPE, SIG_IGN); #endif @@ -882,7 +829,7 @@ int main(int argc, char *argv[]) /* verify existing Info.plist */ if (stat(info_path, &st) == 0) { printf("Reading Info.plist from backup.\n"); - plist_read_from_filename(&info_plist, info_path); + plist_read_from_file(info_path, &info_plist, NULL); if (!info_plist) { printf("Could not read Info.plist\n"); @@ -893,7 +840,7 @@ int main(int argc, char *argv[]) /* update the last backup time within Info.plist */ mobilebackup_info_update_last_backup_date(info_plist); remove(info_path); - plist_write_to_filename(info_plist, info_path, PLIST_FORMAT_XML); + plist_write_to_file(info_plist, info_path, PLIST_FORMAT_XML, 0); } else { printf("Aborting backup. Backup is not compatible with the current device.\n"); cmd = CMD_LEAVE; @@ -959,7 +906,7 @@ int main(int argc, char *argv[]) /* read the last Manifest.plist */ if (!is_full_backup) { printf("Reading existing Manifest.\n"); - plist_read_from_filename(&manifest_plist, manifest_path); + plist_read_from_file(manifest_path, &manifest_plist, NULL); if (!manifest_plist) { printf("Could not read Manifest.plist, switching to full backup mode.\n"); is_full_backup = 1; @@ -977,7 +924,7 @@ int main(int argc, char *argv[]) remove(info_path); printf("Creating Info.plist for new backup.\n"); info_plist = mobilebackup_factory_info_plist_new(udid); - plist_write_to_filename(info_plist, info_path, PLIST_FORMAT_XML); + plist_write_to_file(info_plist, info_path, PLIST_FORMAT_XML, 0); } free(info_path); @@ -1116,7 +1063,7 @@ int main(int argc, char *argv[]) remove(filename_mdinfo); node = plist_dict_get_item(node_tmp, "BackupFileInfo"); - plist_write_to_filename(node, filename_mdinfo, PLIST_FORMAT_BINARY); + plist_write_to_file(node, filename_mdinfo, PLIST_FORMAT_BINARY, 0); free(filename_mdinfo); } @@ -1228,7 +1175,7 @@ files_out: if (manifest_plist) { remove(manifest_path); printf("Storing Manifest.plist...\n"); - plist_write_to_filename(manifest_plist, manifest_path, PLIST_FORMAT_XML); + plist_write_to_file(manifest_plist, manifest_path, PLIST_FORMAT_XML, 0); } backup_ok = 1; @@ -1259,21 +1206,21 @@ files_out: } /* now make sure backup integrity is ok! verify all files */ printf("Reading existing Manifest.\n"); - plist_read_from_filename(&manifest_plist, manifest_path); + plist_read_from_file(manifest_path, &manifest_plist, NULL); if (!manifest_plist) { printf("Could not read Manifest.plist. Aborting.\n"); break; } printf("Verifying backup integrity, please wait.\n"); - char *bin = NULL; + unsigned char *bin = NULL; uint64_t binsize = 0; node = plist_dict_get_item(manifest_plist, "Data"); if (!node || (plist_get_node_type(node) != PLIST_DATA)) { printf("Could not read Data key from Manifest.plist!\n"); break; } - plist_get_data_val(node, &bin, &binsize); + plist_get_data_val(node, (char**)&bin, &binsize); plist_t backup_data = NULL; if (bin) { char *auth_ver = NULL; @@ -1290,7 +1237,7 @@ files_out: if (auth_sig && (auth_sig_len == 20)) { /* calculate the sha1, then compare */ unsigned char data_sha1[20]; - sha1_of_data(bin, binsize, data_sha1); + sha1(bin, binsize, data_sha1); if (compare_hash(auth_sig, data_sha1, 20)) { printf("AuthSignature is valid\n"); } else { @@ -1303,7 +1250,7 @@ files_out: } else if (auth_ver) { printf("Unknown AuthVersion '%s', cannot verify AuthSignature\n", auth_ver); } - plist_from_bin(bin, (uint32_t)binsize, &backup_data); + plist_from_bin((char*)bin, (uint32_t)binsize, &backup_data); free(bin); } if (!backup_data) { @@ -1386,7 +1333,7 @@ files_out: while (node) { /* TODO: read mddata/mdinfo files and send to device using DLSendFile */ file_info_path = mobilebackup_build_path(backup_directory, hash, ".mdinfo"); - plist_read_from_filename(&file_info, file_info_path); + plist_read_from_file(file_info_path, &file_info, NULL); /* get encryption state */ tmp_node = plist_dict_get_item(file_info, "IsEncrypted"); @@ -1416,7 +1363,7 @@ files_out: file_info_path = mobilebackup_build_path(backup_directory, hash, ".mddata"); /* determine file size */ -#ifdef WIN32 +#ifdef _WIN32 struct _stati64 fst; if (_stati64(file_info_path, &fst) != 0) #else diff --git a/tools/idevicebackup2.c b/tools/idevicebackup2.c index be7a132..12d6083 100644 --- a/tools/idevicebackup2.c +++ b/tools/idevicebackup2.c @@ -47,13 +47,14 @@ #include <libimobiledevice/sbservices.h> #include <libimobiledevice/diagnostics_relay.h> #include <libimobiledevice-glue/utils.h> +#include <plist/plist.h> #include <endianness.h> #define LOCK_ATTEMPTS 50 #define LOCK_WAIT 200000 -#ifdef WIN32 +#ifdef _WIN32 #include <windows.h> #include <conio.h> #define sleep(x) Sleep(x*1000) @@ -73,6 +74,7 @@ static int verbose = 1; static int quit_flag = 0; +static int passcode_requested = 0; #define PRINT_VERBOSE(min_level, ...) if (verbose >= min_level) { printf(__VA_ARGS__); }; @@ -114,6 +116,10 @@ static void notify_cb(const char *notification, void *userdata) quit_flag++; } else if (!strcmp(notification, NP_BACKUP_DOMAIN_CHANGED)) { backup_domain_changed = 1; + } else if (!strcmp(notification, "com.apple.LocalAuthentication.ui.presented")) { + passcode_requested = 1; + } else if (!strcmp(notification, "com.apple.LocalAuthentication.ui.dismissed")) { + passcode_requested = 0; } else { PRINT_VERBOSE(1, "Unhandled notification '%s' (TODO: implement)\n", notification); } @@ -125,21 +131,15 @@ static void mobilebackup_afc_get_file_contents(afc_client_t afc, const char *fil return; } - char **fileinfo = NULL; + plist_t fileinfo = NULL; uint32_t fsize = 0; - afc_get_file_info(afc, filename, &fileinfo); + afc_get_file_info_plist(afc, filename, &fileinfo); if (!fileinfo) { return; } - int i; - for (i = 0; fileinfo[i]; i+=2) { - if (!strcmp(fileinfo[i], "st_size")) { - fsize = atol(fileinfo[i+1]); - break; - } - } - afc_dictionary_free(fileinfo); + fsize = plist_dict_get_uint(fileinfo, "st_size"); + plist_free(fileinfo); if (fsize == 0) { return; @@ -172,7 +172,7 @@ static void mobilebackup_afc_get_file_contents(afc_client_t afc, const char *fil static int __mkdir(const char* path, int mode) { -#ifdef WIN32 +#ifdef _WIN32 return mkdir(path); #else return mkdir(path, mode); @@ -201,7 +201,7 @@ static int mkdir_with_parents(const char *dir, int mode) return res; } -#ifdef WIN32 +#ifdef _WIN32 static int win32err_to_errno(int err_value) { switch (err_value) { @@ -218,7 +218,7 @@ static int win32err_to_errno(int err_value) static int remove_file(const char* path) { int e = 0; -#ifdef WIN32 +#ifdef _WIN32 if (!DeleteFile(path)) { e = win32err_to_errno(GetLastError()); } @@ -233,7 +233,7 @@ static int remove_file(const char* path) static int remove_directory(const char* path) { int e = 0; -#ifdef WIN32 +#ifdef _WIN32 if (!RemoveDirectory(path)) { e = win32err_to_errno(GetLastError()); } @@ -454,7 +454,13 @@ static plist_t mobilebackup_factory_info_plist_new(const char* udid, idevice_t d /* Installed Applications */ plist_dict_set_item(ret, "Installed Applications", installed_apps); - plist_dict_set_item(ret, "Last Backup Date", plist_new_date(time(NULL) - MAC_EPOCH, 0)); + plist_dict_set_item(ret, "Last Backup Date", +#ifdef HAVE_PLIST_UNIX_DATE + plist_new_unix_date(time(NULL)) +#else + plist_new_date(time(NULL) - MAC_EPOCH, 0) +#endif + ); value_node = plist_dict_get_item(root_node, "MobileEquipmentIdentifier"); if (value_node) @@ -606,7 +612,7 @@ static int mb2_status_check_snapshot_state(const char *path, const char *udid, c plist_t status_plist = NULL; char *file_path = string_build_path(path, udid, "Status.plist", NULL); - plist_read_from_filename(&status_plist, file_path); + plist_read_from_file(file_path, &status_plist, NULL); free(file_path); if (!status_plist) { printf("Could not read Status.plist!\n"); @@ -767,7 +773,7 @@ static int mb2_handle_send_file(mobilebackup2_client_t mobilebackup2, const char uint32_t bytes = 0; char *localfile = string_build_path(backup_dir, path, NULL); char buf[32768]; -#ifdef WIN32 +#ifdef _WIN32 struct _stati64 fst; #else struct stat fst; @@ -778,7 +784,7 @@ static int mb2_handle_send_file(mobilebackup2_client_t mobilebackup2, const char int errcode = -1; int result = -1; uint32_t length; -#ifdef WIN32 +#ifdef _WIN32 uint64_t total; uint64_t sent; #else @@ -809,7 +815,7 @@ static int mb2_handle_send_file(mobilebackup2_client_t mobilebackup2, const char goto leave_proto_err; } -#ifdef WIN32 +#ifdef _WIN32 if (_stati64(localfile, &fst) < 0) #else if (stat(localfile, &fst) < 0) @@ -1217,7 +1223,12 @@ static void mb2_handle_list_directory(mobilebackup2_client_t mobilebackup2, plis plist_dict_set_item(fdict, "DLFileType", plist_new_string(ftype)); plist_dict_set_item(fdict, "DLFileSize", plist_new_uint(st.st_size)); plist_dict_set_item(fdict, "DLFileModificationDate", - plist_new_date(st.st_mtime - MAC_EPOCH, 0)); +#ifdef HAVE_PLIST_UNIX_DATE + plist_new_unix_date(st.st_mtime) +#else + plist_new_date(st.st_mtime - MAC_EPOCH, 0) +#endif + ); plist_dict_set_item(dirlist, ep->d_name, fdict); free(fpath); @@ -1342,7 +1353,7 @@ static void mb2_copy_directory_by_path(const char *src, const char *dst) } } -#ifdef WIN32 +#ifdef _WIN32 #define BS_CC '\b' #define my_getch getch #else @@ -1462,8 +1473,6 @@ static void print_usage(int argc, char **argv, int is_error) ); } -#define DEVICE_VERSION(maj, min, patch) ((((maj) & 0xFF) << 16) | (((min) & 0xFF) << 8) | ((patch) & 0xFF)) - int main(int argc, char *argv[]) { idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR; @@ -1521,7 +1530,7 @@ int main(int argc, char *argv[]) { "settings", no_argument, NULL, OPT_SETTINGS }, { "remove", no_argument, NULL, OPT_REMOVE }, { "skip-apps", no_argument, NULL, OPT_SKIP_APPS }, - { "password", no_argument, NULL, OPT_PASSWORD }, + { "password", required_argument, NULL, OPT_PASSWORD }, { "full", no_argument, NULL, OPT_FULL }, { NULL, 0, NULL, 0} }; @@ -1529,7 +1538,7 @@ int main(int argc, char *argv[]) /* we need to exit cleanly on running backups and restores or we cause havok */ signal(SIGINT, clean_exit); signal(SIGTERM, clean_exit); -#ifndef WIN32 +#ifndef _WIN32 signal(SIGQUIT, clean_exit); signal(SIGPIPE, SIG_IGN); #endif @@ -1555,6 +1564,7 @@ int main(int argc, char *argv[]) return 2; } source_udid = strdup(optarg); + break; case 'i': interactive_mode = 1; break; @@ -1779,7 +1789,7 @@ int main(int argc, char *argv[]) free(info_path); } plist_t manifest_plist = NULL; - plist_read_from_filename(&manifest_plist, manifest_path); + plist_read_from_file(manifest_path, &manifest_plist, NULL); if (!manifest_plist) { idevice_free(device); free(info_path); @@ -1842,34 +1852,20 @@ int main(int argc, char *argv[]) } /* get ProductVersion */ - char *product_version = NULL; - int device_version = 0; - node_tmp = NULL; - lockdownd_get_value(lockdown, NULL, "ProductVersion", &node_tmp); - if (node_tmp) { - if (plist_get_node_type(node_tmp) == PLIST_STRING) { - plist_get_string_val(node_tmp, &product_version); - } - plist_free(node_tmp); - node_tmp = NULL; - } - if (product_version) { - int vers[3] = { 0, 0, 0 }; - if (sscanf(product_version, "%d.%d.%d", &vers[0], &vers[1], &vers[2]) >= 2) { - device_version = DEVICE_VERSION(vers[0], vers[1], vers[2]); - } - } + int device_version = idevice_get_device_version(device); /* start notification_proxy */ ldret = lockdownd_start_service(lockdown, NP_SERVICE_NAME, &service); if ((ldret == LOCKDOWN_E_SUCCESS) && service && service->port) { np_client_new(device, service, &np); np_set_notify_callback(np, notify_cb, NULL); - const char *noties[5] = { + const char *noties[7] = { NP_SYNC_CANCEL_REQUEST, NP_SYNC_SUSPEND_REQUEST, NP_SYNC_RESUME_REQUEST, NP_BACKUP_DOMAIN_CHANGED, + "com.apple.LocalAuthentication.ui.presented", + "com.apple.LocalAuthentication.ui.dismissed", NULL }; np_observe_notifications(np, noties); @@ -1935,7 +1931,7 @@ int main(int argc, char *argv[]) /* verify existing Info.plist */ if (info_path && (stat(info_path, &st) == 0) && cmd != CMD_CLOUD) { PRINT_VERBOSE(1, "Reading Info.plist from backup.\n"); - plist_read_from_filename(&info_plist, info_path); + plist_read_from_file(info_path, &info_plist, NULL); if (!info_plist) { printf("Could not read Info.plist\n"); @@ -2029,7 +2025,7 @@ checkpoint: cmd = CMD_LEAVE; } remove_file(info_path); - plist_write_to_filename(info_plist, info_path, PLIST_FORMAT_XML); + plist_write_to_file(info_plist, info_path, PLIST_FORMAT_XML, 0); free(info_path); plist_free(info_plist); @@ -2056,6 +2052,16 @@ checkpoint: } else { PRINT_VERBOSE(1, "Incremental backup mode.\n"); } + if (device_version >= IDEVICE_DEVICE_VERSION(16,1,0)) { + /* let's wait 2 second to see if the device passcode is requested */ + int retries = 20; + while (retries-- > 0 && !passcode_requested) { + usleep(100000); + } + if (passcode_requested) { + printf("*** Waiting for passcode to be entered on the device ***\n"); + } + } } else { if (err == MOBILEBACKUP2_E_BAD_VERSION) { printf("ERROR: Could not start backup process: backup protocol version mismatch!\n"); @@ -2227,7 +2233,7 @@ checkpoint: if (newpw || backup_password) { mobilebackup2_send_message(mobilebackup2, "ChangePassword", opts); uint8_t passcode_hint = 0; - if (device_version >= DEVICE_VERSION(13,0,0)) { + if (device_version >= IDEVICE_DEVICE_VERSION(13,0,0)) { diagnostics_relay_client_t diag = NULL; if (diagnostics_relay_client_start_service(device, &diag, TOOL_NAME) == DIAGNOSTICS_RELAY_E_SUCCESS) { plist_t dict = NULL; @@ -2305,7 +2311,7 @@ checkpoint: /* device wants to know how much disk space is available on the computer */ uint64_t freespace = 0; int res = -1; -#ifdef WIN32 +#ifdef _WIN32 if (GetDiskFreeSpaceEx(backup_directory, (PULARGE_INTEGER)&freespace, NULL, NULL)) { res = 0; } @@ -2314,7 +2320,7 @@ checkpoint: memset(&fs, '\0', sizeof(fs)); res = statvfs(backup_directory, &fs); if (res == 0) { - freespace = (uint64_t)fs.f_bavail * (uint64_t)fs.f_bsize; + freespace = (uint64_t)fs.f_bavail * (uint64_t)fs.f_frsize; } #endif plist_t freespace_item = plist_new_uint(freespace); diff --git a/tools/idevicebtlogger.c b/tools/idevicebtlogger.c index 8de6b22..ca68b59 100644 --- a/tools/idevicebtlogger.c +++ b/tools/idevicebtlogger.c @@ -36,7 +36,7 @@ #include <assert.h> #include <fcntl.h> -#ifdef WIN32 +#ifdef _WIN32 #include <windows.h> #define sleep(x) Sleep(x*1000) #else @@ -334,7 +334,7 @@ int main(int argc, char *argv[]) signal(SIGINT, clean_exit); signal(SIGTERM, clean_exit); -#ifndef WIN32 +#ifndef _WIN32 signal(SIGQUIT, clean_exit); signal(SIGPIPE, SIG_IGN); #endif diff --git a/tools/idevicecrashreport.c b/tools/idevicecrashreport.c index d0d2147..b9869ae 100644 --- a/tools/idevicecrashreport.c +++ b/tools/idevicecrashreport.c @@ -31,7 +31,8 @@ #include <string.h> #include <unistd.h> #include <getopt.h> -#ifndef WIN32 +#include <sys/stat.h> +#ifndef _WIN32 #include <signal.h> #endif #include <libimobiledevice-glue/utils.h> @@ -42,7 +43,7 @@ #include <libimobiledevice/afc.h> #include <plist/plist.h> -#ifdef WIN32 +#ifdef _WIN32 #include <windows.h> #define S_IFLNK S_IFREG #define S_IFSOCK S_IFREG @@ -54,11 +55,12 @@ const char* target_directory = NULL; static int extract_raw_crash_reports = 0; static int keep_crash_reports = 0; +static int remove_all = 0; static int file_exists(const char* path) { struct stat tst; -#ifdef WIN32 +#ifdef _WIN32 return (stat(path, &tst) == 0); #else return (lstat(path, &tst) == 0); @@ -81,7 +83,7 @@ static int extract_raw_crash_report(const char* filename) strcpy(p, ".crash"); /* read plist crash report */ - if (plist_read_from_filename(&report, filename)) { + if (plist_read_from_file(filename, &report, NULL)) { plist_t description_node = plist_dict_get_item(report, "description"); if (description_node && plist_get_node_type(description_node) == PLIST_STRING) { plist_get_string_val(description_node, &raw); @@ -144,7 +146,7 @@ static int afc_client_copy_and_remove_crash_reports(afc_client_t afc, const char continue; } - char **fileinfo = NULL; + plist_t fileinfo = NULL; struct stat stbuf; memset(&stbuf, '\0', sizeof(struct stat)); @@ -152,7 +154,7 @@ static int afc_client_copy_and_remove_crash_reports(afc_client_t afc, const char strcpy(((char*)source_filename) + device_directory_length, list[k]); /* assemble absolute target filename */ -#ifdef WIN32 +#ifdef _WIN32 /* replace every ':' with '-' since ':' is an illegal character for file names in windows */ char* current_pos = strchr(list[k], ':'); while (current_pos) { @@ -163,7 +165,7 @@ static int afc_client_copy_and_remove_crash_reports(afc_client_t afc, const char char* p = strrchr(list[k], '.'); if (p != NULL && !strncmp(p, ".synced", 7)) { /* make sure to strip ".synced" extension as seen on iOS 5 */ - int newlen = strlen(list[k]) - 7; + size_t newlen = p - list[k]; strncpy(((char*)target_filename) + host_directory_length, list[k], newlen); target_filename[host_directory_length + newlen] = '\0'; } else { @@ -171,88 +173,93 @@ static int afc_client_copy_and_remove_crash_reports(afc_client_t afc, const char } /* get file information */ - afc_get_file_info(afc, source_filename, &fileinfo); + afc_get_file_info_plist(afc, source_filename, &fileinfo); if (!fileinfo) { printf("Failed to read information for '%s'. Skipping...\n", source_filename); continue; } /* parse file information */ - int i; - for (i = 0; fileinfo[i]; i+=2) { - if (!strcmp(fileinfo[i], "st_size")) { - stbuf.st_size = atoll(fileinfo[i+1]); - } else if (!strcmp(fileinfo[i], "st_ifmt")) { - if (!strcmp(fileinfo[i+1], "S_IFREG")) { - stbuf.st_mode = S_IFREG; - } else if (!strcmp(fileinfo[i+1], "S_IFDIR")) { - stbuf.st_mode = S_IFDIR; - } else if (!strcmp(fileinfo[i+1], "S_IFLNK")) { - stbuf.st_mode = S_IFLNK; - } else if (!strcmp(fileinfo[i+1], "S_IFBLK")) { - stbuf.st_mode = S_IFBLK; - } else if (!strcmp(fileinfo[i+1], "S_IFCHR")) { - stbuf.st_mode = S_IFCHR; - } else if (!strcmp(fileinfo[i+1], "S_IFIFO")) { - stbuf.st_mode = S_IFIFO; - } else if (!strcmp(fileinfo[i+1], "S_IFSOCK")) { - stbuf.st_mode = S_IFSOCK; - } - } else if (!strcmp(fileinfo[i], "st_nlink")) { - stbuf.st_nlink = atoi(fileinfo[i+1]); - } else if (!strcmp(fileinfo[i], "st_mtime")) { - stbuf.st_mtime = (time_t)(atoll(fileinfo[i+1]) / 1000000000); - } else if (!strcmp(fileinfo[i], "LinkTarget")) { - /* report latest crash report filename */ - printf("Link: %s\n", (char*)target_filename + strlen(target_directory)); - - /* remove any previous symlink */ - if (file_exists(target_filename)) { - remove(target_filename); - } + stbuf.st_size = plist_dict_get_uint(fileinfo, "st_size"); + const char* s_ifmt = plist_get_string_ptr(plist_dict_get_item(fileinfo, "st_ifmt"), NULL); + if (s_ifmt) { + if (!strcmp(s_ifmt, "S_IFREG")) { + stbuf.st_mode = S_IFREG; + } else if (!strcmp(s_ifmt, "S_IFDIR")) { + stbuf.st_mode = S_IFDIR; + } else if (!strcmp(s_ifmt, "S_IFLNK")) { + stbuf.st_mode = S_IFLNK; + } else if (!strcmp(s_ifmt, "S_IFBLK")) { + stbuf.st_mode = S_IFBLK; + } else if (!strcmp(s_ifmt, "S_IFCHR")) { + stbuf.st_mode = S_IFCHR; + } else if (!strcmp(s_ifmt, "S_IFIFO")) { + stbuf.st_mode = S_IFIFO; + } else if (!strcmp(s_ifmt, "S_IFSOCK")) { + stbuf.st_mode = S_IFSOCK; + } + } + stbuf.st_nlink = plist_dict_get_uint(fileinfo, "st_nlink"); + stbuf.st_mtime = (time_t)(plist_dict_get_uint(fileinfo, "st_mtime") / 1000000000); + const char* linktarget = plist_get_string_ptr(plist_dict_get_item(fileinfo, "LinkTarget"), NULL); + if (linktarget && !remove_all) { + /* report latest crash report filename */ + printf("Link: %s\n", (char*)target_filename + strlen(target_directory)); + + /* remove any previous symlink */ + if (file_exists(target_filename)) { + remove(target_filename); + } -#ifndef WIN32 - /* use relative filename */ - char* b = strrchr(fileinfo[i+1], '/'); - if (b == NULL) { - b = fileinfo[i+1]; +#ifndef _WIN32 + /* use relative filename */ + const char* b = strrchr(linktarget, '/'); + if (b == NULL) { + b = linktarget; } else { - b++; - } + b++; + } - /* create a symlink pointing to latest log */ - if (symlink(b, target_filename) < 0) { - fprintf(stderr, "Can't create symlink to %s\n", b); - } + /* create a symlink pointing to latest log */ + if (symlink(b, target_filename) < 0) { + fprintf(stderr, "Can't create symlink to %s\n", b); + } #endif - if (!keep_crash_reports) - afc_remove_path(afc, source_filename); + if (!keep_crash_reports) + afc_remove_path(afc, source_filename); - res = 0; - } + res = 0; } /* free file information */ - afc_dictionary_free(fileinfo); + plist_free(fileinfo); /* recurse into child directories */ if (S_ISDIR(stbuf.st_mode)) { -#ifdef WIN32 - mkdir(target_filename); + if (!remove_all) { +#ifdef _WIN32 + mkdir(target_filename); #else - mkdir(target_filename, 0755); + mkdir(target_filename, 0755); #endif + } res = afc_client_copy_and_remove_crash_reports(afc, source_filename, target_filename, filename_filter); /* remove directory from device */ - if (!keep_crash_reports) + if (!remove_all && !keep_crash_reports) afc_remove_path(afc, source_filename); } else if (S_ISREG(stbuf.st_mode)) { if (filename_filter != NULL && strstr(source_filename, filename_filter) == NULL) { continue; } + if (remove_all) { + printf("Remove: %s\n", source_filename); + afc_remove_path(afc, source_filename); + continue; + } + /* copy file to host */ afc_error = afc_file_open(afc, source_filename, AFC_FOPEN_RDONLY, &handle); if(afc_error != AFC_E_SUCCESS) { @@ -331,6 +338,7 @@ static void print_usage(int argc, char **argv, int is_error) " -f, --filter NAME filter crash reports by NAME (case sensitive)\n" " -h, --help prints usage information\n" " -v, --version prints version information\n" + " --remove-all remove all crash logs found\n" "\n" "Homepage: <" PACKAGE_URL ">\n" "Bug Reports: <" PACKAGE_BUGREPORT ">\n" @@ -361,10 +369,11 @@ int main(int argc, char* argv[]) { "filter", required_argument, NULL, 'f' }, { "extract", no_argument, NULL, 'e' }, { "keep", no_argument, NULL, 'k' }, + { "remove-all", no_argument, NULL, 1 }, { NULL, 0, NULL, 0} }; -#ifndef WIN32 +#ifndef _WIN32 signal(SIGPIPE, SIG_IGN); #endif @@ -405,6 +414,9 @@ int main(int argc, char* argv[]) case 'k': keep_crash_reports = 1; break; + case 1: + remove_all = 1; + break; default: print_usage(argc, argv, 1); return 2; @@ -414,12 +426,16 @@ int main(int argc, char* argv[]) argv += optind; /* ensure a target directory was supplied */ - if (!argv[0]) { - fprintf(stderr, "ERROR: missing target directory.\n"); - print_usage(argc+optind, argv-optind, 1); - return 2; + if (!remove_all) { + if (!argv[0]) { + fprintf(stderr, "ERROR: missing target directory.\n"); + print_usage(argc+optind, argv-optind, 1); + return 2; + } + target_directory = argv[0]; + } else { + target_directory = "."; } - target_directory = argv[0]; /* check if target directory exists */ if (!file_exists(target_directory)) { diff --git a/tools/idevicedate.c b/tools/idevicedate.c index d05f63e..31b0cf7 100644 --- a/tools/idevicedate.c +++ b/tools/idevicedate.c @@ -33,7 +33,7 @@ #if HAVE_LANGINFO_CODESET #include <langinfo.h> #endif -#ifndef WIN32 +#ifndef _WIN32 #include <signal.h> #endif @@ -43,7 +43,7 @@ #ifdef _DATE_FMT #define DATE_FMT_LANGINFO nl_langinfo (_DATE_FMT) #else -#ifdef WIN32 +#ifdef _WIN32 #define DATE_FMT_LANGINFO "%a %b %#d %H:%M:%S %Z %Y" #else #define DATE_FMT_LANGINFO "%a %b %e %H:%M:%S %Z %Y" @@ -104,7 +104,7 @@ int main(int argc, char *argv[]) { NULL, 0, NULL, 0} }; -#ifndef WIN32 +#ifndef _WIN32 signal(SIGPIPE, SIG_IGN); #endif /* parse cmdline args */ diff --git a/tools/idevicedebug.c b/tools/idevicedebug.c index fbb6c3e..3f2e289 100644 --- a/tools/idevicedebug.c +++ b/tools/idevicedebug.c @@ -34,7 +34,7 @@ #include <libgen.h> #include <getopt.h> -#ifdef WIN32 +#ifdef _WIN32 #include <windows.h> #define sleep(x) Sleep(x*1000) #endif @@ -239,7 +239,7 @@ int main(int argc, char *argv[]) /* map signals */ signal(SIGINT, on_signal); signal(SIGTERM, on_signal); -#ifndef WIN32 +#ifndef _WIN32 signal(SIGQUIT, on_signal); signal(SIGPIPE, SIG_IGN); #endif @@ -291,6 +291,11 @@ int main(int argc, char *argv[]) res = 0; goto cleanup; break; + default: + print_usage(argc, argv, 1); + res = 2; + goto cleanup; + break; } } argc -= optind; diff --git a/tools/idevicedebugserverproxy.c b/tools/idevicedebugserverproxy.c index 8a3b4ff..fb082b3 100644 --- a/tools/idevicedebugserverproxy.c +++ b/tools/idevicedebugserverproxy.c @@ -32,7 +32,7 @@ #include <getopt.h> #include <errno.h> #include <signal.h> -#ifdef WIN32 +#ifdef _WIN32 #include <winsock2.h> #include <windows.h> #else @@ -52,8 +52,10 @@ #define info(...) fprintf(stdout, __VA_ARGS__); fflush(stdout) #define debug(...) if(debug_mode) fprintf(stdout, __VA_ARGS__) +static int support_lldb = 0; static int debug_mode = 0; static int quit_flag = 0; +static uint16_t local_port = 0; typedef struct { int client_fd; @@ -90,6 +92,7 @@ static void print_usage(int argc, char **argv, int is_error) " -u, --udid UDID target specific device by UDID\n" " -n, --network connect to network device\n" " -d, --debug enable communication debugging\n" + " -l, --lldb enable lldb support\n" " -h, --help prints usage information\n" " -v, --version prints version information\n" "\n" @@ -98,6 +101,26 @@ static void print_usage(int argc, char **argv, int is_error) ); } +static int intercept_packet(char *packet, ssize_t *packet_len) { + static const char kReqLaunchServer[] = "$qLaunchGDBServer;#4b"; + + char buffer[64] = {0}; + if (*packet_len == (ssize_t)(sizeof(kReqLaunchServer) - 1) + && memcmp(packet, kReqLaunchServer, sizeof(kReqLaunchServer) - 1) == 0) { + sprintf(buffer, "port:%d;", local_port); + } else { + return 0; + } + int sum = 0; + for (size_t i = 0; i < strlen(buffer); i++) { + sum += buffer[i]; + } + sum = sum & 255; + sprintf(packet, "$%s#%02x", buffer, sum); + *packet_len = strlen(packet); + return 1; +} + static void* connection_handler(void* data) { debugserver_error_t derr = DEBUGSERVER_E_SUCCESS; @@ -137,7 +160,10 @@ static void* connection_handler(void* data) fprintf(stderr, "connection closed\n"); break; } - + if (support_lldb && intercept_packet(buf, &n)) { + socket_send(client_fd, buf, n); + continue; + } uint32_t sent = 0; debugserver_client_send(socket_info->debugserver_client, buf, n, &sent); } @@ -180,7 +206,6 @@ int main(int argc, char *argv[]) thread_info_t *thread_list = NULL; const char* udid = NULL; int use_network = 0; - uint16_t local_port = 0; int server_fd; int result = EXIT_SUCCESS; int c = 0; @@ -189,11 +214,12 @@ int main(int argc, char *argv[]) { "help", no_argument, NULL, 'h' }, { "udid", required_argument, NULL, 'u' }, { "network", no_argument, NULL, 'n' }, + { "lldb", no_argument, NULL, 'l' }, { "version", no_argument, NULL, 'v' }, { NULL, 0, NULL, 0} }; -#ifndef WIN32 +#ifndef _WIN32 struct sigaction sa; struct sigaction si; memset(&sa, '\0', sizeof(struct sigaction)); @@ -234,6 +260,9 @@ int main(int argc, char *argv[]) case 'n': use_network = 1; break; + case 'l': + support_lldb = 1; + break; case 'h': print_usage(argc, argv, 0); return 0; diff --git a/tools/idevicedevmodectl.c b/tools/idevicedevmodectl.c new file mode 100644 index 0000000..6bf1a1c --- /dev/null +++ b/tools/idevicedevmodectl.c @@ -0,0 +1,462 @@ +/* + * idevicedevmodectl.c + * List or enable Developer Mode on iOS 16+ devices + * + * Copyright (c) 2022 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 + +#define TOOL_NAME "idevicedevmodectl" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> +#ifndef _WIN32 +#include <signal.h> +#endif + +#ifdef _WIN32 +#include <windows.h> +#define __usleep(x) Sleep(x/1000) +#else +#include <arpa/inet.h> +#include <unistd.h> +#define __usleep(x) usleep(x) +#endif + +#include <libimobiledevice/libimobiledevice.h> +#include <libimobiledevice/lockdown.h> +#include <libimobiledevice/property_list_service.h> +#include <libimobiledevice-glue/utils.h> + +#define AMFI_LOCKDOWN_SERVICE_NAME "com.apple.amfi.lockdown" + +static char* udid = NULL; +static int use_network = 0; + +static void print_usage(int argc, char **argv, int is_error) +{ + char *name = strrchr(argv[0], '/'); + fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS] COMMAND\n", (name ? name + 1: argv[0])); + fprintf(is_error ? stderr : stdout, + "\n" + "Enable Developer Mode on iOS 16+ devices or print the current status.\n" + "\n" + "Where COMMAND is one of:\n" + " list Print the Developer Mode status of all connected devices\n" + " or for a specific one if --udid is given.\n" + " enable Enable Developer Mode (device will reboot),\n" + " and confirm it after device booted up again.\n" + "\n" + " arm Arm the Developer Mode (device will reboot)\n" + " confirm Confirm enabling of Developer Mode\n" + " reveal Reveal the Developer Mode menu on the device\n" + "\n" + "The following OPTIONS are accepted:\n" + " -u, --udid UDID target specific device by UDID\n" + " -n, --network connect to network device\n" + " -d, --debug enable communication debugging\n" + " -h, --help print usage information\n" + " -v, --version print version information\n" + "\n" + "Homepage: <" PACKAGE_URL ">\n" + "Bug Reports: <" PACKAGE_BUGREPORT ">\n" + ); +} + +enum { + OP_LIST, + OP_ENABLE, + OP_ARM, + OP_CONFIRM, + OP_REVEAL, + NUM_OPS +}; +#define DEV_MODE_REVEAL 0 +#define DEV_MODE_ARM 1 +#define DEV_MODE_ENABLE 2 + +static int get_developer_mode_status(const char* device_udid, int _use_network) +{ + idevice_error_t ret; + idevice_t device = NULL; + lockdownd_client_t lockdown = NULL; + lockdownd_error_t lerr = LOCKDOWN_E_UNKNOWN_ERROR; + plist_t val = NULL; + + ret = idevice_new_with_options(&device, device_udid, (_use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX); + if (ret != IDEVICE_E_SUCCESS) { + return -1; + } + + if (LOCKDOWN_E_SUCCESS != (lerr = lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME))) { + idevice_free(device); + return -1; + } + + lerr = lockdownd_get_value(lockdown, "com.apple.security.mac.amfi", "DeveloperModeStatus", &val); + if (lerr != LOCKDOWN_E_SUCCESS) { + fprintf(stderr, "ERROR: Could not get DeveloperModeStatus: %s\nPlease note that this feature is only available on iOS 16+.\n", lockdownd_strerror(lerr)); + lockdownd_client_free(lockdown); + idevice_free(device); + return -2; + } + + uint8_t dev_mode_status = 0; + plist_get_bool_val(val, &dev_mode_status); + plist_free(val); + + lockdownd_client_free(lockdown); + idevice_free(device); + + return dev_mode_status; +} + +static int amfi_service_send_msg(property_list_service_client_t amfi, plist_t msg) +{ + int res; + property_list_service_error_t perr; + + perr = property_list_service_send_xml_plist(amfi, plist_copy(msg)); + if (perr != PROPERTY_LIST_SERVICE_E_SUCCESS) { + fprintf(stderr, "Could not send request to device: %d\n", perr); + res = 2; + } else { + plist_t reply = NULL; + perr = property_list_service_receive_plist(amfi, &reply); + if (perr == PROPERTY_LIST_SERVICE_E_SUCCESS) { + plist_t val = plist_dict_get_item(reply, "Error"); + if (val) { + const char* err = plist_get_string_ptr(val, NULL); + fprintf(stderr, "Request failed: %s\n", err); + if (strstr(err, "passcode")) { + res = 2; + } else { + res = 1; + } + } else { + res = plist_dict_get_item(reply, "success") ? 0 : 1; + } + } else { + fprintf(stderr, "Could not receive reply from device: %d\n", perr); + res = 2; + } + plist_free(reply); + } + return res; +} + +static int amfi_send_action(idevice_t device, unsigned int action) +{ + lockdownd_client_t lockdown = NULL; + lockdownd_service_descriptor_t service = NULL; + lockdownd_error_t lerr; + + if (LOCKDOWN_E_SUCCESS != (lerr = lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME))) { + fprintf(stderr, "ERROR: Could not connect to lockdownd, error code %d\n", lerr); + return 1; + } + + lerr = lockdownd_start_service(lockdown, AMFI_LOCKDOWN_SERVICE_NAME, &service); + if (lerr != LOCKDOWN_E_SUCCESS) { + fprintf(stderr, "Could not start service %s: %s\nPlease note that this feature is only available on iOS 16+.\n", AMFI_LOCKDOWN_SERVICE_NAME, lockdownd_strerror(lerr)); + lockdownd_client_free(lockdown); + return 1; + } + lockdownd_client_free(lockdown); + lockdown = NULL; + + property_list_service_client_t amfi = NULL; + if (property_list_service_client_new(device, service, &amfi) != PROPERTY_LIST_SERVICE_E_SUCCESS) { + fprintf(stderr, "Could not connect to %s on device\n", AMFI_LOCKDOWN_SERVICE_NAME); + if (service) + lockdownd_service_descriptor_free(service); + idevice_free(device); + return 1; + } + lockdownd_service_descriptor_free(service); + + plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "action", plist_new_uint(action)); + + int result = amfi_service_send_msg(amfi, dict); + plist_free(dict); + + property_list_service_client_free(amfi); + amfi = NULL; + + return result; +} + +static int device_connected = 0; + +static void device_event_cb(const idevice_event_t* event, void* userdata) +{ + if (use_network && event->conn_type != CONNECTION_NETWORK) { + return; + } + if (!use_network && event->conn_type != CONNECTION_USBMUXD) { + return; + } + if (event->event == IDEVICE_DEVICE_ADD) { + if (!udid) { + udid = strdup(event->udid); + } + if (strcmp(udid, event->udid) == 0) { + device_connected = 1; + } + } else if (event->event == IDEVICE_DEVICE_REMOVE) { + if (strcmp(udid, event->udid) == 0) { + device_connected = 0; + } + } +} + + +#define WAIT_INTERVAL 200000 +#define WAIT_MAX(x) (x * (1000000 / WAIT_INTERVAL)) +#define WAIT_FOR(cond, timeout) { int __repeat = WAIT_MAX(timeout); while (!(cond) && __repeat-- > 0) { __usleep(WAIT_INTERVAL); } } + +int main(int argc, char *argv[]) +{ + idevice_t device = NULL; + idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR; + lockdownd_client_t lockdown = NULL; + lockdownd_error_t lerr = LOCKDOWN_E_UNKNOWN_ERROR; + int res = 0; + int i; + int op = -1; + plist_t val = NULL; + + int c = 0; + const struct option longopts[] = { + { "debug", no_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + { "udid", required_argument, NULL, 'u' }, + { "network", no_argument, NULL, 'n' }, + { "version", no_argument, NULL, 'v' }, + { NULL, 0, NULL, 0} + }; + +#ifndef _WIN32 + signal(SIGPIPE, SIG_IGN); +#endif + /* parse cmdline args */ + while ((c = getopt_long(argc, argv, "dhu:nv", longopts, NULL)) != -1) { + switch (c) { + case 'd': + idevice_set_debug_level(1); + break; + case 'u': + if (!*optarg) { + fprintf(stderr, "ERROR: UDID argument must not be empty!\n"); + print_usage(argc, argv, 1); + return 2; + } + udid = optarg; + break; + case 'n': + use_network = 1; + break; + case 'h': + print_usage(argc, argv, 0); + return 0; + case 'v': + printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION); + return 0; + default: + print_usage(argc, argv, 1); + return 2; + } + } + argc -= optind; + argv += optind; + + if (!argv[0]) { + fprintf(stderr, "ERROR: Missing command.\n"); + print_usage(argc+optind, argv-optind, 1); + return 2; + } + + i = 0; + if (!strcmp(argv[i], "list")) { + op = OP_LIST; + } + else if (!strcmp(argv[i], "enable")) { + op = OP_ENABLE; + } + else if (!strcmp(argv[i], "arm")) { + op = OP_ARM; + } + else if (!strcmp(argv[i], "confirm")) { + op = OP_CONFIRM; + } + else if (!strcmp(argv[i], "reveal")) { + op = OP_REVEAL; + } + + if ((op == -1) || (op >= NUM_OPS)) { + fprintf(stderr, "ERROR: Unsupported command '%s'\n", argv[i]); + print_usage(argc+optind, argv-optind, 1); + return 2; + } + + if (op == OP_LIST) { + idevice_info_t *dev_list = NULL; + + if (idevice_get_device_list_extended(&dev_list, &i) < 0) { + fprintf(stderr, "ERROR: Unable to retrieve device list!\n"); + return -1; + } + if (i > 0) { + printf("%-40s %s\n", "Device", "DeveloperMode"); + } + for (i = 0; dev_list[i] != NULL; i++) { + if (dev_list[i]->conn_type == CONNECTION_USBMUXD && use_network) continue; + if (dev_list[i]->conn_type == CONNECTION_NETWORK && !use_network) continue; + if (udid && (strcmp(dev_list[i]->udid, udid) != 0)) continue; + int mode = get_developer_mode_status(dev_list[i]->udid, use_network); + const char *mode_str = "N/A"; + if (mode == 1) { + mode_str = "enabled"; + } else if (mode == 0) { + mode_str = "disabled"; + } + printf("%-40s %s\n", dev_list[i]->udid, mode_str); + } + idevice_device_list_extended_free(dev_list); + + return 0; + } + + idevice_subscription_context_t context = NULL; + idevice_events_subscribe(&context, device_event_cb, NULL); + + WAIT_FOR(device_connected, 10); + + ret = idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX); + if (ret != IDEVICE_E_SUCCESS) { + if (udid) { + printf("No device found with udid %s.\n", udid); + } else { + printf("No device found.\n"); + } + return 1; + } + + if (!udid) { + idevice_get_udid(device, &udid); + } + + if (LOCKDOWN_E_SUCCESS != (lerr = lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME))) { + fprintf(stderr, "ERROR: Could not connect to lockdownd, error code %d\n", lerr); + idevice_free(device); + return 1; + } + + lerr = lockdownd_get_value(lockdown, "com.apple.security.mac.amfi", "DeveloperModeStatus", &val); + lockdownd_client_free(lockdown); + lockdown = NULL; + if (lerr != LOCKDOWN_E_SUCCESS) { + fprintf(stderr, "ERROR: Could not get DeveloperModeStatus: %s\nPlease note that this feature is only available on iOS 16+.\n", lockdownd_strerror(lerr)); + idevice_free(device); + return 1; + } + + uint8_t dev_mode_status = 0; + plist_get_bool_val(val, &dev_mode_status); + + if ((op == OP_ENABLE || op == OP_ARM) && dev_mode_status) { + if (dev_mode_status) { + idevice_free(device); + printf("DeveloperMode is already enabled.\n"); + return 0; + } + res = 0; + } else { + if (op == OP_ENABLE || op == OP_ARM) { + res = amfi_send_action(device, DEV_MODE_ARM); + if (res == 0) { + if (op == OP_ARM) { + printf("%s: Developer Mode armed, device will reboot now.\n", udid); + } else { + printf("%s: Developer Mode armed, waiting for reboot...\n", udid); + + do { + // waiting for device to disconnect... + idevice_free(device); + device = NULL; + WAIT_FOR(!device_connected, 40); + if (device_connected) { + printf("%s: ERROR: Device didn't reboot?!\n", udid); + res = 2; + break; + } + printf("disconnected\n"); + + // waiting for device to reconnect... + WAIT_FOR(device_connected, 60); + if (!device_connected) { + printf("%s: ERROR: Device didn't re-connect?!\n", udid); + res = 2; + break; + } + printf("connected\n"); + + idevice_new(&device, udid); + res = amfi_send_action(device, DEV_MODE_ENABLE); + } while (0); + if (res == 0) { + printf("%s: Developer Mode successfully enabled.\n", udid); + } else { + printf("%s: Failed to enable developer mode (%d)\n", udid, res); + } + } + } else if (res == 2) { + amfi_send_action(device, DEV_MODE_REVEAL); + printf("%s: Developer Mode could not be enabled because the device has a passcode set. You have to enable it on the device itself under Settings -> Privacy & Security -> Developer Mode.\n", udid); + } else { + printf("%s: Failed to arm Developer Mode (%d)\n", udid, res); + } + } else if (op == OP_CONFIRM) { + res = amfi_send_action(device, DEV_MODE_ENABLE); + if (res == 0) { + printf("%s: Developer Mode successfully enabled.\n", udid); + } else { + printf("%s: Failed to enable Developer Mode (%d)\n", udid, res); + } + } else if (op == OP_REVEAL) { + res = amfi_send_action(device, DEV_MODE_REVEAL); + if (res == 0) { + printf("%s: Developer Mode menu revealed successfully.\n", udid); + } else { + printf("%s: Failed to reveal Developer Mode menu (%d)\n", udid, res); + } + } + } + + idevice_free(device); + + return res; +} diff --git a/tools/idevicediagnostics.c b/tools/idevicediagnostics.c index e699bc4..365c0a4 100644 --- a/tools/idevicediagnostics.c +++ b/tools/idevicediagnostics.c @@ -31,7 +31,7 @@ #include <getopt.h> #include <errno.h> #include <time.h> -#ifndef WIN32 +#ifndef _WIN32 #include <signal.h> #endif @@ -113,7 +113,7 @@ int main(int argc, char **argv) { NULL, 0, NULL, 0} }; -#ifndef WIN32 +#ifndef _WIN32 signal(SIGPIPE, SIG_IGN); #endif /* parse cmdline args */ diff --git a/tools/ideviceenterrecovery.c b/tools/ideviceenterrecovery.c index 29cc5c9..65eb882 100644 --- a/tools/ideviceenterrecovery.c +++ b/tools/ideviceenterrecovery.c @@ -30,7 +30,7 @@ #include <stdlib.h> #include <getopt.h> #include <errno.h> -#ifndef WIN32 +#ifndef _WIN32 #include <signal.h> #endif @@ -70,7 +70,7 @@ int main(int argc, char *argv[]) { NULL, 0, NULL, 0} }; -#ifndef WIN32 +#ifndef _WIN32 signal(SIGPIPE, SIG_IGN); #endif /* parse cmdline args */ diff --git a/tools/ideviceimagemounter.c b/tools/ideviceimagemounter.c index b854d5d..b319d05 100644 --- a/tools/ideviceimagemounter.c +++ b/tools/ideviceimagemounter.c @@ -36,7 +36,8 @@ #include <time.h> #include <sys/time.h> #include <inttypes.h> -#ifndef WIN32 +#include <sys/stat.h> +#ifndef _WIN32 #include <signal.h> #endif @@ -45,8 +46,11 @@ #include <libimobiledevice/afc.h> #include <libimobiledevice/notification_proxy.h> #include <libimobiledevice/mobile_image_mounter.h> -#include <asprintf.h> +#include <libimobiledevice-glue/sha.h> #include <libimobiledevice-glue/utils.h> +#include <asprintf.h> +#include <plist/plist.h> +#include <libtatsu/tss.h> static int list_mode = 0; static int use_network = 0; @@ -62,18 +66,38 @@ typedef enum { DISK_IMAGE_UPLOAD_TYPE_UPLOAD_IMAGE } disk_image_upload_type_t; +enum cmd_mode { + CMD_NONE = 0, + CMD_MOUNT, + CMD_UNMOUNT, + CMD_LIST, + CMD_DEVMODESTATUS +}; + +int cmd = CMD_NONE; + static void print_usage(int argc, char **argv, int is_error) { char *name = strrchr(argv[0], '/'); - fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS] IMAGE_FILE IMAGE_SIGNATURE_FILE\n", (name ? name + 1: argv[0])); + fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS] COMMAND [COMMAND OPTIONS...]\n", (name ? name + 1: argv[0])); fprintf(is_error ? stderr : stdout, "\n" - "Mounts the specified disk image on the device.\n" + "Mount, list, or unmount a disk image on the device.\n" + "\n" + "COMMANDS:\n" + " mount PATH Mount the developer disk image at PATH.\n" + " For iOS 17+, PATH is a directory containing a .dmg image,\n" + " a BuildManifest.plist, and a Firmware sub-directory;\n" + " for older versions PATH is a .dmg filename with a\n" + " .dmg.signature in the same directory, or with another\n" + " parameter pointing to a file elsewhere.\n" + " list List mounted disk images.\n" + " unmount PATH Unmount the image mounted at PATH.\n" + " devmodestatus Query the developer mode status (iOS 16+)\n" "\n" "OPTIONS:\n" " -u, --udid UDID target specific device by UDID\n" " -n, --network connect to network device\n" - " -l, --list List mount information\n" " -t, --imagetype TYPE Image type to use, default is 'Developer'\n" " -x, --xml Use XML output\n" " -d, --debug enable communication debugging\n" @@ -87,11 +111,11 @@ static void print_usage(int argc, char **argv, int is_error) static void parse_opts(int argc, char **argv) { + int debug_level = 0; static struct option longopts[] = { { "help", no_argument, NULL, 'h' }, { "udid", required_argument, NULL, 'u' }, { "network", no_argument, NULL, 'n' }, - { "list", no_argument, NULL, 'l' }, { "imagetype", required_argument, NULL, 't' }, { "xml", no_argument, NULL, 'x' }, { "debug", no_argument, NULL, 'd' }, @@ -101,7 +125,7 @@ static void parse_opts(int argc, char **argv) int c; while (1) { - c = getopt_long(argc, argv, "hu:lt:xdnv", longopts, NULL); + c = getopt_long(argc, argv, "hu:t:xdnv", longopts, NULL); if (c == -1) { break; } @@ -121,9 +145,6 @@ static void parse_opts(int argc, char **argv) case 'n': use_network = 1; break; - case 'l': - list_mode = 1; - break; case 't': imagetype = optarg; break; @@ -131,7 +152,7 @@ static void parse_opts(int argc, char **argv) xml_mode = 1; break; case 'd': - idevice_set_debug_level(1); + debug_level++; break; case 'v': printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION); @@ -141,15 +162,8 @@ static void parse_opts(int argc, char **argv) exit(2); } } -} - -static void print_xml(plist_t node) -{ - char *xml = NULL; - uint32_t len = 0; - plist_to_xml(node, &xml, &len); - if (xml) - puts(xml); + idevice_set_debug_level(debug_level); + tss_set_debug_level(debug_level); } static ssize_t mim_upload_cb(void* buf, size_t size, void* userdata) @@ -170,7 +184,7 @@ int main(int argc, char **argv) size_t image_size = 0; char *image_sig_path = NULL; -#ifndef WIN32 +#ifndef _WIN32 signal(SIGPIPE, SIG_IGN); #endif parse_opts(argc, argv); @@ -178,29 +192,75 @@ int main(int argc, char **argv) argc -= optind; argv += optind; - if (!list_mode) { - if (argc < 1) { - printf("ERROR: No IMAGE_FILE has been given!\n"); - return -1; - } - image_path = strdup(argv[0]); - if (argc >= 2) { - image_sig_path = strdup(argv[1]); + if (argc == 0) { + fprintf(stderr, "ERROR: Missing command.\n\n"); + print_usage(argc+optind, argv-optind, 1); + return 2; + } + + char* cmdstr = argv[0]; + + int optind2 = 0; + if (!strcmp(cmdstr, "mount")) { + cmd = CMD_MOUNT; + optind2++; + } else if (!strcmp(cmdstr, "list")) { + cmd = CMD_LIST; + optind2++; + } else if (!strcmp(cmdstr, "umount") || !strcmp(cmdstr, "unmount")) { + cmd = CMD_UNMOUNT; + optind2++; + } else if (!strcmp(cmdstr, "devmodestatus")) { + cmd = CMD_DEVMODESTATUS; + optind2++; + } else { + // assume mount command, unless -l / --list was specified + if (list_mode) { + cmd = CMD_LIST; } else { - if (asprintf(&image_sig_path, "%s.signature", image_path) < 0) { - printf("Out of memory?!\n"); - return -1; - } + cmd = CMD_MOUNT; } } + argc -= optind2; + argv += optind2; + optind += optind2; + + switch (cmd) { + case CMD_MOUNT: + if (argc < 1) { + fprintf(stderr, "ERROR: Missing IMAGE_FILE for mount command\n"); + print_usage(argc+optind, argv-optind, 1); + return 2; + } + image_path = strdup(argv[0]); + if (argc >= 2) { + image_sig_path = strdup(argv[1]); + } else { + if (asprintf(&image_sig_path, "%s.signature", image_path) < 0) { + printf("Out of memory?!\n"); + return 1; + } + } + break; + case CMD_UNMOUNT: + if (argc != 1) { + fprintf(stderr, "ERROR: Missing mount path (argc = %d)\n", argc); + print_usage(argc+optind, argv-optind, 1); + return 2; + } + break; + default: + break; + } + if (IDEVICE_E_SUCCESS != idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX)) { if (udid) { printf("No device found with udid %s.\n", udid); } else { printf("No device found.\n"); } - return -1; + return 1; } if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &lckd, TOOL_NAME))) { @@ -208,19 +268,24 @@ int main(int argc, char **argv) goto leave; } - plist_t pver = NULL; - char *product_version = NULL; - lockdownd_get_value(lckd, NULL, "ProductVersion", &pver); - if (pver && plist_get_node_type(pver) == PLIST_STRING) { - plist_get_string_val(pver, &product_version); - } + unsigned int device_version = idevice_get_device_version(device); + disk_image_upload_type_t disk_image_upload_type = DISK_IMAGE_UPLOAD_TYPE_AFC; - int product_version_major = 0; - int product_version_minor = 0; - if (product_version) { - if (sscanf(product_version, "%d.%d.%*d", &product_version_major, &product_version_minor) == 2) { - if (product_version_major >= 7) - disk_image_upload_type = DISK_IMAGE_UPLOAD_TYPE_UPLOAD_IMAGE; + if (device_version >= IDEVICE_DEVICE_VERSION(7,0,0)) { + disk_image_upload_type = DISK_IMAGE_UPLOAD_TYPE_UPLOAD_IMAGE; + } + + if (device_version >= IDEVICE_DEVICE_VERSION(16,0,0)) { + uint8_t dev_mode_status = 0; + plist_t val = NULL; + ldret = lockdownd_get_value(lckd, "com.apple.security.mac.amfi", "DeveloperModeStatus", &val); + if (ldret == LOCKDOWN_E_SUCCESS) { + plist_get_bool_val(val, &dev_mode_status); + plist_free(val); + } + if (!dev_mode_status) { + printf("ERROR: You have to enable Developer Mode on the given device in order to allowing mounting a developer disk image.\n"); + goto leave; } } @@ -241,7 +306,7 @@ int main(int argc, char **argv) service = NULL; } - if (!list_mode) { + if (cmd == CMD_MOUNT) { struct stat fst; if (disk_image_upload_type == DISK_IMAGE_UPLOAD_TYPE_AFC) { if ((lockdownd_start_service(lckd, "com.apple.afc", &service) != @@ -263,7 +328,7 @@ int main(int argc, char **argv) goto leave; } image_size = fst.st_size; - if (stat(image_sig_path, &fst) != 0) { + if (device_version < IDEVICE_DEVICE_VERSION(17,0,0) && stat(image_sig_path, &fst) != 0) { fprintf(stderr, "ERROR: stat: %s: %s\n", image_sig_path, strerror(errno)); goto leave; } @@ -275,41 +340,233 @@ int main(int argc, char **argv) mobile_image_mounter_error_t err = MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR; plist_t result = NULL; - if (list_mode) { + if (cmd == CMD_LIST) { /* list mounts mode */ if (!imagetype) { - imagetype = "Developer"; + if (device_version < IDEVICE_DEVICE_VERSION(17,0,0)) { + imagetype = "Developer"; + } else { + imagetype = "Personalized"; + } } err = mobile_image_mounter_lookup_image(mim, imagetype, &result); if (err == MOBILE_IMAGE_MOUNTER_E_SUCCESS) { res = 0; - if (xml_mode) { - print_xml(result); - } else { - plist_print_to_stream(result, stdout); - } + plist_write_to_stream(result, stdout, (xml_mode) ? PLIST_FORMAT_XML : PLIST_FORMAT_LIMD, 0); } else { printf("Error: lookup_image returned %d\n", err); } - } else { - char sig[8192]; + } else if (cmd == CMD_MOUNT) { + unsigned char *sig = NULL; size_t sig_length = 0; - FILE *f = fopen(image_sig_path, "rb"); - if (!f) { - fprintf(stderr, "Error opening signature file '%s': %s\n", image_sig_path, strerror(errno)); - goto leave; - } - sig_length = fread(sig, 1, sizeof(sig), f); - fclose(f); - if (sig_length == 0) { - fprintf(stderr, "Could not read signature from file '%s'\n", image_sig_path); - goto leave; - } + FILE *f; + struct stat fst; + plist_t mount_options = NULL; - f = fopen(image_path, "rb"); - if (!f) { - fprintf(stderr, "Error opening image file '%s': %s\n", image_path, strerror(errno)); - goto leave; + if (device_version < IDEVICE_DEVICE_VERSION(17,0,0)) { + f = fopen(image_sig_path, "rb"); + if (!f) { + fprintf(stderr, "Error opening signature file '%s': %s\n", image_sig_path, strerror(errno)); + goto leave; + } + if (fstat(fileno(f), &fst) != 0) { + fprintf(stderr, "Error: fstat: %s\n", strerror(errno)); + goto leave; + } + sig = malloc(fst.st_size); + sig_length = fread(sig, 1, fst.st_size, f); + fclose(f); + if (sig_length == 0) { + fprintf(stderr, "Could not read signature from file '%s'\n", image_sig_path); + goto leave; + } + + f = fopen(image_path, "rb"); + if (!f) { + fprintf(stderr, "Error opening image file '%s': %s\n", image_path, strerror(errno)); + goto leave; + } + } else { + if (stat(image_path, &fst) != 0) { + fprintf(stderr, "Error: stat: '%s': %s\n", image_path, strerror(errno)); + goto leave; + } + if (!S_ISDIR(fst.st_mode)) { + fprintf(stderr, "Error: Personalized Disk Image mount expects a directory as image path.\n"); + goto leave; + } + char* build_manifest_path = string_build_path(image_path, "BuildManifest.plist", NULL); + plist_t build_manifest = NULL; + if (plist_read_from_file(build_manifest_path, &build_manifest, NULL) != 0) { + free(build_manifest_path); + build_manifest_path = string_build_path(image_path, "Restore", "BuildManifest.plist", NULL); + if (plist_read_from_file(build_manifest_path, &build_manifest, NULL) == 0) { + char* image_path_new = string_build_path(image_path, "Restore", NULL); + free(image_path); + image_path = image_path_new; + } + } + if (!build_manifest) { + fprintf(stderr, "Error: Could not locate BuildManifest.plist inside given disk image path!\n"); + goto leave; + } + + plist_t identifiers = NULL; + mobile_image_mounter_error_t merr = mobile_image_mounter_query_personalization_identifiers(mim, NULL, &identifiers); + if (merr != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { + fprintf(stderr, "Failed to query personalization identifiers: %d\n", merr); + goto error_out; + } + + unsigned int board_id = plist_dict_get_uint(identifiers, "BoardId"); + unsigned int chip_id = plist_dict_get_uint(identifiers, "ChipID"); + + plist_t build_identities = plist_dict_get_item(build_manifest, "BuildIdentities"); + plist_array_iter iter; + plist_array_new_iter(build_identities, &iter); + plist_t item = NULL; + plist_t build_identity = NULL; + do { + plist_array_next_item(build_identities, iter, &item); + if (!item) { + break; + } + unsigned int bi_board_id = (unsigned int)plist_dict_get_uint(item, "ApBoardID"); + unsigned int bi_chip_id = (unsigned int)plist_dict_get_uint(item, "ApChipID"); + if (bi_chip_id == chip_id && bi_board_id == board_id) { + build_identity = item; + break; + } + } while (item); + plist_mem_free(iter); + if (!build_identity) { + fprintf(stderr, "Error: The given disk image is not compatible with the current device.\n"); + goto leave; + } + plist_t p_tc_path = plist_access_path(build_identity, 4, "Manifest", "LoadableTrustCache", "Info", "Path"); + if (!p_tc_path) { + fprintf(stderr, "Error: Could not determine path for trust cache!\n"); + goto leave; + } + plist_t p_dmg_path = plist_access_path(build_identity, 4, "Manifest", "PersonalizedDMG", "Info", "Path"); + if (!p_dmg_path) { + fprintf(stderr, "Error: Could not determine path for disk image!\n"); + goto leave; + } + char *tc_path = string_build_path(image_path, plist_get_string_ptr(p_tc_path, NULL), NULL); + unsigned char* trust_cache = NULL; + uint64_t trust_cache_size = 0; + if (!buffer_read_from_filename(tc_path, (char**)&trust_cache, &trust_cache_size)) { + fprintf(stderr, "Error: Trust cache does not exist at '%s'!\n", tc_path); + goto leave; + } + mount_options = plist_new_dict(); + plist_dict_set_item(mount_options, "ImageTrustCache", plist_new_data((char*)trust_cache, trust_cache_size)); + free(trust_cache); + char *dmg_path = string_build_path(image_path, plist_get_string_ptr(p_dmg_path, NULL), NULL); + free(image_path); + image_path = dmg_path; + f = fopen(image_path, "rb"); + if (!f) { + fprintf(stderr, "Error opening image file '%s': %s\n", image_path, strerror(errno)); + goto leave; + } + + unsigned char buf[8192]; + unsigned char sha384_digest[48]; + sha384_context ctx; + sha384_init(&ctx); + fstat(fileno(f), &fst); + image_size = fst.st_size; + while (!feof(f)) { + ssize_t fr = fread(buf, 1, sizeof(buf), f); + if (fr <= 0) { + break; + } + sha384_update(&ctx, buf, fr); + } + rewind(f); + sha384_final(&ctx, sha384_digest); + unsigned char* manifest = NULL; + unsigned int manifest_size = 0; + /* check if the device already has a personalization manifest for this image */ + if (mobile_image_mounter_query_personalization_manifest(mim, "DeveloperDiskImage", sha384_digest, sizeof(sha384_digest), &manifest, &manifest_size) == MOBILE_IMAGE_MOUNTER_E_SUCCESS) { + printf("Using existing personalization manifest from device.\n"); + } else { + /* we need to re-connect in this case */ + mobile_image_mounter_free(mim); + mim = NULL; + if (mobile_image_mounter_start_service(device, &mim, TOOL_NAME) != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { + goto error_out; + } + printf("No personalization manifest, requesting from TSS...\n"); + unsigned char* nonce = NULL; + unsigned int nonce_size = 0; + + /* create new TSS request and fill parameters */ + plist_t request = tss_request_new(NULL); + plist_t params = plist_new_dict(); + tss_parameters_add_from_manifest(params, build_identity, 1); + + /* copy all `Ap,*` items from identifiers */ + plist_dict_iter di = NULL; + plist_dict_new_iter(identifiers, &di); + plist_t node = NULL; + do { + char* key = NULL; + plist_dict_next_item(identifiers, di, &key, &node); + if (node) { + if (!strncmp(key, "Ap,", 3)) { + plist_dict_set_item(request, key, plist_copy(node)); + } + } + free(key); + } while (node); + plist_mem_free(di); + + plist_dict_copy_uint(params, identifiers, "ApECID", "UniqueChipID"); + plist_dict_set_item(params, "ApProductionMode", plist_new_bool(1)); + plist_dict_set_item(params, "ApSecurityMode", plist_new_bool(1)); + plist_dict_set_item(params, "ApSupportsImg4", plist_new_bool(1)); + + /* query nonce from image mounter service */ + merr = mobile_image_mounter_query_nonce(mim, "DeveloperDiskImage", &nonce, &nonce_size); + if (merr == MOBILE_IMAGE_MOUNTER_E_SUCCESS) { + plist_dict_set_item(params, "ApNonce", plist_new_data((char*)nonce, nonce_size)); + } else { + fprintf(stderr, "ERROR: Failed to query nonce for developer disk image: %d\n", merr); + goto error_out; + } + mobile_image_mounter_free(mim); + mim = NULL; + + plist_dict_set_item(params, "ApSepNonce", plist_new_data("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 20)); + plist_dict_set_item(params, "UID_MODE", plist_new_bool(0)); + tss_request_add_ap_tags(request, params, NULL); + tss_request_add_common_tags(request, params, NULL); + tss_request_add_ap_img4_tags(request, params); + plist_free(params); + + /* request IM4M from TSS */ + plist_t response = tss_request_send(request, NULL); + plist_free(request); + + plist_t p_manifest = plist_dict_get_item(response, "ApImg4Ticket"); + if (!PLIST_IS_DATA(p_manifest)) { + fprintf(stderr, "Failed to get Img4Ticket\n"); + goto error_out; + } + + uint64_t m4m_len = 0; + plist_get_data_val(p_manifest, (char**)&manifest, &m4m_len); + manifest_size = m4m_len; + plist_free(response); + printf("Done.\n"); + } + sig = manifest; + sig_length = manifest_size; + + imagetype = "Personalized"; } char *targetname = NULL; @@ -323,11 +580,16 @@ int main(int argc, char **argv) goto leave; } - if (!imagetype) { imagetype = "Developer"; } + if (!mim) { + if (mobile_image_mounter_start_service(device, &mim, TOOL_NAME) != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { + goto error_out; + } + } + switch(disk_image_upload_type) { case DISK_IMAGE_UPLOAD_TYPE_UPLOAD_IMAGE: printf("Uploading %s\n", image_path); @@ -336,20 +598,13 @@ int main(int argc, char **argv) case DISK_IMAGE_UPLOAD_TYPE_AFC: default: printf("Uploading %s --> afc:///%s\n", image_path, targetname); - char **strs = NULL; - if (afc_get_file_info(afc, PKG_PATH, &strs) != AFC_E_SUCCESS) { + plist_t fileinfo = NULL; + if (afc_get_file_info_plist(afc, PKG_PATH, &fileinfo) != AFC_E_SUCCESS) { if (afc_make_directory(afc, PKG_PATH) != AFC_E_SUCCESS) { fprintf(stderr, "WARNING: Could not create directory '%s' on device!\n", PKG_PATH); } } - if (strs) { - int i = 0; - while (strs[i]) { - free(strs[i]); - i++; - } - free(strs); - } + plist_free(fileinfo); uint64_t af = 0; if ((afc_file_open(afc, targetname, AFC_FOPEN_WRONLY, &af) != @@ -402,7 +657,7 @@ int main(int argc, char **argv) printf("done.\n"); printf("Mounting...\n"); - err = mobile_image_mounter_mount_image(mim, mountname, sig, sig_length, imagetype, &result); + err = mobile_image_mounter_mount_image_with_options(mim, mountname, sig, sig_length, imagetype, mount_options, &result); if (err == MOBILE_IMAGE_MOUNTER_E_SUCCESS) { if (result) { plist_t node = plist_dict_get_item(result, "Status"); @@ -415,20 +670,12 @@ int main(int argc, char **argv) res = 0; } else { printf("unexpected status value:\n"); - if (xml_mode) { - print_xml(result); - } else { - plist_print_to_stream(result, stdout); - } + plist_write_to_stream(result, stdout, (xml_mode) ? PLIST_FORMAT_XML : PLIST_FORMAT_LIMD, 0); } free(status); } else { printf("unexpected result:\n"); - if (xml_mode) { - print_xml(result); - } else { - plist_print_to_stream(result, stdout); - } + plist_write_to_stream(result, stdout, (xml_mode) ? PLIST_FORMAT_XML : PLIST_FORMAT_LIMD, 0); } } node = plist_dict_get_item(result, "Error"); @@ -440,25 +687,51 @@ int main(int argc, char **argv) free(error); } else { printf("unexpected result:\n"); - if (xml_mode) { - print_xml(result); - } else { - plist_print_to_stream(result, stdout); - } + plist_write_to_stream(result, stdout, (xml_mode) ? PLIST_FORMAT_XML : PLIST_FORMAT_LIMD, 0); } - - } else { - if (xml_mode) { - print_xml(result); - } else { - plist_print_to_stream(result, stdout); + node = plist_dict_get_item(result, "DetailedError"); + if (node) { + printf("DetailedError: %s\n", plist_get_string_ptr(node, NULL)); } + } else { + plist_write_to_stream(result, stdout, (xml_mode) ? PLIST_FORMAT_XML : PLIST_FORMAT_LIMD, 0); } } } else { printf("Error: mount_image returned %d\n", err); } + } else if (cmd == CMD_UNMOUNT) { + err = mobile_image_mounter_unmount_image(mim, argv[0]); + switch (err) { + case MOBILE_IMAGE_MOUNTER_E_SUCCESS: + printf("Success\n"); + res = 0; + break; + case MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED: + printf("Error: '%s' is not mounted\n", argv[0]); + res = 1; + break; + case MOBILE_IMAGE_MOUNTER_E_NOT_SUPPORTED: + printf("Error: 'unmount' is not supported on this device\n"); + res = 1; + break; + case MOBILE_IMAGE_MOUNTER_E_DEVICE_LOCKED: + printf("Error: device is locked\n"); + res = 1; + break; + default: + printf("Error: unmount returned %d\n", err); + break; + } + } else if (cmd == CMD_DEVMODESTATUS) { + err = mobile_image_mounter_query_developer_mode_status(mim, &result); + if (err == MOBILE_IMAGE_MOUNTER_E_SUCCESS) { + res = 0; + plist_write_to_stream(result, stdout, (xml_mode) ? PLIST_FORMAT_XML : PLIST_FORMAT_LIMD, 0); + } else { + printf("Error: query_developer_mode_status returned %d\n", err); + } } if (result) { @@ -481,7 +754,7 @@ leave: idevice_free(device); if (image_path) - free(image_path); + free(image_path); if (image_sig_path) free(image_sig_path); diff --git a/tools/ideviceinfo.c b/tools/ideviceinfo.c index fc0527d..20cc916 100644 --- a/tools/ideviceinfo.c +++ b/tools/ideviceinfo.c @@ -31,13 +31,13 @@ #include <errno.h> #include <stdlib.h> #include <getopt.h> -#ifndef WIN32 +#ifndef _WIN32 #include <signal.h> #endif #include <libimobiledevice/libimobiledevice.h> #include <libimobiledevice/lockdown.h> -#include <libimobiledevice-glue/utils.h> +#include <plist/plist.h> #define FORMAT_KEY_VALUE 1 #define FORMAT_XML 2 @@ -152,7 +152,7 @@ int main(int argc, char *argv[]) { NULL, 0, NULL, 0} }; -#ifndef WIN32 +#ifndef _WIN32 signal(SIGPIPE, SIG_IGN); #endif @@ -241,11 +241,11 @@ int main(int argc, char *argv[]) free(xml_doc); break; case FORMAT_KEY_VALUE: - plist_print_to_stream(node, stdout); + plist_write_to_stream(node, stdout, PLIST_FORMAT_LIMD, 0); break; default: if (key != NULL) - plist_print_to_stream(node, stdout); + plist_write_to_stream(node, stdout, PLIST_FORMAT_LIMD, 0); break; } plist_free(node); diff --git a/tools/idevicename.c b/tools/idevicename.c index 69b76f6..248bda3 100644 --- a/tools/idevicename.c +++ b/tools/idevicename.c @@ -30,7 +30,7 @@ #include <unistd.h> #include <stdlib.h> #include <getopt.h> -#ifndef WIN32 +#ifndef _WIN32 #include <signal.h> #endif @@ -72,7 +72,7 @@ int main(int argc, char** argv) const char* udid = NULL; int use_network = 0; -#ifndef WIN32 +#ifndef _WIN32 signal(SIGPIPE, SIG_IGN); #endif diff --git a/tools/idevicenotificationproxy.c b/tools/idevicenotificationproxy.c index d1e25c1..192192a 100644 --- a/tools/idevicenotificationproxy.c +++ b/tools/idevicenotificationproxy.c @@ -2,7 +2,8 @@ * idevicenotificationproxy.c * Simple client for the notification_proxy service * - * Copyright (c) 2009-2015 Martin Szulecki All Rights Reserved. + * Copyright (c) 2018-2024 Nikias Bassen, All Rights Reserved. + * Copyright (c) 2009-2015 Martin Szulecki, 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 @@ -32,7 +33,7 @@ #include <errno.h> #include <signal.h> -#ifdef WIN32 +#ifdef _WIN32 #include <windows.h> #define sleep(x) Sleep(x*1000) #else @@ -75,6 +76,7 @@ static void print_usage(int argc, char **argv, int is_error) "\n" "The following OPTIONS are accepted:\n" " -u, --udid UDID target specific device by UDID\n" + " -i, --insecure use insecure notification proxy (non-paired device)\n" " -n, --network connect to network device\n" " -d, --debug enable communication debugging\n" " -h, --help prints usage information\n" @@ -102,6 +104,7 @@ int main(int argc, char *argv[]) int i = 0; const char* udid = NULL; int use_network = 0; + int insecure = 0; int cmd = CMD_NONE; char* cmd_arg = NULL; @@ -114,6 +117,7 @@ int main(int argc, char *argv[]) { "debug", no_argument, NULL, 'd' }, { "help", no_argument, NULL, 'h' }, { "udid", required_argument, NULL, 'u' }, + { "insecure", no_argument, NULL, 'i' }, { "network", no_argument, NULL, 'n' }, { "version", no_argument, NULL, 'v' }, { NULL, 0, NULL, 0} @@ -121,13 +125,13 @@ int main(int argc, char *argv[]) signal(SIGINT, clean_exit); signal(SIGTERM, clean_exit); -#ifndef WIN32 +#ifndef _WIN32 signal(SIGQUIT, clean_exit); signal(SIGPIPE, SIG_IGN); #endif /* parse cmdline args */ - while ((c = getopt_long(argc, argv, "dhu:nv", longopts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "dhu:inv", longopts, NULL)) != -1) { switch (c) { case 'd': idevice_set_debug_level(1); @@ -143,6 +147,9 @@ int main(int argc, char *argv[]) case 'n': use_network = 1; break; + case 'i': + insecure = 1; + break; case 'h': print_usage(argc, argv, 0); return 0; @@ -214,12 +221,17 @@ int main(int argc, char *argv[]) goto cleanup; } - if (LOCKDOWN_E_SUCCESS != (ret = lockdownd_client_new_with_handshake(device, &client, TOOL_NAME))) { - fprintf(stderr, "ERROR: Could not connect to lockdownd, error code %d\n", ret); + if (insecure) { + ret = lockdownd_client_new(device, &client, TOOL_NAME); + } else { + ret = lockdownd_client_new_with_handshake(device, &client, TOOL_NAME); + } + if (LOCKDOWN_E_SUCCESS != ret) { + fprintf(stderr, "ERROR: Could not connect to lockdownd: %s (%d)\n", lockdownd_strerror(ret), ret); goto cleanup; } - ret = lockdownd_start_service(client, NP_SERVICE_NAME, &service); + ret = lockdownd_start_service(client, (insecure) ? "com.apple.mobile.insecure_notification_proxy" : NP_SERVICE_NAME, &service); lockdownd_client_free(client); diff --git a/tools/idevicepair.c b/tools/idevicepair.c index dda02ec..884c690 100644 --- a/tools/idevicepair.c +++ b/tools/idevicepair.c @@ -32,7 +32,7 @@ #include <getopt.h> #include <ctype.h> #include <unistd.h> -#ifdef WIN32 +#ifdef _WIN32 #include <windows.h> #include <conio.h> #else @@ -41,7 +41,6 @@ #endif #include "common/userpref.h" -#include <libimobiledevice-glue/utils.h> #include <libimobiledevice/libimobiledevice.h> #include <libimobiledevice/lockdown.h> @@ -51,7 +50,7 @@ static char *udid = NULL; #ifdef HAVE_WIRELESS_PAIRING -#ifdef WIN32 +#ifdef _WIN32 #define BS_CC '\b' #define my_getch getch #else @@ -104,7 +103,7 @@ static void pairing_cb(lockdownd_cu_pairing_cb_type_t cb_type, void *user_data, printf("\n"); } else if (cb_type == LOCKDOWN_CU_PAIRING_DEVICE_INFO) { printf("Device info:\n"); - plist_print_to_stream_with_indentation((plist_t)data_ptr, stdout, 2); + plist_write_to_stream((plist_t)data_ptr, stdout, PLIST_FORMAT_LIMD, PLIST_OPT_INDENT | PLIST_OPT_INDENT_BY(2)); } else if (cb_type == LOCKDOWN_CU_PAIRING_ERROR) { printf("ERROR: %s\n", (data_ptr) ? (char*)data_ptr : "(unknown)"); } @@ -257,7 +256,7 @@ int main(int argc, char **argv) goto leave; } if (*optarg == '@') { - plist_read_from_filename(&host_info_plist, optarg+1); + plist_read_from_file(optarg+1, &host_info_plist, NULL); if (!host_info_plist) { fprintf(stderr, "ERROR: Could not read from file '%s'\n", optarg+1); result = EXIT_FAILURE; @@ -294,7 +293,7 @@ int main(int argc, char **argv) } } -#ifndef WIN32 +#ifndef _WIN32 signal(SIGPIPE, SIG_IGN); #endif diff --git a/tools/ideviceprovision.c b/tools/ideviceprovision.c index 7cd4f3f..94f4ec5 100644 --- a/tools/ideviceprovision.c +++ b/tools/ideviceprovision.c @@ -32,11 +32,12 @@ #include <getopt.h> #include <sys/stat.h> #include <errno.h> -#ifndef WIN32 +#ifndef _WIN32 #include <signal.h> #endif -#ifdef WIN32 +#ifdef _WIN32 +#include <winsock2.h> #include <windows.h> #else #include <arpa/inet.h> @@ -45,7 +46,7 @@ #include <libimobiledevice/libimobiledevice.h> #include <libimobiledevice/lockdown.h> #include <libimobiledevice/misagent.h> -#include <libimobiledevice-glue/utils.h> +#include <plist/plist.h> static void print_usage(int argc, char **argv, int is_error) { @@ -314,7 +315,7 @@ int main(int argc, char *argv[]) { NULL, 0, NULL, 0} }; -#ifndef WIN32 +#ifndef _WIN32 signal(SIGPIPE, SIG_IGN); #endif /* parse cmdline args */ @@ -436,7 +437,7 @@ int main(int argc, char *argv[]) } } else { if (pl && (plist_get_node_type(pl) == PLIST_DICT)) { - plist_print_to_stream(pl, stdout); + plist_write_to_stream(pl, stdout, PLIST_FORMAT_LIMD, 0); } else { fprintf(stderr, "ERROR: unexpected node type in profile plist (not PLIST_DICT)\n"); res = -1; @@ -475,27 +476,7 @@ int main(int argc, char *argv[]) return -1; } - plist_t pver = NULL; - char *pver_s = NULL; - lockdownd_get_value(client, NULL, "ProductVersion", &pver); - if (pver && plist_get_node_type(pver) == PLIST_STRING) { - plist_get_string_val(pver, &pver_s); - } - plist_free(pver); - int product_version_major = 0; - int product_version_minor = 0; - int product_version_patch = 0; - if (pver_s) { - sscanf(pver_s, "%d.%d.%d", &product_version_major, &product_version_minor, &product_version_patch); - free(pver_s); - } - if (product_version_major == 0) { - fprintf(stderr, "ERROR: Could not determine the device's ProductVersion\n"); - lockdownd_client_free(client); - idevice_free(device); - return -1; - } - int product_version = ((product_version_major & 0xFF) << 16) | ((product_version_minor & 0xFF) << 8) | (product_version_patch & 0xFF); + unsigned int device_version = idevice_get_device_version(device); lockdownd_error_t lerr = lockdownd_start_service(client, MISAGENT_SERVICE_NAME, &service); if (lerr != LOCKDOWN_E_SUCCESS) { @@ -546,7 +527,7 @@ int main(int argc, char *argv[]) { plist_t profiles = NULL; misagent_error_t merr; - if (product_version < 0x090300) { + if (device_version < IDEVICE_DEVICE_VERSION(9,3,0)) { merr = misagent_copy(mis, &profiles); } else { merr = misagent_copy_all(mis, &profiles); @@ -631,7 +612,7 @@ int main(int argc, char *argv[]) /* remove all provisioning profiles */ plist_t profiles = NULL; misagent_error_t merr; - if (product_version < 0x090300) { + if (device_version < IDEVICE_DEVICE_VERSION(9,3,0)) { merr = misagent_copy(mis, &profiles); } else { merr = misagent_copy_all(mis, &profiles); diff --git a/tools/idevicescreenshot.c b/tools/idevicescreenshot.c index 0e694c7..bfaa059 100644 --- a/tools/idevicescreenshot.c +++ b/tools/idevicescreenshot.c @@ -32,7 +32,7 @@ #include <errno.h> #include <time.h> #include <unistd.h> -#ifndef WIN32 +#ifndef _WIN32 #include <signal.h> #endif @@ -142,7 +142,7 @@ int main(int argc, char **argv) { NULL, 0, NULL, 0} }; -#ifndef WIN32 +#ifndef _WIN32 signal(SIGPIPE, SIG_IGN); #endif /* parse cmdline args */ diff --git a/tools/idevicesetlocation.c b/tools/idevicesetlocation.c index 69fbaf5..dca8830 100644 --- a/tools/idevicesetlocation.c +++ b/tools/idevicesetlocation.c @@ -113,7 +113,7 @@ int main(int argc, char **argv) if ((argc > 2) || (argc < 1)) { print_usage(argc+optind, argv-optind, 1); - return -1; + return 1; } if (argc == 2) { @@ -123,7 +123,7 @@ int main(int argc, char **argv) mode = RESET_LOCATION; } else { print_usage(argc+optind, argv-optind, 1); - return -1; + return 1; } } @@ -135,19 +135,30 @@ int main(int argc, char **argv) } else { printf("ERROR: No device found!\n"); } - return -1; + return 1; } - lockdownd_client_t lockdown; - lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME); + lockdownd_client_t lockdown = NULL; + lockdownd_error_t lerr = lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME); + if (lerr != LOCKDOWN_E_SUCCESS) { + idevice_free(device); + printf("ERROR: Could not connect to lockdownd: %s (%d)\n", lockdownd_strerror(lerr), lerr); + return 1; + } lockdownd_service_descriptor_t svc = NULL; - lockdownd_error_t lerr = lockdownd_start_service(lockdown, DT_SIMULATELOCATION_SERVICE, &svc); + lerr = lockdownd_start_service(lockdown, DT_SIMULATELOCATION_SERVICE, &svc); if (lerr != LOCKDOWN_E_SUCCESS) { + unsigned int device_version = idevice_get_device_version(device); lockdownd_client_free(lockdown); idevice_free(device); - printf("ERROR: Could not start the simulatelocation service: %s\nMake sure a developer disk image is mounted!\n", lockdownd_strerror(lerr)); - return -1; + printf("ERROR: Could not start the simulatelocation service: %s\n", lockdownd_strerror(lerr)); + if (device_version >= IDEVICE_DEVICE_VERSION(17,0,0)) { + printf("Note: This tool is currently not supported on iOS 17+\n"); + } else { + printf("Make sure a developer disk image is mounted!\n"); + } + return 1; } lockdownd_client_free(lockdown); @@ -158,10 +169,9 @@ int main(int argc, char **argv) lockdownd_service_descriptor_free(svc); if (serr != SERVICE_E_SUCCESS) { - lockdownd_client_free(lockdown); idevice_free(device); printf("ERROR: Could not connect to simulatelocation service (%d)\n", serr); - return -1; + return 1; } uint32_t l; diff --git a/tools/idevicesyslog.c b/tools/idevicesyslog.c index 3084b97..88af4c1 100644 --- a/tools/idevicesyslog.c +++ b/tools/idevicesyslog.c @@ -33,8 +33,9 @@ #include <stdlib.h> #include <unistd.h> #include <getopt.h> +#include <time.h> -#ifdef WIN32 +#ifdef _WIN32 #include <windows.h> #define sleep(x) Sleep(x*1000) #endif @@ -42,10 +43,12 @@ #include <libimobiledevice/libimobiledevice.h> #include <libimobiledevice/syslog_relay.h> #include <libimobiledevice-glue/termcolors.h> +#include <libimobiledevice/ostrace.h> static int quit_flag = 0; static int exit_on_disconnect = 0; static int show_device_name = 0; +static int force_syslog_relay = 0; static char* udid = NULL; static char** proc_filters = NULL; @@ -58,6 +61,9 @@ static int num_pid_filters = 0; static char** msg_filters = NULL; static int num_msg_filters = 0; +static char** msg_reverse_filters = NULL; +static int num_msg_reverse_filters = 0; + static char** trigger_filters = NULL; static int num_trigger_filters = 0; static char** untrigger_filters = NULL; @@ -66,11 +72,16 @@ static int triggered = 0; static idevice_t device = NULL; static syslog_relay_client_t syslog = NULL; +static ostrace_client_t ostrace = NULL; static const char QUIET_FILTER[] = "CircleJoinRequested|CommCenter|HeuristicInterpreter|MobileMail|PowerUIAgent|ProtectedCloudKeySyncing|SpringBoard|UserEventAgent|WirelessRadioManagerd|accessoryd|accountsd|aggregated|analyticsd|appstored|apsd|assetsd|assistant_service|backboardd|biometrickitd|bluetoothd|calaccessd|callservicesd|cloudd|com.apple.Safari.SafeBrowsing.Service|contextstored|corecaptured|coreduetd|corespeechd|cdpd|dasd|dataaccessd|distnoted|dprivacyd|duetexpertd|findmydeviced|fmfd|fmflocatord|gpsd|healthd|homed|identityservicesd|imagent|itunescloudd|itunesstored|kernel|locationd|maild|mDNSResponder|mediaremoted|mediaserverd|mobileassetd|nanoregistryd|nanotimekitcompaniond|navd|nsurlsessiond|passd|pasted|photoanalysisd|powerd|powerlogHelperd|ptpd|rapportd|remindd|routined|runningboardd|searchd|sharingd|suggestd|symptomsd|timed|thermalmonitord|useractivityd|vmd|wifid|wirelessproxd"; static int use_network = 0; +static long long start_time = -1; +static long long size_limit = -1; +static long long age_limit = -1; + static char *line = NULL; static int line_buffer_size = 0; static int lp = 0; @@ -129,6 +140,70 @@ static int find_char(char c, char** p, const char* end) static void stop_logging(void); +static int message_filter_matching(const char* message) +{ + if (num_msg_filters > 0) { + int found = 0; + int i; + for (i = 0; i < num_msg_filters; i++) { + if (strstr(message, msg_filters[i])) { + found = 1; + break; + } + } + if (!found) { + return 0; + } + } + if (num_msg_reverse_filters > 0) { + int found = 0; + int i; + for (i = 0; i < num_msg_reverse_filters; i++) { + if (strstr(message, msg_reverse_filters[i])) { + found = 1; + break; + } + } + if (found) { + return 0; + } + } + return 1; +} + +static int process_filter_matching(int pid, const char* process_name, int process_name_length) +{ + int proc_matched = 0; + if (num_pid_filters > 0) { + int found = proc_filter_excluding; + int i = 0; + for (i = 0; i < num_pid_filters; i++) { + if (pid == pid_filters[i]) { + found = !proc_filter_excluding; + break; + } + } + if (found) { + proc_matched = 1; + } + } + if (num_proc_filters > 0 && !proc_matched) { + int found = proc_filter_excluding; + int i = 0; + for (i = 0; i < num_proc_filters; i++) { + if (!proc_filters[i]) continue; + if (strncmp(proc_filters[i], process_name, process_name_length) == 0) { + found = !proc_filter_excluding; + break; + } + } + if (found) { + proc_matched = 1; + } + } + return proc_matched; +} + static void syslog_callback(char c, void *user_data) { if (lp >= line_buffer_size-1) { @@ -149,7 +224,7 @@ static void syslog_callback(char c, void *user_data) do { if (lp < 16) { shall_print = 1; - cprintf(COLOR_WHITE); + cprintf(FG_WHITE); break; } @@ -202,20 +277,9 @@ static void syslog_callback(char c, void *user_data) } /* check message filters */ - if (num_msg_filters > 0) { - int found = 0; - int i; - for (i = 0; i < num_msg_filters; i++) { - if (strstr(device_name_end+1, msg_filters[i])) { - found = 1; - break; - } - } - if (!found) { - shall_print = 0; - break; - } - shall_print = 1; + shall_print = message_filter_matching(device_name_end+1); + if (!shall_print) { + break; } /* process name */ @@ -235,39 +299,10 @@ static void syslog_callback(char c, void *user_data) proc_name_end = p; p++; - int proc_matched = 0; - if (num_pid_filters > 0) { - char* endp = NULL; - int pid_value = (int)strtol(pid_start, &endp, 10); - if (endp && (*endp == ']')) { - int found = proc_filter_excluding; - int i = 0; - for (i = 0; i < num_pid_filters; i++) { - if (pid_value == pid_filters[i]) { - found = !proc_filter_excluding; - break; - } - } - if (found) { - proc_matched = 1; - } - } - } - if (num_proc_filters > 0 && !proc_matched) { - int found = proc_filter_excluding; - int i = 0; - for (i = 0; i < num_proc_filters; i++) { - if (!proc_filters[i]) continue; - if (strncmp(proc_filters[i], process_name_start, process_name_end-process_name_start) == 0) { - found = !proc_filter_excluding; - break; - } - } - if (found) { - proc_matched = 1; - } - } - if (proc_matched) { + /* match pid / process name */ + char* endp = NULL; + int pid_value = (int)strtol(pid_start, &endp, 10); + if (process_filter_matching(pid_value, process_name_start, process_name_end-process_name_start)) { shall_print = 1; } else { if (num_pid_filters > 0 || num_proc_filters > 0) { @@ -282,35 +317,35 @@ static void syslog_callback(char c, void *user_data) const char* level_color = NULL; if (!strncmp(p, "<Notice>:", 9)) { level_end += 9; - level_color = COLOR_GREEN; + level_color = FG_GREEN; } else if (!strncmp(p, "<Error>:", 8)) { level_end += 8; - level_color = COLOR_RED; + level_color = FG_RED; } else if (!strncmp(p, "<Warning>:", 10)) { level_end += 10; - level_color = COLOR_YELLOW; + level_color = FG_YELLOW; } else if (!strncmp(p, "<Debug>:", 8)) { level_end += 8; - level_color = COLOR_MAGENTA; + level_color = FG_MAGENTA; } else { - level_color = COLOR_WHITE; + level_color = FG_WHITE; } /* write date and time */ - cprintf(COLOR_LIGHT_GRAY); + cprintf(FG_LIGHT_GRAY); fwrite(line, 1, 16, stdout); if (show_device_name) { /* write device name */ - cprintf(COLOR_DARK_YELLOW); + cprintf(FG_DARK_YELLOW); fwrite(device_name_start, 1, device_name_end-device_name_start+1, stdout); cprintf(COLOR_RESET); } /* write process name */ - cprintf(COLOR_BRIGHT_CYAN); + cprintf(FG_BRIGHT_CYAN); fwrite(process_name_start, 1, process_name_end-process_name_start, stdout); - cprintf(COLOR_CYAN); + cprintf(FG_CYAN); fwrite(process_name_end, 1, proc_name_end-process_name_end+1, stdout); /* write log level */ @@ -323,15 +358,15 @@ static void syslog_callback(char c, void *user_data) lp -= p - linep; linep = p; - cprintf(COLOR_WHITE); + cprintf(FG_WHITE); } else { shall_print = 1; - cprintf(COLOR_WHITE); + cprintf(FG_WHITE); } } while (0); - if ((num_msg_filters == 0 && num_proc_filters == 0 && num_pid_filters == 0 && num_trigger_filters == 0 && num_untrigger_filters == 0) || shall_print) { + if ((num_msg_filters == 0 && num_msg_reverse_filters == 0 && num_proc_filters == 0 && num_pid_filters == 0 && num_trigger_filters == 0 && num_untrigger_filters == 0) || shall_print) { fwrite(linep, 1, lp, stdout); cprintf(COLOR_RESET); fflush(stdout); @@ -345,12 +380,231 @@ static void syslog_callback(char c, void *user_data) } } -static int start_logging(void) +static void ostrace_syslog_callback(const void* buf, size_t len, void* user_data) { - idevice_error_t ret = idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX); - if (ret != IDEVICE_E_SUCCESS) { - fprintf(stderr, "Device with udid %s not found!?\n", udid); - return -1; + if (len < 0x81) { + fprintf(stderr, "Error: not enough data in callback function?!\n"); + return; + } + + struct ostrace_packet_header_t *trace_hdr = (struct ostrace_packet_header_t*)buf; + + if (trace_hdr->marker != 2 || (trace_hdr->type != 8 && trace_hdr->type != 2)) { + fprintf(stderr, "unexpected packet data %02x %08x\n", trace_hdr->marker, trace_hdr->type); + } + + const char* dataptr = (const char*)buf + trace_hdr->header_size; + const char* process_name = dataptr; + const char* image_name = (trace_hdr->imagepath_len > 0) ? dataptr + trace_hdr->procpath_len : NULL; + const char* message = (trace_hdr->message_len > 0) ? dataptr + trace_hdr->procpath_len + trace_hdr->imagepath_len : NULL; + //const char* subsystem = (trace_hdr->subsystem_len > 0) ? dataptr + trace_hdr->procpath_len + trace_hdr->imagepath_len + trace_hdr->message_len : NULL; + //const char* category = (trace_hdr->category_len > 0) ? dataptr + trace_hdr->procpath_len + trace_hdr->imagepath_len + trace_hdr->message_len + trace_hdr->subsystem_len : NULL; + + int shall_print = 1; + int trigger_off = 0; + const char* process_name_short = (process_name) ? strrchr(process_name, '/') : ""; + process_name_short = (process_name_short) ? process_name_short+1 : process_name; + const char* image_name_short = (image_name) ? strrchr(image_name, '/') : NULL; + image_name_short = (image_name_short) ? image_name_short+1 : process_name; + if (image_name_short && !strcmp(image_name_short, process_name_short)) { + image_name_short = NULL; + } + + do { + /* check if we have any triggers/untriggers */ + if (num_untrigger_filters > 0 && triggered) { + int found = 0; + int i; + for (i = 0; i < num_untrigger_filters; i++) { + if (strstr(message, untrigger_filters[i])) { + found = 1; + break; + } + } + if (!found) { + shall_print = 1; + } else { + shall_print = 1; + trigger_off = 1; + } + } else if (num_trigger_filters > 0 && !triggered) { + int found = 0; + int i; + for (i = 0; i < num_trigger_filters; i++) { + if (strstr(message, trigger_filters[i])) { + found = 1; + break; + } + } + if (!found) { + shall_print = 0; + break; + } + triggered = 1; + shall_print = 1; + } else if (num_trigger_filters == 0 && num_untrigger_filters > 0 && !triggered) { + shall_print = 0; + quit_flag++; + break; + } + + /* check message filters */ + shall_print = message_filter_matching(message); + if (!shall_print) { + break; + } + + /* check process filters */ + if (process_filter_matching(trace_hdr->pid, process_name_short, strlen(process_name_short))) { + shall_print = 1; + } else { + if (num_pid_filters > 0 || num_proc_filters > 0) { + shall_print = 0; + } + } + if (!shall_print) { + break; + } + } while (0); + + if (!shall_print) { + return; + } + + const char* level_str = "Unknown"; + const char* level_color = FG_YELLOW; + switch (trace_hdr->level) { + case 0: + level_str = "Notice"; + level_color = FG_GREEN; + break; + case 0x01: + level_str = "Info"; + level_color = FG_WHITE; + break; + case 0x02: + level_str = "Debug"; + level_color = FG_MAGENTA; + break; + case 0x10: + level_str = "Error"; + level_color = FG_RED; + break; + case 0x11: + level_str = "Fault"; + level_color = FG_RED; + default: + break; + } + + char datebuf[24]; + struct tm *tp; + time_t time_sec = (time_t)trace_hdr->time_sec; +#ifdef HAVE_LOCALTIME_R + struct tm tp_ = {0, }; + tp = localtime_r(&time_sec, &tp_); +#else + tp = localtime(&time_sec); +#endif +#ifdef _WIN32 + strftime(datebuf, 16, "%b %#d %H:%M:%S", tp); +#else + strftime(datebuf, 16, "%b %e %H:%M:%S", tp); +#endif + snprintf(datebuf+15, 9, ".%06u", trace_hdr->time_usec); + + /* write date and time */ + cprintf(FG_LIGHT_GRAY "%s ", datebuf); + + if (show_device_name) { + /* write device name TODO do we need this? */ + //cprintf(FG_DARK_YELLOW "%s ", device_name); + } + + /* write process name */ + cprintf(FG_BRIGHT_CYAN "%s" FG_CYAN, process_name_short); + if (image_name_short) { + cprintf("(%s)", image_name_short); + } + cprintf("[%d]" COLOR_RESET " ", trace_hdr->pid); + + /* write log level */ + cprintf(level_color); + cprintf("<%s>:" COLOR_RESET " ", level_str); + + /* write message */ + cprintf(FG_WHITE); + cprintf("%s" COLOR_RESET "\n", message); + fflush(stdout); + + if (trigger_off) { + triggered = 0; + } +} + +static plist_t get_pid_list() +{ + plist_t list = NULL; + ostrace_client_t ostrace_tmp = NULL; + ostrace_client_start_service(device, &ostrace_tmp, TOOL_NAME); + if (ostrace_tmp) { + ostrace_get_pid_list(ostrace_tmp, &list); + ostrace_client_free(ostrace_tmp); + } + return list; +} + +static int pid_valid(int pid) +{ + plist_t list = get_pid_list(); + if (!list) return 0; + char valbuf[16]; + snprintf(valbuf, 16, "%d", pid); + return (plist_dict_get_item(list, valbuf)) ? 1 : 0; +} + +static int pid_for_proc(const char* procname) +{ + int result = -1; + plist_t list = get_pid_list(); + if (!list) { + return result; + } + plist_dict_iter iter = NULL; + plist_dict_new_iter(list, &iter); + if (iter) { + plist_t node = NULL; + do { + char* key = NULL; + node = NULL; + plist_dict_next_item(list, iter, &key, &node); + if (!key) { + break; + } + if (PLIST_IS_DICT(node)) { + plist_t pname = plist_dict_get_item(node, "ProcessName"); + if (PLIST_IS_STRING(pname)) { + if (!strcmp(plist_get_string_ptr(pname, NULL), procname)) { + result = (int)strtol(key, NULL, 10); + } + } + } + free(key); + } while (node); + plist_mem_free(iter); + } + plist_free(list); + return result; +} + +static int connect_service(int ostrace_required) +{ + if (!device) { + idevice_error_t ret = idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX); + if (ret != IDEVICE_E_SUCCESS) { + fprintf(stderr, "Device with udid %s not found!?\n", udid); + return -1; + } } lockdownd_client_t lockdown = NULL; @@ -361,14 +615,28 @@ static int start_logging(void) device = NULL; return -1; } - - /* start syslog_relay service */ lockdownd_service_descriptor_t svc = NULL; - lerr = lockdownd_start_service(lockdown, SYSLOG_RELAY_SERVICE_NAME, &svc); + + const char* service_name = OSTRACE_SERVICE_NAME; + int use_ostrace = 1; + if (idevice_get_device_version(device) < IDEVICE_DEVICE_VERSION(9,0,0) || force_syslog_relay) { + service_name = SYSLOG_RELAY_SERVICE_NAME; + use_ostrace = 0; + } + if (ostrace_required && !use_ostrace) { + fprintf(stderr, "ERROR: This operation requires iOS 9 or later.\n"); + lockdownd_client_free(lockdown); + idevice_free(device); + device = NULL; + return -1; + } + + /* start syslog_relay/os_trace_relay service */ + lerr = lockdownd_start_service(lockdown, service_name, &svc); if (lerr == LOCKDOWN_E_PASSWORD_PROTECTED) { fprintf(stderr, "*** Device is passcode protected, enter passcode on the device to continue ***\n"); while (!quit_flag) { - lerr = lockdownd_start_service(lockdown, SYSLOG_RELAY_SERVICE_NAME, &svc); + lerr = lockdownd_start_service(lockdown, service_name, &svc); if (lerr != LOCKDOWN_E_PASSWORD_PROTECTED) { break; } @@ -376,32 +644,84 @@ static int start_logging(void) } } if (lerr != LOCKDOWN_E_SUCCESS) { - fprintf(stderr, "ERROR: Could not connect to lockdownd: %d\n", lerr); + fprintf(stderr, "ERROR: Could not start %s service: %s (%d)\n", service_name, lockdownd_strerror(lerr), lerr); idevice_free(device); device = NULL; return -1; } lockdownd_client_free(lockdown); - /* connect to syslog_relay service */ - syslog_relay_error_t serr = SYSLOG_RELAY_E_UNKNOWN_ERROR; - serr = syslog_relay_client_new(device, svc, &syslog); - lockdownd_service_descriptor_free(svc); - if (serr != SYSLOG_RELAY_E_SUCCESS) { - fprintf(stderr, "ERROR: Could not start service com.apple.syslog_relay.\n"); - idevice_free(device); - device = NULL; + if (use_ostrace) { + /* connect to os_trace_relay service */ + ostrace_error_t serr = OSTRACE_E_UNKNOWN_ERROR; + serr = ostrace_client_new(device, svc, &ostrace); + lockdownd_service_descriptor_free(svc); + if (serr != OSTRACE_E_SUCCESS) { + fprintf(stderr, "ERROR: Could not connect to %s service (%d)\n", service_name, serr); + idevice_free(device); + device = NULL; + return -1; + } + } else { + /* connect to syslog_relay service */ + syslog_relay_error_t serr = SYSLOG_RELAY_E_UNKNOWN_ERROR; + serr = syslog_relay_client_new(device, svc, &syslog); + lockdownd_service_descriptor_free(svc); + if (serr != SYSLOG_RELAY_E_SUCCESS) { + fprintf(stderr, "ERROR: Could not connect to %s service (%d)\n", service_name, serr); + idevice_free(device); + device = NULL; + return -1; + } + } + return 0; +} + +static int start_logging(void) +{ + if (connect_service(0) < 0) { return -1; } /* start capturing syslog */ - serr = syslog_relay_start_capture_raw(syslog, syslog_callback, NULL); - if (serr != SYSLOG_RELAY_E_SUCCESS) { - fprintf(stderr, "ERROR: Unable tot start capturing syslog.\n"); - syslog_relay_client_free(syslog); - syslog = NULL; - idevice_free(device); - device = NULL; + if (ostrace) { + plist_t options = plist_new_dict(); + if (num_proc_filters == 0 && num_pid_filters == 1 && !proc_filter_excluding) { + if (pid_filters[0] > 0) { + if (!pid_valid(pid_filters[0])) { + fprintf(stderr, "NOTE: A process with pid doesn't exists!\n"); + } + } + plist_dict_set_item(options, "Pid", plist_new_int(pid_filters[0])); + } else if (num_proc_filters == 1 && num_pid_filters == 0 && !proc_filter_excluding) { + int pid = pid_for_proc(proc_filters[0]); + if (!strcmp(proc_filters[0], "kernel")) { + pid = 0; + } + if (pid >= 0) { + plist_dict_set_item(options, "Pid", plist_new_int(pid)); + } + } + ostrace_error_t serr = ostrace_start_activity(ostrace, options, ostrace_syslog_callback, NULL); + if (serr != OSTRACE_E_SUCCESS) { + fprintf(stderr, "ERROR: Unable to start capturing syslog.\n"); + ostrace_client_free(ostrace); + ostrace = NULL; + idevice_free(device); + device = NULL; + return -1; + } + } else if (syslog) { + syslog_relay_error_t serr = syslog_relay_start_capture_raw(syslog, syslog_callback, NULL); + if (serr != SYSLOG_RELAY_E_SUCCESS) { + fprintf(stderr, "ERROR: Unable to start capturing syslog.\n"); + syslog_relay_client_free(syslog); + syslog = NULL; + idevice_free(device); + device = NULL; + return -1; + } + } else { return -1; } @@ -419,6 +739,11 @@ static void stop_logging(void) syslog_relay_client_free(syslog); syslog = NULL; } + if (ostrace) { + ostrace_stop_activity(ostrace); + ostrace_client_free(ostrace); + ostrace = NULL; + } if (device) { idevice_free(device); @@ -426,6 +751,77 @@ static void stop_logging(void) } } +static int write_callback(const void* buf, size_t len, void *user_data) +{ + FILE* f = (FILE*)user_data; + ssize_t res = fwrite(buf, 1, len, f); + if (res < 0) { + return -1; + } + if (quit_flag > 0) { + return -1; + } + return 0; +} + +static void print_sorted_pidlist(plist_t list) +{ + struct listelem; + struct listelem { + int val; + struct listelem *next; + }; + struct listelem* sortedlist = NULL; + + plist_dict_iter iter = NULL; + plist_dict_new_iter(list, &iter); + if (iter) { + plist_t node = NULL; + do { + char* key = NULL; + node = NULL; + plist_dict_next_item(list, iter, &key, &node); + if (key) { + int pidval = (int)strtol(key, NULL, 10); + struct listelem* elem = (struct listelem*)malloc(sizeof(struct listelem)); + elem->val = pidval; + elem->next = NULL; + struct listelem* prev = NULL; + struct listelem* curr = sortedlist; + + while (curr && pidval > curr->val) { + prev = curr; + curr = curr->next; + } + + elem->next = curr; + if (prev == NULL) { + sortedlist = elem; + } else { + prev->next = elem; + } + free(key); + } + } while (node); + plist_mem_free(iter); + } + struct listelem *listp = sortedlist; + char pidstr[16]; + while (listp) { + snprintf(pidstr, 16, "%d", listp->val); + plist_t node = plist_dict_get_item(list, pidstr); + if (PLIST_IS_DICT(node)) { + plist_t pname = plist_dict_get_item(node, "ProcessName"); + if (PLIST_IS_STRING(pname)) { + printf("%d %s\n", listp->val, plist_get_string_ptr(pname, NULL)); + } + } + struct listelem *curr = listp; + listp = listp->next; + free(curr); + } +} + static void device_event_cb(const idevice_event_t* event, void* userdata) { if (use_network && event->conn_type != CONNECTION_NETWORK) { @@ -435,7 +831,7 @@ static void device_event_cb(const idevice_event_t* event, void* userdata) return; } if (event->event == IDEVICE_DEVICE_ADD) { - if (!syslog) { + if (!syslog && !ostrace) { if (!udid) { udid = strdup(event->udid); } @@ -446,7 +842,7 @@ static void device_event_cb(const idevice_event_t* event, void* userdata) } } } else if (event->event == IDEVICE_DEVICE_REMOVE) { - if (syslog && (strcmp(udid, event->udid) == 0)) { + if ((syslog || ostrace) && (strcmp(udid, event->udid) == 0)) { stop_logging(); fprintf(stdout, "[disconnected:%s]\n", udid); if (exit_on_disconnect) { @@ -480,10 +876,24 @@ static void print_usage(int argc, char **argv, int is_error) " -h, --help prints usage information\n" " -d, --debug enable communication debugging\n" " -v, --version prints version information\n" - " --no-colors disable colored output\n" + " --no-colors disable colored output\n" + " -o, --output FILE write to FILE instead of stdout\n" + " (existing FILE will be overwritten)\n" + " --colors force writing colored output, e.g. for --output\n" + " --syslog-relay force use of syslog_relay service\n" + "\n" + "COMMANDS:\n" + " pidlist Print pid and name of all running processes.\n" + " archive PATH Request a logarchive and write it to PATH.\n" + " Output can be piped to another process using - as PATH.\n" + " The file data will be in .tar format.\n" + " --start-time VALUE start time of the log data as UNIX timestamp\n" + " --age-limit VALUE maximum age of the log data\n" + " --size-limit VALUE limit the size of the archive\n" "\n" "FILTER OPTIONS:\n" " -m, --match STRING only print messages that contain STRING\n" + " -M, --unmatch STRING print messages that not contain STRING\n" " -t, --trigger STRING start logging when matching STRING\n" " -T, --untrigger STRING stop logging when matching STRING\n" " -p, --process PROCESS only print messages from matching process(es)\n" @@ -508,6 +918,7 @@ int main(int argc, char *argv[]) int exclude_filter = 0; int include_kernel = 0; int exclude_kernel = 0; + int force_colors = 0; int c = 0; const struct option longopts[] = { { "debug", no_argument, NULL, 'd' }, @@ -525,18 +936,26 @@ int main(int argc, char *argv[]) { "no-kernel", no_argument, NULL, 'K' }, { "quiet-list", no_argument, NULL, 1 }, { "no-colors", no_argument, NULL, 2 }, + { "colors", no_argument, NULL, 3 }, + { "syslog_relay", no_argument, NULL, 4 }, + { "syslog-relay", no_argument, NULL, 4 }, + { "legacy", no_argument, NULL, 4 }, + { "start-time", required_argument, NULL, 5 }, + { "size-limit", required_argument, NULL, 6 }, + { "age-limit", required_argument, NULL, 7 }, + { "output", required_argument, NULL, 'o' }, { "version", no_argument, NULL, 'v' }, { NULL, 0, NULL, 0} }; signal(SIGINT, clean_exit); signal(SIGTERM, clean_exit); -#ifndef WIN32 +#ifndef _WIN32 signal(SIGQUIT, clean_exit); signal(SIGPIPE, SIG_IGN); #endif - while ((c = getopt_long(argc, argv, "dhu:nxt:T:m:e:p:qkKv", longopts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "dhu:nxt:T:m:M:e:p:qkKo:v", longopts, NULL)) != -1) { switch (c) { case 'd': idevice_set_debug_level(1); @@ -587,6 +1006,22 @@ int main(int argc, char *argv[]) num_msg_filters++; } break; + case 'M': + if (!*optarg) { + fprintf(stderr, "ERROR: reverse message filter string must not be empty!\n"); + print_usage(argc, argv, 1); + return 2; + } else { + char **new_msg_filters = realloc(msg_reverse_filters, sizeof(char*) * (num_msg_reverse_filters+1)); + if (!new_msg_filters) { + fprintf(stderr, "ERROR: realloc() failed\n"); + exit(EXIT_FAILURE); + } + msg_reverse_filters = new_msg_filters; + msg_reverse_filters[num_msg_reverse_filters] = strdup(optarg); + num_msg_reverse_filters++; + } + break; case 't': if (!*optarg) { fprintf(stderr, "ERROR: trigger filter string must not be empty!\n"); @@ -638,6 +1073,34 @@ int main(int argc, char *argv[]) case 2: term_colors_set_enabled(0); break; + case 3: + force_colors = 1; + break; + case 4: + force_syslog_relay = 1; + break; + case 5: + start_time = strtoll(optarg, NULL, 10); + break; + case 6: + size_limit = strtoll(optarg, NULL, 10); + break; + case 7: + age_limit = strtoll(optarg, NULL, 10); + break; + case 'o': + if (!*optarg) { + fprintf(stderr, "ERROR: --output option requires an argument!\n"); + print_usage(argc, argv, 1); + return 2; + } else { + if (freopen(optarg, "w", stdout) == NULL) { + fprintf(stderr, "ERROR: Failed to open output file '%s' for writing: %s\n", optarg, strerror(errno)); + return 1; + } + term_colors_set_enabled(0); + } + break; case 'v': printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION); return 0; @@ -647,6 +1110,10 @@ int main(int argc, char *argv[]) } } + if (force_colors) { + term_colors_set_enabled(1); + } + if (include_kernel > 0 && exclude_kernel > 0) { fprintf(stderr, "ERROR: -k and -K cannot be used together.\n"); print_usage(argc, argv, 1); @@ -693,14 +1160,92 @@ int main(int argc, char *argv[]) argc -= optind; argv += optind; + if (argc > 0) { + if (!strcmp(argv[0], "pidlist")) { + if (connect_service(1) < 0) { + return 1; + } + plist_t list = NULL; + ostrace_get_pid_list(ostrace, &list); + ostrace_client_free(ostrace); + ostrace = NULL; + idevice_free(device); + device = NULL; + if (!list) { + return 1; + } + print_sorted_pidlist(list); + plist_free(list); + return 0; + } else if (!strcmp(argv[0], "archive")) { + if (force_syslog_relay) { + force_syslog_relay = 0; + } + if (argc < 2) { + fprintf(stderr, "Please specify an output filename.\n"); + return 1; + } + FILE* outf = NULL; + if (!strcmp(argv[1], "-")) { + if (isatty(1)) { + fprintf(stderr, "Refusing to directly write to stdout. Pipe the output to another process.\n"); + return 1; + } + outf = stdout; + } else { + outf = fopen(argv[1], "w"); + } + if (!outf) { + fprintf(stderr, "Failed to open %s: %s\n", argv[1], strerror(errno)); + return 1; + } + if (connect_service(1) < 0) { + if (outf != stdout) { + fclose(outf); + } + return 1; + } + plist_t options = plist_new_dict(); + if (start_time > 0) { + plist_dict_set_item(options, "StartTime", plist_new_int(start_time)); + } + if (size_limit > 0) { + plist_dict_set_item(options, "SizeLimit", plist_new_int(size_limit)); + } + if (age_limit > 0) { + plist_dict_set_item(options, "AgeLimit", plist_new_int(age_limit)); + } + ostrace_create_archive(ostrace, options, write_callback, outf); + ostrace_client_free(ostrace); + ostrace = NULL; + idevice_free(device); + device = NULL; + if (outf != stdout) { + fclose(outf); + } + return 0; + } else { + fprintf(stderr, "Unknown command '%s'. See --help for valid commands.\n", argv[0]); + return 1; + } + } + int num = 0; idevice_info_t *devices = NULL; idevice_get_device_list_extended(&devices, &num); + int count = 0; + for (int i = 0; i < num; i++) { + if (devices[i]->conn_type == CONNECTION_NETWORK && use_network) { + count++; + } else if (devices[i]->conn_type == CONNECTION_USBMUXD) { + count++; + } + } idevice_device_list_extended_free(devices); - if (num == 0) { + if (count == 0) { if (!udid) { - fprintf(stderr, "No device found. Plug in a device or pass UDID with -u to wait for device to be available.\n"); - return -1; + fprintf(stderr, "No device found. Plug in a device or pass UDID with -u to wait for device to become available.\n"); + return 1; } fprintf(stderr, "Waiting for device with UDID %s to become available...\n", udid); @@ -735,6 +1280,13 @@ int main(int argc, char *argv[]) } free(msg_filters); } + if (num_msg_reverse_filters > 0) { + int i; + for (i = 0; i < num_msg_reverse_filters; i++) { + free(msg_reverse_filters[i]); + } + free(msg_reverse_filters); + } if (num_trigger_filters > 0) { int i; for (i = 0; i < num_trigger_filters; i++) { |