summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitattributes1
-rw-r--r--.github/workflows/build.yml239
-rw-r--r--3rd_party/Makefile.am6
-rw-r--r--3rd_party/README.md36
-rw-r--r--3rd_party/ed25519/LICENSE16
-rw-r--r--3rd_party/ed25519/Makefile.am26
-rw-r--r--3rd_party/ed25519/README.md165
-rw-r--r--3rd_party/ed25519/add_scalar.c69
-rw-r--r--3rd_party/ed25519/ed25519.h38
-rw-r--r--3rd_party/ed25519/fe.c1491
-rw-r--r--3rd_party/ed25519/fe.h41
-rw-r--r--3rd_party/ed25519/fixedint.h72
-rw-r--r--3rd_party/ed25519/ge.c467
-rw-r--r--3rd_party/ed25519/ge.h74
-rw-r--r--3rd_party/ed25519/key_exchange.c79
-rw-r--r--3rd_party/ed25519/keypair.c16
-rw-r--r--3rd_party/ed25519/precomp_data.h1391
-rw-r--r--3rd_party/ed25519/sc.c809
-rw-r--r--3rd_party/ed25519/sc.h12
-rw-r--r--3rd_party/ed25519/seed.c40
-rw-r--r--3rd_party/ed25519/sha512.c275
-rw-r--r--3rd_party/ed25519/sha512.h21
-rw-r--r--3rd_party/ed25519/sign.c31
-rw-r--r--3rd_party/ed25519/verify.c77
-rw-r--r--3rd_party/libsrp6a-sha512/LICENSE62
-rw-r--r--3rd_party/libsrp6a-sha512/Makefile.am31
-rw-r--r--3rd_party/libsrp6a-sha512/README.md35
-rw-r--r--3rd_party/libsrp6a-sha512/cstr.c226
-rw-r--r--3rd_party/libsrp6a-sha512/cstr.h94
-rw-r--r--3rd_party/libsrp6a-sha512/srp.c274
-rw-r--r--3rd_party/libsrp6a-sha512/srp.h372
-rw-r--r--3rd_party/libsrp6a-sha512/srp6a_sha512_client.c363
-rw-r--r--3rd_party/libsrp6a-sha512/srp_aux.h146
-rw-r--r--3rd_party/libsrp6a-sha512/t_conv.c239
-rw-r--r--3rd_party/libsrp6a-sha512/t_defines.h137
-rw-r--r--3rd_party/libsrp6a-sha512/t_math.c964
-rw-r--r--3rd_party/libsrp6a-sha512/t_misc.c439
-rw-r--r--3rd_party/libsrp6a-sha512/t_pwd.h246
-rw-r--r--3rd_party/libsrp6a-sha512/t_sha.c314
-rw-r--r--3rd_party/libsrp6a-sha512/t_sha.h147
-rw-r--r--3rd_party/libsrp6a-sha512/t_truerand.c241
-rw-r--r--Makefile.am8
-rw-r--r--README.md27
-rw-r--r--common/Makefile.am18
-rw-r--r--common/debug.c8
-rw-r--r--common/socket.c1171
-rw-r--r--common/socket.h68
-rw-r--r--common/thread.c140
-rw-r--r--common/thread.h76
-rw-r--r--common/userpref.c381
-rw-r--r--common/userpref.h13
-rw-r--r--common/utils.c530
-rw-r--r--common/utils.h64
-rw-r--r--configure.ac227
-rw-r--r--cython/Makefile.am16
-rw-r--r--cython/imobiledevice.pxd3
-rw-r--r--cython/imobiledevice.pyx2
-rw-r--r--cython/installation_proxy.pxi2
-rw-r--r--cython/lockdown.pxi20
-rw-r--r--cython/notification_proxy.pxi2
-rw-r--r--docs/Makefile.am2
-rw-r--r--docs/afcclient.176
-rw-r--r--docs/idevicebackup.12
-rw-r--r--docs/idevicebackup2.122
-rw-r--r--docs/idevicebtlogger.160
-rw-r--r--docs/idevicecrashreport.13
-rw-r--r--docs/idevicedebugserverproxy.16
-rw-r--r--docs/idevicedevmodectl.158
-rw-r--r--docs/idevicepair.126
-rw-r--r--docs/idevicesyslog.19
-rw-r--r--doxygen.cfg.in62
-rwxr-xr-xgit-version-gen20
-rw-r--r--include/Makefile.am1
-rw-r--r--include/asprintf.h2
-rw-r--r--include/endianness.h23
-rw-r--r--include/libimobiledevice/afc.h58
-rw-r--r--include/libimobiledevice/bt_packet_logger.h156
-rw-r--r--include/libimobiledevice/companion_proxy.h30
-rw-r--r--include/libimobiledevice/debugserver.h58
-rw-r--r--include/libimobiledevice/diagnostics_relay.h85
-rw-r--r--include/libimobiledevice/file_relay.h17
-rw-r--r--include/libimobiledevice/heartbeat.h17
-rw-r--r--include/libimobiledevice/house_arrest.h17
-rw-r--r--include/libimobiledevice/installation_proxy.h57
-rw-r--r--include/libimobiledevice/libimobiledevice.h131
-rw-r--r--include/libimobiledevice/lockdown.h170
-rw-r--r--include/libimobiledevice/misagent.h19
-rw-r--r--include/libimobiledevice/mobile_image_mounter.h17
-rw-r--r--include/libimobiledevice/mobileactivation.h25
-rw-r--r--include/libimobiledevice/mobilebackup.h28
-rw-r--r--include/libimobiledevice/mobilebackup2.h25
-rw-r--r--include/libimobiledevice/mobilesync.h53
-rw-r--r--include/libimobiledevice/notification_proxy.h32
-rw-r--r--include/libimobiledevice/preboard.h24
-rw-r--r--include/libimobiledevice/property_list_service.h40
-rw-r--r--include/libimobiledevice/restore.h24
-rw-r--r--include/libimobiledevice/reverse_proxy.h213
-rw-r--r--include/libimobiledevice/sbservices.h23
-rw-r--r--include/libimobiledevice/screenshotr.h11
-rw-r--r--include/libimobiledevice/service.h42
-rw-r--r--include/libimobiledevice/syslog_relay.h20
-rw-r--r--include/libimobiledevice/webinspector.h17
-rw-r--r--m4/ac_pkg_cython.m44
-rw-r--r--m4/as-compiler-flag.m44
-rw-r--r--m4/ax_pthread.m4255
-rw-r--r--src/Makefile.am32
-rw-r--r--src/afc.c203
-rw-r--r--src/afc.h2
-rw-r--r--src/bt_packet_logger.c231
-rw-r--r--src/bt_packet_logger.h37
-rw-r--r--src/companion_proxy.c25
-rw-r--r--src/companion_proxy.h3
-rw-r--r--src/debugserver.c264
-rw-r--r--src/debugserver.h3
-rw-r--r--src/device_link_service.c8
-rw-r--r--src/device_link_service.h1
-rw-r--r--src/diagnostics_relay.c31
-rw-r--r--src/diagnostics_relay.h1
-rw-r--r--src/file_relay.c12
-rw-r--r--src/file_relay.h1
-rw-r--r--src/heartbeat.c12
-rw-r--r--src/heartbeat.h1
-rw-r--r--src/house_arrest.c14
-rw-r--r--src/house_arrest.h1
-rw-r--r--src/idevice.c752
-rw-r--r--src/idevice.h45
-rw-r--r--src/installation_proxy.c80
-rw-r--r--src/installation_proxy.h3
-rw-r--r--src/libimobiledevice-1.0.pc.in2
-rw-r--r--src/lockdown-cu.c1193
-rw-r--r--src/lockdown.c225
-rw-r--r--src/lockdown.h8
-rw-r--r--src/misagent.c19
-rw-r--r--src/misagent.h1
-rw-r--r--src/mobile_image_mounter.c14
-rw-r--r--src/mobile_image_mounter.h3
-rw-r--r--src/mobileactivation.c35
-rw-r--r--src/mobileactivation.h1
-rw-r--r--src/mobilebackup.c47
-rw-r--r--src/mobilebackup.h1
-rw-r--r--src/mobilebackup2.c31
-rw-r--r--src/mobilebackup2.h1
-rw-r--r--src/mobilesync.c46
-rw-r--r--src/mobilesync.h1
-rw-r--r--src/notification_proxy.c14
-rw-r--r--src/notification_proxy.h3
-rw-r--r--src/preboard.c19
-rw-r--r--src/preboard.h3
-rw-r--r--src/property_list_service.c23
-rw-r--r--src/property_list_service.h1
-rw-r--r--src/restore.c40
-rw-r--r--src/restore.h1
-rw-r--r--src/reverse_proxy.c810
-rw-r--r--src/reverse_proxy.h51
-rw-r--r--src/sbservices.c21
-rw-r--r--src/sbservices.h3
-rw-r--r--src/screenshotr.c10
-rw-r--r--src/screenshotr.h1
-rw-r--r--src/service.c31
-rw-r--r--src/service.h2
-rw-r--r--src/syslog_relay.c25
-rw-r--r--src/syslog_relay.h3
-rw-r--r--src/webinspector.c12
-rw-r--r--src/webinspector.h1
-rw-r--r--tools/Makefile.am79
-rw-r--r--tools/afcclient.c1346
-rw-r--r--tools/idevice_id.c27
-rw-r--r--tools/idevicebackup.c368
-rw-r--r--tools/idevicebackup2.c538
-rw-r--r--tools/idevicebtlogger.c458
-rw-r--r--tools/idevicecrashreport.c172
-rw-r--r--tools/idevicedate.c137
-rw-r--r--tools/idevicedebug.c653
-rw-r--r--tools/idevicedebugserverproxy.c338
-rw-r--r--tools/idevicedevmodectl.c462
-rw-r--r--tools/idevicediagnostics.c244
-rw-r--r--tools/ideviceenterrecovery.c99
-rw-r--r--tools/ideviceimagemounter.c101
-rw-r--r--tools/ideviceinfo.c41
-rw-r--r--tools/idevicename.c41
-rw-r--r--tools/idevicenotificationproxy.c182
-rw-r--r--tools/idevicepair.c256
-rw-r--r--tools/ideviceprovision.c257
-rw-r--r--tools/idevicescreenshot.c234
-rw-r--r--tools/idevicesetlocation.c24
-rw-r--r--tools/idevicesyslog.c216
186 files changed, 20016 insertions, 5363 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..176a458
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+* text=auto
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..b740952
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,239 @@
+name: build
+
+on:
+ push:
+ schedule:
+ - cron: '0 0 1 * *'
+
+jobs:
+ build-linux-ubuntu:
+ runs-on: ubuntu-latest
+ steps:
+ - name: install dependencies
+ run: |
+ sudo apt-get update
+ pip install cython
+ - name: prepare environment
+ run: |
+ echo "target_triplet=`gcc -dumpmachine`" >> $GITHUB_ENV
+ - name: fetch libplist
+ uses: dawidd6/action-download-artifact@v2
+ 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
+ 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
+ with:
+ github_token: ${{secrets.GITHUB_TOKEN}}
+ workflow: build.yml
+ name: libimobiledevice-glue-latest_${{env.target_triplet}}
+ repo: libimobiledevice/libimobiledevice-glue
+ - name: install external dependencies
+ run: |
+ mkdir extract
+ for I in *.tar; do
+ tar -C extract -xvf $I
+ done
+ sudo cp -r extract/* /
+ sudo ldconfig
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+ - name: autogen
+ run: ./autogen.sh PKG_CONFIG_PATH=/usr/local/lib/pkgconfig LDFLAGS="-Wl,-rpath=/usr/local/lib" --enable-debug
+ - name: make
+ run: make
+ - name: make install
+ run: sudo make install
+ - name: prepare artifact
+ run: |
+ mkdir -p dest
+ DESTDIR=`pwd`/dest make install
+ tar -C dest -cf libimobiledevice.tar usr
+ - name: publish artifact
+ uses: actions/upload-artifact@v3
+ with:
+ name: libimobiledevice-latest_${{env.target_triplet}}
+ path: libimobiledevice.tar
+ build-macOS:
+ runs-on: macOS-latest
+ steps:
+ - name: install dependencies
+ run: |
+ if test -x "`which port`"; then
+ sudo port install libtool autoconf automake pkgconfig
+ else
+ brew install libtool autoconf automake pkgconfig
+ fi
+ pip3 install cython
+ shell: bash
+ - name: fetch libplist
+ uses: dawidd6/action-download-artifact@v2
+ 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
+ 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
+ with:
+ github_token: ${{secrets.GITHUB_TOKEN}}
+ workflow: build.yml
+ name: libimobiledevice-glue-latest_macOS
+ repo: libimobiledevice/libimobiledevice-glue
+ - name: install external dependencies
+ run: |
+ mkdir extract
+ for I in *.tar; do
+ tar -C extract -xvf $I
+ done
+ sudo cp -r extract/* /
+ - uses: actions/checkout@v3
+ - name: install additional requirements
+ run: |
+ mkdir -p lib
+ curl -o lib/libcrypto.35.tbd -Ls \
+ https://gist.github.com/nikias/94c99fd145a75a5104415e5117b0cafa/raw/5209dfbff5a871a14272afe4794e76eb4cf6f062/libcrypto.35.tbd
+ curl -o lib/libssl.35.tbd -Ls \
+ https://gist.github.com/nikias/94c99fd145a75a5104415e5117b0cafa/raw/5209dfbff5a871a14272afe4794e76eb4cf6f062/libssl.35.tbd
+ echo "LIBSSL=`pwd`/lib/libssl.35.tbd" >> $GITHUB_ENV
+ echo "LIBCRYPTO=`pwd`/lib/libcrypto.35.tbd" >> $GITHUB_ENV
+ LIBRESSL_VER=2.2.7
+ echo "LIBRESSL_VER=$LIBRESSL_VER" >> $GITHUB_ENV
+ FILENAME="libressl-$LIBRESSL_VER.tar.gz"
+ curl -o $FILENAME -Ls "https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/$FILENAME"
+ mkdir -p deps
+ tar -C deps -xzf $FILENAME
+ echo "DEPSDIR=`pwd`/deps" >> $GITHUB_ENV
+ - name: autogen
+ run: |
+ SDKDIR=`xcrun --sdk macosx --show-sdk-path`
+ TESTARCHS="arm64 x86_64"
+ USEARCHS=
+ for ARCH in $TESTARCHS; do
+ if echo "int main(int argc, char **argv) { return 0; }" |clang -arch $ARCH -o /dev/null -isysroot $SDKDIR -x c - 2>/dev/null; then
+ USEARCHS="$USEARCHS -arch $ARCH"
+ fi
+ 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_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 }}"
+ - name: make
+ run: make
+ - name: make install
+ run: sudo make install
+ - name: prepare artifact
+ run: |
+ mkdir -p dest
+ DESTDIR=`pwd`/dest make install
+ tar -C dest -cf libimobiledevice.tar usr
+ - name: publish artifact
+ uses: actions/upload-artifact@v3
+ with:
+ name: libimobiledevice-latest_macOS
+ path: libimobiledevice.tar
+ build-windows:
+ runs-on: windows-2019
+ defaults:
+ run:
+ shell: msys2 {0}
+ strategy:
+ fail-fast: false
+ matrix:
+ include: [
+ { msystem: MINGW64, arch: x86_64 },
+ { msystem: MINGW32, arch: i686 }
+ ]
+ steps:
+ - uses: msys2/setup-msys2@v2
+ with:
+ msystem: ${{ matrix.msystem }}
+ release: false
+ update: false
+ install: >-
+ base-devel
+ git
+ mingw-w64-${{ matrix.arch }}-gcc
+ make
+ libtool
+ autoconf
+ automake-wrapper
+ - name: prepare environment
+ run: |
+ dest=`echo ${{ matrix.msystem }} |tr [:upper:] [:lower:]`
+ echo "dest=$dest" >> $GITHUB_ENV
+ echo "target_triplet=`gcc -dumpmachine`" >> $GITHUB_ENV
+ git config --global core.autocrlf false
+ - name: fetch libplist
+ uses: dawidd6/action-download-artifact@v2
+ 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
+ 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
+ with:
+ github_token: ${{secrets.GITHUB_TOKEN}}
+ workflow: build.yml
+ name: libimobiledevice-glue-latest_${{ matrix.arch }}-${{ env.dest }}
+ repo: libimobiledevice/libimobiledevice-glue
+ - name: install external dependencies
+ run: |
+ mkdir extract
+ for I in *.tar; do
+ tar -C extract -xvf $I
+ done
+ cp -r extract/* /
+ - uses: actions/checkout@v3
+ - name: autogen
+ run: ./autogen.sh CC=gcc CXX=g++ --enable-debug
+ - name: make
+ run: make
+ - name: make install
+ run: make install
+ - name: prepare artifact
+ run: |
+ mkdir -p dest
+ DESTDIR=`pwd`/dest make install
+ tar -C dest -cf libimobiledevice.tar ${{ env.dest }}
+ - name: publish artifact
+ uses: actions/upload-artifact@v3
+ with:
+ name: libimobiledevice-latest_${{ matrix.arch }}-${{ env.dest }}
+ path: libimobiledevice.tar
diff --git a/3rd_party/Makefile.am b/3rd_party/Makefile.am
new file mode 100644
index 0000000..a196ea3
--- /dev/null
+++ b/3rd_party/Makefile.am
@@ -0,0 +1,6 @@
+AUTOMAKE_OPTIONS = foreign
+ACLOCAL_AMFLAGS = -I m4
+SUBDIRS =
+if HAVE_WIRELESS_PAIRING
+SUBDIRS += ed25519 libsrp6a-sha512
+endif
diff --git a/3rd_party/README.md b/3rd_party/README.md
new file mode 100644
index 0000000..0bec640
--- /dev/null
+++ b/3rd_party/README.md
@@ -0,0 +1,36 @@
+# Third party components/libraries
+
+This folder contains third party components or libraries that are used
+within the libimobiledevice project. They have been bundled since they
+are either not readily available on the intended target platforms and/or
+have been modified.
+
+Their respective licenses are provided in each corresponding folder in a
+file called LICENSE.
+
+
+## ed25519
+
+Source: https://github.com/orlp/ed25519
+Based on commit 7fa6712ef5d581a6981ec2b08ee623314cd1d1c4.
+[LICENCE](ed25519/LICENSE)
+
+The original source has not been modified, except that the file `test.c`
+and the contained DLL files have been removed. To allow building within
+libimobiledevice, a `Makefile.am` has been added.
+
+
+## libsrp6a-sha512
+
+Source: https://github.com/secure-remote-password/stanford-srp
+Based on commit 587900d32777348f98477cb25123d5761fbe3725.
+[LICENCE](libsrp6a-sha512/LICENSE)
+
+For the usage within libimobiledevice, only [libsrp](https://github.com/secure-remote-password/stanford-srp/tree/master/libsrp)
+has been used as a basis.
+It has been adapted to the needs of the libimobiledevice project, and
+contains just a part of the original code; it only supports the SRP6a
+client method which has been modified to use SHA512 instead of SHA1,
+hence the name was changed to `libsrp6a-sha512`.
+More details about the modifications can be found in [libsrp6a-sha512/README.md](libsrp6a-sha512/README.md).
+
diff --git a/3rd_party/ed25519/LICENSE b/3rd_party/ed25519/LICENSE
new file mode 100644
index 0000000..c1503f9
--- /dev/null
+++ b/3rd_party/ed25519/LICENSE
@@ -0,0 +1,16 @@
+Copyright (c) 2015 Orson Peters <orsonpeters@gmail.com>
+
+This software is provided 'as-is', without any express or implied warranty. In no event will the
+authors be held liable for any damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, including commercial
+applications, and to alter it and redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the
+ original software. If you use this software in a product, an acknowledgment in the product
+ documentation would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as
+ being the original software.
+
+3. This notice may not be removed or altered from any source distribution.
diff --git a/3rd_party/ed25519/Makefile.am b/3rd_party/ed25519/Makefile.am
new file mode 100644
index 0000000..d8e4e04
--- /dev/null
+++ b/3rd_party/ed25519/Makefile.am
@@ -0,0 +1,26 @@
+AUTOMAKE_OPTIONS = foreign no-dependencies
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)
+
+AM_CFLAGS = \
+ $(GLOBAL_CFLAGS) \
+ $(ssl_lib_CFLAGS)
+
+AM_LDFLAGS =
+
+noinst_LTLIBRARIES = libed25519.la
+libed25519_la_LIBADD =
+libed25519_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined
+libed25519_la_SOURCES = \
+ add_scalar.c \
+ fe.c \
+ ge.c \
+ keypair.c \
+ key_exchange.c \
+ sc.c \
+ seed.c \
+ sign.c \
+ sha512.c \
+ verify.c
diff --git a/3rd_party/ed25519/README.md b/3rd_party/ed25519/README.md
new file mode 100644
index 0000000..2c431c2
--- /dev/null
+++ b/3rd_party/ed25519/README.md
@@ -0,0 +1,165 @@
+Ed25519
+=======
+
+This is a portable implementation of [Ed25519](http://ed25519.cr.yp.to/) based
+on the SUPERCOP "ref10" implementation. Additionally there is key exchanging
+and scalar addition included to further aid building a PKI using Ed25519. All
+code is licensed under the permissive zlib license.
+
+All code is pure ANSI C without any dependencies, except for the random seed
+generation which uses standard OS cryptography APIs (`CryptGenRandom` on
+Windows, `/dev/urandom` on nix). If you wish to be entirely portable define
+`ED25519_NO_SEED`. This disables the `ed25519_create_seed` function, so if your
+application requires key generation you must supply your own seeding function
+(which is simply a 256 bit (32 byte) cryptographic random number generator).
+
+
+Performance
+-----------
+
+On a Windows machine with an Intel Pentium B970 @ 2.3GHz I got the following
+speeds (running on only one a single core):
+
+ Seed generation: 64us (15625 per second)
+ Key generation: 88us (11364 per second)
+ Message signing (short message): 87us (11494 per second)
+ Message verifying (short message): 228us (4386 per second)
+ Scalar addition: 100us (10000 per second)
+ Key exchange: 220us (4545 per second)
+
+The speeds on other machines may vary. Sign/verify times will be higher with
+longer messages. The implementation significantly benefits from 64 bit
+architectures, if possible compile as 64 bit.
+
+
+Usage
+-----
+
+Simply add all .c and .h files in the `src/` folder to your project and include
+`ed25519.h` in any file you want to use the API. If you prefer to use a shared
+library, only copy `ed25519.h` and define `ED25519_DLL` before importing.
+
+There are no defined types for seeds, private keys, public keys, shared secrets
+or signatures. Instead simple `unsigned char` buffers are used with the
+following sizes:
+
+```c
+unsigned char seed[32];
+unsigned char signature[64];
+unsigned char public_key[32];
+unsigned char private_key[64];
+unsigned char scalar[32];
+unsigned char shared_secret[32];
+```
+
+API
+---
+
+```c
+int ed25519_create_seed(unsigned char *seed);
+```
+
+Creates a 32 byte random seed in `seed` for key generation. `seed` must be a
+writable 32 byte buffer. Returns 0 on success, and nonzero on failure.
+
+```c
+void ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key,
+ const unsigned char *seed);
+```
+
+Creates a new key pair from the given seed. `public_key` must be a writable 32
+byte buffer, `private_key` must be a writable 64 byte buffer and `seed` must be
+a 32 byte buffer.
+
+```c
+void ed25519_sign(unsigned char *signature,
+ const unsigned char *message, size_t message_len,
+ const unsigned char *public_key, const unsigned char *private_key);
+```
+
+Creates a signature of the given message with the given key pair. `signature`
+must be a writable 64 byte buffer. `message` must have at least `message_len`
+bytes to be read.
+
+```c
+int ed25519_verify(const unsigned char *signature,
+ const unsigned char *message, size_t message_len,
+ const unsigned char *public_key);
+```
+
+Verifies the signature on the given message using `public_key`. `signature`
+must be a readable 64 byte buffer. `message` must have at least `message_len`
+bytes to be read. Returns 1 if the signature matches, 0 otherwise.
+
+```c
+void ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key,
+ const unsigned char *scalar);
+```
+
+Adds `scalar` to the given key pair where scalar is a 32 byte buffer (possibly
+generated with `ed25519_create_seed`), generating a new key pair. You can
+calculate the public key sum without knowing the private key and vice versa by
+passing in `NULL` for the key you don't know. This is useful for enforcing
+randomness on a key pair by a third party while only knowing the public key,
+among other things. Warning: the last bit of the scalar is ignored - if
+comparing scalars make sure to clear it with `scalar[31] &= 127`.
+
+
+```c
+void ed25519_key_exchange(unsigned char *shared_secret,
+ const unsigned char *public_key, const unsigned char *private_key);
+```
+
+Performs a key exchange on the given public key and private key, producing a
+shared secret. It is recommended to hash the shared secret before using it.
+`shared_secret` must be a 32 byte writable buffer where the shared secret will
+be stored.
+
+Example
+-------
+
+```c
+unsigned char seed[32], public_key[32], private_key[64], signature[64];
+unsigned char other_public_key[32], other_private_key[64], shared_secret[32];
+const unsigned char message[] = "TEST MESSAGE";
+
+/* create a random seed, and a key pair out of that seed */
+if (ed25519_create_seed(seed)) {
+ printf("error while generating seed\n");
+ exit(1);
+}
+
+ed25519_create_keypair(public_key, private_key, seed);
+
+/* create signature on the message with the key pair */
+ed25519_sign(signature, message, strlen(message), public_key, private_key);
+
+/* verify the signature */
+if (ed25519_verify(signature, message, strlen(message), public_key)) {
+ printf("valid signature\n");
+} else {
+ printf("invalid signature\n");
+}
+
+/* create a dummy keypair to use for a key exchange, normally you'd only have
+the public key and receive it through some communication channel */
+if (ed25519_create_seed(seed)) {
+ printf("error while generating seed\n");
+ exit(1);
+}
+
+ed25519_create_keypair(other_public_key, other_private_key, seed);
+
+/* do a key exchange with other_public_key */
+ed25519_key_exchange(shared_secret, other_public_key, private_key);
+
+/*
+ the magic here is that ed25519_key_exchange(shared_secret, public_key,
+ other_private_key); would result in the same shared_secret
+*/
+
+```
+
+License
+-------
+All code is released under the zlib license. See LICENSE for details.
diff --git a/3rd_party/ed25519/add_scalar.c b/3rd_party/ed25519/add_scalar.c
new file mode 100644
index 0000000..7528a7a
--- /dev/null
+++ b/3rd_party/ed25519/add_scalar.c
@@ -0,0 +1,69 @@
+#include "ed25519.h"
+#include "ge.h"
+#include "sc.h"
+#include "sha512.h"
+
+
+/* see http://crypto.stackexchange.com/a/6215/4697 */
+void ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key, const unsigned char *scalar) {
+ const unsigned char SC_1[32] = {1}; /* scalar with value 1 */
+
+ unsigned char n[32];
+ ge_p3 nB;
+ ge_p1p1 A_p1p1;
+ ge_p3 A;
+ ge_p3 public_key_unpacked;
+ ge_cached T;
+
+ sha512_context hash;
+ unsigned char hashbuf[64];
+
+ int i;
+
+ /* copy the scalar and clear highest bit */
+ for (i = 0; i < 31; ++i) {
+ n[i] = scalar[i];
+ }
+ n[31] = scalar[31] & 127;
+
+ /* private key: a = n + t */
+ if (private_key) {
+ sc_muladd(private_key, SC_1, n, private_key);
+
+ // https://github.com/orlp/ed25519/issues/3
+ sha512_init(&hash);
+ sha512_update(&hash, private_key + 32, 32);
+ sha512_update(&hash, scalar, 32);
+ sha512_final(&hash, hashbuf);
+ for (i = 0; i < 32; ++i) {
+ private_key[32 + i] = hashbuf[i];
+ }
+ }
+
+ /* public key: A = nB + T */
+ if (public_key) {
+ /* if we know the private key we don't need a point addition, which is faster */
+ /* using a "timing attack" you could find out wether or not we know the private
+ key, but this information seems rather useless - if this is important pass
+ public_key and private_key seperately in 2 function calls */
+ if (private_key) {
+ ge_scalarmult_base(&A, private_key);
+ } else {
+ /* unpack public key into T */
+ ge_frombytes_negate_vartime(&public_key_unpacked, public_key);
+ fe_neg(public_key_unpacked.X, public_key_unpacked.X); /* undo negate */
+ fe_neg(public_key_unpacked.T, public_key_unpacked.T); /* undo negate */
+ ge_p3_to_cached(&T, &public_key_unpacked);
+
+ /* calculate n*B */
+ ge_scalarmult_base(&nB, n);
+
+ /* A = n*B + T */
+ ge_add(&A_p1p1, &nB, &T);
+ ge_p1p1_to_p3(&A, &A_p1p1);
+ }
+
+ /* pack public key */
+ ge_p3_tobytes(public_key, &A);
+ }
+}
diff --git a/3rd_party/ed25519/ed25519.h b/3rd_party/ed25519/ed25519.h
new file mode 100644
index 0000000..8924659
--- /dev/null
+++ b/3rd_party/ed25519/ed25519.h
@@ -0,0 +1,38 @@
+#ifndef ED25519_H
+#define ED25519_H
+
+#include <stddef.h>
+
+#if defined(_WIN32)
+ #if defined(ED25519_BUILD_DLL)
+ #define ED25519_DECLSPEC __declspec(dllexport)
+ #elif defined(ED25519_DLL)
+ #define ED25519_DECLSPEC __declspec(dllimport)
+ #else
+ #define ED25519_DECLSPEC
+ #endif
+#else
+ #define ED25519_DECLSPEC
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef ED25519_NO_SEED
+int ED25519_DECLSPEC ed25519_create_seed(unsigned char *seed);
+#endif
+
+void ED25519_DECLSPEC ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed);
+void ED25519_DECLSPEC ed25519_sign(unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key, const unsigned char *private_key);
+int ED25519_DECLSPEC ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key);
+void ED25519_DECLSPEC ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key, const unsigned char *scalar);
+void ED25519_DECLSPEC ed25519_key_exchange(unsigned char *shared_secret, const unsigned char *public_key, const unsigned char *private_key);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/3rd_party/ed25519/fe.c b/3rd_party/ed25519/fe.c
new file mode 100644
index 0000000..2105eb7
--- /dev/null
+++ b/3rd_party/ed25519/fe.c
@@ -0,0 +1,1491 @@
+#include "fixedint.h"
+#include "fe.h"
+
+
+/*
+ helper functions
+*/
+static uint64_t load_3(const unsigned char *in) {
+ uint64_t result;
+
+ result = (uint64_t) in[0];
+ result |= ((uint64_t) in[1]) << 8;
+ result |= ((uint64_t) in[2]) << 16;
+
+ return result;
+}
+
+static uint64_t load_4(const unsigned char *in) {
+ uint64_t result;
+
+ result = (uint64_t) in[0];
+ result |= ((uint64_t) in[1]) << 8;
+ result |= ((uint64_t) in[2]) << 16;
+ result |= ((uint64_t) in[3]) << 24;
+
+ return result;
+}
+
+
+
+/*
+ h = 0
+*/
+
+void fe_0(fe h) {
+ h[0] = 0;
+ h[1] = 0;
+ h[2] = 0;
+ h[3] = 0;
+ h[4] = 0;
+ h[5] = 0;
+ h[6] = 0;
+ h[7] = 0;
+ h[8] = 0;
+ h[9] = 0;
+}
+
+
+
+/*
+ h = 1
+*/
+
+void fe_1(fe h) {
+ h[0] = 1;
+ h[1] = 0;
+ h[2] = 0;
+ h[3] = 0;
+ h[4] = 0;
+ h[5] = 0;
+ h[6] = 0;
+ h[7] = 0;
+ h[8] = 0;
+ h[9] = 0;
+}
+
+
+
+/*
+ h = f + g
+ Can overlap h with f or g.
+
+ Preconditions:
+ |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+ |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+ Postconditions:
+ |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+void fe_add(fe h, const fe f, const fe g) {
+ int32_t f0 = f[0];
+ int32_t f1 = f[1];
+ int32_t f2 = f[2];
+ int32_t f3 = f[3];
+ int32_t f4 = f[4];
+ int32_t f5 = f[5];
+ int32_t f6 = f[6];
+ int32_t f7 = f[7];
+ int32_t f8 = f[8];
+ int32_t f9 = f[9];
+ int32_t g0 = g[0];
+ int32_t g1 = g[1];
+ int32_t g2 = g[2];
+ int32_t g3 = g[3];
+ int32_t g4 = g[4];
+ int32_t g5 = g[5];
+ int32_t g6 = g[6];
+ int32_t g7 = g[7];
+ int32_t g8 = g[8];
+ int32_t g9 = g[9];
+ int32_t h0 = f0 + g0;
+ int32_t h1 = f1 + g1;
+ int32_t h2 = f2 + g2;
+ int32_t h3 = f3 + g3;
+ int32_t h4 = f4 + g4;
+ int32_t h5 = f5 + g5;
+ int32_t h6 = f6 + g6;
+ int32_t h7 = f7 + g7;
+ int32_t h8 = f8 + g8;
+ int32_t h9 = f9 + g9;
+
+ h[0] = h0;
+ h[1] = h1;
+ h[2] = h2;
+ h[3] = h3;
+ h[4] = h4;
+ h[5] = h5;
+ h[6] = h6;
+ h[7] = h7;
+ h[8] = h8;
+ h[9] = h9;
+}
+
+
+
+/*
+ Replace (f,g) with (g,g) if b == 1;
+ replace (f,g) with (f,g) if b == 0.
+
+ Preconditions: b in {0,1}.
+*/
+
+void fe_cmov(fe f, const fe g, unsigned int b) {
+ int32_t f0 = f[0];
+ int32_t f1 = f[1];
+ int32_t f2 = f[2];
+ int32_t f3 = f[3];
+ int32_t f4 = f[4];
+ int32_t f5 = f[5];
+ int32_t f6 = f[6];
+ int32_t f7 = f[7];
+ int32_t f8 = f[8];
+ int32_t f9 = f[9];
+ int32_t g0 = g[0];
+ int32_t g1 = g[1];
+ int32_t g2 = g[2];
+ int32_t g3 = g[3];
+ int32_t g4 = g[4];
+ int32_t g5 = g[5];
+ int32_t g6 = g[6];
+ int32_t g7 = g[7];
+ int32_t g8 = g[8];
+ int32_t g9 = g[9];
+ int32_t x0 = f0 ^ g0;
+ int32_t x1 = f1 ^ g1;
+ int32_t x2 = f2 ^ g2;
+ int32_t x3 = f3 ^ g3;
+ int32_t x4 = f4 ^ g4;
+ int32_t x5 = f5 ^ g5;
+ int32_t x6 = f6 ^ g6;
+ int32_t x7 = f7 ^ g7;
+ int32_t x8 = f8 ^ g8;
+ int32_t x9 = f9 ^ g9;
+
+ b = (unsigned int) (- (int) b); /* silence warning */
+ x0 &= b;
+ x1 &= b;
+ x2 &= b;
+ x3 &= b;
+ x4 &= b;
+ x5 &= b;
+ x6 &= b;
+ x7 &= b;
+ x8 &= b;
+ x9 &= b;
+
+ f[0] = f0 ^ x0;
+ f[1] = f1 ^ x1;
+ f[2] = f2 ^ x2;
+ f[3] = f3 ^ x3;
+ f[4] = f4 ^ x4;
+ f[5] = f5 ^ x5;
+ f[6] = f6 ^ x6;
+ f[7] = f7 ^ x7;
+ f[8] = f8 ^ x8;
+ f[9] = f9 ^ x9;
+}
+
+/*
+ Replace (f,g) with (g,f) if b == 1;
+ replace (f,g) with (f,g) if b == 0.
+
+ Preconditions: b in {0,1}.
+*/
+
+void fe_cswap(fe f,fe g,unsigned int b) {
+ int32_t f0 = f[0];
+ int32_t f1 = f[1];
+ int32_t f2 = f[2];
+ int32_t f3 = f[3];
+ int32_t f4 = f[4];
+ int32_t f5 = f[5];
+ int32_t f6 = f[6];
+ int32_t f7 = f[7];
+ int32_t f8 = f[8];
+ int32_t f9 = f[9];
+ int32_t g0 = g[0];
+ int32_t g1 = g[1];
+ int32_t g2 = g[2];
+ int32_t g3 = g[3];
+ int32_t g4 = g[4];
+ int32_t g5 = g[5];
+ int32_t g6 = g[6];
+ int32_t g7 = g[7];
+ int32_t g8 = g[8];
+ int32_t g9 = g[9];
+ int32_t x0 = f0 ^ g0;
+ int32_t x1 = f1 ^ g1;
+ int32_t x2 = f2 ^ g2;
+ int32_t x3 = f3 ^ g3;
+ int32_t x4 = f4 ^ g4;
+ int32_t x5 = f5 ^ g5;
+ int32_t x6 = f6 ^ g6;
+ int32_t x7 = f7 ^ g7;
+ int32_t x8 = f8 ^ g8;
+ int32_t x9 = f9 ^ g9;
+ b = (unsigned int) (- (int) b); /* silence warning */
+ x0 &= b;
+ x1 &= b;
+ x2 &= b;
+ x3 &= b;
+ x4 &= b;
+ x5 &= b;
+ x6 &= b;
+ x7 &= b;
+ x8 &= b;
+ x9 &= b;
+ f[0] = f0 ^ x0;
+ f[1] = f1 ^ x1;
+ f[2] = f2 ^ x2;
+ f[3] = f3 ^ x3;
+ f[4] = f4 ^ x4;
+ f[5] = f5 ^ x5;
+ f[6] = f6 ^ x6;
+ f[7] = f7 ^ x7;
+ f[8] = f8 ^ x8;
+ f[9] = f9 ^ x9;
+ g[0] = g0 ^ x0;
+ g[1] = g1 ^ x1;
+ g[2] = g2 ^ x2;
+ g[3] = g3 ^ x3;
+ g[4] = g4 ^ x4;
+ g[5] = g5 ^ x5;
+ g[6] = g6 ^ x6;
+ g[7] = g7 ^ x7;
+ g[8] = g8 ^ x8;
+ g[9] = g9 ^ x9;
+}
+
+
+
+/*
+ h = f
+*/
+
+void fe_copy(fe h, const fe f) {
+ int32_t f0 = f[0];
+ int32_t f1 = f[1];
+ int32_t f2 = f[2];
+ int32_t f3 = f[3];
+ int32_t f4 = f[4];
+ int32_t f5 = f[5];
+ int32_t f6 = f[6];
+ int32_t f7 = f[7];
+ int32_t f8 = f[8];
+ int32_t f9 = f[9];
+
+ h[0] = f0;
+ h[1] = f1;
+ h[2] = f2;
+ h[3] = f3;
+ h[4] = f4;
+ h[5] = f5;
+ h[6] = f6;
+ h[7] = f7;
+ h[8] = f8;
+ h[9] = f9;
+}
+
+
+
+/*
+ Ignores top bit of h.
+*/
+
+void fe_frombytes(fe h, const unsigned char *s) {
+ int64_t h0 = load_4(s);
+ int64_t h1 = load_3(s + 4) << 6;
+ int64_t h2 = load_3(s + 7) << 5;
+ int64_t h3 = load_3(s + 10) << 3;
+ int64_t h4 = load_3(s + 13) << 2;
+ int64_t h5 = load_4(s + 16);
+ int64_t h6 = load_3(s + 20) << 7;
+ int64_t h7 = load_3(s + 23) << 5;
+ int64_t h8 = load_3(s + 26) << 4;
+ int64_t h9 = (load_3(s + 29) & 8388607) << 2;
+ int64_t carry0;
+ int64_t carry1;
+ int64_t carry2;
+ int64_t carry3;
+ int64_t carry4;
+ int64_t carry5;
+ int64_t carry6;
+ int64_t carry7;
+ int64_t carry8;
+ int64_t carry9;
+
+ carry9 = (h9 + (int64_t) (1 << 24)) >> 25;
+ h0 += carry9 * 19;
+ h9 -= carry9 << 25;
+ carry1 = (h1 + (int64_t) (1 << 24)) >> 25;
+ h2 += carry1;
+ h1 -= carry1 << 25;
+ carry3 = (h3 + (int64_t) (1 << 24)) >> 25;
+ h4 += carry3;
+ h3 -= carry3 << 25;
+ carry5 = (h5 + (int64_t) (1 << 24)) >> 25;
+ h6 += carry5;
+ h5 -= carry5 << 25;
+ carry7 = (h7 + (int64_t) (1 << 24)) >> 25;
+ h8 += carry7;
+ h7 -= carry7 << 25;
+ carry0 = (h0 + (int64_t) (1 << 25)) >> 26;
+ h1 += carry0;
+ h0 -= carry0 << 26;
+ carry2 = (h2 + (int64_t) (1 << 25)) >> 26;
+ h3 += carry2;
+ h2 -= carry2 << 26;
+ carry4 = (h4 + (int64_t) (1 << 25)) >> 26;
+ h5 += carry4;
+ h4 -= carry4 << 26;
+ carry6 = (h6 + (int64_t) (1 << 25)) >> 26;
+ h7 += carry6;
+ h6 -= carry6 << 26;
+ carry8 = (h8 + (int64_t) (1 << 25)) >> 26;
+ h9 += carry8;
+ h8 -= carry8 << 26;
+
+ h[0] = (int32_t) h0;
+ h[1] = (int32_t) h1;
+ h[2] = (int32_t) h2;
+ h[3] = (int32_t) h3;
+ h[4] = (int32_t) h4;
+ h[5] = (int32_t) h5;
+ h[6] = (int32_t) h6;
+ h[7] = (int32_t) h7;
+ h[8] = (int32_t) h8;
+ h[9] = (int32_t) h9;
+}
+
+
+
+void fe_invert(fe out, const fe z) {
+ fe t0;
+ fe t1;
+ fe t2;
+ fe t3;
+ int i;
+
+ fe_sq(t0, z);
+
+ for (i = 1; i < 1; ++i) {
+ fe_sq(t0, t0);
+ }
+
+ fe_sq(t1, t0);
+
+ for (i = 1; i < 2; ++i) {
+ fe_sq(t1, t1);
+ }
+
+ fe_mul(t1, z, t1);
+ fe_mul(t0, t0, t1);
+ fe_sq(t2, t0);
+
+ for (i = 1; i < 1; ++i) {
+ fe_sq(t2, t2);
+ }
+
+ fe_mul(t1, t1, t2);
+ fe_sq(t2, t1);
+
+ for (i = 1; i < 5; ++i) {
+ fe_sq(t2, t2);
+ }
+
+ fe_mul(t1, t2, t1);
+ fe_sq(t2, t1);
+
+ for (i = 1; i < 10; ++i) {
+ fe_sq(t2, t2);
+ }
+
+ fe_mul(t2, t2, t1);
+ fe_sq(t3, t2);
+
+ for (i = 1; i < 20; ++i) {
+ fe_sq(t3, t3);
+ }
+
+ fe_mul(t2, t3, t2);
+ fe_sq(t2, t2);
+
+ for (i = 1; i < 10; ++i) {
+ fe_sq(t2, t2);
+ }
+
+ fe_mul(t1, t2, t1);
+ fe_sq(t2, t1);
+
+ for (i = 1; i < 50; ++i) {
+ fe_sq(t2, t2);
+ }
+
+ fe_mul(t2, t2, t1);
+ fe_sq(t3, t2);
+
+ for (i = 1; i < 100; ++i) {
+ fe_sq(t3, t3);
+ }
+
+ fe_mul(t2, t3, t2);
+ fe_sq(t2, t2);
+
+ for (i = 1; i < 50; ++i) {
+ fe_sq(t2, t2);
+ }
+
+ fe_mul(t1, t2, t1);
+ fe_sq(t1, t1);
+
+ for (i = 1; i < 5; ++i) {
+ fe_sq(t1, t1);
+ }
+
+ fe_mul(out, t1, t0);
+}
+
+
+
+/*
+ return 1 if f is in {1,3,5,...,q-2}
+ return 0 if f is in {0,2,4,...,q-1}
+
+ Preconditions:
+ |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+int fe_isnegative(const fe f) {
+ unsigned char s[32];
+
+ fe_tobytes(s, f);
+
+ return s[0] & 1;
+}
+
+
+
+/*
+ return 1 if f == 0
+ return 0 if f != 0
+
+ Preconditions:
+ |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+int fe_isnonzero(const fe f) {
+ unsigned char s[32];
+ unsigned char r;
+
+ fe_tobytes(s, f);
+
+ r = s[0];
+ #define F(i) r |= s[i]
+ F(1);
+ F(2);
+ F(3);
+ F(4);
+ F(5);
+ F(6);
+ F(7);
+ F(8);
+ F(9);
+ F(10);
+ F(11);
+ F(12);
+ F(13);
+ F(14);
+ F(15);
+ F(16);
+ F(17);
+ F(18);
+ F(19);
+ F(20);
+ F(21);
+ F(22);
+ F(23);
+ F(24);
+ F(25);
+ F(26);
+ F(27);
+ F(28);
+ F(29);
+ F(30);
+ F(31);
+ #undef F
+
+ return r != 0;
+}
+
+
+
+/*
+ h = f * g
+ Can overlap h with f or g.
+
+ Preconditions:
+ |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+ |g| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+ Postconditions:
+ |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+ */
+
+ /*
+ Notes on implementation strategy:
+
+ Using schoolbook multiplication.
+ Karatsuba would save a little in some cost models.
+
+ Most multiplications by 2 and 19 are 32-bit precomputations;
+ cheaper than 64-bit postcomputations.
+
+ There is one remaining multiplication by 19 in the carry chain;
+ one *19 precomputation can be merged into this,
+ but the resulting data flow is considerably less clean.
+
+ There are 12 carries below.
+ 10 of them are 2-way parallelizable and vectorizable.
+ Can get away with 11 carries, but then data flow is much deeper.
+
+ With tighter constraints on inputs can squeeze carries into int32.
+*/
+
+void fe_mul(fe h, const fe f, const fe g) {
+ int32_t f0 = f[0];
+ int32_t f1 = f[1];
+ int32_t f2 = f[2];
+ int32_t f3 = f[3];
+ int32_t f4 = f[4];
+ int32_t f5 = f[5];
+ int32_t f6 = f[6];
+ int32_t f7 = f[7];
+ int32_t f8 = f[8];
+ int32_t f9 = f[9];
+ int32_t g0 = g[0];
+ int32_t g1 = g[1];
+ int32_t g2 = g[2];
+ int32_t g3 = g[3];
+ int32_t g4 = g[4];
+ int32_t g5 = g[5];
+ int32_t g6 = g[6];
+ int32_t g7 = g[7];
+ int32_t g8 = g[8];
+ int32_t g9 = g[9];
+ int32_t g1_19 = 19 * g1; /* 1.959375*2^29 */
+ int32_t g2_19 = 19 * g2; /* 1.959375*2^30; still ok */
+ int32_t g3_19 = 19 * g3;
+ int32_t g4_19 = 19 * g4;
+ int32_t g5_19 = 19 * g5;
+ int32_t g6_19 = 19 * g6;
+ int32_t g7_19 = 19 * g7;
+ int32_t g8_19 = 19 * g8;
+ int32_t g9_19 = 19 * g9;
+ int32_t f1_2 = 2 * f1;
+ int32_t f3_2 = 2 * f3;
+ int32_t f5_2 = 2 * f5;
+ int32_t f7_2 = 2 * f7;
+ int32_t f9_2 = 2 * f9;
+ int64_t f0g0 = f0 * (int64_t) g0;
+ int64_t f0g1 = f0 * (int64_t) g1;
+ int64_t f0g2 = f0 * (int64_t) g2;
+ int64_t f0g3 = f0 * (int64_t) g3;
+ int64_t f0g4 = f0 * (int64_t) g4;
+ int64_t f0g5 = f0 * (int64_t) g5;
+ int64_t f0g6 = f0 * (int64_t) g6;
+ int64_t f0g7 = f0 * (int64_t) g7;
+ int64_t f0g8 = f0 * (int64_t) g8;
+ int64_t f0g9 = f0 * (int64_t) g9;
+ int64_t f1g0 = f1 * (int64_t) g0;
+ int64_t f1g1_2 = f1_2 * (int64_t) g1;
+ int64_t f1g2 = f1 * (int64_t) g2;
+ int64_t f1g3_2 = f1_2 * (int64_t) g3;
+ int64_t f1g4 = f1 * (int64_t) g4;
+ int64_t f1g5_2 = f1_2 * (int64_t) g5;
+ int64_t f1g6 = f1 * (int64_t) g6;
+ int64_t f1g7_2 = f1_2 * (int64_t) g7;
+ int64_t f1g8 = f1 * (int64_t) g8;
+ int64_t f1g9_38 = f1_2 * (int64_t) g9_19;
+ int64_t f2g0 = f2 * (int64_t) g0;
+ int64_t f2g1 = f2 * (int64_t) g1;
+ int64_t f2g2 = f2 * (int64_t) g2;
+ int64_t f2g3 = f2 * (int64_t) g3;
+ int64_t f2g4 = f2 * (int64_t) g4;
+ int64_t f2g5 = f2 * (int64_t) g5;
+ int64_t f2g6 = f2 * (int64_t) g6;
+ int64_t f2g7 = f2 * (int64_t) g7;
+ int64_t f2g8_19 = f2 * (int64_t) g8_19;
+ int64_t f2g9_19 = f2 * (int64_t) g9_19;
+ int64_t f3g0 = f3 * (int64_t) g0;
+ int64_t f3g1_2 = f3_2 * (int64_t) g1;
+ int64_t f3g2 = f3 * (int64_t) g2;
+ int64_t f3g3_2 = f3_2 * (int64_t) g3;
+ int64_t f3g4 = f3 * (int64_t) g4;
+ int64_t f3g5_2 = f3_2 * (int64_t) g5;
+ int64_t f3g6 = f3 * (int64_t) g6;
+ int64_t f3g7_38 = f3_2 * (int64_t) g7_19;
+ int64_t f3g8_19 = f3 * (int64_t) g8_19;
+ int64_t f3g9_38 = f3_2 * (int64_t) g9_19;
+ int64_t f4g0 = f4 * (int64_t) g0;
+ int64_t f4g1 = f4 * (int64_t) g1;
+ int64_t f4g2 = f4 * (int64_t) g2;
+ int64_t f4g3 = f4 * (int64_t) g3;
+ int64_t f4g4 = f4 * (int64_t) g4;
+ int64_t f4g5 = f4 * (int64_t) g5;
+ int64_t f4g6_19 = f4 * (int64_t) g6_19;
+ int64_t f4g7_19 = f4 * (int64_t) g7_19;
+ int64_t f4g8_19 = f4 * (int64_t) g8_19;
+ int64_t f4g9_19 = f4 * (int64_t) g9_19;
+ int64_t f5g0 = f5 * (int64_t) g0;
+ int64_t f5g1_2 = f5_2 * (int64_t) g1;
+ int64_t f5g2 = f5 * (int64_t) g2;
+ int64_t f5g3_2 = f5_2 * (int64_t) g3;
+ int64_t f5g4 = f5 * (int64_t) g4;
+ int64_t f5g5_38 = f5_2 * (int64_t) g5_19;
+ int64_t f5g6_19 = f5 * (int64_t) g6_19;
+ int64_t f5g7_38 = f5_2 * (int64_t) g7_19;
+ int64_t f5g8_19 = f5 * (int64_t) g8_19;
+ int64_t f5g9_38 = f5_2 * (int64_t) g9_19;
+ int64_t f6g0 = f6 * (int64_t) g0;
+ int64_t f6g1 = f6 * (int64_t) g1;
+ int64_t f6g2 = f6 * (int64_t) g2;
+ int64_t f6g3 = f6 * (int64_t) g3;
+ int64_t f6g4_19 = f6 * (int64_t) g4_19;
+ int64_t f6g5_19 = f6 * (int64_t) g5_19;
+ int64_t f6g6_19 = f6 * (int64_t) g6_19;
+ int64_t f6g7_19 = f6 * (int64_t) g7_19;
+ int64_t f6g8_19 = f6 * (int64_t) g8_19;
+ int64_t f6g9_19 = f6 * (int64_t) g9_19;
+ int64_t f7g0 = f7 * (int64_t) g0;
+ int64_t f7g1_2 = f7_2 * (int64_t) g1;
+ int64_t f7g2 = f7 * (int64_t) g2;
+ int64_t f7g3_38 = f7_2 * (int64_t) g3_19;
+ int64_t f7g4_19 = f7 * (int64_t) g4_19;
+ int64_t f7g5_38 = f7_2 * (int64_t) g5_19;
+ int64_t f7g6_19 = f7 * (int64_t) g6_19;
+ int64_t f7g7_38 = f7_2 * (int64_t) g7_19;
+ int64_t f7g8_19 = f7 * (int64_t) g8_19;
+ int64_t f7g9_38 = f7_2 * (int64_t) g9_19;
+ int64_t f8g0 = f8 * (int64_t) g0;
+ int64_t f8g1 = f8 * (int64_t) g1;
+ int64_t f8g2_19 = f8 * (int64_t) g2_19;
+ int64_t f8g3_19 = f8 * (int64_t) g3_19;
+ int64_t f8g4_19 = f8 * (int64_t) g4_19;
+ int64_t f8g5_19 = f8 * (int64_t) g5_19;
+ int64_t f8g6_19 = f8 * (int64_t) g6_19;
+ int64_t f8g7_19 = f8 * (int64_t) g7_19;
+ int64_t f8g8_19 = f8 * (int64_t) g8_19;
+ int64_t f8g9_19 = f8 * (int64_t) g9_19;
+ int64_t f9g0 = f9 * (int64_t) g0;
+ int64_t f9g1_38 = f9_2 * (int64_t) g1_19;
+ int64_t f9g2_19 = f9 * (int64_t) g2_19;
+ int64_t f9g3_38 = f9_2 * (int64_t) g3_19;
+ int64_t f9g4_19 = f9 * (int64_t) g4_19;
+ int64_t f9g5_38 = f9_2 * (int64_t) g5_19;
+ int64_t f9g6_19 = f9 * (int64_t) g6_19;
+ int64_t f9g7_38 = f9_2 * (int64_t) g7_19;
+ int64_t f9g8_19 = f9 * (int64_t) g8_19;
+ int64_t f9g9_38 = f9_2 * (int64_t) g9_19;
+ int64_t h0 = f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38;
+ int64_t h1 = f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + f7g4_19 + f8g3_19 + f9g2_19;
+ int64_t h2 = f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + f7g5_38 + f8g4_19 + f9g3_38;
+ int64_t h3 = f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + f7g6_19 + f8g5_19 + f9g4_19;
+ int64_t h4 = f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + f7g7_38 + f8g6_19 + f9g5_38;
+ int64_t h5 = f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + f8g7_19 + f9g6_19;
+ int64_t h6 = f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + f7g9_38 + f8g8_19 + f9g7_38;
+ int64_t h7 = f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + f8g9_19 + f9g8_19;
+ int64_t h8 = f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + f8g0 + f9g9_38;
+ int64_t h9 = f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0 ;
+ int64_t carry0;
+ int64_t carry1;
+ int64_t carry2;
+ int64_t carry3;
+ int64_t carry4;
+ int64_t carry5;
+ int64_t carry6;
+ int64_t carry7;
+ int64_t carry8;
+ int64_t carry9;
+
+ carry0 = (h0 + (int64_t) (1 << 25)) >> 26;
+ h1 += carry0;
+ h0 -= carry0 << 26;
+ carry4 = (h4 + (int64_t) (1 << 25)) >> 26;
+ h5 += carry4;
+ h4 -= carry4 << 26;
+
+ carry1 = (h1 + (int64_t) (1 << 24)) >> 25;
+ h2 += carry1;
+ h1 -= carry1 << 25;
+ carry5 = (h5 + (int64_t) (1 << 24)) >> 25;
+ h6 += carry5;
+ h5 -= carry5 << 25;
+
+ carry2 = (h2 + (int64_t) (1 << 25)) >> 26;
+ h3 += carry2;
+ h2 -= carry2 << 26;
+ carry6 = (h6 + (int64_t) (1 << 25)) >> 26;
+ h7 += carry6;
+ h6 -= carry6 << 26;
+
+ carry3 = (h3 + (int64_t) (1 << 24)) >> 25;
+ h4 += carry3;
+ h3 -= carry3 << 25;
+ carry7 = (h7 + (int64_t) (1 << 24)) >> 25;
+ h8 += carry7;
+ h7 -= carry7 << 25;
+
+ carry4 = (h4 + (int64_t) (1 << 25)) >> 26;
+ h5 += carry4;
+ h4 -= carry4 << 26;
+ carry8 = (h8 + (int64_t) (1 << 25)) >> 26;
+ h9 += carry8;
+ h8 -= carry8 << 26;
+
+ carry9 = (h9 + (int64_t) (1 << 24)) >> 25;
+ h0 += carry9 * 19;
+ h9 -= carry9 << 25;
+
+ carry0 = (h0 + (int64_t) (1 << 25)) >> 26;
+ h1 += carry0;
+ h0 -= carry0 << 26;
+
+ h[0] = (int32_t) h0;
+ h[1] = (int32_t) h1;
+ h[2] = (int32_t) h2;
+ h[3] = (int32_t) h3;
+ h[4] = (int32_t) h4;
+ h[5] = (int32_t) h5;
+ h[6] = (int32_t) h6;
+ h[7] = (int32_t) h7;
+ h[8] = (int32_t) h8;
+ h[9] = (int32_t) h9;
+}
+
+
+/*
+h = f * 121666
+Can overlap h with f.
+
+Preconditions:
+ |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+
+Postconditions:
+ |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+*/
+
+void fe_mul121666(fe h, fe f) {
+ int32_t f0 = f[0];
+ int32_t f1 = f[1];
+ int32_t f2 = f[2];
+ int32_t f3 = f[3];
+ int32_t f4 = f[4];
+ int32_t f5 = f[5];
+ int32_t f6 = f[6];
+ int32_t f7 = f[7];
+ int32_t f8 = f[8];
+ int32_t f9 = f[9];
+ int64_t h0 = f0 * (int64_t) 121666;
+ int64_t h1 = f1 * (int64_t) 121666;
+ int64_t h2 = f2 * (int64_t) 121666;
+ int64_t h3 = f3 * (int64_t) 121666;
+ int64_t h4 = f4 * (int64_t) 121666;
+ int64_t h5 = f5 * (int64_t) 121666;
+ int64_t h6 = f6 * (int64_t) 121666;
+ int64_t h7 = f7 * (int64_t) 121666;
+ int64_t h8 = f8 * (int64_t) 121666;
+ int64_t h9 = f9 * (int64_t) 121666;
+ int64_t carry0;
+ int64_t carry1;
+ int64_t carry2;
+ int64_t carry3;
+ int64_t carry4;
+ int64_t carry5;
+ int64_t carry6;
+ int64_t carry7;
+ int64_t carry8;
+ int64_t carry9;
+
+ carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+ carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+ carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+ carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+ carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+ carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+ carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+ carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+ carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+ carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+ h[0] = (int32_t) h0;
+ h[1] = (int32_t) h1;
+ h[2] = (int32_t) h2;
+ h[3] = (int32_t) h3;
+ h[4] = (int32_t) h4;
+ h[5] = (int32_t) h5;
+ h[6] = (int32_t) h6;
+ h[7] = (int32_t) h7;
+ h[8] = (int32_t) h8;
+ h[9] = (int32_t) h9;
+}
+
+
+/*
+h = -f
+
+Preconditions:
+ |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+ |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+*/
+
+void fe_neg(fe h, const fe f) {
+ int32_t f0 = f[0];
+ int32_t f1 = f[1];
+ int32_t f2 = f[2];
+ int32_t f3 = f[3];
+ int32_t f4 = f[4];
+ int32_t f5 = f[5];
+ int32_t f6 = f[6];
+ int32_t f7 = f[7];
+ int32_t f8 = f[8];
+ int32_t f9 = f[9];
+ int32_t h0 = -f0;
+ int32_t h1 = -f1;
+ int32_t h2 = -f2;
+ int32_t h3 = -f3;
+ int32_t h4 = -f4;
+ int32_t h5 = -f5;
+ int32_t h6 = -f6;
+ int32_t h7 = -f7;
+ int32_t h8 = -f8;
+ int32_t h9 = -f9;
+
+ h[0] = h0;
+ h[1] = h1;
+ h[2] = h2;
+ h[3] = h3;
+ h[4] = h4;
+ h[5] = h5;
+ h[6] = h6;
+ h[7] = h7;
+ h[8] = h8;
+ h[9] = h9;
+}
+
+
+void fe_pow22523(fe out, const fe z) {
+ fe t0;
+ fe t1;
+ fe t2;
+ int i;
+ fe_sq(t0, z);
+
+ for (i = 1; i < 1; ++i) {
+ fe_sq(t0, t0);
+ }
+
+ fe_sq(t1, t0);
+
+ for (i = 1; i < 2; ++i) {
+ fe_sq(t1, t1);
+ }
+
+ fe_mul(t1, z, t1);
+ fe_mul(t0, t0, t1);
+ fe_sq(t0, t0);
+
+ for (i = 1; i < 1; ++i) {
+ fe_sq(t0, t0);
+ }
+
+ fe_mul(t0, t1, t0);
+ fe_sq(t1, t0);
+
+ for (i = 1; i < 5; ++i) {
+ fe_sq(t1, t1);
+ }
+
+ fe_mul(t0, t1, t0);
+ fe_sq(t1, t0);
+
+ for (i = 1; i < 10; ++i) {
+ fe_sq(t1, t1);
+ }
+
+ fe_mul(t1, t1, t0);
+ fe_sq(t2, t1);
+
+ for (i = 1; i < 20; ++i) {
+ fe_sq(t2, t2);
+ }
+
+ fe_mul(t1, t2, t1);
+ fe_sq(t1, t1);
+
+ for (i = 1; i < 10; ++i) {
+ fe_sq(t1, t1);
+ }
+
+ fe_mul(t0, t1, t0);
+ fe_sq(t1, t0);
+
+ for (i = 1; i < 50; ++i) {
+ fe_sq(t1, t1);
+ }
+
+ fe_mul(t1, t1, t0);
+ fe_sq(t2, t1);
+
+ for (i = 1; i < 100; ++i) {
+ fe_sq(t2, t2);
+ }
+
+ fe_mul(t1, t2, t1);
+ fe_sq(t1, t1);
+
+ for (i = 1; i < 50; ++i) {
+ fe_sq(t1, t1);
+ }
+
+ fe_mul(t0, t1, t0);
+ fe_sq(t0, t0);
+
+ for (i = 1; i < 2; ++i) {
+ fe_sq(t0, t0);
+ }
+
+ fe_mul(out, t0, z);
+ return;
+}
+
+
+/*
+h = f * f
+Can overlap h with f.
+
+Preconditions:
+ |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+ |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+See fe_mul.c for discussion of implementation strategy.
+*/
+
+void fe_sq(fe h, const fe f) {
+ int32_t f0 = f[0];
+ int32_t f1 = f[1];
+ int32_t f2 = f[2];
+ int32_t f3 = f[3];
+ int32_t f4 = f[4];
+ int32_t f5 = f[5];
+ int32_t f6 = f[6];
+ int32_t f7 = f[7];
+ int32_t f8 = f[8];
+ int32_t f9 = f[9];
+ int32_t f0_2 = 2 * f0;
+ int32_t f1_2 = 2 * f1;
+ int32_t f2_2 = 2 * f2;
+ int32_t f3_2 = 2 * f3;
+ int32_t f4_2 = 2 * f4;
+ int32_t f5_2 = 2 * f5;
+ int32_t f6_2 = 2 * f6;
+ int32_t f7_2 = 2 * f7;
+ int32_t f5_38 = 38 * f5; /* 1.959375*2^30 */
+ int32_t f6_19 = 19 * f6; /* 1.959375*2^30 */
+ int32_t f7_38 = 38 * f7; /* 1.959375*2^30 */
+ int32_t f8_19 = 19 * f8; /* 1.959375*2^30 */
+ int32_t f9_38 = 38 * f9; /* 1.959375*2^30 */
+ int64_t f0f0 = f0 * (int64_t) f0;
+ int64_t f0f1_2 = f0_2 * (int64_t) f1;
+ int64_t f0f2_2 = f0_2 * (int64_t) f2;
+ int64_t f0f3_2 = f0_2 * (int64_t) f3;
+ int64_t f0f4_2 = f0_2 * (int64_t) f4;
+ int64_t f0f5_2 = f0_2 * (int64_t) f5;
+ int64_t f0f6_2 = f0_2 * (int64_t) f6;
+ int64_t f0f7_2 = f0_2 * (int64_t) f7;
+ int64_t f0f8_2 = f0_2 * (int64_t) f8;
+ int64_t f0f9_2 = f0_2 * (int64_t) f9;
+ int64_t f1f1_2 = f1_2 * (int64_t) f1;
+ int64_t f1f2_2 = f1_2 * (int64_t) f2;
+ int64_t f1f3_4 = f1_2 * (int64_t) f3_2;
+ int64_t f1f4_2 = f1_2 * (int64_t) f4;
+ int64_t f1f5_4 = f1_2 * (int64_t) f5_2;
+ int64_t f1f6_2 = f1_2 * (int64_t) f6;
+ int64_t f1f7_4 = f1_2 * (int64_t) f7_2;
+ int64_t f1f8_2 = f1_2 * (int64_t) f8;
+ int64_t f1f9_76 = f1_2 * (int64_t) f9_38;
+ int64_t f2f2 = f2 * (int64_t) f2;
+ int64_t f2f3_2 = f2_2 * (int64_t) f3;
+ int64_t f2f4_2 = f2_2 * (int64_t) f4;
+ int64_t f2f5_2 = f2_2 * (int64_t) f5;
+ int64_t f2f6_2 = f2_2 * (int64_t) f6;
+ int64_t f2f7_2 = f2_2 * (int64_t) f7;
+ int64_t f2f8_38 = f2_2 * (int64_t) f8_19;
+ int64_t f2f9_38 = f2 * (int64_t) f9_38;
+ int64_t f3f3_2 = f3_2 * (int64_t) f3;
+ int64_t f3f4_2 = f3_2 * (int64_t) f4;
+ int64_t f3f5_4 = f3_2 * (int64_t) f5_2;
+ int64_t f3f6_2 = f3_2 * (int64_t) f6;
+ int64_t f3f7_76 = f3_2 * (int64_t) f7_38;
+ int64_t f3f8_38 = f3_2 * (int64_t) f8_19;
+ int64_t f3f9_76 = f3_2 * (int64_t) f9_38;
+ int64_t f4f4 = f4 * (int64_t) f4;
+ int64_t f4f5_2 = f4_2 * (int64_t) f5;
+ int64_t f4f6_38 = f4_2 * (int64_t) f6_19;
+ int64_t f4f7_38 = f4 * (int64_t) f7_38;
+ int64_t f4f8_38 = f4_2 * (int64_t) f8_19;
+ int64_t f4f9_38 = f4 * (int64_t) f9_38;
+ int64_t f5f5_38 = f5 * (int64_t) f5_38;
+ int64_t f5f6_38 = f5_2 * (int64_t) f6_19;
+ int64_t f5f7_76 = f5_2 * (int64_t) f7_38;
+ int64_t f5f8_38 = f5_2 * (int64_t) f8_19;
+ int64_t f5f9_76 = f5_2 * (int64_t) f9_38;
+ int64_t f6f6_19 = f6 * (int64_t) f6_19;
+ int64_t f6f7_38 = f6 * (int64_t) f7_38;
+ int64_t f6f8_38 = f6_2 * (int64_t) f8_19;
+ int64_t f6f9_38 = f6 * (int64_t) f9_38;
+ int64_t f7f7_38 = f7 * (int64_t) f7_38;
+ int64_t f7f8_38 = f7_2 * (int64_t) f8_19;
+ int64_t f7f9_76 = f7_2 * (int64_t) f9_38;
+ int64_t f8f8_19 = f8 * (int64_t) f8_19;
+ int64_t f8f9_38 = f8 * (int64_t) f9_38;
+ int64_t f9f9_38 = f9 * (int64_t) f9_38;
+ int64_t h0 = f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38;
+ int64_t h1 = f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38;
+ int64_t h2 = f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19;
+ int64_t h3 = f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38;
+ int64_t h4 = f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38;
+ int64_t h5 = f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38;
+ int64_t h6 = f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19;
+ int64_t h7 = f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38;
+ int64_t h8 = f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38;
+ int64_t h9 = f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2;
+ int64_t carry0;
+ int64_t carry1;
+ int64_t carry2;
+ int64_t carry3;
+ int64_t carry4;
+ int64_t carry5;
+ int64_t carry6;
+ int64_t carry7;
+ int64_t carry8;
+ int64_t carry9;
+ carry0 = (h0 + (int64_t) (1 << 25)) >> 26;
+ h1 += carry0;
+ h0 -= carry0 << 26;
+ carry4 = (h4 + (int64_t) (1 << 25)) >> 26;
+ h5 += carry4;
+ h4 -= carry4 << 26;
+ carry1 = (h1 + (int64_t) (1 << 24)) >> 25;
+ h2 += carry1;
+ h1 -= carry1 << 25;
+ carry5 = (h5 + (int64_t) (1 << 24)) >> 25;
+ h6 += carry5;
+ h5 -= carry5 << 25;
+ carry2 = (h2 + (int64_t) (1 << 25)) >> 26;
+ h3 += carry2;
+ h2 -= carry2 << 26;
+ carry6 = (h6 + (int64_t) (1 << 25)) >> 26;
+ h7 += carry6;
+ h6 -= carry6 << 26;
+ carry3 = (h3 + (int64_t) (1 << 24)) >> 25;
+ h4 += carry3;
+ h3 -= carry3 << 25;
+ carry7 = (h7 + (int64_t) (1 << 24)) >> 25;
+ h8 += carry7;
+ h7 -= carry7 << 25;
+ carry4 = (h4 + (int64_t) (1 << 25)) >> 26;
+ h5 += carry4;
+ h4 -= carry4 << 26;
+ carry8 = (h8 + (int64_t) (1 << 25)) >> 26;
+ h9 += carry8;
+ h8 -= carry8 << 26;
+ carry9 = (h9 + (int64_t) (1 << 24)) >> 25;
+ h0 += carry9 * 19;
+ h9 -= carry9 << 25;
+ carry0 = (h0 + (int64_t) (1 << 25)) >> 26;
+ h1 += carry0;
+ h0 -= carry0 << 26;
+ h[0] = (int32_t) h0;
+ h[1] = (int32_t) h1;
+ h[2] = (int32_t) h2;
+ h[3] = (int32_t) h3;
+ h[4] = (int32_t) h4;
+ h[5] = (int32_t) h5;
+ h[6] = (int32_t) h6;
+ h[7] = (int32_t) h7;
+ h[8] = (int32_t) h8;
+ h[9] = (int32_t) h9;
+}
+
+
+/*
+h = 2 * f * f
+Can overlap h with f.
+
+Preconditions:
+ |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+ |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+See fe_mul.c for discussion of implementation strategy.
+*/
+
+void fe_sq2(fe h, const fe f) {
+ int32_t f0 = f[0];
+ int32_t f1 = f[1];
+ int32_t f2 = f[2];
+ int32_t f3 = f[3];
+ int32_t f4 = f[4];
+ int32_t f5 = f[5];
+ int32_t f6 = f[6];
+ int32_t f7 = f[7];
+ int32_t f8 = f[8];
+ int32_t f9 = f[9];
+ int32_t f0_2 = 2 * f0;
+ int32_t f1_2 = 2 * f1;
+ int32_t f2_2 = 2 * f2;
+ int32_t f3_2 = 2 * f3;
+ int32_t f4_2 = 2 * f4;
+ int32_t f5_2 = 2 * f5;
+ int32_t f6_2 = 2 * f6;
+ int32_t f7_2 = 2 * f7;
+ int32_t f5_38 = 38 * f5; /* 1.959375*2^30 */
+ int32_t f6_19 = 19 * f6; /* 1.959375*2^30 */
+ int32_t f7_38 = 38 * f7; /* 1.959375*2^30 */
+ int32_t f8_19 = 19 * f8; /* 1.959375*2^30 */
+ int32_t f9_38 = 38 * f9; /* 1.959375*2^30 */
+ int64_t f0f0 = f0 * (int64_t) f0;
+ int64_t f0f1_2 = f0_2 * (int64_t) f1;
+ int64_t f0f2_2 = f0_2 * (int64_t) f2;
+ int64_t f0f3_2 = f0_2 * (int64_t) f3;
+ int64_t f0f4_2 = f0_2 * (int64_t) f4;
+ int64_t f0f5_2 = f0_2 * (int64_t) f5;
+ int64_t f0f6_2 = f0_2 * (int64_t) f6;
+ int64_t f0f7_2 = f0_2 * (int64_t) f7;
+ int64_t f0f8_2 = f0_2 * (int64_t) f8;
+ int64_t f0f9_2 = f0_2 * (int64_t) f9;
+ int64_t f1f1_2 = f1_2 * (int64_t) f1;
+ int64_t f1f2_2 = f1_2 * (int64_t) f2;
+ int64_t f1f3_4 = f1_2 * (int64_t) f3_2;
+ int64_t f1f4_2 = f1_2 * (int64_t) f4;
+ int64_t f1f5_4 = f1_2 * (int64_t) f5_2;
+ int64_t f1f6_2 = f1_2 * (int64_t) f6;
+ int64_t f1f7_4 = f1_2 * (int64_t) f7_2;
+ int64_t f1f8_2 = f1_2 * (int64_t) f8;
+ int64_t f1f9_76 = f1_2 * (int64_t) f9_38;
+ int64_t f2f2 = f2 * (int64_t) f2;
+ int64_t f2f3_2 = f2_2 * (int64_t) f3;
+ int64_t f2f4_2 = f2_2 * (int64_t) f4;
+ int64_t f2f5_2 = f2_2 * (int64_t) f5;
+ int64_t f2f6_2 = f2_2 * (int64_t) f6;
+ int64_t f2f7_2 = f2_2 * (int64_t) f7;
+ int64_t f2f8_38 = f2_2 * (int64_t) f8_19;
+ int64_t f2f9_38 = f2 * (int64_t) f9_38;
+ int64_t f3f3_2 = f3_2 * (int64_t) f3;
+ int64_t f3f4_2 = f3_2 * (int64_t) f4;
+ int64_t f3f5_4 = f3_2 * (int64_t) f5_2;
+ int64_t f3f6_2 = f3_2 * (int64_t) f6;
+ int64_t f3f7_76 = f3_2 * (int64_t) f7_38;
+ int64_t f3f8_38 = f3_2 * (int64_t) f8_19;
+ int64_t f3f9_76 = f3_2 * (int64_t) f9_38;
+ int64_t f4f4 = f4 * (int64_t) f4;
+ int64_t f4f5_2 = f4_2 * (int64_t) f5;
+ int64_t f4f6_38 = f4_2 * (int64_t) f6_19;
+ int64_t f4f7_38 = f4 * (int64_t) f7_38;
+ int64_t f4f8_38 = f4_2 * (int64_t) f8_19;
+ int64_t f4f9_38 = f4 * (int64_t) f9_38;
+ int64_t f5f5_38 = f5 * (int64_t) f5_38;
+ int64_t f5f6_38 = f5_2 * (int64_t) f6_19;
+ int64_t f5f7_76 = f5_2 * (int64_t) f7_38;
+ int64_t f5f8_38 = f5_2 * (int64_t) f8_19;
+ int64_t f5f9_76 = f5_2 * (int64_t) f9_38;
+ int64_t f6f6_19 = f6 * (int64_t) f6_19;
+ int64_t f6f7_38 = f6 * (int64_t) f7_38;
+ int64_t f6f8_38 = f6_2 * (int64_t) f8_19;
+ int64_t f6f9_38 = f6 * (int64_t) f9_38;
+ int64_t f7f7_38 = f7 * (int64_t) f7_38;
+ int64_t f7f8_38 = f7_2 * (int64_t) f8_19;
+ int64_t f7f9_76 = f7_2 * (int64_t) f9_38;
+ int64_t f8f8_19 = f8 * (int64_t) f8_19;
+ int64_t f8f9_38 = f8 * (int64_t) f9_38;
+ int64_t f9f9_38 = f9 * (int64_t) f9_38;
+ int64_t h0 = f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38;
+ int64_t h1 = f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38;
+ int64_t h2 = f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19;
+ int64_t h3 = f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38;
+ int64_t h4 = f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38;
+ int64_t h5 = f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38;
+ int64_t h6 = f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19;
+ int64_t h7 = f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38;
+ int64_t h8 = f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38;
+ int64_t h9 = f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2;
+ int64_t carry0;
+ int64_t carry1;
+ int64_t carry2;
+ int64_t carry3;
+ int64_t carry4;
+ int64_t carry5;
+ int64_t carry6;
+ int64_t carry7;
+ int64_t carry8;
+ int64_t carry9;
+ h0 += h0;
+ h1 += h1;
+ h2 += h2;
+ h3 += h3;
+ h4 += h4;
+ h5 += h5;
+ h6 += h6;
+ h7 += h7;
+ h8 += h8;
+ h9 += h9;
+ carry0 = (h0 + (int64_t) (1 << 25)) >> 26;
+ h1 += carry0;
+ h0 -= carry0 << 26;
+ carry4 = (h4 + (int64_t) (1 << 25)) >> 26;
+ h5 += carry4;
+ h4 -= carry4 << 26;
+ carry1 = (h1 + (int64_t) (1 << 24)) >> 25;
+ h2 += carry1;
+ h1 -= carry1 << 25;
+ carry5 = (h5 + (int64_t) (1 << 24)) >> 25;
+ h6 += carry5;
+ h5 -= carry5 << 25;
+ carry2 = (h2 + (int64_t) (1 << 25)) >> 26;
+ h3 += carry2;
+ h2 -= carry2 << 26;
+ carry6 = (h6 + (int64_t) (1 << 25)) >> 26;
+ h7 += carry6;
+ h6 -= carry6 << 26;
+ carry3 = (h3 + (int64_t) (1 << 24)) >> 25;
+ h4 += carry3;
+ h3 -= carry3 << 25;
+ carry7 = (h7 + (int64_t) (1 << 24)) >> 25;
+ h8 += carry7;
+ h7 -= carry7 << 25;
+ carry4 = (h4 + (int64_t) (1 << 25)) >> 26;
+ h5 += carry4;
+ h4 -= carry4 << 26;
+ carry8 = (h8 + (int64_t) (1 << 25)) >> 26;
+ h9 += carry8;
+ h8 -= carry8 << 26;
+ carry9 = (h9 + (int64_t) (1 << 24)) >> 25;
+ h0 += carry9 * 19;
+ h9 -= carry9 << 25;
+ carry0 = (h0 + (int64_t) (1 << 25)) >> 26;
+ h1 += carry0;
+ h0 -= carry0 << 26;
+ h[0] = (int32_t) h0;
+ h[1] = (int32_t) h1;
+ h[2] = (int32_t) h2;
+ h[3] = (int32_t) h3;
+ h[4] = (int32_t) h4;
+ h[5] = (int32_t) h5;
+ h[6] = (int32_t) h6;
+ h[7] = (int32_t) h7;
+ h[8] = (int32_t) h8;
+ h[9] = (int32_t) h9;
+}
+
+
+/*
+h = f - g
+Can overlap h with f or g.
+
+Preconditions:
+ |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+ |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+ |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+void fe_sub(fe h, const fe f, const fe g) {
+ int32_t f0 = f[0];
+ int32_t f1 = f[1];
+ int32_t f2 = f[2];
+ int32_t f3 = f[3];
+ int32_t f4 = f[4];
+ int32_t f5 = f[5];
+ int32_t f6 = f[6];
+ int32_t f7 = f[7];
+ int32_t f8 = f[8];
+ int32_t f9 = f[9];
+ int32_t g0 = g[0];
+ int32_t g1 = g[1];
+ int32_t g2 = g[2];
+ int32_t g3 = g[3];
+ int32_t g4 = g[4];
+ int32_t g5 = g[5];
+ int32_t g6 = g[6];
+ int32_t g7 = g[7];
+ int32_t g8 = g[8];
+ int32_t g9 = g[9];
+ int32_t h0 = f0 - g0;
+ int32_t h1 = f1 - g1;
+ int32_t h2 = f2 - g2;
+ int32_t h3 = f3 - g3;
+ int32_t h4 = f4 - g4;
+ int32_t h5 = f5 - g5;
+ int32_t h6 = f6 - g6;
+ int32_t h7 = f7 - g7;
+ int32_t h8 = f8 - g8;
+ int32_t h9 = f9 - g9;
+
+ h[0] = h0;
+ h[1] = h1;
+ h[2] = h2;
+ h[3] = h3;
+ h[4] = h4;
+ h[5] = h5;
+ h[6] = h6;
+ h[7] = h7;
+ h[8] = h8;
+ h[9] = h9;
+}
+
+
+
+/*
+Preconditions:
+ |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+
+Write p=2^255-19; q=floor(h/p).
+Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
+
+Proof:
+ Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
+ Also have |h-2^230 h9|<2^231 so |19 2^(-255)(h-2^230 h9)|<1/4.
+
+ Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
+ Then 0<y<1.
+
+ Write r=h-pq.
+ Have 0<=r<=p-1=2^255-20.
+ Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
+
+ Write x=r+19(2^-255)r+y.
+ Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
+
+ Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
+ so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
+*/
+
+void fe_tobytes(unsigned char *s, const fe h) {
+ int32_t h0 = h[0];
+ int32_t h1 = h[1];
+ int32_t h2 = h[2];
+ int32_t h3 = h[3];
+ int32_t h4 = h[4];
+ int32_t h5 = h[5];
+ int32_t h6 = h[6];
+ int32_t h7 = h[7];
+ int32_t h8 = h[8];
+ int32_t h9 = h[9];
+ int32_t q;
+ int32_t carry0;
+ int32_t carry1;
+ int32_t carry2;
+ int32_t carry3;
+ int32_t carry4;
+ int32_t carry5;
+ int32_t carry6;
+ int32_t carry7;
+ int32_t carry8;
+ int32_t carry9;
+ q = (19 * h9 + (((int32_t) 1) << 24)) >> 25;
+ q = (h0 + q) >> 26;
+ q = (h1 + q) >> 25;
+ q = (h2 + q) >> 26;
+ q = (h3 + q) >> 25;
+ q = (h4 + q) >> 26;
+ q = (h5 + q) >> 25;
+ q = (h6 + q) >> 26;
+ q = (h7 + q) >> 25;
+ q = (h8 + q) >> 26;
+ q = (h9 + q) >> 25;
+ /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */
+ h0 += 19 * q;
+ /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */
+ carry0 = h0 >> 26;
+ h1 += carry0;
+ h0 -= carry0 << 26;
+ carry1 = h1 >> 25;
+ h2 += carry1;
+ h1 -= carry1 << 25;
+ carry2 = h2 >> 26;
+ h3 += carry2;
+ h2 -= carry2 << 26;
+ carry3 = h3 >> 25;
+ h4 += carry3;
+ h3 -= carry3 << 25;
+ carry4 = h4 >> 26;
+ h5 += carry4;
+ h4 -= carry4 << 26;
+ carry5 = h5 >> 25;
+ h6 += carry5;
+ h5 -= carry5 << 25;
+ carry6 = h6 >> 26;
+ h7 += carry6;
+ h6 -= carry6 << 26;
+ carry7 = h7 >> 25;
+ h8 += carry7;
+ h7 -= carry7 << 25;
+ carry8 = h8 >> 26;
+ h9 += carry8;
+ h8 -= carry8 << 26;
+ carry9 = h9 >> 25;
+ h9 -= carry9 << 25;
+
+ /* h10 = carry9 */
+ /*
+ Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
+ Have h0+...+2^230 h9 between 0 and 2^255-1;
+ evidently 2^255 h10-2^255 q = 0.
+ Goal: Output h0+...+2^230 h9.
+ */
+ s[0] = (unsigned char) (h0 >> 0);
+ s[1] = (unsigned char) (h0 >> 8);
+ s[2] = (unsigned char) (h0 >> 16);
+ s[3] = (unsigned char) ((h0 >> 24) | (h1 << 2));
+ s[4] = (unsigned char) (h1 >> 6);
+ s[5] = (unsigned char) (h1 >> 14);
+ s[6] = (unsigned char) ((h1 >> 22) | (h2 << 3));
+ s[7] = (unsigned char) (h2 >> 5);
+ s[8] = (unsigned char) (h2 >> 13);
+ s[9] = (unsigned char) ((h2 >> 21) | (h3 << 5));
+ s[10] = (unsigned char) (h3 >> 3);
+ s[11] = (unsigned char) (h3 >> 11);
+ s[12] = (unsigned char) ((h3 >> 19) | (h4 << 6));
+ s[13] = (unsigned char) (h4 >> 2);
+ s[14] = (unsigned char) (h4 >> 10);
+ s[15] = (unsigned char) (h4 >> 18);
+ s[16] = (unsigned char) (h5 >> 0);
+ s[17] = (unsigned char) (h5 >> 8);
+ s[18] = (unsigned char) (h5 >> 16);
+ s[19] = (unsigned char) ((h5 >> 24) | (h6 << 1));
+ s[20] = (unsigned char) (h6 >> 7);
+ s[21] = (unsigned char) (h6 >> 15);
+ s[22] = (unsigned char) ((h6 >> 23) | (h7 << 3));
+ s[23] = (unsigned char) (h7 >> 5);
+ s[24] = (unsigned char) (h7 >> 13);
+ s[25] = (unsigned char) ((h7 >> 21) | (h8 << 4));
+ s[26] = (unsigned char) (h8 >> 4);
+ s[27] = (unsigned char) (h8 >> 12);
+ s[28] = (unsigned char) ((h8 >> 20) | (h9 << 6));
+ s[29] = (unsigned char) (h9 >> 2);
+ s[30] = (unsigned char) (h9 >> 10);
+ s[31] = (unsigned char) (h9 >> 18);
+}
diff --git a/3rd_party/ed25519/fe.h b/3rd_party/ed25519/fe.h
new file mode 100644
index 0000000..b4b62d2
--- /dev/null
+++ b/3rd_party/ed25519/fe.h
@@ -0,0 +1,41 @@
+#ifndef FE_H
+#define FE_H
+
+#include "fixedint.h"
+
+
+/*
+ fe means field element.
+ Here the field is \Z/(2^255-19).
+ An element t, entries t[0]...t[9], represents the integer
+ t[0]+2^26 t[1]+2^51 t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9].
+ Bounds on each t[i] vary depending on context.
+*/
+
+
+typedef int32_t fe[10];
+
+
+void fe_0(fe h);
+void fe_1(fe h);
+
+void fe_frombytes(fe h, const unsigned char *s);
+void fe_tobytes(unsigned char *s, const fe h);
+
+void fe_copy(fe h, const fe f);
+int fe_isnegative(const fe f);
+int fe_isnonzero(const fe f);
+void fe_cmov(fe f, const fe g, unsigned int b);
+void fe_cswap(fe f, fe g, unsigned int b);
+
+void fe_neg(fe h, const fe f);
+void fe_add(fe h, const fe f, const fe g);
+void fe_invert(fe out, const fe z);
+void fe_sq(fe h, const fe f);
+void fe_sq2(fe h, const fe f);
+void fe_mul(fe h, const fe f, const fe g);
+void fe_mul121666(fe h, fe f);
+void fe_pow22523(fe out, const fe z);
+void fe_sub(fe h, const fe f, const fe g);
+
+#endif
diff --git a/3rd_party/ed25519/fixedint.h b/3rd_party/ed25519/fixedint.h
new file mode 100644
index 0000000..1a8745b
--- /dev/null
+++ b/3rd_party/ed25519/fixedint.h
@@ -0,0 +1,72 @@
+/*
+ Portable header to provide the 32 and 64 bits type.
+
+ Not a compatible replacement for <stdint.h>, do not blindly use it as such.
+*/
+
+#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(__WATCOMC__) && (defined(_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_) || defined(__UINT_FAST64_TYPE__)) )) && !defined(FIXEDINT_H_INCLUDED)
+ #include <stdint.h>
+ #define FIXEDINT_H_INCLUDED
+
+ #if defined(__WATCOMC__) && __WATCOMC__ >= 1250 && !defined(UINT64_C)
+ #include <limits.h>
+ #define UINT64_C(x) (x + (UINT64_MAX - UINT64_MAX))
+ #endif
+#endif
+
+
+#ifndef FIXEDINT_H_INCLUDED
+ #define FIXEDINT_H_INCLUDED
+
+ #include <limits.h>
+
+ /* (u)int32_t */
+ #ifndef uint32_t
+ #if (ULONG_MAX == 0xffffffffUL)
+ typedef unsigned long uint32_t;
+ #elif (UINT_MAX == 0xffffffffUL)
+ typedef unsigned int uint32_t;
+ #elif (USHRT_MAX == 0xffffffffUL)
+ typedef unsigned short uint32_t;
+ #endif
+ #endif
+
+
+ #ifndef int32_t
+ #if (LONG_MAX == 0x7fffffffL)
+ typedef signed long int32_t;
+ #elif (INT_MAX == 0x7fffffffL)
+ typedef signed int int32_t;
+ #elif (SHRT_MAX == 0x7fffffffL)
+ typedef signed short int32_t;
+ #endif
+ #endif
+
+
+ /* (u)int64_t */
+ #if (defined(__STDC__) && defined(__STDC_VERSION__) && __STDC__ && __STDC_VERSION__ >= 199901L)
+ typedef long long int64_t;
+ typedef unsigned long long uint64_t;
+
+ #define UINT64_C(v) v ##ULL
+ #define INT64_C(v) v ##LL
+ #elif defined(__GNUC__)
+ __extension__ typedef long long int64_t;
+ __extension__ typedef unsigned long long uint64_t;
+
+ #define UINT64_C(v) v ##ULL
+ #define INT64_C(v) v ##LL
+ #elif defined(__MWERKS__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__APPLE_CC__) || defined(_LONG_LONG) || defined(_CRAYC)
+ typedef long long int64_t;
+ typedef unsigned long long uint64_t;
+
+ #define UINT64_C(v) v ##ULL
+ #define INT64_C(v) v ##LL
+ #elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined(__BORLANDC__) && __BORLANDC__ > 0x460) || defined(__alpha) || defined(__DECC)
+ typedef __int64 int64_t;
+ typedef unsigned __int64 uint64_t;
+
+ #define UINT64_C(v) v ##UI64
+ #define INT64_C(v) v ##I64
+ #endif
+#endif
diff --git a/3rd_party/ed25519/ge.c b/3rd_party/ed25519/ge.c
new file mode 100644
index 0000000..87c691b
--- /dev/null
+++ b/3rd_party/ed25519/ge.c
@@ -0,0 +1,467 @@
+#include "ge.h"
+#include "precomp_data.h"
+
+
+/*
+r = p + q
+*/
+
+void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
+ fe t0;
+ fe_add(r->X, p->Y, p->X);
+ fe_sub(r->Y, p->Y, p->X);
+ fe_mul(r->Z, r->X, q->YplusX);
+ fe_mul(r->Y, r->Y, q->YminusX);
+ fe_mul(r->T, q->T2d, p->T);
+ fe_mul(r->X, p->Z, q->Z);
+ fe_add(t0, r->X, r->X);
+ fe_sub(r->X, r->Z, r->Y);
+ fe_add(r->Y, r->Z, r->Y);
+ fe_add(r->Z, t0, r->T);
+ fe_sub(r->T, t0, r->T);
+}
+
+
+static void slide(signed char *r, const unsigned char *a) {
+ int i;
+ int b;
+ int k;
+
+ for (i = 0; i < 256; ++i) {
+ r[i] = 1 & (a[i >> 3] >> (i & 7));
+ }
+
+ for (i = 0; i < 256; ++i)
+ if (r[i]) {
+ for (b = 1; b <= 6 && i + b < 256; ++b) {
+ if (r[i + b]) {
+ if (r[i] + (r[i + b] << b) <= 15) {
+ r[i] += r[i + b] << b;
+ r[i + b] = 0;
+ } else if (r[i] - (r[i + b] << b) >= -15) {
+ r[i] -= r[i + b] << b;
+
+ for (k = i + b; k < 256; ++k) {
+ if (!r[k]) {
+ r[k] = 1;
+ break;
+ }
+
+ r[k] = 0;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+ }
+}
+
+/*
+r = a * A + b * B
+where a = a[0]+256*a[1]+...+256^31 a[31].
+and b = b[0]+256*b[1]+...+256^31 b[31].
+B is the Ed25519 base point (x,4/5) with x positive.
+*/
+
+void ge_double_scalarmult_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b) {
+ signed char aslide[256];
+ signed char bslide[256];
+ ge_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */
+ ge_p1p1 t;
+ ge_p3 u;
+ ge_p3 A2;
+ int i;
+ slide(aslide, a);
+ slide(bslide, b);
+ ge_p3_to_cached(&Ai[0], A);
+ ge_p3_dbl(&t, A);
+ ge_p1p1_to_p3(&A2, &t);
+ ge_add(&t, &A2, &Ai[0]);
+ ge_p1p1_to_p3(&u, &t);
+ ge_p3_to_cached(&Ai[1], &u);
+ ge_add(&t, &A2, &Ai[1]);
+ ge_p1p1_to_p3(&u, &t);
+ ge_p3_to_cached(&Ai[2], &u);
+ ge_add(&t, &A2, &Ai[2]);
+ ge_p1p1_to_p3(&u, &t);
+ ge_p3_to_cached(&Ai[3], &u);
+ ge_add(&t, &A2, &Ai[3]);
+ ge_p1p1_to_p3(&u, &t);
+ ge_p3_to_cached(&Ai[4], &u);
+ ge_add(&t, &A2, &Ai[4]);
+ ge_p1p1_to_p3(&u, &t);
+ ge_p3_to_cached(&Ai[5], &u);
+ ge_add(&t, &A2, &Ai[5]);
+ ge_p1p1_to_p3(&u, &t);
+ ge_p3_to_cached(&Ai[6], &u);
+ ge_add(&t, &A2, &Ai[6]);
+ ge_p1p1_to_p3(&u, &t);
+ ge_p3_to_cached(&Ai[7], &u);
+ ge_p2_0(r);
+
+ for (i = 255; i >= 0; --i) {
+ if (aslide[i] || bslide[i]) {
+ break;
+ }
+ }
+
+ for (; i >= 0; --i) {
+ ge_p2_dbl(&t, r);
+
+ if (aslide[i] > 0) {
+ ge_p1p1_to_p3(&u, &t);
+ ge_add(&t, &u, &Ai[aslide[i] / 2]);
+ } else if (aslide[i] < 0) {
+ ge_p1p1_to_p3(&u, &t);
+ ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]);
+ }
+
+ if (bslide[i] > 0) {
+ ge_p1p1_to_p3(&u, &t);
+ ge_madd(&t, &u, &Bi[bslide[i] / 2]);
+ } else if (bslide[i] < 0) {
+ ge_p1p1_to_p3(&u, &t);
+ ge_msub(&t, &u, &Bi[(-bslide[i]) / 2]);
+ }
+
+ ge_p1p1_to_p2(r, &t);
+ }
+}
+
+
+static const fe d = {
+ -10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116
+};
+
+static const fe sqrtm1 = {
+ -32595792, -7943725, 9377950, 3500415, 12389472, -272473, -25146209, -2005654, 326686, 11406482
+};
+
+int ge_frombytes_negate_vartime(ge_p3 *h, const unsigned char *s) {
+ fe u;
+ fe v;
+ fe v3;
+ fe vxx;
+ fe check;
+ fe_frombytes(h->Y, s);
+ fe_1(h->Z);
+ fe_sq(u, h->Y);
+ fe_mul(v, u, d);
+ fe_sub(u, u, h->Z); /* u = y^2-1 */
+ fe_add(v, v, h->Z); /* v = dy^2+1 */
+ fe_sq(v3, v);
+ fe_mul(v3, v3, v); /* v3 = v^3 */
+ fe_sq(h->X, v3);
+ fe_mul(h->X, h->X, v);
+ fe_mul(h->X, h->X, u); /* x = uv^7 */
+ fe_pow22523(h->X, h->X); /* x = (uv^7)^((q-5)/8) */
+ fe_mul(h->X, h->X, v3);
+ fe_mul(h->X, h->X, u); /* x = uv^3(uv^7)^((q-5)/8) */
+ fe_sq(vxx, h->X);
+ fe_mul(vxx, vxx, v);
+ fe_sub(check, vxx, u); /* vx^2-u */
+
+ if (fe_isnonzero(check)) {
+ fe_add(check, vxx, u); /* vx^2+u */
+
+ if (fe_isnonzero(check)) {
+ return -1;
+ }
+
+ fe_mul(h->X, h->X, sqrtm1);
+ }
+
+ if (fe_isnegative(h->X) == (s[31] >> 7)) {
+ fe_neg(h->X, h->X);
+ }
+
+ fe_mul(h->T, h->X, h->Y);
+ return 0;
+}
+
+
+/*
+r = p + q
+*/
+
+void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
+ fe t0;
+ fe_add(r->X, p->Y, p->X);
+ fe_sub(r->Y, p->Y, p->X);
+ fe_mul(r->Z, r->X, q->yplusx);
+ fe_mul(r->Y, r->Y, q->yminusx);
+ fe_mul(r->T, q->xy2d, p->T);
+ fe_add(t0, p->Z, p->Z);
+ fe_sub(r->X, r->Z, r->Y);
+ fe_add(r->Y, r->Z, r->Y);
+ fe_add(r->Z, t0, r->T);
+ fe_sub(r->T, t0, r->T);
+}
+
+
+/*
+r = p - q
+*/
+
+void ge_msub(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
+ fe t0;
+
+ fe_add(r->X, p->Y, p->X);
+ fe_sub(r->Y, p->Y, p->X);
+ fe_mul(r->Z, r->X, q->yminusx);
+ fe_mul(r->Y, r->Y, q->yplusx);
+ fe_mul(r->T, q->xy2d, p->T);
+ fe_add(t0, p->Z, p->Z);
+ fe_sub(r->X, r->Z, r->Y);
+ fe_add(r->Y, r->Z, r->Y);
+ fe_sub(r->Z, t0, r->T);
+ fe_add(r->T, t0, r->T);
+}
+
+
+/*
+r = p
+*/
+
+void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p) {
+ fe_mul(r->X, p->X, p->T);
+ fe_mul(r->Y, p->Y, p->Z);
+ fe_mul(r->Z, p->Z, p->T);
+}
+
+
+
+/*
+r = p
+*/
+
+void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p) {
+ fe_mul(r->X, p->X, p->T);
+ fe_mul(r->Y, p->Y, p->Z);
+ fe_mul(r->Z, p->Z, p->T);
+ fe_mul(r->T, p->X, p->Y);
+}
+
+
+void ge_p2_0(ge_p2 *h) {
+ fe_0(h->X);
+ fe_1(h->Y);
+ fe_1(h->Z);
+}
+
+
+
+/*
+r = 2 * p
+*/
+
+void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p) {
+ fe t0;
+
+ fe_sq(r->X, p->X);
+ fe_sq(r->Z, p->Y);
+ fe_sq2(r->T, p->Z);
+ fe_add(r->Y, p->X, p->Y);
+ fe_sq(t0, r->Y);
+ fe_add(r->Y, r->Z, r->X);
+ fe_sub(r->Z, r->Z, r->X);
+ fe_sub(r->X, t0, r->Y);
+ fe_sub(r->T, r->T, r->Z);
+}
+
+
+void ge_p3_0(ge_p3 *h) {
+ fe_0(h->X);
+ fe_1(h->Y);
+ fe_1(h->Z);
+ fe_0(h->T);
+}
+
+
+/*
+r = 2 * p
+*/
+
+void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p) {
+ ge_p2 q;
+ ge_p3_to_p2(&q, p);
+ ge_p2_dbl(r, &q);
+}
+
+
+
+/*
+r = p
+*/
+
+static const fe d2 = {
+ -21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199
+};
+
+void ge_p3_to_cached(ge_cached *r, const ge_p3 *p) {
+ fe_add(r->YplusX, p->Y, p->X);
+ fe_sub(r->YminusX, p->Y, p->X);
+ fe_copy(r->Z, p->Z);
+ fe_mul(r->T2d, p->T, d2);
+}
+
+
+/*
+r = p
+*/
+
+void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p) {
+ fe_copy(r->X, p->X);
+ fe_copy(r->Y, p->Y);
+ fe_copy(r->Z, p->Z);
+}
+
+
+void ge_p3_tobytes(unsigned char *s, const ge_p3 *h) {
+ fe recip;
+ fe x;
+ fe y;
+ fe_invert(recip, h->Z);
+ fe_mul(x, h->X, recip);
+ fe_mul(y, h->Y, recip);
+ fe_tobytes(s, y);
+ s[31] ^= fe_isnegative(x) << 7;
+}
+
+
+static unsigned char equal(signed char b, signed char c) {
+ unsigned char ub = b;
+ unsigned char uc = c;
+ unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */
+ uint64_t y = x; /* 0: yes; 1..255: no */
+ y -= 1; /* large: yes; 0..254: no */
+ y >>= 63; /* 1: yes; 0: no */
+ return (unsigned char) y;
+}
+
+static unsigned char negative(signed char b) {
+ uint64_t x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */
+ x >>= 63; /* 1: yes; 0: no */
+ return (unsigned char) x;
+}
+
+static void cmov(ge_precomp *t, const ge_precomp *u, unsigned char b) {
+ fe_cmov(t->yplusx, u->yplusx, b);
+ fe_cmov(t->yminusx, u->yminusx, b);
+ fe_cmov(t->xy2d, u->xy2d, b);
+}
+
+
+static void select(ge_precomp *t, int pos, signed char b) {
+ ge_precomp minust;
+ unsigned char bnegative = negative(b);
+ unsigned char babs = b - (((-bnegative) & b) << 1);
+ fe_1(t->yplusx);
+ fe_1(t->yminusx);
+ fe_0(t->xy2d);
+ cmov(t, &base[pos][0], equal(babs, 1));
+ cmov(t, &base[pos][1], equal(babs, 2));
+ cmov(t, &base[pos][2], equal(babs, 3));
+ cmov(t, &base[pos][3], equal(babs, 4));
+ cmov(t, &base[pos][4], equal(babs, 5));
+ cmov(t, &base[pos][5], equal(babs, 6));
+ cmov(t, &base[pos][6], equal(babs, 7));
+ cmov(t, &base[pos][7], equal(babs, 8));
+ fe_copy(minust.yplusx, t->yminusx);
+ fe_copy(minust.yminusx, t->yplusx);
+ fe_neg(minust.xy2d, t->xy2d);
+ cmov(t, &minust, bnegative);
+}
+
+/*
+h = a * B
+where a = a[0]+256*a[1]+...+256^31 a[31]
+B is the Ed25519 base point (x,4/5) with x positive.
+
+Preconditions:
+ a[31] <= 127
+*/
+
+void ge_scalarmult_base(ge_p3 *h, const unsigned char *a) {
+ signed char e[64];
+ signed char carry;
+ ge_p1p1 r;
+ ge_p2 s;
+ ge_precomp t;
+ int i;
+
+ for (i = 0; i < 32; ++i) {
+ e[2 * i + 0] = (a[i] >> 0) & 15;
+ e[2 * i + 1] = (a[i] >> 4) & 15;
+ }
+
+ /* each e[i] is between 0 and 15 */
+ /* e[63] is between 0 and 7 */
+ carry = 0;
+
+ for (i = 0; i < 63; ++i) {
+ e[i] += carry;
+ carry = e[i] + 8;
+ carry >>= 4;
+ e[i] -= carry << 4;
+ }
+
+ e[63] += carry;
+ /* each e[i] is between -8 and 8 */
+ ge_p3_0(h);
+
+ for (i = 1; i < 64; i += 2) {
+ select(&t, i / 2, e[i]);
+ ge_madd(&r, h, &t);
+ ge_p1p1_to_p3(h, &r);
+ }
+
+ ge_p3_dbl(&r, h);
+ ge_p1p1_to_p2(&s, &r);
+ ge_p2_dbl(&r, &s);
+ ge_p1p1_to_p2(&s, &r);
+ ge_p2_dbl(&r, &s);
+ ge_p1p1_to_p2(&s, &r);
+ ge_p2_dbl(&r, &s);
+ ge_p1p1_to_p3(h, &r);
+
+ for (i = 0; i < 64; i += 2) {
+ select(&t, i / 2, e[i]);
+ ge_madd(&r, h, &t);
+ ge_p1p1_to_p3(h, &r);
+ }
+}
+
+
+/*
+r = p - q
+*/
+
+void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
+ fe t0;
+
+ fe_add(r->X, p->Y, p->X);
+ fe_sub(r->Y, p->Y, p->X);
+ fe_mul(r->Z, r->X, q->YminusX);
+ fe_mul(r->Y, r->Y, q->YplusX);
+ fe_mul(r->T, q->T2d, p->T);
+ fe_mul(r->X, p->Z, q->Z);
+ fe_add(t0, r->X, r->X);
+ fe_sub(r->X, r->Z, r->Y);
+ fe_add(r->Y, r->Z, r->Y);
+ fe_sub(r->Z, t0, r->T);
+ fe_add(r->T, t0, r->T);
+}
+
+
+void ge_tobytes(unsigned char *s, const ge_p2 *h) {
+ fe recip;
+ fe x;
+ fe y;
+ fe_invert(recip, h->Z);
+ fe_mul(x, h->X, recip);
+ fe_mul(y, h->Y, recip);
+ fe_tobytes(s, y);
+ s[31] ^= fe_isnegative(x) << 7;
+}
diff --git a/3rd_party/ed25519/ge.h b/3rd_party/ed25519/ge.h
new file mode 100644
index 0000000..17fde2d
--- /dev/null
+++ b/3rd_party/ed25519/ge.h
@@ -0,0 +1,74 @@
+#ifndef GE_H
+#define GE_H
+
+#include "fe.h"
+
+
+/*
+ge means group element.
+
+Here the group is the set of pairs (x,y) of field elements (see fe.h)
+satisfying -x^2 + y^2 = 1 + d x^2y^2
+where d = -121665/121666.
+
+Representations:
+ ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
+ ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
+ ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
+ ge_precomp (Duif): (y+x,y-x,2dxy)
+*/
+
+typedef struct {
+ fe X;
+ fe Y;
+ fe Z;
+} ge_p2;
+
+typedef struct {
+ fe X;
+ fe Y;
+ fe Z;
+ fe T;
+} ge_p3;
+
+typedef struct {
+ fe X;
+ fe Y;
+ fe Z;
+ fe T;
+} ge_p1p1;
+
+typedef struct {
+ fe yplusx;
+ fe yminusx;
+ fe xy2d;
+} ge_precomp;
+
+typedef struct {
+ fe YplusX;
+ fe YminusX;
+ fe Z;
+ fe T2d;
+} ge_cached;
+
+void ge_p3_tobytes(unsigned char *s, const ge_p3 *h);
+void ge_tobytes(unsigned char *s, const ge_p2 *h);
+int ge_frombytes_negate_vartime(ge_p3 *h, const unsigned char *s);
+
+void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q);
+void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q);
+void ge_double_scalarmult_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b);
+void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q);
+void ge_msub(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q);
+void ge_scalarmult_base(ge_p3 *h, const unsigned char *a);
+
+void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p);
+void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p);
+void ge_p2_0(ge_p2 *h);
+void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p);
+void ge_p3_0(ge_p3 *h);
+void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p);
+void ge_p3_to_cached(ge_cached *r, const ge_p3 *p);
+void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p);
+
+#endif
diff --git a/3rd_party/ed25519/key_exchange.c b/3rd_party/ed25519/key_exchange.c
new file mode 100644
index 0000000..abd75da
--- /dev/null
+++ b/3rd_party/ed25519/key_exchange.c
@@ -0,0 +1,79 @@
+#include "ed25519.h"
+#include "fe.h"
+
+void ed25519_key_exchange(unsigned char *shared_secret, const unsigned char *public_key, const unsigned char *private_key) {
+ unsigned char e[32];
+ unsigned int i;
+
+ fe x1;
+ fe x2;
+ fe z2;
+ fe x3;
+ fe z3;
+ fe tmp0;
+ fe tmp1;
+
+ int pos;
+ unsigned int swap;
+ unsigned int b;
+
+ /* copy the private key and make sure it's valid */
+ for (i = 0; i < 32; ++i) {
+ e[i] = private_key[i];
+ }
+
+ e[0] &= 248;
+ e[31] &= 63;
+ e[31] |= 64;
+
+ /* unpack the public key and convert edwards to montgomery */
+ /* due to CodesInChaos: montgomeryX = (edwardsY + 1)*inverse(1 - edwardsY) mod p */
+ fe_frombytes(x1, public_key);
+ fe_1(tmp1);
+ fe_add(tmp0, x1, tmp1);
+ fe_sub(tmp1, tmp1, x1);
+ fe_invert(tmp1, tmp1);
+ fe_mul(x1, tmp0, tmp1);
+
+ fe_1(x2);
+ fe_0(z2);
+ fe_copy(x3, x1);
+ fe_1(z3);
+
+ swap = 0;
+ for (pos = 254; pos >= 0; --pos) {
+ b = e[pos / 8] >> (pos & 7);
+ b &= 1;
+ swap ^= b;
+ fe_cswap(x2, x3, swap);
+ fe_cswap(z2, z3, swap);
+ swap = b;
+
+ /* from montgomery.h */
+ fe_sub(tmp0, x3, z3);
+ fe_sub(tmp1, x2, z2);
+ fe_add(x2, x2, z2);
+ fe_add(z2, x3, z3);
+ fe_mul(z3, tmp0, x2);
+ fe_mul(z2, z2, tmp1);
+ fe_sq(tmp0, tmp1);
+ fe_sq(tmp1, x2);
+ fe_add(x3, z3, z2);
+ fe_sub(z2, z3, z2);
+ fe_mul(x2, tmp1, tmp0);
+ fe_sub(tmp1, tmp1, tmp0);
+ fe_sq(z2, z2);
+ fe_mul121666(z3, tmp1);
+ fe_sq(x3, x3);
+ fe_add(tmp0, tmp0, z3);
+ fe_mul(z3, x1, z2);
+ fe_mul(z2, tmp1, tmp0);
+ }
+
+ fe_cswap(x2, x3, swap);
+ fe_cswap(z2, z3, swap);
+
+ fe_invert(z2, z2);
+ fe_mul(x2, x2, z2);
+ fe_tobytes(shared_secret, x2);
+}
diff --git a/3rd_party/ed25519/keypair.c b/3rd_party/ed25519/keypair.c
new file mode 100644
index 0000000..dc1b8ec
--- /dev/null
+++ b/3rd_party/ed25519/keypair.c
@@ -0,0 +1,16 @@
+#include "ed25519.h"
+#include "sha512.h"
+#include "ge.h"
+
+
+void ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed) {
+ ge_p3 A;
+
+ sha512(seed, 32, private_key);
+ private_key[0] &= 248;
+ private_key[31] &= 63;
+ private_key[31] |= 64;
+
+ ge_scalarmult_base(&A, private_key);
+ ge_p3_tobytes(public_key, &A);
+}
diff --git a/3rd_party/ed25519/precomp_data.h b/3rd_party/ed25519/precomp_data.h
new file mode 100644
index 0000000..ff23986
--- /dev/null
+++ b/3rd_party/ed25519/precomp_data.h
@@ -0,0 +1,1391 @@
+static const ge_precomp Bi[8] = {
+ {
+ { 25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605 },
+ { -12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378 },
+ { -8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546 },
+ },
+ {
+ { 15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024 },
+ { 16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574 },
+ { 30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357 },
+ },
+ {
+ { 10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380 },
+ { 4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306 },
+ { 19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942 },
+ },
+ {
+ { 5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766 },
+ { -30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701 },
+ { 28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300 },
+ },
+ {
+ { -22518993, -6692182, 14201702, -8745502, -23510406, 8844726, 18474211, -1361450, -13062696, 13821877 },
+ { -6455177, -7839871, 3374702, -4740862, -27098617, -10571707, 31655028, -7212327, 18853322, -14220951 },
+ { 4566830, -12963868, -28974889, -12240689, -7602672, -2830569, -8514358, -10431137, 2207753, -3209784 },
+ },
+ {
+ { -25154831, -4185821, 29681144, 7868801, -6854661, -9423865, -12437364, -663000, -31111463, -16132436 },
+ { 25576264, -2703214, 7349804, -11814844, 16472782, 9300885, 3844789, 15725684, 171356, 6466918 },
+ { 23103977, 13316479, 9739013, -16149481, 817875, -15038942, 8965339, -14088058, -30714912, 16193877 },
+ },
+ {
+ { -33521811, 3180713, -2394130, 14003687, -16903474, -16270840, 17238398, 4729455, -18074513, 9256800 },
+ { -25182317, -4174131, 32336398, 5036987, -21236817, 11360617, 22616405, 9761698, -19827198, 630305 },
+ { -13720693, 2639453, -24237460, -7406481, 9494427, -5774029, -6554551, -15960994, -2449256, -14291300 },
+ },
+ {
+ { -3151181, -5046075, 9282714, 6866145, -31907062, -863023, -18940575, 15033784, 25105118, -7894876 },
+ { -24326370, 15950226, -31801215, -14592823, -11662737, -5090925, 1573892, -2625887, 2198790, -15804619 },
+ { -3099351, 10324967, -2241613, 7453183, -5446979, -2735503, -13812022, -16236442, -32461234, -12290683 },
+ },
+};
+
+
+/* base[i][j] = (j+1)*256^i*B */
+static const ge_precomp base[32][8] = {
+ {
+ {
+ { 25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605 },
+ { -12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378 },
+ { -8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546 },
+ },
+ {
+ { -12815894, -12976347, -21581243, 11784320, -25355658, -2750717, -11717903, -3814571, -358445, -10211303 },
+ { -21703237, 6903825, 27185491, 6451973, -29577724, -9554005, -15616551, 11189268, -26829678, -5319081 },
+ { 26966642, 11152617, 32442495, 15396054, 14353839, -12752335, -3128826, -9541118, -15472047, -4166697 },
+ },
+ {
+ { 15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024 },
+ { 16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574 },
+ { 30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357 },
+ },
+ {
+ { -17036878, 13921892, 10945806, -6033431, 27105052, -16084379, -28926210, 15006023, 3284568, -6276540 },
+ { 23599295, -8306047, -11193664, -7687416, 13236774, 10506355, 7464579, 9656445, 13059162, 10374397 },
+ { 7798556, 16710257, 3033922, 2874086, 28997861, 2835604, 32406664, -3839045, -641708, -101325 },
+ },
+ {
+ { 10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380 },
+ { 4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306 },
+ { 19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942 },
+ },
+ {
+ { -15371964, -12862754, 32573250, 4720197, -26436522, 5875511, -19188627, -15224819, -9818940, -12085777 },
+ { -8549212, 109983, 15149363, 2178705, 22900618, 4543417, 3044240, -15689887, 1762328, 14866737 },
+ { -18199695, -15951423, -10473290, 1707278, -17185920, 3916101, -28236412, 3959421, 27914454, 4383652 },
+ },
+ {
+ { 5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766 },
+ { -30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701 },
+ { 28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300 },
+ },
+ {
+ { 14499471, -2729599, -33191113, -4254652, 28494862, 14271267, 30290735, 10876454, -33154098, 2381726 },
+ { -7195431, -2655363, -14730155, 462251, -27724326, 3941372, -6236617, 3696005, -32300832, 15351955 },
+ { 27431194, 8222322, 16448760, -3907995, -18707002, 11938355, -32961401, -2970515, 29551813, 10109425 },
+ },
+ },
+ {
+ {
+ { -13657040, -13155431, -31283750, 11777098, 21447386, 6519384, -2378284, -1627556, 10092783, -4764171 },
+ { 27939166, 14210322, 4677035, 16277044, -22964462, -12398139, -32508754, 12005538, -17810127, 12803510 },
+ { 17228999, -15661624, -1233527, 300140, -1224870, -11714777, 30364213, -9038194, 18016357, 4397660 },
+ },
+ {
+ { -10958843, -7690207, 4776341, -14954238, 27850028, -15602212, -26619106, 14544525, -17477504, 982639 },
+ { 29253598, 15796703, -2863982, -9908884, 10057023, 3163536, 7332899, -4120128, -21047696, 9934963 },
+ { 5793303, 16271923, -24131614, -10116404, 29188560, 1206517, -14747930, 4559895, -30123922, -10897950 },
+ },
+ {
+ { -27643952, -11493006, 16282657, -11036493, 28414021, -15012264, 24191034, 4541697, -13338309, 5500568 },
+ { 12650548, -1497113, 9052871, 11355358, -17680037, -8400164, -17430592, 12264343, 10874051, 13524335 },
+ { 25556948, -3045990, 714651, 2510400, 23394682, -10415330, 33119038, 5080568, -22528059, 5376628 },
+ },
+ {
+ { -26088264, -4011052, -17013699, -3537628, -6726793, 1920897, -22321305, -9447443, 4535768, 1569007 },
+ { -2255422, 14606630, -21692440, -8039818, 28430649, 8775819, -30494562, 3044290, 31848280, 12543772 },
+ { -22028579, 2943893, -31857513, 6777306, 13784462, -4292203, -27377195, -2062731, 7718482, 14474653 },
+ },
+ {
+ { 2385315, 2454213, -22631320, 46603, -4437935, -15680415, 656965, -7236665, 24316168, -5253567 },
+ { 13741529, 10911568, -33233417, -8603737, -20177830, -1033297, 33040651, -13424532, -20729456, 8321686 },
+ { 21060490, -2212744, 15712757, -4336099, 1639040, 10656336, 23845965, -11874838, -9984458, 608372 },
+ },
+ {
+ { -13672732, -15087586, -10889693, -7557059, -6036909, 11305547, 1123968, -6780577, 27229399, 23887 },
+ { -23244140, -294205, -11744728, 14712571, -29465699, -2029617, 12797024, -6440308, -1633405, 16678954 },
+ { -29500620, 4770662, -16054387, 14001338, 7830047, 9564805, -1508144, -4795045, -17169265, 4904953 },
+ },
+ {
+ { 24059557, 14617003, 19037157, -15039908, 19766093, -14906429, 5169211, 16191880, 2128236, -4326833 },
+ { -16981152, 4124966, -8540610, -10653797, 30336522, -14105247, -29806336, 916033, -6882542, -2986532 },
+ { -22630907, 12419372, -7134229, -7473371, -16478904, 16739175, 285431, 2763829, 15736322, 4143876 },
+ },
+ {
+ { 2379352, 11839345, -4110402, -5988665, 11274298, 794957, 212801, -14594663, 23527084, -16458268 },
+ { 33431127, -11130478, -17838966, -15626900, 8909499, 8376530, -32625340, 4087881, -15188911, -14416214 },
+ { 1767683, 7197987, -13205226, -2022635, -13091350, 448826, 5799055, 4357868, -4774191, -16323038 },
+ },
+ },
+ {
+ {
+ { 6721966, 13833823, -23523388, -1551314, 26354293, -11863321, 23365147, -3949732, 7390890, 2759800 },
+ { 4409041, 2052381, 23373853, 10530217, 7676779, -12885954, 21302353, -4264057, 1244380, -12919645 },
+ { -4421239, 7169619, 4982368, -2957590, 30256825, -2777540, 14086413, 9208236, 15886429, 16489664 },
+ },
+ {
+ { 1996075, 10375649, 14346367, 13311202, -6874135, -16438411, -13693198, 398369, -30606455, -712933 },
+ { -25307465, 9795880, -2777414, 14878809, -33531835, 14780363, 13348553, 12076947, -30836462, 5113182 },
+ { -17770784, 11797796, 31950843, 13929123, -25888302, 12288344, -30341101, -7336386, 13847711, 5387222 },
+ },
+ {
+ { -18582163, -3416217, 17824843, -2340966, 22744343, -10442611, 8763061, 3617786, -19600662, 10370991 },
+ { 20246567, -14369378, 22358229, -543712, 18507283, -10413996, 14554437, -8746092, 32232924, 16763880 },
+ { 9648505, 10094563, 26416693, 14745928, -30374318, -6472621, 11094161, 15689506, 3140038, -16510092 },
+ },
+ {
+ { -16160072, 5472695, 31895588, 4744994, 8823515, 10365685, -27224800, 9448613, -28774454, 366295 },
+ { 19153450, 11523972, -11096490, -6503142, -24647631, 5420647, 28344573, 8041113, 719605, 11671788 },
+ { 8678025, 2694440, -6808014, 2517372, 4964326, 11152271, -15432916, -15266516, 27000813, -10195553 },
+ },
+ {
+ { -15157904, 7134312, 8639287, -2814877, -7235688, 10421742, 564065, 5336097, 6750977, -14521026 },
+ { 11836410, -3979488, 26297894, 16080799, 23455045, 15735944, 1695823, -8819122, 8169720, 16220347 },
+ { -18115838, 8653647, 17578566, -6092619, -8025777, -16012763, -11144307, -2627664, -5990708, -14166033 },
+ },
+ {
+ { -23308498, -10968312, 15213228, -10081214, -30853605, -11050004, 27884329, 2847284, 2655861, 1738395 },
+ { -27537433, -14253021, -25336301, -8002780, -9370762, 8129821, 21651608, -3239336, -19087449, -11005278 },
+ { 1533110, 3437855, 23735889, 459276, 29970501, 11335377, 26030092, 5821408, 10478196, 8544890 },
+ },
+ {
+ { 32173121, -16129311, 24896207, 3921497, 22579056, -3410854, 19270449, 12217473, 17789017, -3395995 },
+ { -30552961, -2228401, -15578829, -10147201, 13243889, 517024, 15479401, -3853233, 30460520, 1052596 },
+ { -11614875, 13323618, 32618793, 8175907, -15230173, 12596687, 27491595, -4612359, 3179268, -9478891 },
+ },
+ {
+ { 31947069, -14366651, -4640583, -15339921, -15125977, -6039709, -14756777, -16411740, 19072640, -9511060 },
+ { 11685058, 11822410, 3158003, -13952594, 33402194, -4165066, 5977896, -5215017, 473099, 5040608 },
+ { -20290863, 8198642, -27410132, 11602123, 1290375, -2799760, 28326862, 1721092, -19558642, -3131606 },
+ },
+ },
+ {
+ {
+ { 7881532, 10687937, 7578723, 7738378, -18951012, -2553952, 21820786, 8076149, -27868496, 11538389 },
+ { -19935666, 3899861, 18283497, -6801568, -15728660, -11249211, 8754525, 7446702, -5676054, 5797016 },
+ { -11295600, -3793569, -15782110, -7964573, 12708869, -8456199, 2014099, -9050574, -2369172, -5877341 },
+ },
+ {
+ { -22472376, -11568741, -27682020, 1146375, 18956691, 16640559, 1192730, -3714199, 15123619, 10811505 },
+ { 14352098, -3419715, -18942044, 10822655, 32750596, 4699007, -70363, 15776356, -28886779, -11974553 },
+ { -28241164, -8072475, -4978962, -5315317, 29416931, 1847569, -20654173, -16484855, 4714547, -9600655 },
+ },
+ {
+ { 15200332, 8368572, 19679101, 15970074, -31872674, 1959451, 24611599, -4543832, -11745876, 12340220 },
+ { 12876937, -10480056, 33134381, 6590940, -6307776, 14872440, 9613953, 8241152, 15370987, 9608631 },
+ { -4143277, -12014408, 8446281, -391603, 4407738, 13629032, -7724868, 15866074, -28210621, -8814099 },
+ },
+ {
+ { 26660628, -15677655, 8393734, 358047, -7401291, 992988, -23904233, 858697, 20571223, 8420556 },
+ { 14620715, 13067227, -15447274, 8264467, 14106269, 15080814, 33531827, 12516406, -21574435, -12476749 },
+ { 236881, 10476226, 57258, -14677024, 6472998, 2466984, 17258519, 7256740, 8791136, 15069930 },
+ },
+ {
+ { 1276410, -9371918, 22949635, -16322807, -23493039, -5702186, 14711875, 4874229, -30663140, -2331391 },
+ { 5855666, 4990204, -13711848, 7294284, -7804282, 1924647, -1423175, -7912378, -33069337, 9234253 },
+ { 20590503, -9018988, 31529744, -7352666, -2706834, 10650548, 31559055, -11609587, 18979186, 13396066 },
+ },
+ {
+ { 24474287, 4968103, 22267082, 4407354, 24063882, -8325180, -18816887, 13594782, 33514650, 7021958 },
+ { -11566906, -6565505, -21365085, 15928892, -26158305, 4315421, -25948728, -3916677, -21480480, 12868082 },
+ { -28635013, 13504661, 19988037, -2132761, 21078225, 6443208, -21446107, 2244500, -12455797, -8089383 },
+ },
+ {
+ { -30595528, 13793479, -5852820, 319136, -25723172, -6263899, 33086546, 8957937, -15233648, 5540521 },
+ { -11630176, -11503902, -8119500, -7643073, 2620056, 1022908, -23710744, -1568984, -16128528, -14962807 },
+ { 23152971, 775386, 27395463, 14006635, -9701118, 4649512, 1689819, 892185, -11513277, -15205948 },
+ },
+ {
+ { 9770129, 9586738, 26496094, 4324120, 1556511, -3550024, 27453819, 4763127, -19179614, 5867134 },
+ { -32765025, 1927590, 31726409, -4753295, 23962434, -16019500, 27846559, 5931263, -29749703, -16108455 },
+ { 27461885, -2977536, 22380810, 1815854, -23033753, -3031938, 7283490, -15148073, -19526700, 7734629 },
+ },
+ },
+ {
+ {
+ { -8010264, -9590817, -11120403, 6196038, 29344158, -13430885, 7585295, -3176626, 18549497, 15302069 },
+ { -32658337, -6171222, -7672793, -11051681, 6258878, 13504381, 10458790, -6418461, -8872242, 8424746 },
+ { 24687205, 8613276, -30667046, -3233545, 1863892, -1830544, 19206234, 7134917, -11284482, -828919 },
+ },
+ {
+ { 11334899, -9218022, 8025293, 12707519, 17523892, -10476071, 10243738, -14685461, -5066034, 16498837 },
+ { 8911542, 6887158, -9584260, -6958590, 11145641, -9543680, 17303925, -14124238, 6536641, 10543906 },
+ { -28946384, 15479763, -17466835, 568876, -1497683, 11223454, -2669190, -16625574, -27235709, 8876771 },
+ },
+ {
+ { -25742899, -12566864, -15649966, -846607, -33026686, -796288, -33481822, 15824474, -604426, -9039817 },
+ { 10330056, 70051, 7957388, -9002667, 9764902, 15609756, 27698697, -4890037, 1657394, 3084098 },
+ { 10477963, -7470260, 12119566, -13250805, 29016247, -5365589, 31280319, 14396151, -30233575, 15272409 },
+ },
+ {
+ { -12288309, 3169463, 28813183, 16658753, 25116432, -5630466, -25173957, -12636138, -25014757, 1950504 },
+ { -26180358, 9489187, 11053416, -14746161, -31053720, 5825630, -8384306, -8767532, 15341279, 8373727 },
+ { 28685821, 7759505, -14378516, -12002860, -31971820, 4079242, 298136, -10232602, -2878207, 15190420 },
+ },
+ {
+ { -32932876, 13806336, -14337485, -15794431, -24004620, 10940928, 8669718, 2742393, -26033313, -6875003 },
+ { -1580388, -11729417, -25979658, -11445023, -17411874, -10912854, 9291594, -16247779, -12154742, 6048605 },
+ { -30305315, 14843444, 1539301, 11864366, 20201677, 1900163, 13934231, 5128323, 11213262, 9168384 },
+ },
+ {
+ { -26280513, 11007847, 19408960, -940758, -18592965, -4328580, -5088060, -11105150, 20470157, -16398701 },
+ { -23136053, 9282192, 14855179, -15390078, -7362815, -14408560, -22783952, 14461608, 14042978, 5230683 },
+ { 29969567, -2741594, -16711867, -8552442, 9175486, -2468974, 21556951, 3506042, -5933891, -12449708 },
+ },
+ {
+ { -3144746, 8744661, 19704003, 4581278, -20430686, 6830683, -21284170, 8971513, -28539189, 15326563 },
+ { -19464629, 10110288, -17262528, -3503892, -23500387, 1355669, -15523050, 15300988, -20514118, 9168260 },
+ { -5353335, 4488613, -23803248, 16314347, 7780487, -15638939, -28948358, 9601605, 33087103, -9011387 },
+ },
+ {
+ { -19443170, -15512900, -20797467, -12445323, -29824447, 10229461, -27444329, -15000531, -5996870, 15664672 },
+ { 23294591, -16632613, -22650781, -8470978, 27844204, 11461195, 13099750, -2460356, 18151676, 13417686 },
+ { -24722913, -4176517, -31150679, 5988919, -26858785, 6685065, 1661597, -12551441, 15271676, -15452665 },
+ },
+ },
+ {
+ {
+ { 11433042, -13228665, 8239631, -5279517, -1985436, -725718, -18698764, 2167544, -6921301, -13440182 },
+ { -31436171, 15575146, 30436815, 12192228, -22463353, 9395379, -9917708, -8638997, 12215110, 12028277 },
+ { 14098400, 6555944, 23007258, 5757252, -15427832, -12950502, 30123440, 4617780, -16900089, -655628 },
+ },
+ {
+ { -4026201, -15240835, 11893168, 13718664, -14809462, 1847385, -15819999, 10154009, 23973261, -12684474 },
+ { -26531820, -3695990, -1908898, 2534301, -31870557, -16550355, 18341390, -11419951, 32013174, -10103539 },
+ { -25479301, 10876443, -11771086, -14625140, -12369567, 1838104, 21911214, 6354752, 4425632, -837822 },
+ },
+ {
+ { -10433389, -14612966, 22229858, -3091047, -13191166, 776729, -17415375, -12020462, 4725005, 14044970 },
+ { 19268650, -7304421, 1555349, 8692754, -21474059, -9910664, 6347390, -1411784, -19522291, -16109756 },
+ { -24864089, 12986008, -10898878, -5558584, -11312371, -148526, 19541418, 8180106, 9282262, 10282508 },
+ },
+ {
+ { -26205082, 4428547, -8661196, -13194263, 4098402, -14165257, 15522535, 8372215, 5542595, -10702683 },
+ { -10562541, 14895633, 26814552, -16673850, -17480754, -2489360, -2781891, 6993761, -18093885, 10114655 },
+ { -20107055, -929418, 31422704, 10427861, -7110749, 6150669, -29091755, -11529146, 25953725, -106158 },
+ },
+ {
+ { -4234397, -8039292, -9119125, 3046000, 2101609, -12607294, 19390020, 6094296, -3315279, 12831125 },
+ { -15998678, 7578152, 5310217, 14408357, -33548620, -224739, 31575954, 6326196, 7381791, -2421839 },
+ { -20902779, 3296811, 24736065, -16328389, 18374254, 7318640, 6295303, 8082724, -15362489, 12339664 },
+ },
+ {
+ { 27724736, 2291157, 6088201, -14184798, 1792727, 5857634, 13848414, 15768922, 25091167, 14856294 },
+ { -18866652, 8331043, 24373479, 8541013, -701998, -9269457, 12927300, -12695493, -22182473, -9012899 },
+ { -11423429, -5421590, 11632845, 3405020, 30536730, -11674039, -27260765, 13866390, 30146206, 9142070 },
+ },
+ {
+ { 3924129, -15307516, -13817122, -10054960, 12291820, -668366, -27702774, 9326384, -8237858, 4171294 },
+ { -15921940, 16037937, 6713787, 16606682, -21612135, 2790944, 26396185, 3731949, 345228, -5462949 },
+ { -21327538, 13448259, 25284571, 1143661, 20614966, -8849387, 2031539, -12391231, -16253183, -13582083 },
+ },
+ {
+ { 31016211, -16722429, 26371392, -14451233, -5027349, 14854137, 17477601, 3842657, 28012650, -16405420 },
+ { -5075835, 9368966, -8562079, -4600902, -15249953, 6970560, -9189873, 16292057, -8867157, 3507940 },
+ { 29439664, 3537914, 23333589, 6997794, -17555561, -11018068, -15209202, -15051267, -9164929, 6580396 },
+ },
+ },
+ {
+ {
+ { -12185861, -7679788, 16438269, 10826160, -8696817, -6235611, 17860444, -9273846, -2095802, 9304567 },
+ { 20714564, -4336911, 29088195, 7406487, 11426967, -5095705, 14792667, -14608617, 5289421, -477127 },
+ { -16665533, -10650790, -6160345, -13305760, 9192020, -1802462, 17271490, 12349094, 26939669, -3752294 },
+ },
+ {
+ { -12889898, 9373458, 31595848, 16374215, 21471720, 13221525, -27283495, -12348559, -3698806, 117887 },
+ { 22263325, -6560050, 3984570, -11174646, -15114008, -566785, 28311253, 5358056, -23319780, 541964 },
+ { 16259219, 3261970, 2309254, -15534474, -16885711, -4581916, 24134070, -16705829, -13337066, -13552195 },
+ },
+ {
+ { 9378160, -13140186, -22845982, -12745264, 28198281, -7244098, -2399684, -717351, 690426, 14876244 },
+ { 24977353, -314384, -8223969, -13465086, 28432343, -1176353, -13068804, -12297348, -22380984, 6618999 },
+ { -1538174, 11685646, 12944378, 13682314, -24389511, -14413193, 8044829, -13817328, 32239829, -5652762 },
+ },
+ {
+ { -18603066, 4762990, -926250, 8885304, -28412480, -3187315, 9781647, -10350059, 32779359, 5095274 },
+ { -33008130, -5214506, -32264887, -3685216, 9460461, -9327423, -24601656, 14506724, 21639561, -2630236 },
+ { -16400943, -13112215, 25239338, 15531969, 3987758, -4499318, -1289502, -6863535, 17874574, 558605 },
+ },
+ {
+ { -13600129, 10240081, 9171883, 16131053, -20869254, 9599700, 33499487, 5080151, 2085892, 5119761 },
+ { -22205145, -2519528, -16381601, 414691, -25019550, 2170430, 30634760, -8363614, -31999993, -5759884 },
+ { -6845704, 15791202, 8550074, -1312654, 29928809, -12092256, 27534430, -7192145, -22351378, 12961482 },
+ },
+ {
+ { -24492060, -9570771, 10368194, 11582341, -23397293, -2245287, 16533930, 8206996, -30194652, -5159638 },
+ { -11121496, -3382234, 2307366, 6362031, -135455, 8868177, -16835630, 7031275, 7589640, 8945490 },
+ { -32152748, 8917967, 6661220, -11677616, -1192060, -15793393, 7251489, -11182180, 24099109, -14456170 },
+ },
+ {
+ { 5019558, -7907470, 4244127, -14714356, -26933272, 6453165, -19118182, -13289025, -6231896, -10280736 },
+ { 10853594, 10721687, 26480089, 5861829, -22995819, 1972175, -1866647, -10557898, -3363451, -6441124 },
+ { -17002408, 5906790, 221599, -6563147, 7828208, -13248918, 24362661, -2008168, -13866408, 7421392 },
+ },
+ {
+ { 8139927, -6546497, 32257646, -5890546, 30375719, 1886181, -21175108, 15441252, 28826358, -4123029 },
+ { 6267086, 9695052, 7709135, -16603597, -32869068, -1886135, 14795160, -7840124, 13746021, -1742048 },
+ { 28584902, 7787108, -6732942, -15050729, 22846041, -7571236, -3181936, -363524, 4771362, -8419958 },
+ },
+ },
+ {
+ {
+ { 24949256, 6376279, -27466481, -8174608, -18646154, -9930606, 33543569, -12141695, 3569627, 11342593 },
+ { 26514989, 4740088, 27912651, 3697550, 19331575, -11472339, 6809886, 4608608, 7325975, -14801071 },
+ { -11618399, -14554430, -24321212, 7655128, -1369274, 5214312, -27400540, 10258390, -17646694, -8186692 },
+ },
+ {
+ { 11431204, 15823007, 26570245, 14329124, 18029990, 4796082, -31446179, 15580664, 9280358, -3973687 },
+ { -160783, -10326257, -22855316, -4304997, -20861367, -13621002, -32810901, -11181622, -15545091, 4387441 },
+ { -20799378, 12194512, 3937617, -5805892, -27154820, 9340370, -24513992, 8548137, 20617071, -7482001 },
+ },
+ {
+ { -938825, -3930586, -8714311, 16124718, 24603125, -6225393, -13775352, -11875822, 24345683, 10325460 },
+ { -19855277, -1568885, -22202708, 8714034, 14007766, 6928528, 16318175, -1010689, 4766743, 3552007 },
+ { -21751364, -16730916, 1351763, -803421, -4009670, 3950935, 3217514, 14481909, 10988822, -3994762 },
+ },
+ {
+ { 15564307, -14311570, 3101243, 5684148, 30446780, -8051356, 12677127, -6505343, -8295852, 13296005 },
+ { -9442290, 6624296, -30298964, -11913677, -4670981, -2057379, 31521204, 9614054, -30000824, 12074674 },
+ { 4771191, -135239, 14290749, -13089852, 27992298, 14998318, -1413936, -1556716, 29832613, -16391035 },
+ },
+ {
+ { 7064884, -7541174, -19161962, -5067537, -18891269, -2912736, 25825242, 5293297, -27122660, 13101590 },
+ { -2298563, 2439670, -7466610, 1719965, -27267541, -16328445, 32512469, -5317593, -30356070, -4190957 },
+ { -30006540, 10162316, -33180176, 3981723, -16482138, -13070044, 14413974, 9515896, 19568978, 9628812 },
+ },
+ {
+ { 33053803, 199357, 15894591, 1583059, 27380243, -4580435, -17838894, -6106839, -6291786, 3437740 },
+ { -18978877, 3884493, 19469877, 12726490, 15913552, 13614290, -22961733, 70104, 7463304, 4176122 },
+ { -27124001, 10659917, 11482427, -16070381, 12771467, -6635117, -32719404, -5322751, 24216882, 5944158 },
+ },
+ {
+ { 8894125, 7450974, -2664149, -9765752, -28080517, -12389115, 19345746, 14680796, 11632993, 5847885 },
+ { 26942781, -2315317, 9129564, -4906607, 26024105, 11769399, -11518837, 6367194, -9727230, 4782140 },
+ { 19916461, -4828410, -22910704, -11414391, 25606324, -5972441, 33253853, 8220911, 6358847, -1873857 },
+ },
+ {
+ { 801428, -2081702, 16569428, 11065167, 29875704, 96627, 7908388, -4480480, -13538503, 1387155 },
+ { 19646058, 5720633, -11416706, 12814209, 11607948, 12749789, 14147075, 15156355, -21866831, 11835260 },
+ { 19299512, 1155910, 28703737, 14890794, 2925026, 7269399, 26121523, 15467869, -26560550, 5052483 },
+ },
+ },
+ {
+ {
+ { -3017432, 10058206, 1980837, 3964243, 22160966, 12322533, -6431123, -12618185, 12228557, -7003677 },
+ { 32944382, 14922211, -22844894, 5188528, 21913450, -8719943, 4001465, 13238564, -6114803, 8653815 },
+ { 22865569, -4652735, 27603668, -12545395, 14348958, 8234005, 24808405, 5719875, 28483275, 2841751 },
+ },
+ {
+ { -16420968, -1113305, -327719, -12107856, 21886282, -15552774, -1887966, -315658, 19932058, -12739203 },
+ { -11656086, 10087521, -8864888, -5536143, -19278573, -3055912, 3999228, 13239134, -4777469, -13910208 },
+ { 1382174, -11694719, 17266790, 9194690, -13324356, 9720081, 20403944, 11284705, -14013818, 3093230 },
+ },
+ {
+ { 16650921, -11037932, -1064178, 1570629, -8329746, 7352753, -302424, 16271225, -24049421, -6691850 },
+ { -21911077, -5927941, -4611316, -5560156, -31744103, -10785293, 24123614, 15193618, -21652117, -16739389 },
+ { -9935934, -4289447, -25279823, 4372842, 2087473, 10399484, 31870908, 14690798, 17361620, 11864968 },
+ },
+ {
+ { -11307610, 6210372, 13206574, 5806320, -29017692, -13967200, -12331205, -7486601, -25578460, -16240689 },
+ { 14668462, -12270235, 26039039, 15305210, 25515617, 4542480, 10453892, 6577524, 9145645, -6443880 },
+ { 5974874, 3053895, -9433049, -10385191, -31865124, 3225009, -7972642, 3936128, -5652273, -3050304 },
+ },
+ {
+ { 30625386, -4729400, -25555961, -12792866, -20484575, 7695099, 17097188, -16303496, -27999779, 1803632 },
+ { -3553091, 9865099, -5228566, 4272701, -5673832, -16689700, 14911344, 12196514, -21405489, 7047412 },
+ { 20093277, 9920966, -11138194, -5343857, 13161587, 12044805, -32856851, 4124601, -32343828, -10257566 },
+ },
+ {
+ { -20788824, 14084654, -13531713, 7842147, 19119038, -13822605, 4752377, -8714640, -21679658, 2288038 },
+ { -26819236, -3283715, 29965059, 3039786, -14473765, 2540457, 29457502, 14625692, -24819617, 12570232 },
+ { -1063558, -11551823, 16920318, 12494842, 1278292, -5869109, -21159943, -3498680, -11974704, 4724943 },
+ },
+ {
+ { 17960970, -11775534, -4140968, -9702530, -8876562, -1410617, -12907383, -8659932, -29576300, 1903856 },
+ { 23134274, -14279132, -10681997, -1611936, 20684485, 15770816, -12989750, 3190296, 26955097, 14109738 },
+ { 15308788, 5320727, -30113809, -14318877, 22902008, 7767164, 29425325, -11277562, 31960942, 11934971 },
+ },
+ {
+ { -27395711, 8435796, 4109644, 12222639, -24627868, 14818669, 20638173, 4875028, 10491392, 1379718 },
+ { -13159415, 9197841, 3875503, -8936108, -1383712, -5879801, 33518459, 16176658, 21432314, 12180697 },
+ { -11787308, 11500838, 13787581, -13832590, -22430679, 10140205, 1465425, 12689540, -10301319, -13872883 },
+ },
+ },
+ {
+ {
+ { 5414091, -15386041, -21007664, 9643570, 12834970, 1186149, -2622916, -1342231, 26128231, 6032912 },
+ { -26337395, -13766162, 32496025, -13653919, 17847801, -12669156, 3604025, 8316894, -25875034, -10437358 },
+ { 3296484, 6223048, 24680646, -12246460, -23052020, 5903205, -8862297, -4639164, 12376617, 3188849 },
+ },
+ {
+ { 29190488, -14659046, 27549113, -1183516, 3520066, -10697301, 32049515, -7309113, -16109234, -9852307 },
+ { -14744486, -9309156, 735818, -598978, -20407687, -5057904, 25246078, -15795669, 18640741, -960977 },
+ { -6928835, -16430795, 10361374, 5642961, 4910474, 12345252, -31638386, -494430, 10530747, 1053335 },
+ },
+ {
+ { -29265967, -14186805, -13538216, -12117373, -19457059, -10655384, -31462369, -2948985, 24018831, 15026644 },
+ { -22592535, -3145277, -2289276, 5953843, -13440189, 9425631, 25310643, 13003497, -2314791, -15145616 },
+ { -27419985, -603321, -8043984, -1669117, -26092265, 13987819, -27297622, 187899, -23166419, -2531735 },
+ },
+ {
+ { -21744398, -13810475, 1844840, 5021428, -10434399, -15911473, 9716667, 16266922, -5070217, 726099 },
+ { 29370922, -6053998, 7334071, -15342259, 9385287, 2247707, -13661962, -4839461, 30007388, -15823341 },
+ { -936379, 16086691, 23751945, -543318, -1167538, -5189036, 9137109, 730663, 9835848, 4555336 },
+ },
+ {
+ { -23376435, 1410446, -22253753, -12899614, 30867635, 15826977, 17693930, 544696, -11985298, 12422646 },
+ { 31117226, -12215734, -13502838, 6561947, -9876867, -12757670, -5118685, -4096706, 29120153, 13924425 },
+ { -17400879, -14233209, 19675799, -2734756, -11006962, -5858820, -9383939, -11317700, 7240931, -237388 },
+ },
+ {
+ { -31361739, -11346780, -15007447, -5856218, -22453340, -12152771, 1222336, 4389483, 3293637, -15551743 },
+ { -16684801, -14444245, 11038544, 11054958, -13801175, -3338533, -24319580, 7733547, 12796905, -6335822 },
+ { -8759414, -10817836, -25418864, 10783769, -30615557, -9746811, -28253339, 3647836, 3222231, -11160462 },
+ },
+ {
+ { 18606113, 1693100, -25448386, -15170272, 4112353, 10045021, 23603893, -2048234, -7550776, 2484985 },
+ { 9255317, -3131197, -12156162, -1004256, 13098013, -9214866, 16377220, -2102812, -19802075, -3034702 },
+ { -22729289, 7496160, -5742199, 11329249, 19991973, -3347502, -31718148, 9936966, -30097688, -10618797 },
+ },
+ {
+ { 21878590, -5001297, 4338336, 13643897, -3036865, 13160960, 19708896, 5415497, -7360503, -4109293 },
+ { 27736861, 10103576, 12500508, 8502413, -3413016, -9633558, 10436918, -1550276, -23659143, -8132100 },
+ { 19492550, -12104365, -29681976, -852630, -3208171, 12403437, 30066266, 8367329, 13243957, 8709688 },
+ },
+ },
+ {
+ {
+ { 12015105, 2801261, 28198131, 10151021, 24818120, -4743133, -11194191, -5645734, 5150968, 7274186 },
+ { 2831366, -12492146, 1478975, 6122054, 23825128, -12733586, 31097299, 6083058, 31021603, -9793610 },
+ { -2529932, -2229646, 445613, 10720828, -13849527, -11505937, -23507731, 16354465, 15067285, -14147707 },
+ },
+ {
+ { 7840942, 14037873, -33364863, 15934016, -728213, -3642706, 21403988, 1057586, -19379462, -12403220 },
+ { 915865, -16469274, 15608285, -8789130, -24357026, 6060030, -17371319, 8410997, -7220461, 16527025 },
+ { 32922597, -556987, 20336074, -16184568, 10903705, -5384487, 16957574, 52992, 23834301, 6588044 },
+ },
+ {
+ { 32752030, 11232950, 3381995, -8714866, 22652988, -10744103, 17159699, 16689107, -20314580, -1305992 },
+ { -4689649, 9166776, -25710296, -10847306, 11576752, 12733943, 7924251, -2752281, 1976123, -7249027 },
+ { 21251222, 16309901, -2983015, -6783122, 30810597, 12967303, 156041, -3371252, 12331345, -8237197 },
+ },
+ {
+ { 8651614, -4477032, -16085636, -4996994, 13002507, 2950805, 29054427, -5106970, 10008136, -4667901 },
+ { 31486080, 15114593, -14261250, 12951354, 14369431, -7387845, 16347321, -13662089, 8684155, -10532952 },
+ { 19443825, 11385320, 24468943, -9659068, -23919258, 2187569, -26263207, -6086921, 31316348, 14219878 },
+ },
+ {
+ { -28594490, 1193785, 32245219, 11392485, 31092169, 15722801, 27146014, 6992409, 29126555, 9207390 },
+ { 32382935, 1110093, 18477781, 11028262, -27411763, -7548111, -4980517, 10843782, -7957600, -14435730 },
+ { 2814918, 7836403, 27519878, -7868156, -20894015, -11553689, -21494559, 8550130, 28346258, 1994730 },
+ },
+ {
+ { -19578299, 8085545, -14000519, -3948622, 2785838, -16231307, -19516951, 7174894, 22628102, 8115180 },
+ { -30405132, 955511, -11133838, -15078069, -32447087, -13278079, -25651578, 3317160, -9943017, 930272 },
+ { -15303681, -6833769, 28856490, 1357446, 23421993, 1057177, 24091212, -1388970, -22765376, -10650715 },
+ },
+ {
+ { -22751231, -5303997, -12907607, -12768866, -15811511, -7797053, -14839018, -16554220, -1867018, 8398970 },
+ { -31969310, 2106403, -4736360, 1362501, 12813763, 16200670, 22981545, -6291273, 18009408, -15772772 },
+ { -17220923, -9545221, -27784654, 14166835, 29815394, 7444469, 29551787, -3727419, 19288549, 1325865 },
+ },
+ {
+ { 15100157, -15835752, -23923978, -1005098, -26450192, 15509408, 12376730, -3479146, 33166107, -8042750 },
+ { 20909231, 13023121, -9209752, 16251778, -5778415, -8094914, 12412151, 10018715, 2213263, -13878373 },
+ { 32529814, -11074689, 30361439, -16689753, -9135940, 1513226, 22922121, 6382134, -5766928, 8371348 },
+ },
+ },
+ {
+ {
+ { 9923462, 11271500, 12616794, 3544722, -29998368, -1721626, 12891687, -8193132, -26442943, 10486144 },
+ { -22597207, -7012665, 8587003, -8257861, 4084309, -12970062, 361726, 2610596, -23921530, -11455195 },
+ { 5408411, -1136691, -4969122, 10561668, 24145918, 14240566, 31319731, -4235541, 19985175, -3436086 },
+ },
+ {
+ { -13994457, 16616821, 14549246, 3341099, 32155958, 13648976, -17577068, 8849297, 65030, 8370684 },
+ { -8320926, -12049626, 31204563, 5839400, -20627288, -1057277, -19442942, 6922164, 12743482, -9800518 },
+ { -2361371, 12678785, 28815050, 4759974, -23893047, 4884717, 23783145, 11038569, 18800704, 255233 },
+ },
+ {
+ { -5269658, -1773886, 13957886, 7990715, 23132995, 728773, 13393847, 9066957, 19258688, -14753793 },
+ { -2936654, -10827535, -10432089, 14516793, -3640786, 4372541, -31934921, 2209390, -1524053, 2055794 },
+ { 580882, 16705327, 5468415, -2683018, -30926419, -14696000, -7203346, -8994389, -30021019, 7394435 },
+ },
+ {
+ { 23838809, 1822728, -15738443, 15242727, 8318092, -3733104, -21672180, -3492205, -4821741, 14799921 },
+ { 13345610, 9759151, 3371034, -16137791, 16353039, 8577942, 31129804, 13496856, -9056018, 7402518 },
+ { 2286874, -4435931, -20042458, -2008336, -13696227, 5038122, 11006906, -15760352, 8205061, 1607563 },
+ },
+ {
+ { 14414086, -8002132, 3331830, -3208217, 22249151, -5594188, 18364661, -2906958, 30019587, -9029278 },
+ { -27688051, 1585953, -10775053, 931069, -29120221, -11002319, -14410829, 12029093, 9944378, 8024 },
+ { 4368715, -3709630, 29874200, -15022983, -20230386, -11410704, -16114594, -999085, -8142388, 5640030 },
+ },
+ {
+ { 10299610, 13746483, 11661824, 16234854, 7630238, 5998374, 9809887, -16694564, 15219798, -14327783 },
+ { 27425505, -5719081, 3055006, 10660664, 23458024, 595578, -15398605, -1173195, -18342183, 9742717 },
+ { 6744077, 2427284, 26042789, 2720740, -847906, 1118974, 32324614, 7406442, 12420155, 1994844 },
+ },
+ {
+ { 14012521, -5024720, -18384453, -9578469, -26485342, -3936439, -13033478, -10909803, 24319929, -6446333 },
+ { 16412690, -4507367, 10772641, 15929391, -17068788, -4658621, 10555945, -10484049, -30102368, -4739048 },
+ { 22397382, -7767684, -9293161, -12792868, 17166287, -9755136, -27333065, 6199366, 21880021, -12250760 },
+ },
+ {
+ { -4283307, 5368523, -31117018, 8163389, -30323063, 3209128, 16557151, 8890729, 8840445, 4957760 },
+ { -15447727, 709327, -6919446, -10870178, -29777922, 6522332, -21720181, 12130072, -14796503, 5005757 },
+ { -2114751, -14308128, 23019042, 15765735, -25269683, 6002752, 10183197, -13239326, -16395286, -2176112 },
+ },
+ },
+ {
+ {
+ { -19025756, 1632005, 13466291, -7995100, -23640451, 16573537, -32013908, -3057104, 22208662, 2000468 },
+ { 3065073, -1412761, -25598674, -361432, -17683065, -5703415, -8164212, 11248527, -3691214, -7414184 },
+ { 10379208, -6045554, 8877319, 1473647, -29291284, -12507580, 16690915, 2553332, -3132688, 16400289 },
+ },
+ {
+ { 15716668, 1254266, -18472690, 7446274, -8448918, 6344164, -22097271, -7285580, 26894937, 9132066 },
+ { 24158887, 12938817, 11085297, -8177598, -28063478, -4457083, -30576463, 64452, -6817084, -2692882 },
+ { 13488534, 7794716, 22236231, 5989356, 25426474, -12578208, 2350710, -3418511, -4688006, 2364226 },
+ },
+ {
+ { 16335052, 9132434, 25640582, 6678888, 1725628, 8517937, -11807024, -11697457, 15445875, -7798101 },
+ { 29004207, -7867081, 28661402, -640412, -12794003, -7943086, 31863255, -4135540, -278050, -15759279 },
+ { -6122061, -14866665, -28614905, 14569919, -10857999, -3591829, 10343412, -6976290, -29828287, -10815811 },
+ },
+ {
+ { 27081650, 3463984, 14099042, -4517604, 1616303, -6205604, 29542636, 15372179, 17293797, 960709 },
+ { 20263915, 11434237, -5765435, 11236810, 13505955, -10857102, -16111345, 6493122, -19384511, 7639714 },
+ { -2830798, -14839232, 25403038, -8215196, -8317012, -16173699, 18006287, -16043750, 29994677, -15808121 },
+ },
+ {
+ { 9769828, 5202651, -24157398, -13631392, -28051003, -11561624, -24613141, -13860782, -31184575, 709464 },
+ { 12286395, 13076066, -21775189, -1176622, -25003198, 4057652, -32018128, -8890874, 16102007, 13205847 },
+ { 13733362, 5599946, 10557076, 3195751, -5557991, 8536970, -25540170, 8525972, 10151379, 10394400 },
+ },
+ {
+ { 4024660, -16137551, 22436262, 12276534, -9099015, -2686099, 19698229, 11743039, -33302334, 8934414 },
+ { -15879800, -4525240, -8580747, -2934061, 14634845, -698278, -9449077, 3137094, -11536886, 11721158 },
+ { 17555939, -5013938, 8268606, 2331751, -22738815, 9761013, 9319229, 8835153, -9205489, -1280045 },
+ },
+ {
+ { -461409, -7830014, 20614118, 16688288, -7514766, -4807119, 22300304, 505429, 6108462, -6183415 },
+ { -5070281, 12367917, -30663534, 3234473, 32617080, -8422642, 29880583, -13483331, -26898490, -7867459 },
+ { -31975283, 5726539, 26934134, 10237677, -3173717, -605053, 24199304, 3795095, 7592688, -14992079 },
+ },
+ {
+ { 21594432, -14964228, 17466408, -4077222, 32537084, 2739898, 6407723, 12018833, -28256052, 4298412 },
+ { -20650503, -11961496, -27236275, 570498, 3767144, -1717540, 13891942, -1569194, 13717174, 10805743 },
+ { -14676630, -15644296, 15287174, 11927123, 24177847, -8175568, -796431, 14860609, -26938930, -5863836 },
+ },
+ },
+ {
+ {
+ { 12962541, 5311799, -10060768, 11658280, 18855286, -7954201, 13286263, -12808704, -4381056, 9882022 },
+ { 18512079, 11319350, -20123124, 15090309, 18818594, 5271736, -22727904, 3666879, -23967430, -3299429 },
+ { -6789020, -3146043, 16192429, 13241070, 15898607, -14206114, -10084880, -6661110, -2403099, 5276065 },
+ },
+ {
+ { 30169808, -5317648, 26306206, -11750859, 27814964, 7069267, 7152851, 3684982, 1449224, 13082861 },
+ { 10342826, 3098505, 2119311, 193222, 25702612, 12233820, 23697382, 15056736, -21016438, -8202000 },
+ { -33150110, 3261608, 22745853, 7948688, 19370557, -15177665, -26171976, 6482814, -10300080, -11060101 },
+ },
+ {
+ { 32869458, -5408545, 25609743, 15678670, -10687769, -15471071, 26112421, 2521008, -22664288, 6904815 },
+ { 29506923, 4457497, 3377935, -9796444, -30510046, 12935080, 1561737, 3841096, -29003639, -6657642 },
+ { 10340844, -6630377, -18656632, -2278430, 12621151, -13339055, 30878497, -11824370, -25584551, 5181966 },
+ },
+ {
+ { 25940115, -12658025, 17324188, -10307374, -8671468, 15029094, 24396252, -16450922, -2322852, -12388574 },
+ { -21765684, 9916823, -1300409, 4079498, -1028346, 11909559, 1782390, 12641087, 20603771, -6561742 },
+ { -18882287, -11673380, 24849422, 11501709, 13161720, -4768874, 1925523, 11914390, 4662781, 7820689 },
+ },
+ {
+ { 12241050, -425982, 8132691, 9393934, 32846760, -1599620, 29749456, 12172924, 16136752, 15264020 },
+ { -10349955, -14680563, -8211979, 2330220, -17662549, -14545780, 10658213, 6671822, 19012087, 3772772 },
+ { 3753511, -3421066, 10617074, 2028709, 14841030, -6721664, 28718732, -15762884, 20527771, 12988982 },
+ },
+ {
+ { -14822485, -5797269, -3707987, 12689773, -898983, -10914866, -24183046, -10564943, 3299665, -12424953 },
+ { -16777703, -15253301, -9642417, 4978983, 3308785, 8755439, 6943197, 6461331, -25583147, 8991218 },
+ { -17226263, 1816362, -1673288, -6086439, 31783888, -8175991, -32948145, 7417950, -30242287, 1507265 },
+ },
+ {
+ { 29692663, 6829891, -10498800, 4334896, 20945975, -11906496, -28887608, 8209391, 14606362, -10647073 },
+ { -3481570, 8707081, 32188102, 5672294, 22096700, 1711240, -33020695, 9761487, 4170404, -2085325 },
+ { -11587470, 14855945, -4127778, -1531857, -26649089, 15084046, 22186522, 16002000, -14276837, -8400798 },
+ },
+ {
+ { -4811456, 13761029, -31703877, -2483919, -3312471, 7869047, -7113572, -9620092, 13240845, 10965870 },
+ { -7742563, -8256762, -14768334, -13656260, -23232383, 12387166, 4498947, 14147411, 29514390, 4302863 },
+ { -13413405, -12407859, 20757302, -13801832, 14785143, 8976368, -5061276, -2144373, 17846988, -13971927 },
+ },
+ },
+ {
+ {
+ { -2244452, -754728, -4597030, -1066309, -6247172, 1455299, -21647728, -9214789, -5222701, 12650267 },
+ { -9906797, -16070310, 21134160, 12198166, -27064575, 708126, 387813, 13770293, -19134326, 10958663 },
+ { 22470984, 12369526, 23446014, -5441109, -21520802, -9698723, -11772496, -11574455, -25083830, 4271862 },
+ },
+ {
+ { -25169565, -10053642, -19909332, 15361595, -5984358, 2159192, 75375, -4278529, -32526221, 8469673 },
+ { 15854970, 4148314, -8893890, 7259002, 11666551, 13824734, -30531198, 2697372, 24154791, -9460943 },
+ { 15446137, -15806644, 29759747, 14019369, 30811221, -9610191, -31582008, 12840104, 24913809, 9815020 },
+ },
+ {
+ { -4709286, -5614269, -31841498, -12288893, -14443537, 10799414, -9103676, 13438769, 18735128, 9466238 },
+ { 11933045, 9281483, 5081055, -5183824, -2628162, -4905629, -7727821, -10896103, -22728655, 16199064 },
+ { 14576810, 379472, -26786533, -8317236, -29426508, -10812974, -102766, 1876699, 30801119, 2164795 },
+ },
+ {
+ { 15995086, 3199873, 13672555, 13712240, -19378835, -4647646, -13081610, -15496269, -13492807, 1268052 },
+ { -10290614, -3659039, -3286592, 10948818, 23037027, 3794475, -3470338, -12600221, -17055369, 3565904 },
+ { 29210088, -9419337, -5919792, -4952785, 10834811, -13327726, -16512102, -10820713, -27162222, -14030531 },
+ },
+ {
+ { -13161890, 15508588, 16663704, -8156150, -28349942, 9019123, -29183421, -3769423, 2244111, -14001979 },
+ { -5152875, -3800936, -9306475, -6071583, 16243069, 14684434, -25673088, -16180800, 13491506, 4641841 },
+ { 10813417, 643330, -19188515, -728916, 30292062, -16600078, 27548447, -7721242, 14476989, -12767431 },
+ },
+ {
+ { 10292079, 9984945, 6481436, 8279905, -7251514, 7032743, 27282937, -1644259, -27912810, 12651324 },
+ { -31185513, -813383, 22271204, 11835308, 10201545, 15351028, 17099662, 3988035, 21721536, -3148940 },
+ { 10202177, -6545839, -31373232, -9574638, -32150642, -8119683, -12906320, 3852694, 13216206, 14842320 },
+ },
+ {
+ { -15815640, -10601066, -6538952, -7258995, -6984659, -6581778, -31500847, 13765824, -27434397, 9900184 },
+ { 14465505, -13833331, -32133984, -14738873, -27443187, 12990492, 33046193, 15796406, -7051866, -8040114 },
+ { 30924417, -8279620, 6359016, -12816335, 16508377, 9071735, -25488601, 15413635, 9524356, -7018878 },
+ },
+ {
+ { 12274201, -13175547, 32627641, -1785326, 6736625, 13267305, 5237659, -5109483, 15663516, 4035784 },
+ { -2951309, 8903985, 17349946, 601635, -16432815, -4612556, -13732739, -15889334, -22258478, 4659091 },
+ { -16916263, -4952973, -30393711, -15158821, 20774812, 15897498, 5736189, 15026997, -2178256, -13455585 },
+ },
+ },
+ {
+ {
+ { -8858980, -2219056, 28571666, -10155518, -474467, -10105698, -3801496, 278095, 23440562, -290208 },
+ { 10226241, -5928702, 15139956, 120818, -14867693, 5218603, 32937275, 11551483, -16571960, -7442864 },
+ { 17932739, -12437276, -24039557, 10749060, 11316803, 7535897, 22503767, 5561594, -3646624, 3898661 },
+ },
+ {
+ { 7749907, -969567, -16339731, -16464, -25018111, 15122143, -1573531, 7152530, 21831162, 1245233 },
+ { 26958459, -14658026, 4314586, 8346991, -5677764, 11960072, -32589295, -620035, -30402091, -16716212 },
+ { -12165896, 9166947, 33491384, 13673479, 29787085, 13096535, 6280834, 14587357, -22338025, 13987525 },
+ },
+ {
+ { -24349909, 7778775, 21116000, 15572597, -4833266, -5357778, -4300898, -5124639, -7469781, -2858068 },
+ { 9681908, -6737123, -31951644, 13591838, -6883821, 386950, 31622781, 6439245, -14581012, 4091397 },
+ { -8426427, 1470727, -28109679, -1596990, 3978627, -5123623, -19622683, 12092163, 29077877, -14741988 },
+ },
+ {
+ { 5269168, -6859726, -13230211, -8020715, 25932563, 1763552, -5606110, -5505881, -20017847, 2357889 },
+ { 32264008, -15407652, -5387735, -1160093, -2091322, -3946900, 23104804, -12869908, 5727338, 189038 },
+ { 14609123, -8954470, -6000566, -16622781, -14577387, -7743898, -26745169, 10942115, -25888931, -14884697 },
+ },
+ {
+ { 20513500, 5557931, -15604613, 7829531, 26413943, -2019404, -21378968, 7471781, 13913677, -5137875 },
+ { -25574376, 11967826, 29233242, 12948236, -6754465, 4713227, -8940970, 14059180, 12878652, 8511905 },
+ { -25656801, 3393631, -2955415, -7075526, -2250709, 9366908, -30223418, 6812974, 5568676, -3127656 },
+ },
+ {
+ { 11630004, 12144454, 2116339, 13606037, 27378885, 15676917, -17408753, -13504373, -14395196, 8070818 },
+ { 27117696, -10007378, -31282771, -5570088, 1127282, 12772488, -29845906, 10483306, -11552749, -1028714 },
+ { 10637467, -5688064, 5674781, 1072708, -26343588, -6982302, -1683975, 9177853, -27493162, 15431203 },
+ },
+ {
+ { 20525145, 10892566, -12742472, 12779443, -29493034, 16150075, -28240519, 14943142, -15056790, -7935931 },
+ { -30024462, 5626926, -551567, -9981087, 753598, 11981191, 25244767, -3239766, -3356550, 9594024 },
+ { -23752644, 2636870, -5163910, -10103818, 585134, 7877383, 11345683, -6492290, 13352335, -10977084 },
+ },
+ {
+ { -1931799, -5407458, 3304649, -12884869, 17015806, -4877091, -29783850, -7752482, -13215537, -319204 },
+ { 20239939, 6607058, 6203985, 3483793, -18386976, -779229, -20723742, 15077870, -22750759, 14523817 },
+ { 27406042, -6041657, 27423596, -4497394, 4996214, 10002360, -28842031, -4545494, -30172742, -4805667 },
+ },
+ },
+ {
+ {
+ { 11374242, 12660715, 17861383, -12540833, 10935568, 1099227, -13886076, -9091740, -27727044, 11358504 },
+ { -12730809, 10311867, 1510375, 10778093, -2119455, -9145702, 32676003, 11149336, -26123651, 4985768 },
+ { -19096303, 341147, -6197485, -239033, 15756973, -8796662, -983043, 13794114, -19414307, -15621255 },
+ },
+ {
+ { 6490081, 11940286, 25495923, -7726360, 8668373, -8751316, 3367603, 6970005, -1691065, -9004790 },
+ { 1656497, 13457317, 15370807, 6364910, 13605745, 8362338, -19174622, -5475723, -16796596, -5031438 },
+ { -22273315, -13524424, -64685, -4334223, -18605636, -10921968, -20571065, -7007978, -99853, -10237333 },
+ },
+ {
+ { 17747465, 10039260, 19368299, -4050591, -20630635, -16041286, 31992683, -15857976, -29260363, -5511971 },
+ { 31932027, -4986141, -19612382, 16366580, 22023614, 88450, 11371999, -3744247, 4882242, -10626905 },
+ { 29796507, 37186, 19818052, 10115756, -11829032, 3352736, 18551198, 3272828, -5190932, -4162409 },
+ },
+ {
+ { 12501286, 4044383, -8612957, -13392385, -32430052, 5136599, -19230378, -3529697, 330070, -3659409 },
+ { 6384877, 2899513, 17807477, 7663917, -2358888, 12363165, 25366522, -8573892, -271295, 12071499 },
+ { -8365515, -4042521, 25133448, -4517355, -6211027, 2265927, -32769618, 1936675, -5159697, 3829363 },
+ },
+ {
+ { 28425966, -5835433, -577090, -4697198, -14217555, 6870930, 7921550, -6567787, 26333140, 14267664 },
+ { -11067219, 11871231, 27385719, -10559544, -4585914, -11189312, 10004786, -8709488, -21761224, 8930324 },
+ { -21197785, -16396035, 25654216, -1725397, 12282012, 11008919, 1541940, 4757911, -26491501, -16408940 },
+ },
+ {
+ { 13537262, -7759490, -20604840, 10961927, -5922820, -13218065, -13156584, 6217254, -15943699, 13814990 },
+ { -17422573, 15157790, 18705543, 29619, 24409717, -260476, 27361681, 9257833, -1956526, -1776914 },
+ { -25045300, -10191966, 15366585, 15166509, -13105086, 8423556, -29171540, 12361135, -18685978, 4578290 },
+ },
+ {
+ { 24579768, 3711570, 1342322, -11180126, -27005135, 14124956, -22544529, 14074919, 21964432, 8235257 },
+ { -6528613, -2411497, 9442966, -5925588, 12025640, -1487420, -2981514, -1669206, 13006806, 2355433 },
+ { -16304899, -13605259, -6632427, -5142349, 16974359, -10911083, 27202044, 1719366, 1141648, -12796236 },
+ },
+ {
+ { -12863944, -13219986, -8318266, -11018091, -6810145, -4843894, 13475066, -3133972, 32674895, 13715045 },
+ { 11423335, -5468059, 32344216, 8962751, 24989809, 9241752, -13265253, 16086212, -28740881, -15642093 },
+ { -1409668, 12530728, -6368726, 10847387, 19531186, -14132160, -11709148, 7791794, -27245943, 4383347 },
+ },
+ },
+ {
+ {
+ { -28970898, 5271447, -1266009, -9736989, -12455236, 16732599, -4862407, -4906449, 27193557, 6245191 },
+ { -15193956, 5362278, -1783893, 2695834, 4960227, 12840725, 23061898, 3260492, 22510453, 8577507 },
+ { -12632451, 11257346, -32692994, 13548177, -721004, 10879011, 31168030, 13952092, -29571492, -3635906 },
+ },
+ {
+ { 3877321, -9572739, 32416692, 5405324, -11004407, -13656635, 3759769, 11935320, 5611860, 8164018 },
+ { -16275802, 14667797, 15906460, 12155291, -22111149, -9039718, 32003002, -8832289, 5773085, -8422109 },
+ { -23788118, -8254300, 1950875, 8937633, 18686727, 16459170, -905725, 12376320, 31632953, 190926 },
+ },
+ {
+ { -24593607, -16138885, -8423991, 13378746, 14162407, 6901328, -8288749, 4508564, -25341555, -3627528 },
+ { 8884438, -5884009, 6023974, 10104341, -6881569, -4941533, 18722941, -14786005, -1672488, 827625 },
+ { -32720583, -16289296, -32503547, 7101210, 13354605, 2659080, -1800575, -14108036, -24878478, 1541286 },
+ },
+ {
+ { 2901347, -1117687, 3880376, -10059388, -17620940, -3612781, -21802117, -3567481, 20456845, -1885033 },
+ { 27019610, 12299467, -13658288, -1603234, -12861660, -4861471, -19540150, -5016058, 29439641, 15138866 },
+ { 21536104, -6626420, -32447818, -10690208, -22408077, 5175814, -5420040, -16361163, 7779328, 109896 },
+ },
+ {
+ { 30279744, 14648750, -8044871, 6425558, 13639621, -743509, 28698390, 12180118, 23177719, -554075 },
+ { 26572847, 3405927, -31701700, 12890905, -19265668, 5335866, -6493768, 2378492, 4439158, -13279347 },
+ { -22716706, 3489070, -9225266, -332753, 18875722, -1140095, 14819434, -12731527, -17717757, -5461437 },
+ },
+ {
+ { -5056483, 16566551, 15953661, 3767752, -10436499, 15627060, -820954, 2177225, 8550082, -15114165 },
+ { -18473302, 16596775, -381660, 15663611, 22860960, 15585581, -27844109, -3582739, -23260460, -8428588 },
+ { -32480551, 15707275, -8205912, -5652081, 29464558, 2713815, -22725137, 15860482, -21902570, 1494193 },
+ },
+ {
+ { -19562091, -14087393, -25583872, -9299552, 13127842, 759709, 21923482, 16529112, 8742704, 12967017 },
+ { -28464899, 1553205, 32536856, -10473729, -24691605, -406174, -8914625, -2933896, -29903758, 15553883 },
+ { 21877909, 3230008, 9881174, 10539357, -4797115, 2841332, 11543572, 14513274, 19375923, -12647961 },
+ },
+ {
+ { 8832269, -14495485, 13253511, 5137575, 5037871, 4078777, 24880818, -6222716, 2862653, 9455043 },
+ { 29306751, 5123106, 20245049, -14149889, 9592566, 8447059, -2077124, -2990080, 15511449, 4789663 },
+ { -20679756, 7004547, 8824831, -9434977, -4045704, -3750736, -5754762, 108893, 23513200, 16652362 },
+ },
+ },
+ {
+ {
+ { -33256173, 4144782, -4476029, -6579123, 10770039, -7155542, -6650416, -12936300, -18319198, 10212860 },
+ { 2756081, 8598110, 7383731, -6859892, 22312759, -1105012, 21179801, 2600940, -9988298, -12506466 },
+ { -24645692, 13317462, -30449259, -15653928, 21365574, -10869657, 11344424, 864440, -2499677, -16710063 },
+ },
+ {
+ { -26432803, 6148329, -17184412, -14474154, 18782929, -275997, -22561534, 211300, 2719757, 4940997 },
+ { -1323882, 3911313, -6948744, 14759765, -30027150, 7851207, 21690126, 8518463, 26699843, 5276295 },
+ { -13149873, -6429067, 9396249, 365013, 24703301, -10488939, 1321586, 149635, -15452774, 7159369 },
+ },
+ {
+ { 9987780, -3404759, 17507962, 9505530, 9731535, -2165514, 22356009, 8312176, 22477218, -8403385 },
+ { 18155857, -16504990, 19744716, 9006923, 15154154, -10538976, 24256460, -4864995, -22548173, 9334109 },
+ { 2986088, -4911893, 10776628, -3473844, 10620590, -7083203, -21413845, 14253545, -22587149, 536906 },
+ },
+ {
+ { 4377756, 8115836, 24567078, 15495314, 11625074, 13064599, 7390551, 10589625, 10838060, -15420424 },
+ { -19342404, 867880, 9277171, -3218459, -14431572, -1986443, 19295826, -15796950, 6378260, 699185 },
+ { 7895026, 4057113, -7081772, -13077756, -17886831, -323126, -716039, 15693155, -5045064, -13373962 },
+ },
+ {
+ { -7737563, -5869402, -14566319, -7406919, 11385654, 13201616, 31730678, -10962840, -3918636, -9669325 },
+ { 10188286, -15770834, -7336361, 13427543, 22223443, 14896287, 30743455, 7116568, -21786507, 5427593 },
+ { 696102, 13206899, 27047647, -10632082, 15285305, -9853179, 10798490, -4578720, 19236243, 12477404 },
+ },
+ {
+ { -11229439, 11243796, -17054270, -8040865, -788228, -8167967, -3897669, 11180504, -23169516, 7733644 },
+ { 17800790, -14036179, -27000429, -11766671, 23887827, 3149671, 23466177, -10538171, 10322027, 15313801 },
+ { 26246234, 11968874, 32263343, -5468728, 6830755, -13323031, -15794704, -101982, -24449242, 10890804 },
+ },
+ {
+ { -31365647, 10271363, -12660625, -6267268, 16690207, -13062544, -14982212, 16484931, 25180797, -5334884 },
+ { -586574, 10376444, -32586414, -11286356, 19801893, 10997610, 2276632, 9482883, 316878, 13820577 },
+ { -9882808, -4510367, -2115506, 16457136, -11100081, 11674996, 30756178, -7515054, 30696930, -3712849 },
+ },
+ {
+ { 32988917, -9603412, 12499366, 7910787, -10617257, -11931514, -7342816, -9985397, -32349517, 7392473 },
+ { -8855661, 15927861, 9866406, -3649411, -2396914, -16655781, -30409476, -9134995, 25112947, -2926644 },
+ { -2504044, -436966, 25621774, -5678772, 15085042, -5479877, -24884878, -13526194, 5537438, -13914319 },
+ },
+ },
+ {
+ {
+ { -11225584, 2320285, -9584280, 10149187, -33444663, 5808648, -14876251, -1729667, 31234590, 6090599 },
+ { -9633316, 116426, 26083934, 2897444, -6364437, -2688086, 609721, 15878753, -6970405, -9034768 },
+ { -27757857, 247744, -15194774, -9002551, 23288161, -10011936, -23869595, 6503646, 20650474, 1804084 },
+ },
+ {
+ { -27589786, 15456424, 8972517, 8469608, 15640622, 4439847, 3121995, -10329713, 27842616, -202328 },
+ { -15306973, 2839644, 22530074, 10026331, 4602058, 5048462, 28248656, 5031932, -11375082, 12714369 },
+ { 20807691, -7270825, 29286141, 11421711, -27876523, -13868230, -21227475, 1035546, -19733229, 12796920 },
+ },
+ {
+ { 12076899, -14301286, -8785001, -11848922, -25012791, 16400684, -17591495, -12899438, 3480665, -15182815 },
+ { -32361549, 5457597, 28548107, 7833186, 7303070, -11953545, -24363064, -15921875, -33374054, 2771025 },
+ { -21389266, 421932, 26597266, 6860826, 22486084, -6737172, -17137485, -4210226, -24552282, 15673397 },
+ },
+ {
+ { -20184622, 2338216, 19788685, -9620956, -4001265, -8740893, -20271184, 4733254, 3727144, -12934448 },
+ { 6120119, 814863, -11794402, -622716, 6812205, -15747771, 2019594, 7975683, 31123697, -10958981 },
+ { 30069250, -11435332, 30434654, 2958439, 18399564, -976289, 12296869, 9204260, -16432438, 9648165 },
+ },
+ {
+ { 32705432, -1550977, 30705658, 7451065, -11805606, 9631813, 3305266, 5248604, -26008332, -11377501 },
+ { 17219865, 2375039, -31570947, -5575615, -19459679, 9219903, 294711, 15298639, 2662509, -16297073 },
+ { -1172927, -7558695, -4366770, -4287744, -21346413, -8434326, 32087529, -1222777, 32247248, -14389861 },
+ },
+ {
+ { 14312628, 1221556, 17395390, -8700143, -4945741, -8684635, -28197744, -9637817, -16027623, -13378845 },
+ { -1428825, -9678990, -9235681, 6549687, -7383069, -468664, 23046502, 9803137, 17597934, 2346211 },
+ { 18510800, 15337574, 26171504, 981392, -22241552, 7827556, -23491134, -11323352, 3059833, -11782870 },
+ },
+ {
+ { 10141598, 6082907, 17829293, -1947643, 9830092, 13613136, -25556636, -5544586, -33502212, 3592096 },
+ { 33114168, -15889352, -26525686, -13343397, 33076705, 8716171, 1151462, 1521897, -982665, -6837803 },
+ { -32939165, -4255815, 23947181, -324178, -33072974, -12305637, -16637686, 3891704, 26353178, 693168 },
+ },
+ {
+ { 30374239, 1595580, -16884039, 13186931, 4600344, 406904, 9585294, -400668, 31375464, 14369965 },
+ { -14370654, -7772529, 1510301, 6434173, -18784789, -6262728, 32732230, -13108839, 17901441, 16011505 },
+ { 18171223, -11934626, -12500402, 15197122, -11038147, -15230035, -19172240, -16046376, 8764035, 12309598 },
+ },
+ },
+ {
+ {
+ { 5975908, -5243188, -19459362, -9681747, -11541277, 14015782, -23665757, 1228319, 17544096, -10593782 },
+ { 5811932, -1715293, 3442887, -2269310, -18367348, -8359541, -18044043, -15410127, -5565381, 12348900 },
+ { -31399660, 11407555, 25755363, 6891399, -3256938, 14872274, -24849353, 8141295, -10632534, -585479 },
+ },
+ {
+ { -12675304, 694026, -5076145, 13300344, 14015258, -14451394, -9698672, -11329050, 30944593, 1130208 },
+ { 8247766, -6710942, -26562381, -7709309, -14401939, -14648910, 4652152, 2488540, 23550156, -271232 },
+ { 17294316, -3788438, 7026748, 15626851, 22990044, 113481, 2267737, -5908146, -408818, -137719 },
+ },
+ {
+ { 16091085, -16253926, 18599252, 7340678, 2137637, -1221657, -3364161, 14550936, 3260525, -7166271 },
+ { -4910104, -13332887, 18550887, 10864893, -16459325, -7291596, -23028869, -13204905, -12748722, 2701326 },
+ { -8574695, 16099415, 4629974, -16340524, -20786213, -6005432, -10018363, 9276971, 11329923, 1862132 },
+ },
+ {
+ { 14763076, -15903608, -30918270, 3689867, 3511892, 10313526, -21951088, 12219231, -9037963, -940300 },
+ { 8894987, -3446094, 6150753, 3013931, 301220, 15693451, -31981216, -2909717, -15438168, 11595570 },
+ { 15214962, 3537601, -26238722, -14058872, 4418657, -15230761, 13947276, 10730794, -13489462, -4363670 },
+ },
+ {
+ { -2538306, 7682793, 32759013, 263109, -29984731, -7955452, -22332124, -10188635, 977108, 699994 },
+ { -12466472, 4195084, -9211532, 550904, -15565337, 12917920, 19118110, -439841, -30534533, -14337913 },
+ { 31788461, -14507657, 4799989, 7372237, 8808585, -14747943, 9408237, -10051775, 12493932, -5409317 },
+ },
+ {
+ { -25680606, 5260744, -19235809, -6284470, -3695942, 16566087, 27218280, 2607121, 29375955, 6024730 },
+ { 842132, -2794693, -4763381, -8722815, 26332018, -12405641, 11831880, 6985184, -9940361, 2854096 },
+ { -4847262, -7969331, 2516242, -5847713, 9695691, -7221186, 16512645, 960770, 12121869, 16648078 },
+ },
+ {
+ { -15218652, 14667096, -13336229, 2013717, 30598287, -464137, -31504922, -7882064, 20237806, 2838411 },
+ { -19288047, 4453152, 15298546, -16178388, 22115043, -15972604, 12544294, -13470457, 1068881, -12499905 },
+ { -9558883, -16518835, 33238498, 13506958, 30505848, -1114596, -8486907, -2630053, 12521378, 4845654 },
+ },
+ {
+ { -28198521, 10744108, -2958380, 10199664, 7759311, -13088600, 3409348, -873400, -6482306, -12885870 },
+ { -23561822, 6230156, -20382013, 10655314, -24040585, -11621172, 10477734, -1240216, -3113227, 13974498 },
+ { 12966261, 15550616, -32038948, -1615346, 21025980, -629444, 5642325, 7188737, 18895762, 12629579 },
+ },
+ },
+ {
+ {
+ { 14741879, -14946887, 22177208, -11721237, 1279741, 8058600, 11758140, 789443, 32195181, 3895677 },
+ { 10758205, 15755439, -4509950, 9243698, -4879422, 6879879, -2204575, -3566119, -8982069, 4429647 },
+ { -2453894, 15725973, -20436342, -10410672, -5803908, -11040220, -7135870, -11642895, 18047436, -15281743 },
+ },
+ {
+ { -25173001, -11307165, 29759956, 11776784, -22262383, -15820455, 10993114, -12850837, -17620701, -9408468 },
+ { 21987233, 700364, -24505048, 14972008, -7774265, -5718395, 32155026, 2581431, -29958985, 8773375 },
+ { -25568350, 454463, -13211935, 16126715, 25240068, 8594567, 20656846, 12017935, -7874389, -13920155 },
+ },
+ {
+ { 6028182, 6263078, -31011806, -11301710, -818919, 2461772, -31841174, -5468042, -1721788, -2776725 },
+ { -12278994, 16624277, 987579, -5922598, 32908203, 1248608, 7719845, -4166698, 28408820, 6816612 },
+ { -10358094, -8237829, 19549651, -12169222, 22082623, 16147817, 20613181, 13982702, -10339570, 5067943 },
+ },
+ {
+ { -30505967, -3821767, 12074681, 13582412, -19877972, 2443951, -19719286, 12746132, 5331210, -10105944 },
+ { 30528811, 3601899, -1957090, 4619785, -27361822, -15436388, 24180793, -12570394, 27679908, -1648928 },
+ { 9402404, -13957065, 32834043, 10838634, -26580150, -13237195, 26653274, -8685565, 22611444, -12715406 },
+ },
+ {
+ { 22190590, 1118029, 22736441, 15130463, -30460692, -5991321, 19189625, -4648942, 4854859, 6622139 },
+ { -8310738, -2953450, -8262579, -3388049, -10401731, -271929, 13424426, -3567227, 26404409, 13001963 },
+ { -31241838, -15415700, -2994250, 8939346, 11562230, -12840670, -26064365, -11621720, -15405155, 11020693 },
+ },
+ {
+ { 1866042, -7949489, -7898649, -10301010, 12483315, 13477547, 3175636, -12424163, 28761762, 1406734 },
+ { -448555, -1777666, 13018551, 3194501, -9580420, -11161737, 24760585, -4347088, 25577411, -13378680 },
+ { -24290378, 4759345, -690653, -1852816, 2066747, 10693769, -29595790, 9884936, -9368926, 4745410 },
+ },
+ {
+ { -9141284, 6049714, -19531061, -4341411, -31260798, 9944276, -15462008, -11311852, 10931924, -11931931 },
+ { -16561513, 14112680, -8012645, 4817318, -8040464, -11414606, -22853429, 10856641, -20470770, 13434654 },
+ { 22759489, -10073434, -16766264, -1871422, 13637442, -10168091, 1765144, -12654326, 28445307, -5364710 },
+ },
+ {
+ { 29875063, 12493613, 2795536, -3786330, 1710620, 15181182, -10195717, -8788675, 9074234, 1167180 },
+ { -26205683, 11014233, -9842651, -2635485, -26908120, 7532294, -18716888, -9535498, 3843903, 9367684 },
+ { -10969595, -6403711, 9591134, 9582310, 11349256, 108879, 16235123, 8601684, -139197, 4242895 },
+ },
+ },
+ {
+ {
+ { 22092954, -13191123, -2042793, -11968512, 32186753, -11517388, -6574341, 2470660, -27417366, 16625501 },
+ { -11057722, 3042016, 13770083, -9257922, 584236, -544855, -7770857, 2602725, -27351616, 14247413 },
+ { 6314175, -10264892, -32772502, 15957557, -10157730, 168750, -8618807, 14290061, 27108877, -1180880 },
+ },
+ {
+ { -8586597, -7170966, 13241782, 10960156, -32991015, -13794596, 33547976, -11058889, -27148451, 981874 },
+ { 22833440, 9293594, -32649448, -13618667, -9136966, 14756819, -22928859, -13970780, -10479804, -16197962 },
+ { -7768587, 3326786, -28111797, 10783824, 19178761, 14905060, 22680049, 13906969, -15933690, 3797899 },
+ },
+ {
+ { 21721356, -4212746, -12206123, 9310182, -3882239, -13653110, 23740224, -2709232, 20491983, -8042152 },
+ { 9209270, -15135055, -13256557, -6167798, -731016, 15289673, 25947805, 15286587, 30997318, -6703063 },
+ { 7392032, 16618386, 23946583, -8039892, -13265164, -1533858, -14197445, -2321576, 17649998, -250080 },
+ },
+ {
+ { -9301088, -14193827, 30609526, -3049543, -25175069, -1283752, -15241566, -9525724, -2233253, 7662146 },
+ { -17558673, 1763594, -33114336, 15908610, -30040870, -12174295, 7335080, -8472199, -3174674, 3440183 },
+ { -19889700, -5977008, -24111293, -9688870, 10799743, -16571957, 40450, -4431835, 4862400, 1133 },
+ },
+ {
+ { -32856209, -7873957, -5422389, 14860950, -16319031, 7956142, 7258061, 311861, -30594991, -7379421 },
+ { -3773428, -1565936, 28985340, 7499440, 24445838, 9325937, 29727763, 16527196, 18278453, 15405622 },
+ { -4381906, 8508652, -19898366, -3674424, -5984453, 15149970, -13313598, 843523, -21875062, 13626197 },
+ },
+ {
+ { 2281448, -13487055, -10915418, -2609910, 1879358, 16164207, -10783882, 3953792, 13340839, 15928663 },
+ { 31727126, -7179855, -18437503, -8283652, 2875793, -16390330, -25269894, -7014826, -23452306, 5964753 },
+ { 4100420, -5959452, -17179337, 6017714, -18705837, 12227141, -26684835, 11344144, 2538215, -7570755 },
+ },
+ {
+ { -9433605, 6123113, 11159803, -2156608, 30016280, 14966241, -20474983, 1485421, -629256, -15958862 },
+ { -26804558, 4260919, 11851389, 9658551, -32017107, 16367492, -20205425, -13191288, 11659922, -11115118 },
+ { 26180396, 10015009, -30844224, -8581293, 5418197, 9480663, 2231568, -10170080, 33100372, -1306171 },
+ },
+ {
+ { 15121113, -5201871, -10389905, 15427821, -27509937, -15992507, 21670947, 4486675, -5931810, -14466380 },
+ { 16166486, -9483733, -11104130, 6023908, -31926798, -1364923, 2340060, -16254968, -10735770, -10039824 },
+ { 28042865, -3557089, -12126526, 12259706, -3717498, -6945899, 6766453, -8689599, 18036436, 5803270 },
+ },
+ },
+ {
+ {
+ { -817581, 6763912, 11803561, 1585585, 10958447, -2671165, 23855391, 4598332, -6159431, -14117438 },
+ { -31031306, -14256194, 17332029, -2383520, 31312682, -5967183, 696309, 50292, -20095739, 11763584 },
+ { -594563, -2514283, -32234153, 12643980, 12650761, 14811489, 665117, -12613632, -19773211, -10713562 },
+ },
+ {
+ { 30464590, -11262872, -4127476, -12734478, 19835327, -7105613, -24396175, 2075773, -17020157, 992471 },
+ { 18357185, -6994433, 7766382, 16342475, -29324918, 411174, 14578841, 8080033, -11574335, -10601610 },
+ { 19598397, 10334610, 12555054, 2555664, 18821899, -10339780, 21873263, 16014234, 26224780, 16452269 },
+ },
+ {
+ { -30223925, 5145196, 5944548, 16385966, 3976735, 2009897, -11377804, -7618186, -20533829, 3698650 },
+ { 14187449, 3448569, -10636236, -10810935, -22663880, -3433596, 7268410, -10890444, 27394301, 12015369 },
+ { 19695761, 16087646, 28032085, 12999827, 6817792, 11427614, 20244189, -1312777, -13259127, -3402461 },
+ },
+ {
+ { 30860103, 12735208, -1888245, -4699734, -16974906, 2256940, -8166013, 12298312, -8550524, -10393462 },
+ { -5719826, -11245325, -1910649, 15569035, 26642876, -7587760, -5789354, -15118654, -4976164, 12651793 },
+ { -2848395, 9953421, 11531313, -5282879, 26895123, -12697089, -13118820, -16517902, 9768698, -2533218 },
+ },
+ {
+ { -24719459, 1894651, -287698, -4704085, 15348719, -8156530, 32767513, 12765450, 4940095, 10678226 },
+ { 18860224, 15980149, -18987240, -1562570, -26233012, -11071856, -7843882, 13944024, -24372348, 16582019 },
+ { -15504260, 4970268, -29893044, 4175593, -20993212, -2199756, -11704054, 15444560, -11003761, 7989037 },
+ },
+ {
+ { 31490452, 5568061, -2412803, 2182383, -32336847, 4531686, -32078269, 6200206, -19686113, -14800171 },
+ { -17308668, -15879940, -31522777, -2831, -32887382, 16375549, 8680158, -16371713, 28550068, -6857132 },
+ { -28126887, -5688091, 16837845, -1820458, -6850681, 12700016, -30039981, 4364038, 1155602, 5988841 },
+ },
+ {
+ { 21890435, -13272907, -12624011, 12154349, -7831873, 15300496, 23148983, -4470481, 24618407, 8283181 },
+ { -33136107, -10512751, 9975416, 6841041, -31559793, 16356536, 3070187, -7025928, 1466169, 10740210 },
+ { -1509399, -15488185, -13503385, -10655916, 32799044, 909394, -13938903, -5779719, -32164649, -15327040 },
+ },
+ {
+ { 3960823, -14267803, -28026090, -15918051, -19404858, 13146868, 15567327, 951507, -3260321, -573935 },
+ { 24740841, 5052253, -30094131, 8961361, 25877428, 6165135, -24368180, 14397372, -7380369, -6144105 },
+ { -28888365, 3510803, -28103278, -1158478, -11238128, -10631454, -15441463, -14453128, -1625486, -6494814 },
+ },
+ },
+ {
+ {
+ { 793299, -9230478, 8836302, -6235707, -27360908, -2369593, 33152843, -4885251, -9906200, -621852 },
+ { 5666233, 525582, 20782575, -8038419, -24538499, 14657740, 16099374, 1468826, -6171428, -15186581 },
+ { -4859255, -3779343, -2917758, -6748019, 7778750, 11688288, -30404353, -9871238, -1558923, -9863646 },
+ },
+ {
+ { 10896332, -7719704, 824275, 472601, -19460308, 3009587, 25248958, 14783338, -30581476, -15757844 },
+ { 10566929, 12612572, -31944212, 11118703, -12633376, 12362879, 21752402, 8822496, 24003793, 14264025 },
+ { 27713862, -7355973, -11008240, 9227530, 27050101, 2504721, 23886875, -13117525, 13958495, -5732453 },
+ },
+ {
+ { -23481610, 4867226, -27247128, 3900521, 29838369, -8212291, -31889399, -10041781, 7340521, -15410068 },
+ { 4646514, -8011124, -22766023, -11532654, 23184553, 8566613, 31366726, -1381061, -15066784, -10375192 },
+ { -17270517, 12723032, -16993061, 14878794, 21619651, -6197576, 27584817, 3093888, -8843694, 3849921 },
+ },
+ {
+ { -9064912, 2103172, 25561640, -15125738, -5239824, 9582958, 32477045, -9017955, 5002294, -15550259 },
+ { -12057553, -11177906, 21115585, -13365155, 8808712, -12030708, 16489530, 13378448, -25845716, 12741426 },
+ { -5946367, 10645103, -30911586, 15390284, -3286982, -7118677, 24306472, 15852464, 28834118, -7646072 },
+ },
+ {
+ { -17335748, -9107057, -24531279, 9434953, -8472084, -583362, -13090771, 455841, 20461858, 5491305 },
+ { 13669248, -16095482, -12481974, -10203039, -14569770, -11893198, -24995986, 11293807, -28588204, -9421832 },
+ { 28497928, 6272777, -33022994, 14470570, 8906179, -1225630, 18504674, -14165166, 29867745, -8795943 },
+ },
+ {
+ { -16207023, 13517196, -27799630, -13697798, 24009064, -6373891, -6367600, -13175392, 22853429, -4012011 },
+ { 24191378, 16712145, -13931797, 15217831, 14542237, 1646131, 18603514, -11037887, 12876623, -2112447 },
+ { 17902668, 4518229, -411702, -2829247, 26878217, 5258055, -12860753, 608397, 16031844, 3723494 },
+ },
+ {
+ { -28632773, 12763728, -20446446, 7577504, 33001348, -13017745, 17558842, -7872890, 23896954, -4314245 },
+ { -20005381, -12011952, 31520464, 605201, 2543521, 5991821, -2945064, 7229064, -9919646, -8826859 },
+ { 28816045, 298879, -28165016, -15920938, 19000928, -1665890, -12680833, -2949325, -18051778, -2082915 },
+ },
+ {
+ { 16000882, -344896, 3493092, -11447198, -29504595, -13159789, 12577740, 16041268, -19715240, 7847707 },
+ { 10151868, 10572098, 27312476, 7922682, 14825339, 4723128, -32855931, -6519018, -10020567, 3852848 },
+ { -11430470, 15697596, -21121557, -4420647, 5386314, 15063598, 16514493, -15932110, 29330899, -15076224 },
+ },
+ },
+ {
+ {
+ { -25499735, -4378794, -15222908, -6901211, 16615731, 2051784, 3303702, 15490, -27548796, 12314391 },
+ { 15683520, -6003043, 18109120, -9980648, 15337968, -5997823, -16717435, 15921866, 16103996, -3731215 },
+ { -23169824, -10781249, 13588192, -1628807, -3798557, -1074929, -19273607, 5402699, -29815713, -9841101 },
+ },
+ {
+ { 23190676, 2384583, -32714340, 3462154, -29903655, -1529132, -11266856, 8911517, -25205859, 2739713 },
+ { 21374101, -3554250, -33524649, 9874411, 15377179, 11831242, -33529904, 6134907, 4931255, 11987849 },
+ { -7732, -2978858, -16223486, 7277597, 105524, -322051, -31480539, 13861388, -30076310, 10117930 },
+ },
+ {
+ { -29501170, -10744872, -26163768, 13051539, -25625564, 5089643, -6325503, 6704079, 12890019, 15728940 },
+ { -21972360, -11771379, -951059, -4418840, 14704840, 2695116, 903376, -10428139, 12885167, 8311031 },
+ { -17516482, 5352194, 10384213, -13811658, 7506451, 13453191, 26423267, 4384730, 1888765, -5435404 },
+ },
+ {
+ { -25817338, -3107312, -13494599, -3182506, 30896459, -13921729, -32251644, -12707869, -19464434, -3340243 },
+ { -23607977, -2665774, -526091, 4651136, 5765089, 4618330, 6092245, 14845197, 17151279, -9854116 },
+ { -24830458, -12733720, -15165978, 10367250, -29530908, -265356, 22825805, -7087279, -16866484, 16176525 },
+ },
+ {
+ { -23583256, 6564961, 20063689, 3798228, -4740178, 7359225, 2006182, -10363426, -28746253, -10197509 },
+ { -10626600, -4486402, -13320562, -5125317, 3432136, -6393229, 23632037, -1940610, 32808310, 1099883 },
+ { 15030977, 5768825, -27451236, -2887299, -6427378, -15361371, -15277896, -6809350, 2051441, -15225865 },
+ },
+ {
+ { -3362323, -7239372, 7517890, 9824992, 23555850, 295369, 5148398, -14154188, -22686354, 16633660 },
+ { 4577086, -16752288, 13249841, -15304328, 19958763, -14537274, 18559670, -10759549, 8402478, -9864273 },
+ { -28406330, -1051581, -26790155, -907698, -17212414, -11030789, 9453451, -14980072, 17983010, 9967138 },
+ },
+ {
+ { -25762494, 6524722, 26585488, 9969270, 24709298, 1220360, -1677990, 7806337, 17507396, 3651560 },
+ { -10420457, -4118111, 14584639, 15971087, -15768321, 8861010, 26556809, -5574557, -18553322, -11357135 },
+ { 2839101, 14284142, 4029895, 3472686, 14402957, 12689363, -26642121, 8459447, -5605463, -7621941 },
+ },
+ {
+ { -4839289, -3535444, 9744961, 2871048, 25113978, 3187018, -25110813, -849066, 17258084, -7977739 },
+ { 18164541, -10595176, -17154882, -1542417, 19237078, -9745295, 23357533, -15217008, 26908270, 12150756 },
+ { -30264870, -7647865, 5112249, -7036672, -1499807, -6974257, 43168, -5537701, -32302074, 16215819 },
+ },
+ },
+ {
+ {
+ { -6898905, 9824394, -12304779, -4401089, -31397141, -6276835, 32574489, 12532905, -7503072, -8675347 },
+ { -27343522, -16515468, -27151524, -10722951, 946346, 16291093, 254968, 7168080, 21676107, -1943028 },
+ { 21260961, -8424752, -16831886, -11920822, -23677961, 3968121, -3651949, -6215466, -3556191, -7913075 },
+ },
+ {
+ { 16544754, 13250366, -16804428, 15546242, -4583003, 12757258, -2462308, -8680336, -18907032, -9662799 },
+ { -2415239, -15577728, 18312303, 4964443, -15272530, -12653564, 26820651, 16690659, 25459437, -4564609 },
+ { -25144690, 11425020, 28423002, -11020557, -6144921, -15826224, 9142795, -2391602, -6432418, -1644817 },
+ },
+ {
+ { -23104652, 6253476, 16964147, -3768872, -25113972, -12296437, -27457225, -16344658, 6335692, 7249989 },
+ { -30333227, 13979675, 7503222, -12368314, -11956721, -4621693, -30272269, 2682242, 25993170, -12478523 },
+ { 4364628, 5930691, 32304656, -10044554, -8054781, 15091131, 22857016, -10598955, 31820368, 15075278 },
+ },
+ {
+ { 31879134, -8918693, 17258761, 90626, -8041836, -4917709, 24162788, -9650886, -17970238, 12833045 },
+ { 19073683, 14851414, -24403169, -11860168, 7625278, 11091125, -19619190, 2074449, -9413939, 14905377 },
+ { 24483667, -11935567, -2518866, -11547418, -1553130, 15355506, -25282080, 9253129, 27628530, -7555480 },
+ },
+ {
+ { 17597607, 8340603, 19355617, 552187, 26198470, -3176583, 4593324, -9157582, -14110875, 15297016 },
+ { 510886, 14337390, -31785257, 16638632, 6328095, 2713355, -20217417, -11864220, 8683221, 2921426 },
+ { 18606791, 11874196, 27155355, -5281482, -24031742, 6265446, -25178240, -1278924, 4674690, 13890525 },
+ },
+ {
+ { 13609624, 13069022, -27372361, -13055908, 24360586, 9592974, 14977157, 9835105, 4389687, 288396 },
+ { 9922506, -519394, 13613107, 5883594, -18758345, -434263, -12304062, 8317628, 23388070, 16052080 },
+ { 12720016, 11937594, -31970060, -5028689, 26900120, 8561328, -20155687, -11632979, -14754271, -10812892 },
+ },
+ {
+ { 15961858, 14150409, 26716931, -665832, -22794328, 13603569, 11829573, 7467844, -28822128, 929275 },
+ { 11038231, -11582396, -27310482, -7316562, -10498527, -16307831, -23479533, -9371869, -21393143, 2465074 },
+ { 20017163, -4323226, 27915242, 1529148, 12396362, 15675764, 13817261, -9658066, 2463391, -4622140 },
+ },
+ {
+ { -16358878, -12663911, -12065183, 4996454, -1256422, 1073572, 9583558, 12851107, 4003896, 12673717 },
+ { -1731589, -15155870, -3262930, 16143082, 19294135, 13385325, 14741514, -9103726, 7903886, 2348101 },
+ { 24536016, -16515207, 12715592, -3862155, 1511293, 10047386, -3842346, -7129159, -28377538, 10048127 },
+ },
+ },
+ {
+ {
+ { -12622226, -6204820, 30718825, 2591312, -10617028, 12192840, 18873298, -7297090, -32297756, 15221632 },
+ { -26478122, -11103864, 11546244, -1852483, 9180880, 7656409, -21343950, 2095755, 29769758, 6593415 },
+ { -31994208, -2907461, 4176912, 3264766, 12538965, -868111, 26312345, -6118678, 30958054, 8292160 },
+ },
+ {
+ { 31429822, -13959116, 29173532, 15632448, 12174511, -2760094, 32808831, 3977186, 26143136, -3148876 },
+ { 22648901, 1402143, -22799984, 13746059, 7936347, 365344, -8668633, -1674433, -3758243, -2304625 },
+ { -15491917, 8012313, -2514730, -12702462, -23965846, -10254029, -1612713, -1535569, -16664475, 8194478 },
+ },
+ {
+ { 27338066, -7507420, -7414224, 10140405, -19026427, -6589889, 27277191, 8855376, 28572286, 3005164 },
+ { 26287124, 4821776, 25476601, -4145903, -3764513, -15788984, -18008582, 1182479, -26094821, -13079595 },
+ { -7171154, 3178080, 23970071, 6201893, -17195577, -4489192, -21876275, -13982627, 32208683, -1198248 },
+ },
+ {
+ { -16657702, 2817643, -10286362, 14811298, 6024667, 13349505, -27315504, -10497842, -27672585, -11539858 },
+ { 15941029, -9405932, -21367050, 8062055, 31876073, -238629, -15278393, -1444429, 15397331, -4130193 },
+ { 8934485, -13485467, -23286397, -13423241, -32446090, 14047986, 31170398, -1441021, -27505566, 15087184 },
+ },
+ {
+ { -18357243, -2156491, 24524913, -16677868, 15520427, -6360776, -15502406, 11461896, 16788528, -5868942 },
+ { -1947386, 16013773, 21750665, 3714552, -17401782, -16055433, -3770287, -10323320, 31322514, -11615635 },
+ { 21426655, -5650218, -13648287, -5347537, -28812189, -4920970, -18275391, -14621414, 13040862, -12112948 },
+ },
+ {
+ { 11293895, 12478086, -27136401, 15083750, -29307421, 14748872, 14555558, -13417103, 1613711, 4896935 },
+ { -25894883, 15323294, -8489791, -8057900, 25967126, -13425460, 2825960, -4897045, -23971776, -11267415 },
+ { -15924766, -5229880, -17443532, 6410664, 3622847, 10243618, 20615400, 12405433, -23753030, -8436416 },
+ },
+ {
+ { -7091295, 12556208, -20191352, 9025187, -17072479, 4333801, 4378436, 2432030, 23097949, -566018 },
+ { 4565804, -16025654, 20084412, -7842817, 1724999, 189254, 24767264, 10103221, -18512313, 2424778 },
+ { 366633, -11976806, 8173090, -6890119, 30788634, 5745705, -7168678, 1344109, -3642553, 12412659 },
+ },
+ {
+ { -24001791, 7690286, 14929416, -168257, -32210835, -13412986, 24162697, -15326504, -3141501, 11179385 },
+ { 18289522, -14724954, 8056945, 16430056, -21729724, 7842514, -6001441, -1486897, -18684645, -11443503 },
+ { 476239, 6601091, -6152790, -9723375, 17503545, -4863900, 27672959, 13403813, 11052904, 5219329 },
+ },
+ },
+ {
+ {
+ { 20678546, -8375738, -32671898, 8849123, -5009758, 14574752, 31186971, -3973730, 9014762, -8579056 },
+ { -13644050, -10350239, -15962508, 5075808, -1514661, -11534600, -33102500, 9160280, 8473550, -3256838 },
+ { 24900749, 14435722, 17209120, -15292541, -22592275, 9878983, -7689309, -16335821, -24568481, 11788948 },
+ },
+ {
+ { -3118155, -11395194, -13802089, 14797441, 9652448, -6845904, -20037437, 10410733, -24568470, -1458691 },
+ { -15659161, 16736706, -22467150, 10215878, -9097177, 7563911, 11871841, -12505194, -18513325, 8464118 },
+ { -23400612, 8348507, -14585951, -861714, -3950205, -6373419, 14325289, 8628612, 33313881, -8370517 },
+ },
+ {
+ { -20186973, -4967935, 22367356, 5271547, -1097117, -4788838, -24805667, -10236854, -8940735, -5818269 },
+ { -6948785, -1795212, -32625683, -16021179, 32635414, -7374245, 15989197, -12838188, 28358192, -4253904 },
+ { -23561781, -2799059, -32351682, -1661963, -9147719, 10429267, -16637684, 4072016, -5351664, 5596589 },
+ },
+ {
+ { -28236598, -3390048, 12312896, 6213178, 3117142, 16078565, 29266239, 2557221, 1768301, 15373193 },
+ { -7243358, -3246960, -4593467, -7553353, -127927, -912245, -1090902, -4504991, -24660491, 3442910 },
+ { -30210571, 5124043, 14181784, 8197961, 18964734, -11939093, 22597931, 7176455, -18585478, 13365930 },
+ },
+ {
+ { -7877390, -1499958, 8324673, 4690079, 6261860, 890446, 24538107, -8570186, -9689599, -3031667 },
+ { 25008904, -10771599, -4305031, -9638010, 16265036, 15721635, 683793, -11823784, 15723479, -15163481 },
+ { -9660625, 12374379, -27006999, -7026148, -7724114, -12314514, 11879682, 5400171, 519526, -1235876 },
+ },
+ {
+ { 22258397, -16332233, -7869817, 14613016, -22520255, -2950923, -20353881, 7315967, 16648397, 7605640 },
+ { -8081308, -8464597, -8223311, 9719710, 19259459, -15348212, 23994942, -5281555, -9468848, 4763278 },
+ { -21699244, 9220969, -15730624, 1084137, -25476107, -2852390, 31088447, -7764523, -11356529, 728112 },
+ },
+ {
+ { 26047220, -11751471, -6900323, -16521798, 24092068, 9158119, -4273545, -12555558, -29365436, -5498272 },
+ { 17510331, -322857, 5854289, 8403524, 17133918, -3112612, -28111007, 12327945, 10750447, 10014012 },
+ { -10312768, 3936952, 9156313, -8897683, 16498692, -994647, -27481051, -666732, 3424691, 7540221 },
+ },
+ {
+ { 30322361, -6964110, 11361005, -4143317, 7433304, 4989748, -7071422, -16317219, -9244265, 15258046 },
+ { 13054562, -2779497, 19155474, 469045, -12482797, 4566042, 5631406, 2711395, 1062915, -5136345 },
+ { -19240248, -11254599, -29509029, -7499965, -5835763, 13005411, -6066489, 12194497, 32960380, 1459310 },
+ },
+ },
+ {
+ {
+ { 19852034, 7027924, 23669353, 10020366, 8586503, -6657907, 394197, -6101885, 18638003, -11174937 },
+ { 31395534, 15098109, 26581030, 8030562, -16527914, -5007134, 9012486, -7584354, -6643087, -5442636 },
+ { -9192165, -2347377, -1997099, 4529534, 25766844, 607986, -13222, 9677543, -32294889, -6456008 },
+ },
+ {
+ { -2444496, -149937, 29348902, 8186665, 1873760, 12489863, -30934579, -7839692, -7852844, -8138429 },
+ { -15236356, -15433509, 7766470, 746860, 26346930, -10221762, -27333451, 10754588, -9431476, 5203576 },
+ { 31834314, 14135496, -770007, 5159118, 20917671, -16768096, -7467973, -7337524, 31809243, 7347066 },
+ },
+ {
+ { -9606723, -11874240, 20414459, 13033986, 13716524, -11691881, 19797970, -12211255, 15192876, -2087490 },
+ { -12663563, -2181719, 1168162, -3804809, 26747877, -14138091, 10609330, 12694420, 33473243, -13382104 },
+ { 33184999, 11180355, 15832085, -11385430, -1633671, 225884, 15089336, -11023903, -6135662, 14480053 },
+ },
+ {
+ { 31308717, -5619998, 31030840, -1897099, 15674547, -6582883, 5496208, 13685227, 27595050, 8737275 },
+ { -20318852, -15150239, 10933843, -16178022, 8335352, -7546022, -31008351, -12610604, 26498114, 66511 },
+ { 22644454, -8761729, -16671776, 4884562, -3105614, -13559366, 30540766, -4286747, -13327787, -7515095 },
+ },
+ {
+ { -28017847, 9834845, 18617207, -2681312, -3401956, -13307506, 8205540, 13585437, -17127465, 15115439 },
+ { 23711543, -672915, 31206561, -8362711, 6164647, -9709987, -33535882, -1426096, 8236921, 16492939 },
+ { -23910559, -13515526, -26299483, -4503841, 25005590, -7687270, 19574902, 10071562, 6708380, -6222424 },
+ },
+ {
+ { 2101391, -4930054, 19702731, 2367575, -15427167, 1047675, 5301017, 9328700, 29955601, -11678310 },
+ { 3096359, 9271816, -21620864, -15521844, -14847996, -7592937, -25892142, -12635595, -9917575, 6216608 },
+ { -32615849, 338663, -25195611, 2510422, -29213566, -13820213, 24822830, -6146567, -26767480, 7525079 },
+ },
+ {
+ { -23066649, -13985623, 16133487, -7896178, -3389565, 778788, -910336, -2782495, -19386633, 11994101 },
+ { 21691500, -13624626, -641331, -14367021, 3285881, -3483596, -25064666, 9718258, -7477437, 13381418 },
+ { 18445390, -4202236, 14979846, 11622458, -1727110, -3582980, 23111648, -6375247, 28535282, 15779576 },
+ },
+ {
+ { 30098053, 3089662, -9234387, 16662135, -21306940, 11308411, -14068454, 12021730, 9955285, -16303356 },
+ { 9734894, -14576830, -7473633, -9138735, 2060392, 11313496, -18426029, 9924399, 20194861, 13380996 },
+ { -26378102, -7965207, -22167821, 15789297, -18055342, -6168792, -1984914, 15707771, 26342023, 10146099 },
+ },
+ },
+ {
+ {
+ { -26016874, -219943, 21339191, -41388, 19745256, -2878700, -29637280, 2227040, 21612326, -545728 },
+ { -13077387, 1184228, 23562814, -5970442, -20351244, -6348714, 25764461, 12243797, -20856566, 11649658 },
+ { -10031494, 11262626, 27384172, 2271902, 26947504, -15997771, 39944, 6114064, 33514190, 2333242 },
+ },
+ {
+ { -21433588, -12421821, 8119782, 7219913, -21830522, -9016134, -6679750, -12670638, 24350578, -13450001 },
+ { -4116307, -11271533, -23886186, 4843615, -30088339, 690623, -31536088, -10406836, 8317860, 12352766 },
+ { 18200138, -14475911, -33087759, -2696619, -23702521, -9102511, -23552096, -2287550, 20712163, 6719373 },
+ },
+ {
+ { 26656208, 6075253, -7858556, 1886072, -28344043, 4262326, 11117530, -3763210, 26224235, -3297458 },
+ { -17168938, -14854097, -3395676, -16369877, -19954045, 14050420, 21728352, 9493610, 18620611, -16428628 },
+ { -13323321, 13325349, 11432106, 5964811, 18609221, 6062965, -5269471, -9725556, -30701573, -16479657 },
+ },
+ {
+ { -23860538, -11233159, 26961357, 1640861, -32413112, -16737940, 12248509, -5240639, 13735342, 1934062 },
+ { 25089769, 6742589, 17081145, -13406266, 21909293, -16067981, -15136294, -3765346, -21277997, 5473616 },
+ { 31883677, -7961101, 1083432, -11572403, 22828471, 13290673, -7125085, 12469656, 29111212, -5451014 },
+ },
+ {
+ { 24244947, -15050407, -26262976, 2791540, -14997599, 16666678, 24367466, 6388839, -10295587, 452383 },
+ { -25640782, -3417841, 5217916, 16224624, 19987036, -4082269, -24236251, -5915248, 15766062, 8407814 },
+ { -20406999, 13990231, 15495425, 16395525, 5377168, 15166495, -8917023, -4388953, -8067909, 2276718 },
+ },
+ {
+ { 30157918, 12924066, -17712050, 9245753, 19895028, 3368142, -23827587, 5096219, 22740376, -7303417 },
+ { 2041139, -14256350, 7783687, 13876377, -25946985, -13352459, 24051124, 13742383, -15637599, 13295222 },
+ { 33338237, -8505733, 12532113, 7977527, 9106186, -1715251, -17720195, -4612972, -4451357, -14669444 },
+ },
+ {
+ { -20045281, 5454097, -14346548, 6447146, 28862071, 1883651, -2469266, -4141880, 7770569, 9620597 },
+ { 23208068, 7979712, 33071466, 8149229, 1758231, -10834995, 30945528, -1694323, -33502340, -14767970 },
+ { 1439958, -16270480, -1079989, -793782, 4625402, 10647766, -5043801, 1220118, 30494170, -11440799 },
+ },
+ {
+ { -5037580, -13028295, -2970559, -3061767, 15640974, -6701666, -26739026, 926050, -1684339, -13333647 },
+ { 13908495, -3549272, 30919928, -6273825, -21521863, 7989039, 9021034, 9078865, 3353509, 4033511 },
+ { -29663431, -15113610, 32259991, -344482, 24295849, -12912123, 23161163, 8839127, 27485041, 7356032 },
+ },
+ },
+ {
+ {
+ { 9661027, 705443, 11980065, -5370154, -1628543, 14661173, -6346142, 2625015, 28431036, -16771834 },
+ { -23839233, -8311415, -25945511, 7480958, -17681669, -8354183, -22545972, 14150565, 15970762, 4099461 },
+ { 29262576, 16756590, 26350592, -8793563, 8529671, -11208050, 13617293, -9937143, 11465739, 8317062 },
+ },
+ {
+ { -25493081, -6962928, 32500200, -9419051, -23038724, -2302222, 14898637, 3848455, 20969334, -5157516 },
+ { -20384450, -14347713, -18336405, 13884722, -33039454, 2842114, -21610826, -3649888, 11177095, 14989547 },
+ { -24496721, -11716016, 16959896, 2278463, 12066309, 10137771, 13515641, 2581286, -28487508, 9930240 },
+ },
+ {
+ { -17751622, -2097826, 16544300, -13009300, -15914807, -14949081, 18345767, -13403753, 16291481, -5314038 },
+ { -33229194, 2553288, 32678213, 9875984, 8534129, 6889387, -9676774, 6957617, 4368891, 9788741 },
+ { 16660756, 7281060, -10830758, 12911820, 20108584, -8101676, -21722536, -8613148, 16250552, -11111103 },
+ },
+ {
+ { -19765507, 2390526, -16551031, 14161980, 1905286, 6414907, 4689584, 10604807, -30190403, 4782747 },
+ { -1354539, 14736941, -7367442, -13292886, 7710542, -14155590, -9981571, 4383045, 22546403, 437323 },
+ { 31665577, -12180464, -16186830, 1491339, -18368625, 3294682, 27343084, 2786261, -30633590, -14097016 },
+ },
+ {
+ { -14467279, -683715, -33374107, 7448552, 19294360, 14334329, -19690631, 2355319, -19284671, -6114373 },
+ { 15121312, -15796162, 6377020, -6031361, -10798111, -12957845, 18952177, 15496498, -29380133, 11754228 },
+ { -2637277, -13483075, 8488727, -14303896, 12728761, -1622493, 7141596, 11724556, 22761615, -10134141 },
+ },
+ {
+ { 16918416, 11729663, -18083579, 3022987, -31015732, -13339659, -28741185, -12227393, 32851222, 11717399 },
+ { 11166634, 7338049, -6722523, 4531520, -29468672, -7302055, 31474879, 3483633, -1193175, -4030831 },
+ { -185635, 9921305, 31456609, -13536438, -12013818, 13348923, 33142652, 6546660, -19985279, -3948376 },
+ },
+ {
+ { -32460596, 11266712, -11197107, -7899103, 31703694, 3855903, -8537131, -12833048, -30772034, -15486313 },
+ { -18006477, 12709068, 3991746, -6479188, -21491523, -10550425, -31135347, -16049879, 10928917, 3011958 },
+ { -6957757, -15594337, 31696059, 334240, 29576716, 14796075, -30831056, -12805180, 18008031, 10258577 },
+ },
+ {
+ { -22448644, 15655569, 7018479, -4410003, -30314266, -1201591, -1853465, 1367120, 25127874, 6671743 },
+ { 29701166, -14373934, -10878120, 9279288, -17568, 13127210, 21382910, 11042292, 25838796, 4642684 },
+ { -20430234, 14955537, -24126347, 8124619, -5369288, -5990470, 30468147, -13900640, 18423289, 4177476 },
+ },
+ },
+};
diff --git a/3rd_party/ed25519/sc.c b/3rd_party/ed25519/sc.c
new file mode 100644
index 0000000..ca5bad2
--- /dev/null
+++ b/3rd_party/ed25519/sc.c
@@ -0,0 +1,809 @@
+#include "fixedint.h"
+#include "sc.h"
+
+static uint64_t load_3(const unsigned char *in) {
+ uint64_t result;
+
+ result = (uint64_t) in[0];
+ result |= ((uint64_t) in[1]) << 8;
+ result |= ((uint64_t) in[2]) << 16;
+
+ return result;
+}
+
+static uint64_t load_4(const unsigned char *in) {
+ uint64_t result;
+
+ result = (uint64_t) in[0];
+ result |= ((uint64_t) in[1]) << 8;
+ result |= ((uint64_t) in[2]) << 16;
+ result |= ((uint64_t) in[3]) << 24;
+
+ return result;
+}
+
+/*
+Input:
+ s[0]+256*s[1]+...+256^63*s[63] = s
+
+Output:
+ s[0]+256*s[1]+...+256^31*s[31] = s mod l
+ where l = 2^252 + 27742317777372353535851937790883648493.
+ Overwrites s in place.
+*/
+
+void sc_reduce(unsigned char *s) {
+ int64_t s0 = 2097151 & load_3(s);
+ int64_t s1 = 2097151 & (load_4(s + 2) >> 5);
+ int64_t s2 = 2097151 & (load_3(s + 5) >> 2);
+ int64_t s3 = 2097151 & (load_4(s + 7) >> 7);
+ int64_t s4 = 2097151 & (load_4(s + 10) >> 4);
+ int64_t s5 = 2097151 & (load_3(s + 13) >> 1);
+ int64_t s6 = 2097151 & (load_4(s + 15) >> 6);
+ int64_t s7 = 2097151 & (load_3(s + 18) >> 3);
+ int64_t s8 = 2097151 & load_3(s + 21);
+ int64_t s9 = 2097151 & (load_4(s + 23) >> 5);
+ int64_t s10 = 2097151 & (load_3(s + 26) >> 2);
+ int64_t s11 = 2097151 & (load_4(s + 28) >> 7);
+ int64_t s12 = 2097151 & (load_4(s + 31) >> 4);
+ int64_t s13 = 2097151 & (load_3(s + 34) >> 1);
+ int64_t s14 = 2097151 & (load_4(s + 36) >> 6);
+ int64_t s15 = 2097151 & (load_3(s + 39) >> 3);
+ int64_t s16 = 2097151 & load_3(s + 42);
+ int64_t s17 = 2097151 & (load_4(s + 44) >> 5);
+ int64_t s18 = 2097151 & (load_3(s + 47) >> 2);
+ int64_t s19 = 2097151 & (load_4(s + 49) >> 7);
+ int64_t s20 = 2097151 & (load_4(s + 52) >> 4);
+ int64_t s21 = 2097151 & (load_3(s + 55) >> 1);
+ int64_t s22 = 2097151 & (load_4(s + 57) >> 6);
+ int64_t s23 = (load_4(s + 60) >> 3);
+ int64_t carry0;
+ int64_t carry1;
+ int64_t carry2;
+ int64_t carry3;
+ int64_t carry4;
+ int64_t carry5;
+ int64_t carry6;
+ int64_t carry7;
+ int64_t carry8;
+ int64_t carry9;
+ int64_t carry10;
+ int64_t carry11;
+ int64_t carry12;
+ int64_t carry13;
+ int64_t carry14;
+ int64_t carry15;
+ int64_t carry16;
+
+ s11 += s23 * 666643;
+ s12 += s23 * 470296;
+ s13 += s23 * 654183;
+ s14 -= s23 * 997805;
+ s15 += s23 * 136657;
+ s16 -= s23 * 683901;
+ s23 = 0;
+ s10 += s22 * 666643;
+ s11 += s22 * 470296;
+ s12 += s22 * 654183;
+ s13 -= s22 * 997805;
+ s14 += s22 * 136657;
+ s15 -= s22 * 683901;
+ s22 = 0;
+ s9 += s21 * 666643;
+ s10 += s21 * 470296;
+ s11 += s21 * 654183;
+ s12 -= s21 * 997805;
+ s13 += s21 * 136657;
+ s14 -= s21 * 683901;
+ s21 = 0;
+ s8 += s20 * 666643;
+ s9 += s20 * 470296;
+ s10 += s20 * 654183;
+ s11 -= s20 * 997805;
+ s12 += s20 * 136657;
+ s13 -= s20 * 683901;
+ s20 = 0;
+ s7 += s19 * 666643;
+ s8 += s19 * 470296;
+ s9 += s19 * 654183;
+ s10 -= s19 * 997805;
+ s11 += s19 * 136657;
+ s12 -= s19 * 683901;
+ s19 = 0;
+ s6 += s18 * 666643;
+ s7 += s18 * 470296;
+ s8 += s18 * 654183;
+ s9 -= s18 * 997805;
+ s10 += s18 * 136657;
+ s11 -= s18 * 683901;
+ s18 = 0;
+ carry6 = (s6 + (1 << 20)) >> 21;
+ s7 += carry6;
+ s6 -= carry6 << 21;
+ carry8 = (s8 + (1 << 20)) >> 21;
+ s9 += carry8;
+ s8 -= carry8 << 21;
+ carry10 = (s10 + (1 << 20)) >> 21;
+ s11 += carry10;
+ s10 -= carry10 << 21;
+ carry12 = (s12 + (1 << 20)) >> 21;
+ s13 += carry12;
+ s12 -= carry12 << 21;
+ carry14 = (s14 + (1 << 20)) >> 21;
+ s15 += carry14;
+ s14 -= carry14 << 21;
+ carry16 = (s16 + (1 << 20)) >> 21;
+ s17 += carry16;
+ s16 -= carry16 << 21;
+ carry7 = (s7 + (1 << 20)) >> 21;
+ s8 += carry7;
+ s7 -= carry7 << 21;
+ carry9 = (s9 + (1 << 20)) >> 21;
+ s10 += carry9;
+ s9 -= carry9 << 21;
+ carry11 = (s11 + (1 << 20)) >> 21;
+ s12 += carry11;
+ s11 -= carry11 << 21;
+ carry13 = (s13 + (1 << 20)) >> 21;
+ s14 += carry13;
+ s13 -= carry13 << 21;
+ carry15 = (s15 + (1 << 20)) >> 21;
+ s16 += carry15;
+ s15 -= carry15 << 21;
+ s5 += s17 * 666643;
+ s6 += s17 * 470296;
+ s7 += s17 * 654183;
+ s8 -= s17 * 997805;
+ s9 += s17 * 136657;
+ s10 -= s17 * 683901;
+ s17 = 0;
+ s4 += s16 * 666643;
+ s5 += s16 * 470296;
+ s6 += s16 * 654183;
+ s7 -= s16 * 997805;
+ s8 += s16 * 136657;
+ s9 -= s16 * 683901;
+ s16 = 0;
+ s3 += s15 * 666643;
+ s4 += s15 * 470296;
+ s5 += s15 * 654183;
+ s6 -= s15 * 997805;
+ s7 += s15 * 136657;
+ s8 -= s15 * 683901;
+ s15 = 0;
+ s2 += s14 * 666643;
+ s3 += s14 * 470296;
+ s4 += s14 * 654183;
+ s5 -= s14 * 997805;
+ s6 += s14 * 136657;
+ s7 -= s14 * 683901;
+ s14 = 0;
+ s1 += s13 * 666643;
+ s2 += s13 * 470296;
+ s3 += s13 * 654183;
+ s4 -= s13 * 997805;
+ s5 += s13 * 136657;
+ s6 -= s13 * 683901;
+ s13 = 0;
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+ carry0 = (s0 + (1 << 20)) >> 21;
+ s1 += carry0;
+ s0 -= carry0 << 21;
+ carry2 = (s2 + (1 << 20)) >> 21;
+ s3 += carry2;
+ s2 -= carry2 << 21;
+ carry4 = (s4 + (1 << 20)) >> 21;
+ s5 += carry4;
+ s4 -= carry4 << 21;
+ carry6 = (s6 + (1 << 20)) >> 21;
+ s7 += carry6;
+ s6 -= carry6 << 21;
+ carry8 = (s8 + (1 << 20)) >> 21;
+ s9 += carry8;
+ s8 -= carry8 << 21;
+ carry10 = (s10 + (1 << 20)) >> 21;
+ s11 += carry10;
+ s10 -= carry10 << 21;
+ carry1 = (s1 + (1 << 20)) >> 21;
+ s2 += carry1;
+ s1 -= carry1 << 21;
+ carry3 = (s3 + (1 << 20)) >> 21;
+ s4 += carry3;
+ s3 -= carry3 << 21;
+ carry5 = (s5 + (1 << 20)) >> 21;
+ s6 += carry5;
+ s5 -= carry5 << 21;
+ carry7 = (s7 + (1 << 20)) >> 21;
+ s8 += carry7;
+ s7 -= carry7 << 21;
+ carry9 = (s9 + (1 << 20)) >> 21;
+ s10 += carry9;
+ s9 -= carry9 << 21;
+ carry11 = (s11 + (1 << 20)) >> 21;
+ s12 += carry11;
+ s11 -= carry11 << 21;
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+ carry0 = s0 >> 21;
+ s1 += carry0;
+ s0 -= carry0 << 21;
+ carry1 = s1 >> 21;
+ s2 += carry1;
+ s1 -= carry1 << 21;
+ carry2 = s2 >> 21;
+ s3 += carry2;
+ s2 -= carry2 << 21;
+ carry3 = s3 >> 21;
+ s4 += carry3;
+ s3 -= carry3 << 21;
+ carry4 = s4 >> 21;
+ s5 += carry4;
+ s4 -= carry4 << 21;
+ carry5 = s5 >> 21;
+ s6 += carry5;
+ s5 -= carry5 << 21;
+ carry6 = s6 >> 21;
+ s7 += carry6;
+ s6 -= carry6 << 21;
+ carry7 = s7 >> 21;
+ s8 += carry7;
+ s7 -= carry7 << 21;
+ carry8 = s8 >> 21;
+ s9 += carry8;
+ s8 -= carry8 << 21;
+ carry9 = s9 >> 21;
+ s10 += carry9;
+ s9 -= carry9 << 21;
+ carry10 = s10 >> 21;
+ s11 += carry10;
+ s10 -= carry10 << 21;
+ carry11 = s11 >> 21;
+ s12 += carry11;
+ s11 -= carry11 << 21;
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+ carry0 = s0 >> 21;
+ s1 += carry0;
+ s0 -= carry0 << 21;
+ carry1 = s1 >> 21;
+ s2 += carry1;
+ s1 -= carry1 << 21;
+ carry2 = s2 >> 21;
+ s3 += carry2;
+ s2 -= carry2 << 21;
+ carry3 = s3 >> 21;
+ s4 += carry3;
+ s3 -= carry3 << 21;
+ carry4 = s4 >> 21;
+ s5 += carry4;
+ s4 -= carry4 << 21;
+ carry5 = s5 >> 21;
+ s6 += carry5;
+ s5 -= carry5 << 21;
+ carry6 = s6 >> 21;
+ s7 += carry6;
+ s6 -= carry6 << 21;
+ carry7 = s7 >> 21;
+ s8 += carry7;
+ s7 -= carry7 << 21;
+ carry8 = s8 >> 21;
+ s9 += carry8;
+ s8 -= carry8 << 21;
+ carry9 = s9 >> 21;
+ s10 += carry9;
+ s9 -= carry9 << 21;
+ carry10 = s10 >> 21;
+ s11 += carry10;
+ s10 -= carry10 << 21;
+
+ s[0] = (unsigned char) (s0 >> 0);
+ s[1] = (unsigned char) (s0 >> 8);
+ s[2] = (unsigned char) ((s0 >> 16) | (s1 << 5));
+ s[3] = (unsigned char) (s1 >> 3);
+ s[4] = (unsigned char) (s1 >> 11);
+ s[5] = (unsigned char) ((s1 >> 19) | (s2 << 2));
+ s[6] = (unsigned char) (s2 >> 6);
+ s[7] = (unsigned char) ((s2 >> 14) | (s3 << 7));
+ s[8] = (unsigned char) (s3 >> 1);
+ s[9] = (unsigned char) (s3 >> 9);
+ s[10] = (unsigned char) ((s3 >> 17) | (s4 << 4));
+ s[11] = (unsigned char) (s4 >> 4);
+ s[12] = (unsigned char) (s4 >> 12);
+ s[13] = (unsigned char) ((s4 >> 20) | (s5 << 1));
+ s[14] = (unsigned char) (s5 >> 7);
+ s[15] = (unsigned char) ((s5 >> 15) | (s6 << 6));
+ s[16] = (unsigned char) (s6 >> 2);
+ s[17] = (unsigned char) (s6 >> 10);
+ s[18] = (unsigned char) ((s6 >> 18) | (s7 << 3));
+ s[19] = (unsigned char) (s7 >> 5);
+ s[20] = (unsigned char) (s7 >> 13);
+ s[21] = (unsigned char) (s8 >> 0);
+ s[22] = (unsigned char) (s8 >> 8);
+ s[23] = (unsigned char) ((s8 >> 16) | (s9 << 5));
+ s[24] = (unsigned char) (s9 >> 3);
+ s[25] = (unsigned char) (s9 >> 11);
+ s[26] = (unsigned char) ((s9 >> 19) | (s10 << 2));
+ s[27] = (unsigned char) (s10 >> 6);
+ s[28] = (unsigned char) ((s10 >> 14) | (s11 << 7));
+ s[29] = (unsigned char) (s11 >> 1);
+ s[30] = (unsigned char) (s11 >> 9);
+ s[31] = (unsigned char) (s11 >> 17);
+}
+
+
+
+/*
+Input:
+ a[0]+256*a[1]+...+256^31*a[31] = a
+ b[0]+256*b[1]+...+256^31*b[31] = b
+ c[0]+256*c[1]+...+256^31*c[31] = c
+
+Output:
+ s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l
+ where l = 2^252 + 27742317777372353535851937790883648493.
+*/
+
+void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c) {
+ int64_t a0 = 2097151 & load_3(a);
+ int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
+ int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
+ int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
+ int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
+ int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
+ int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
+ int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
+ int64_t a8 = 2097151 & load_3(a + 21);
+ int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
+ int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
+ int64_t a11 = (load_4(a + 28) >> 7);
+ int64_t b0 = 2097151 & load_3(b);
+ int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
+ int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
+ int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
+ int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
+ int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
+ int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
+ int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
+ int64_t b8 = 2097151 & load_3(b + 21);
+ int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
+ int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
+ int64_t b11 = (load_4(b + 28) >> 7);
+ int64_t c0 = 2097151 & load_3(c);
+ int64_t c1 = 2097151 & (load_4(c + 2) >> 5);
+ int64_t c2 = 2097151 & (load_3(c + 5) >> 2);
+ int64_t c3 = 2097151 & (load_4(c + 7) >> 7);
+ int64_t c4 = 2097151 & (load_4(c + 10) >> 4);
+ int64_t c5 = 2097151 & (load_3(c + 13) >> 1);
+ int64_t c6 = 2097151 & (load_4(c + 15) >> 6);
+ int64_t c7 = 2097151 & (load_3(c + 18) >> 3);
+ int64_t c8 = 2097151 & load_3(c + 21);
+ int64_t c9 = 2097151 & (load_4(c + 23) >> 5);
+ int64_t c10 = 2097151 & (load_3(c + 26) >> 2);
+ int64_t c11 = (load_4(c + 28) >> 7);
+ int64_t s0;
+ int64_t s1;
+ int64_t s2;
+ int64_t s3;
+ int64_t s4;
+ int64_t s5;
+ int64_t s6;
+ int64_t s7;
+ int64_t s8;
+ int64_t s9;
+ int64_t s10;
+ int64_t s11;
+ int64_t s12;
+ int64_t s13;
+ int64_t s14;
+ int64_t s15;
+ int64_t s16;
+ int64_t s17;
+ int64_t s18;
+ int64_t s19;
+ int64_t s20;
+ int64_t s21;
+ int64_t s22;
+ int64_t s23;
+ int64_t carry0;
+ int64_t carry1;
+ int64_t carry2;
+ int64_t carry3;
+ int64_t carry4;
+ int64_t carry5;
+ int64_t carry6;
+ int64_t carry7;
+ int64_t carry8;
+ int64_t carry9;
+ int64_t carry10;
+ int64_t carry11;
+ int64_t carry12;
+ int64_t carry13;
+ int64_t carry14;
+ int64_t carry15;
+ int64_t carry16;
+ int64_t carry17;
+ int64_t carry18;
+ int64_t carry19;
+ int64_t carry20;
+ int64_t carry21;
+ int64_t carry22;
+
+ s0 = c0 + a0 * b0;
+ s1 = c1 + a0 * b1 + a1 * b0;
+ s2 = c2 + a0 * b2 + a1 * b1 + a2 * b0;
+ s3 = c3 + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0;
+ s4 = c4 + a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0;
+ s5 = c5 + a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0;
+ s6 = c6 + a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0;
+ s7 = c7 + a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 + a6 * b1 + a7 * b0;
+ s8 = c8 + a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 + a6 * b2 + a7 * b1 + a8 * b0;
+ s9 = c9 + a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 + a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0;
+ s10 = c10 + a0 * b10 + a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 + a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1 + a10 * b0;
+ s11 = c11 + a0 * b11 + a1 * b10 + a2 * b9 + a3 * b8 + a4 * b7 + a5 * b6 + a6 * b5 + a7 * b4 + a8 * b3 + a9 * b2 + a10 * b1 + a11 * b0;
+ s12 = a1 * b11 + a2 * b10 + a3 * b9 + a4 * b8 + a5 * b7 + a6 * b6 + a7 * b5 + a8 * b4 + a9 * b3 + a10 * b2 + a11 * b1;
+ s13 = a2 * b11 + a3 * b10 + a4 * b9 + a5 * b8 + a6 * b7 + a7 * b6 + a8 * b5 + a9 * b4 + a10 * b3 + a11 * b2;
+ s14 = a3 * b11 + a4 * b10 + a5 * b9 + a6 * b8 + a7 * b7 + a8 * b6 + a9 * b5 + a10 * b4 + a11 * b3;
+ s15 = a4 * b11 + a5 * b10 + a6 * b9 + a7 * b8 + a8 * b7 + a9 * b6 + a10 * b5 + a11 * b4;
+ s16 = a5 * b11 + a6 * b10 + a7 * b9 + a8 * b8 + a9 * b7 + a10 * b6 + a11 * b5;
+ s17 = a6 * b11 + a7 * b10 + a8 * b9 + a9 * b8 + a10 * b7 + a11 * b6;
+ s18 = a7 * b11 + a8 * b10 + a9 * b9 + a10 * b8 + a11 * b7;
+ s19 = a8 * b11 + a9 * b10 + a10 * b9 + a11 * b8;
+ s20 = a9 * b11 + a10 * b10 + a11 * b9;
+ s21 = a10 * b11 + a11 * b10;
+ s22 = a11 * b11;
+ s23 = 0;
+ carry0 = (s0 + (1 << 20)) >> 21;
+ s1 += carry0;
+ s0 -= carry0 << 21;
+ carry2 = (s2 + (1 << 20)) >> 21;
+ s3 += carry2;
+ s2 -= carry2 << 21;
+ carry4 = (s4 + (1 << 20)) >> 21;
+ s5 += carry4;
+ s4 -= carry4 << 21;
+ carry6 = (s6 + (1 << 20)) >> 21;
+ s7 += carry6;
+ s6 -= carry6 << 21;
+ carry8 = (s8 + (1 << 20)) >> 21;
+ s9 += carry8;
+ s8 -= carry8 << 21;
+ carry10 = (s10 + (1 << 20)) >> 21;
+ s11 += carry10;
+ s10 -= carry10 << 21;
+ carry12 = (s12 + (1 << 20)) >> 21;
+ s13 += carry12;
+ s12 -= carry12 << 21;
+ carry14 = (s14 + (1 << 20)) >> 21;
+ s15 += carry14;
+ s14 -= carry14 << 21;
+ carry16 = (s16 + (1 << 20)) >> 21;
+ s17 += carry16;
+ s16 -= carry16 << 21;
+ carry18 = (s18 + (1 << 20)) >> 21;
+ s19 += carry18;
+ s18 -= carry18 << 21;
+ carry20 = (s20 + (1 << 20)) >> 21;
+ s21 += carry20;
+ s20 -= carry20 << 21;
+ carry22 = (s22 + (1 << 20)) >> 21;
+ s23 += carry22;
+ s22 -= carry22 << 21;
+ carry1 = (s1 + (1 << 20)) >> 21;
+ s2 += carry1;
+ s1 -= carry1 << 21;
+ carry3 = (s3 + (1 << 20)) >> 21;
+ s4 += carry3;
+ s3 -= carry3 << 21;
+ carry5 = (s5 + (1 << 20)) >> 21;
+ s6 += carry5;
+ s5 -= carry5 << 21;
+ carry7 = (s7 + (1 << 20)) >> 21;
+ s8 += carry7;
+ s7 -= carry7 << 21;
+ carry9 = (s9 + (1 << 20)) >> 21;
+ s10 += carry9;
+ s9 -= carry9 << 21;
+ carry11 = (s11 + (1 << 20)) >> 21;
+ s12 += carry11;
+ s11 -= carry11 << 21;
+ carry13 = (s13 + (1 << 20)) >> 21;
+ s14 += carry13;
+ s13 -= carry13 << 21;
+ carry15 = (s15 + (1 << 20)) >> 21;
+ s16 += carry15;
+ s15 -= carry15 << 21;
+ carry17 = (s17 + (1 << 20)) >> 21;
+ s18 += carry17;
+ s17 -= carry17 << 21;
+ carry19 = (s19 + (1 << 20)) >> 21;
+ s20 += carry19;
+ s19 -= carry19 << 21;
+ carry21 = (s21 + (1 << 20)) >> 21;
+ s22 += carry21;
+ s21 -= carry21 << 21;
+ s11 += s23 * 666643;
+ s12 += s23 * 470296;
+ s13 += s23 * 654183;
+ s14 -= s23 * 997805;
+ s15 += s23 * 136657;
+ s16 -= s23 * 683901;
+ s23 = 0;
+ s10 += s22 * 666643;
+ s11 += s22 * 470296;
+ s12 += s22 * 654183;
+ s13 -= s22 * 997805;
+ s14 += s22 * 136657;
+ s15 -= s22 * 683901;
+ s22 = 0;
+ s9 += s21 * 666643;
+ s10 += s21 * 470296;
+ s11 += s21 * 654183;
+ s12 -= s21 * 997805;
+ s13 += s21 * 136657;
+ s14 -= s21 * 683901;
+ s21 = 0;
+ s8 += s20 * 666643;
+ s9 += s20 * 470296;
+ s10 += s20 * 654183;
+ s11 -= s20 * 997805;
+ s12 += s20 * 136657;
+ s13 -= s20 * 683901;
+ s20 = 0;
+ s7 += s19 * 666643;
+ s8 += s19 * 470296;
+ s9 += s19 * 654183;
+ s10 -= s19 * 997805;
+ s11 += s19 * 136657;
+ s12 -= s19 * 683901;
+ s19 = 0;
+ s6 += s18 * 666643;
+ s7 += s18 * 470296;
+ s8 += s18 * 654183;
+ s9 -= s18 * 997805;
+ s10 += s18 * 136657;
+ s11 -= s18 * 683901;
+ s18 = 0;
+ carry6 = (s6 + (1 << 20)) >> 21;
+ s7 += carry6;
+ s6 -= carry6 << 21;
+ carry8 = (s8 + (1 << 20)) >> 21;
+ s9 += carry8;
+ s8 -= carry8 << 21;
+ carry10 = (s10 + (1 << 20)) >> 21;
+ s11 += carry10;
+ s10 -= carry10 << 21;
+ carry12 = (s12 + (1 << 20)) >> 21;
+ s13 += carry12;
+ s12 -= carry12 << 21;
+ carry14 = (s14 + (1 << 20)) >> 21;
+ s15 += carry14;
+ s14 -= carry14 << 21;
+ carry16 = (s16 + (1 << 20)) >> 21;
+ s17 += carry16;
+ s16 -= carry16 << 21;
+ carry7 = (s7 + (1 << 20)) >> 21;
+ s8 += carry7;
+ s7 -= carry7 << 21;
+ carry9 = (s9 + (1 << 20)) >> 21;
+ s10 += carry9;
+ s9 -= carry9 << 21;
+ carry11 = (s11 + (1 << 20)) >> 21;
+ s12 += carry11;
+ s11 -= carry11 << 21;
+ carry13 = (s13 + (1 << 20)) >> 21;
+ s14 += carry13;
+ s13 -= carry13 << 21;
+ carry15 = (s15 + (1 << 20)) >> 21;
+ s16 += carry15;
+ s15 -= carry15 << 21;
+ s5 += s17 * 666643;
+ s6 += s17 * 470296;
+ s7 += s17 * 654183;
+ s8 -= s17 * 997805;
+ s9 += s17 * 136657;
+ s10 -= s17 * 683901;
+ s17 = 0;
+ s4 += s16 * 666643;
+ s5 += s16 * 470296;
+ s6 += s16 * 654183;
+ s7 -= s16 * 997805;
+ s8 += s16 * 136657;
+ s9 -= s16 * 683901;
+ s16 = 0;
+ s3 += s15 * 666643;
+ s4 += s15 * 470296;
+ s5 += s15 * 654183;
+ s6 -= s15 * 997805;
+ s7 += s15 * 136657;
+ s8 -= s15 * 683901;
+ s15 = 0;
+ s2 += s14 * 666643;
+ s3 += s14 * 470296;
+ s4 += s14 * 654183;
+ s5 -= s14 * 997805;
+ s6 += s14 * 136657;
+ s7 -= s14 * 683901;
+ s14 = 0;
+ s1 += s13 * 666643;
+ s2 += s13 * 470296;
+ s3 += s13 * 654183;
+ s4 -= s13 * 997805;
+ s5 += s13 * 136657;
+ s6 -= s13 * 683901;
+ s13 = 0;
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+ carry0 = (s0 + (1 << 20)) >> 21;
+ s1 += carry0;
+ s0 -= carry0 << 21;
+ carry2 = (s2 + (1 << 20)) >> 21;
+ s3 += carry2;
+ s2 -= carry2 << 21;
+ carry4 = (s4 + (1 << 20)) >> 21;
+ s5 += carry4;
+ s4 -= carry4 << 21;
+ carry6 = (s6 + (1 << 20)) >> 21;
+ s7 += carry6;
+ s6 -= carry6 << 21;
+ carry8 = (s8 + (1 << 20)) >> 21;
+ s9 += carry8;
+ s8 -= carry8 << 21;
+ carry10 = (s10 + (1 << 20)) >> 21;
+ s11 += carry10;
+ s10 -= carry10 << 21;
+ carry1 = (s1 + (1 << 20)) >> 21;
+ s2 += carry1;
+ s1 -= carry1 << 21;
+ carry3 = (s3 + (1 << 20)) >> 21;
+ s4 += carry3;
+ s3 -= carry3 << 21;
+ carry5 = (s5 + (1 << 20)) >> 21;
+ s6 += carry5;
+ s5 -= carry5 << 21;
+ carry7 = (s7 + (1 << 20)) >> 21;
+ s8 += carry7;
+ s7 -= carry7 << 21;
+ carry9 = (s9 + (1 << 20)) >> 21;
+ s10 += carry9;
+ s9 -= carry9 << 21;
+ carry11 = (s11 + (1 << 20)) >> 21;
+ s12 += carry11;
+ s11 -= carry11 << 21;
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+ carry0 = s0 >> 21;
+ s1 += carry0;
+ s0 -= carry0 << 21;
+ carry1 = s1 >> 21;
+ s2 += carry1;
+ s1 -= carry1 << 21;
+ carry2 = s2 >> 21;
+ s3 += carry2;
+ s2 -= carry2 << 21;
+ carry3 = s3 >> 21;
+ s4 += carry3;
+ s3 -= carry3 << 21;
+ carry4 = s4 >> 21;
+ s5 += carry4;
+ s4 -= carry4 << 21;
+ carry5 = s5 >> 21;
+ s6 += carry5;
+ s5 -= carry5 << 21;
+ carry6 = s6 >> 21;
+ s7 += carry6;
+ s6 -= carry6 << 21;
+ carry7 = s7 >> 21;
+ s8 += carry7;
+ s7 -= carry7 << 21;
+ carry8 = s8 >> 21;
+ s9 += carry8;
+ s8 -= carry8 << 21;
+ carry9 = s9 >> 21;
+ s10 += carry9;
+ s9 -= carry9 << 21;
+ carry10 = s10 >> 21;
+ s11 += carry10;
+ s10 -= carry10 << 21;
+ carry11 = s11 >> 21;
+ s12 += carry11;
+ s11 -= carry11 << 21;
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+ carry0 = s0 >> 21;
+ s1 += carry0;
+ s0 -= carry0 << 21;
+ carry1 = s1 >> 21;
+ s2 += carry1;
+ s1 -= carry1 << 21;
+ carry2 = s2 >> 21;
+ s3 += carry2;
+ s2 -= carry2 << 21;
+ carry3 = s3 >> 21;
+ s4 += carry3;
+ s3 -= carry3 << 21;
+ carry4 = s4 >> 21;
+ s5 += carry4;
+ s4 -= carry4 << 21;
+ carry5 = s5 >> 21;
+ s6 += carry5;
+ s5 -= carry5 << 21;
+ carry6 = s6 >> 21;
+ s7 += carry6;
+ s6 -= carry6 << 21;
+ carry7 = s7 >> 21;
+ s8 += carry7;
+ s7 -= carry7 << 21;
+ carry8 = s8 >> 21;
+ s9 += carry8;
+ s8 -= carry8 << 21;
+ carry9 = s9 >> 21;
+ s10 += carry9;
+ s9 -= carry9 << 21;
+ carry10 = s10 >> 21;
+ s11 += carry10;
+ s10 -= carry10 << 21;
+
+ s[0] = (unsigned char) (s0 >> 0);
+ s[1] = (unsigned char) (s0 >> 8);
+ s[2] = (unsigned char) ((s0 >> 16) | (s1 << 5));
+ s[3] = (unsigned char) (s1 >> 3);
+ s[4] = (unsigned char) (s1 >> 11);
+ s[5] = (unsigned char) ((s1 >> 19) | (s2 << 2));
+ s[6] = (unsigned char) (s2 >> 6);
+ s[7] = (unsigned char) ((s2 >> 14) | (s3 << 7));
+ s[8] = (unsigned char) (s3 >> 1);
+ s[9] = (unsigned char) (s3 >> 9);
+ s[10] = (unsigned char) ((s3 >> 17) | (s4 << 4));
+ s[11] = (unsigned char) (s4 >> 4);
+ s[12] = (unsigned char) (s4 >> 12);
+ s[13] = (unsigned char) ((s4 >> 20) | (s5 << 1));
+ s[14] = (unsigned char) (s5 >> 7);
+ s[15] = (unsigned char) ((s5 >> 15) | (s6 << 6));
+ s[16] = (unsigned char) (s6 >> 2);
+ s[17] = (unsigned char) (s6 >> 10);
+ s[18] = (unsigned char) ((s6 >> 18) | (s7 << 3));
+ s[19] = (unsigned char) (s7 >> 5);
+ s[20] = (unsigned char) (s7 >> 13);
+ s[21] = (unsigned char) (s8 >> 0);
+ s[22] = (unsigned char) (s8 >> 8);
+ s[23] = (unsigned char) ((s8 >> 16) | (s9 << 5));
+ s[24] = (unsigned char) (s9 >> 3);
+ s[25] = (unsigned char) (s9 >> 11);
+ s[26] = (unsigned char) ((s9 >> 19) | (s10 << 2));
+ s[27] = (unsigned char) (s10 >> 6);
+ s[28] = (unsigned char) ((s10 >> 14) | (s11 << 7));
+ s[29] = (unsigned char) (s11 >> 1);
+ s[30] = (unsigned char) (s11 >> 9);
+ s[31] = (unsigned char) (s11 >> 17);
+}
diff --git a/3rd_party/ed25519/sc.h b/3rd_party/ed25519/sc.h
new file mode 100644
index 0000000..e29e7fa
--- /dev/null
+++ b/3rd_party/ed25519/sc.h
@@ -0,0 +1,12 @@
+#ifndef SC_H
+#define SC_H
+
+/*
+The set of scalars is \Z/l
+where l = 2^252 + 27742317777372353535851937790883648493.
+*/
+
+void sc_reduce(unsigned char *s);
+void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c);
+
+#endif
diff --git a/3rd_party/ed25519/seed.c b/3rd_party/ed25519/seed.c
new file mode 100644
index 0000000..cf252b8
--- /dev/null
+++ b/3rd_party/ed25519/seed.c
@@ -0,0 +1,40 @@
+#include "ed25519.h"
+
+#ifndef ED25519_NO_SEED
+
+#ifdef _WIN32
+#include <windows.h>
+#include <wincrypt.h>
+#else
+#include <stdio.h>
+#endif
+
+int ed25519_create_seed(unsigned char *seed) {
+#ifdef _WIN32
+ HCRYPTPROV prov;
+
+ if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
+ return 1;
+ }
+
+ if (!CryptGenRandom(prov, 32, seed)) {
+ CryptReleaseContext(prov, 0);
+ return 1;
+ }
+
+ CryptReleaseContext(prov, 0);
+#else
+ FILE *f = fopen("/dev/urandom", "rb");
+
+ if (f == NULL) {
+ return 1;
+ }
+
+ if(fread(seed, 1, 32, f)){}
+ fclose(f);
+#endif
+
+ return 0;
+}
+
+#endif
diff --git a/3rd_party/ed25519/sha512.c b/3rd_party/ed25519/sha512.c
new file mode 100644
index 0000000..cb8ae71
--- /dev/null
+++ b/3rd_party/ed25519/sha512.c
@@ -0,0 +1,275 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+#include "fixedint.h"
+#include "sha512.h"
+
+/* the K array */
+static const uint64_t K[80] = {
+ UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd),
+ UINT64_C(0xb5c0fbcfec4d3b2f), UINT64_C(0xe9b5dba58189dbbc),
+ UINT64_C(0x3956c25bf348b538), UINT64_C(0x59f111f1b605d019),
+ UINT64_C(0x923f82a4af194f9b), UINT64_C(0xab1c5ed5da6d8118),
+ UINT64_C(0xd807aa98a3030242), UINT64_C(0x12835b0145706fbe),
+ UINT64_C(0x243185be4ee4b28c), UINT64_C(0x550c7dc3d5ffb4e2),
+ UINT64_C(0x72be5d74f27b896f), UINT64_C(0x80deb1fe3b1696b1),
+ UINT64_C(0x9bdc06a725c71235), UINT64_C(0xc19bf174cf692694),
+ UINT64_C(0xe49b69c19ef14ad2), UINT64_C(0xefbe4786384f25e3),
+ UINT64_C(0x0fc19dc68b8cd5b5), UINT64_C(0x240ca1cc77ac9c65),
+ UINT64_C(0x2de92c6f592b0275), UINT64_C(0x4a7484aa6ea6e483),
+ UINT64_C(0x5cb0a9dcbd41fbd4), UINT64_C(0x76f988da831153b5),
+ UINT64_C(0x983e5152ee66dfab), UINT64_C(0xa831c66d2db43210),
+ UINT64_C(0xb00327c898fb213f), UINT64_C(0xbf597fc7beef0ee4),
+ UINT64_C(0xc6e00bf33da88fc2), UINT64_C(0xd5a79147930aa725),
+ UINT64_C(0x06ca6351e003826f), UINT64_C(0x142929670a0e6e70),
+ UINT64_C(0x27b70a8546d22ffc), UINT64_C(0x2e1b21385c26c926),
+ UINT64_C(0x4d2c6dfc5ac42aed), UINT64_C(0x53380d139d95b3df),
+ UINT64_C(0x650a73548baf63de), UINT64_C(0x766a0abb3c77b2a8),
+ UINT64_C(0x81c2c92e47edaee6), UINT64_C(0x92722c851482353b),
+ UINT64_C(0xa2bfe8a14cf10364), UINT64_C(0xa81a664bbc423001),
+ UINT64_C(0xc24b8b70d0f89791), UINT64_C(0xc76c51a30654be30),
+ UINT64_C(0xd192e819d6ef5218), UINT64_C(0xd69906245565a910),
+ UINT64_C(0xf40e35855771202a), UINT64_C(0x106aa07032bbd1b8),
+ UINT64_C(0x19a4c116b8d2d0c8), UINT64_C(0x1e376c085141ab53),
+ UINT64_C(0x2748774cdf8eeb99), UINT64_C(0x34b0bcb5e19b48a8),
+ UINT64_C(0x391c0cb3c5c95a63), UINT64_C(0x4ed8aa4ae3418acb),
+ UINT64_C(0x5b9cca4f7763e373), UINT64_C(0x682e6ff3d6b2b8a3),
+ UINT64_C(0x748f82ee5defb2fc), UINT64_C(0x78a5636f43172f60),
+ UINT64_C(0x84c87814a1f0ab72), UINT64_C(0x8cc702081a6439ec),
+ UINT64_C(0x90befffa23631e28), UINT64_C(0xa4506cebde82bde9),
+ UINT64_C(0xbef9a3f7b2c67915), UINT64_C(0xc67178f2e372532b),
+ UINT64_C(0xca273eceea26619c), UINT64_C(0xd186b8c721c0c207),
+ UINT64_C(0xeada7dd6cde0eb1e), UINT64_C(0xf57d4f7fee6ed178),
+ UINT64_C(0x06f067aa72176fba), UINT64_C(0x0a637dc5a2c898a6),
+ UINT64_C(0x113f9804bef90dae), UINT64_C(0x1b710b35131c471b),
+ UINT64_C(0x28db77f523047d84), UINT64_C(0x32caab7b40c72493),
+ UINT64_C(0x3c9ebe0a15c9bebc), UINT64_C(0x431d67c49c100d4c),
+ UINT64_C(0x4cc5d4becb3e42b6), UINT64_C(0x597f299cfc657e2a),
+ UINT64_C(0x5fcb6fab3ad6faec), UINT64_C(0x6c44198c4a475817)
+};
+
+/* Various logical functions */
+
+#define ROR64c(x, y) \
+ ( ((((x)&UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)(y)&UINT64_C(63))) | \
+ ((x)<<((uint64_t)(64-((y)&UINT64_C(63)))))) & UINT64_C(0xFFFFFFFFFFFFFFFF))
+
+#define STORE64H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
+ (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
+ (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
+ (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
+
+#define LOAD64H(x, y) \
+ { x = (((uint64_t)((y)[0] & 255))<<56)|(((uint64_t)((y)[1] & 255))<<48) | \
+ (((uint64_t)((y)[2] & 255))<<40)|(((uint64_t)((y)[3] & 255))<<32) | \
+ (((uint64_t)((y)[4] & 255))<<24)|(((uint64_t)((y)[5] & 255))<<16) | \
+ (((uint64_t)((y)[6] & 255))<<8)|(((uint64_t)((y)[7] & 255))); }
+
+
+#define Ch(x,y,z) (z ^ (x & (y ^ z)))
+#define Maj(x,y,z) (((x | y) & z) | (x & y))
+#define S(x, n) ROR64c(x, n)
+#define R(x, n) (((x) &UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)n))
+#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
+#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
+#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))
+#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6))
+#ifndef MIN
+ #define MIN(x, y) ( ((x)<(y))?(x):(y) )
+#endif
+
+/* compress 1024-bits */
+static int sha512_compress(sha512_context *md, unsigned char *buf)
+{
+ uint64_t S[8], W[80], t0, t1;
+ int i;
+
+ /* copy state into S */
+ for (i = 0; i < 8; i++) {
+ S[i] = md->state[i];
+ }
+
+ /* copy the state into 1024-bits into W[0..15] */
+ for (i = 0; i < 16; i++) {
+ LOAD64H(W[i], buf + (8*i));
+ }
+
+ /* fill W[16..79] */
+ for (i = 16; i < 80; i++) {
+ W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
+ }
+
+/* Compress */
+ #define RND(a,b,c,d,e,f,g,h,i) \
+ t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
+ t1 = Sigma0(a) + Maj(a, b, c);\
+ d += t0; \
+ h = t0 + t1;
+
+ for (i = 0; i < 80; i += 8) {
+ RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0);
+ RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1);
+ RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2);
+ RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3);
+ RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4);
+ RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5);
+ RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6);
+ RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7);
+ }
+
+ #undef RND
+
+
+
+ /* feedback */
+ for (i = 0; i < 8; i++) {
+ md->state[i] = md->state[i] + S[i];
+ }
+
+ return 0;
+}
+
+
+/**
+ Initialize the hash state
+ @param md The hash state you wish to initialize
+ @return 0 if successful
+*/
+int sha512_init(sha512_context * md) {
+ if (md == NULL) return 1;
+
+ md->curlen = 0;
+ md->length = 0;
+ md->state[0] = UINT64_C(0x6a09e667f3bcc908);
+ md->state[1] = UINT64_C(0xbb67ae8584caa73b);
+ md->state[2] = UINT64_C(0x3c6ef372fe94f82b);
+ md->state[3] = UINT64_C(0xa54ff53a5f1d36f1);
+ md->state[4] = UINT64_C(0x510e527fade682d1);
+ md->state[5] = UINT64_C(0x9b05688c2b3e6c1f);
+ md->state[6] = UINT64_C(0x1f83d9abfb41bd6b);
+ md->state[7] = UINT64_C(0x5be0cd19137e2179);
+
+ return 0;
+}
+
+/**
+ Process a block of memory though the hash
+ @param md The hash state
+ @param in The data to hash
+ @param inlen The length of the data (octets)
+ @return 0 if successful
+*/
+int sha512_update (sha512_context * md, const unsigned char *in, size_t inlen)
+{
+ size_t n;
+ size_t i;
+ int err;
+ if (md == NULL) return 1;
+ if (in == NULL) return 1;
+ if (md->curlen > sizeof(md->buf)) {
+ return 1;
+ }
+ while (inlen > 0) {
+ if (md->curlen == 0 && inlen >= 128) {
+ if ((err = sha512_compress (md, (unsigned char *)in)) != 0) {
+ return err;
+ }
+ md->length += 128 * 8;
+ in += 128;
+ inlen -= 128;
+ } else {
+ n = MIN(inlen, (128 - md->curlen));
+
+ for (i = 0; i < n; i++) {
+ md->buf[i + md->curlen] = in[i];
+ }
+
+
+ md->curlen += n;
+ in += n;
+ inlen -= n;
+ if (md->curlen == 128) {
+ if ((err = sha512_compress (md, md->buf)) != 0) {
+ return err;
+ }
+ md->length += 8*128;
+ md->curlen = 0;
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ Terminate the hash to get the digest
+ @param md The hash state
+ @param out [out] The destination of the hash (64 bytes)
+ @return 0 if successful
+*/
+ int sha512_final(sha512_context * md, unsigned char *out)
+ {
+ int i;
+
+ if (md == NULL) return 1;
+ if (out == NULL) return 1;
+
+ if (md->curlen >= sizeof(md->buf)) {
+ return 1;
+ }
+
+ /* increase the length of the message */
+ md->length += md->curlen * UINT64_C(8);
+
+ /* append the '1' bit */
+ md->buf[md->curlen++] = (unsigned char)0x80;
+
+ /* if the length is currently above 112 bytes we append zeros
+ * then compress. Then we can fall back to padding zeros and length
+ * encoding like normal.
+ */
+ if (md->curlen > 112) {
+ while (md->curlen < 128) {
+ md->buf[md->curlen++] = (unsigned char)0;
+ }
+ sha512_compress(md, md->buf);
+ md->curlen = 0;
+ }
+
+ /* pad upto 120 bytes of zeroes
+ * note: that from 112 to 120 is the 64 MSB of the length. We assume that you won't hash
+ * > 2^64 bits of data... :-)
+ */
+while (md->curlen < 120) {
+ md->buf[md->curlen++] = (unsigned char)0;
+}
+
+ /* store length */
+STORE64H(md->length, md->buf+120);
+sha512_compress(md, md->buf);
+
+ /* copy output */
+for (i = 0; i < 8; i++) {
+ STORE64H(md->state[i], out+(8*i));
+}
+
+return 0;
+}
+
+int sha512(const unsigned char *message, size_t message_len, unsigned char *out)
+{
+ sha512_context ctx;
+ int ret;
+ if ((ret = sha512_init(&ctx))) return ret;
+ if ((ret = sha512_update(&ctx, message, message_len))) return ret;
+ if ((ret = sha512_final(&ctx, out))) return ret;
+ return 0;
+}
diff --git a/3rd_party/ed25519/sha512.h b/3rd_party/ed25519/sha512.h
new file mode 100644
index 0000000..a34dd5e
--- /dev/null
+++ b/3rd_party/ed25519/sha512.h
@@ -0,0 +1,21 @@
+#ifndef SHA512_H
+#define SHA512_H
+
+#include <stddef.h>
+
+#include "fixedint.h"
+
+/* state */
+typedef struct sha512_context_ {
+ uint64_t length, state[8];
+ size_t curlen;
+ unsigned char buf[128];
+} sha512_context;
+
+
+int sha512_init(sha512_context * md);
+int sha512_final(sha512_context * md, unsigned char *out);
+int sha512_update(sha512_context * md, const unsigned char *in, size_t inlen);
+int sha512(const unsigned char *message, size_t message_len, unsigned char *out);
+
+#endif
diff --git a/3rd_party/ed25519/sign.c b/3rd_party/ed25519/sign.c
new file mode 100644
index 0000000..199a839
--- /dev/null
+++ b/3rd_party/ed25519/sign.c
@@ -0,0 +1,31 @@
+#include "ed25519.h"
+#include "sha512.h"
+#include "ge.h"
+#include "sc.h"
+
+
+void ed25519_sign(unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key, const unsigned char *private_key) {
+ sha512_context hash;
+ unsigned char hram[64];
+ unsigned char r[64];
+ ge_p3 R;
+
+
+ sha512_init(&hash);
+ sha512_update(&hash, private_key + 32, 32);
+ sha512_update(&hash, message, message_len);
+ sha512_final(&hash, r);
+
+ sc_reduce(r);
+ ge_scalarmult_base(&R, r);
+ ge_p3_tobytes(signature, &R);
+
+ sha512_init(&hash);
+ sha512_update(&hash, signature, 32);
+ sha512_update(&hash, public_key, 32);
+ sha512_update(&hash, message, message_len);
+ sha512_final(&hash, hram);
+
+ sc_reduce(hram);
+ sc_muladd(signature + 32, hram, private_key, r);
+}
diff --git a/3rd_party/ed25519/verify.c b/3rd_party/ed25519/verify.c
new file mode 100644
index 0000000..32f988e
--- /dev/null
+++ b/3rd_party/ed25519/verify.c
@@ -0,0 +1,77 @@
+#include "ed25519.h"
+#include "sha512.h"
+#include "ge.h"
+#include "sc.h"
+
+static int consttime_equal(const unsigned char *x, const unsigned char *y) {
+ unsigned char r = 0;
+
+ r = x[0] ^ y[0];
+ #define F(i) r |= x[i] ^ y[i]
+ F(1);
+ F(2);
+ F(3);
+ F(4);
+ F(5);
+ F(6);
+ F(7);
+ F(8);
+ F(9);
+ F(10);
+ F(11);
+ F(12);
+ F(13);
+ F(14);
+ F(15);
+ F(16);
+ F(17);
+ F(18);
+ F(19);
+ F(20);
+ F(21);
+ F(22);
+ F(23);
+ F(24);
+ F(25);
+ F(26);
+ F(27);
+ F(28);
+ F(29);
+ F(30);
+ F(31);
+ #undef F
+
+ return !r;
+}
+
+int ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key) {
+ unsigned char h[64];
+ unsigned char checker[32];
+ sha512_context hash;
+ ge_p3 A;
+ ge_p2 R;
+
+ if (signature[63] & 224) {
+ return 0;
+ }
+
+ if (ge_frombytes_negate_vartime(&A, public_key) != 0) {
+ return 0;
+ }
+
+ sha512_init(&hash);
+ sha512_update(&hash, signature, 32);
+ sha512_update(&hash, public_key, 32);
+ sha512_update(&hash, message, message_len);
+ sha512_final(&hash, h);
+
+ sc_reduce(h);
+ ge_double_scalarmult_vartime(&R, h, &A, signature + 32);
+ ge_tobytes(checker, &R);
+
+ if (!consttime_equal(checker, signature)) {
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/3rd_party/libsrp6a-sha512/LICENSE b/3rd_party/libsrp6a-sha512/LICENSE
new file mode 100644
index 0000000..7f70640
--- /dev/null
+++ b/3rd_party/libsrp6a-sha512/LICENSE
@@ -0,0 +1,62 @@
+Licensing
+---------
+
+SRP is royalty-free worldwide for commercial and non-commercial use.
+The SRP library has been carefully written not to depend on any
+encumbered algorithms, and it is distributed under a standard
+BSD-style Open Source license which is shown below. This license
+covers implementations based on the SRP library as well as
+independent implementations based on RFC 2945.
+
+The SRP distribution itself contains algorithms and code from
+various freeware packages; these parts fall under both the SRP
+Open Source license and the packages' own licenses. Care has
+been taken to ensure that these licenses are compatible with
+Open Source distribution, but it is the responsibility of the
+licensee to comply with the terms of these licenses. This
+disclaimer also applies to third-party libraries that may be
+linked into the distribution, since they may contain patented
+intellectual property. The file "Copyrights" contains a list
+of the copyrights incorporated by portions of the software.
+
+Broader use of the SRP authentication technology, such as variants
+incorporating the use of an explicit server secret (SRP-Z), may
+require a license; please contact the Stanford Office of Technology
+Licensing (http://otl.stanford.edu/) for more information about
+terms and conditions.
+
+This software is covered under the following copyright:
+
+/*
+ * Copyright (c) 1997-2007 The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Redistributions in source or binary form must retain an intact copy
+ * of this copyright notice.
+ */
+
+Address all questions regarding this license to:
+
+ Tom Wu
+ tjw@cs.Stanford.EDU
diff --git a/3rd_party/libsrp6a-sha512/Makefile.am b/3rd_party/libsrp6a-sha512/Makefile.am
new file mode 100644
index 0000000..2acd582
--- /dev/null
+++ b/3rd_party/libsrp6a-sha512/Makefile.am
@@ -0,0 +1,31 @@
+AUTOMAKE_OPTIONS = foreign no-dependencies
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir) \
+ -Wno-incompatible-pointer-types
+
+AM_CFLAGS = -DHAVE_CONFIG_H
+if HAVE_OPENSSL
+AM_CFLAGS += -DOPENSSL=1 $(openssl_CFLAGS)
+else
+if HAVE_GCRYPT
+AM_CFLAGS += -DGCRYPT=1 $(libgcrypt_CFLAGS)
+else
+if HAVE_MBEDTLS
+AM_CFLAGS += -DMBEDTLS=1 $(mbedtls_CFLAGS)
+endif
+endif
+endif
+
+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 \
+ srp.h srp_aux.h cstr.h \
+ t_sha.c
+#if !HAVE_OPENSSL
+#libsrp6a_sha512_la_SOURCES += t_sha.c
+#endif
diff --git a/3rd_party/libsrp6a-sha512/README.md b/3rd_party/libsrp6a-sha512/README.md
new file mode 100644
index 0000000..4affe4a
--- /dev/null
+++ b/3rd_party/libsrp6a-sha512/README.md
@@ -0,0 +1,35 @@
+# SRP6a-sha512 library
+
+## About
+
+This library is based on Stanford's Secure Remote Password (SRP) protocol
+implementation, or more precise on the `libsrp` part thereof.
+The entire source code for the SRP project can be obtained from [here](https://github.com/secure-remote-password/stanford-srp).
+
+It has been adapted to the needs of the libimobiledevice project, and
+contains just a part of the original code; it only supports the SRP6a
+client method which has been modified to use SHA512 instead of SHA1.
+The only supported SRP method is `SRP6a_sha512_client_method()`.
+Besides that, support for MbedTLS has been added.
+
+Also, all server-side code has been removed, and the client-side code
+has been reduced to a minimum, so that basically only the following
+functions remain operational:
+
+- `SRP_initialize_library`
+- `SRP_new`
+- `SRP_free`
+- `SRP_set_user_raw`
+- `SRP_set_params`
+- `SRP_set_auth_password`
+- `SRP_gen_pub`
+- `SRP_compute_key`
+- `SRP_respond`
+- `SRP_verify`
+
+Anything else has not been tested and must be considered non-functional.
+
+## License
+
+The license of the original work does still apply and can be found in the
+LICENSE file that comes with the code.
diff --git a/3rd_party/libsrp6a-sha512/cstr.c b/3rd_party/libsrp6a-sha512/cstr.c
new file mode 100644
index 0000000..9856f46
--- /dev/null
+++ b/3rd_party/libsrp6a-sha512/cstr.c
@@ -0,0 +1,226 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+#include "cstr.h"
+
+#define EXPFACTOR 2 /* Minimum expansion factor */
+#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 * str;
+
+ if(alloc == NULL) {
+ if(default_alloc == NULL) {
+ default_alloc = &malloc_allocator;
+ }
+ alloc = default_alloc;
+ }
+
+ str = (cstr *) (*alloc->alloc)(sizeof(cstr), alloc->heap);
+ 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 * nstr = cstr_new_alloc(alloc);
+ 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));
+}
+
+_TYPE( cstr * )
+cstr_createn(const char * s, int len)
+{
+ cstr * str = cstr_new();
+ if(str) {
+ cstr_setn(str, s, len);
+ }
+ return str;
+}
+
+_TYPE( void )
+cstr_use(cstr * str)
+{
+ ++str->ref;
+}
+
+_TYPE( void )
+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);
+ }
+ (*str->allocator->free)(str, str->allocator->heap);
+ }
+}
+
+_TYPE( void )
+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);
+ }
+}
+
+_TYPE( void )
+cstr_empty(cstr * str)
+{
+ if(str->cap > 0)
+ (*str->allocator->free)(str->data, str->allocator->heap);
+ str->data = cstr_empty_string;
+ str->length = str->cap = 0;
+}
+
+static int
+cstr_alloc(cstr * str, int len)
+{
+ char * t;
+
+ if(len > str->cap) {
+ if(len < EXPFACTOR * str->cap)
+ len = EXPFACTOR * str->cap;
+ if(len < MINSIZE)
+ len = MINSIZE;
+
+ t = (char *) (*str->allocator->alloc)(len * sizeof(char),
+ str->allocator->heap);
+ if(t) {
+ if(str->data) {
+ t[str->length] = 0;
+ if(str->cap > 0) {
+ if(str->length > 0)
+ memcpy(t, str->data, str->length);
+ free(str->data);
+ }
+ }
+ str->data = t;
+ str->cap = len;
+ return 1;
+ }
+ else
+ return -1;
+ }
+ else
+ return 0;
+}
+
+_TYPE( int )
+cstr_copy(cstr * dst, const cstr * src)
+{
+ return cstr_setn(dst, src->data, src->length);
+}
+
+_TYPE( int )
+cstr_set(cstr * str, const char * s)
+{
+ return cstr_setn(str, s, strlen(s));
+}
+
+_TYPE( int )
+cstr_setn(cstr * str, const char * s, int len)
+{
+ if(cstr_alloc(str, len + 1) < 0)
+ return -1;
+ str->data[len] = 0;
+ if(s != NULL && len > 0)
+ memmove(str->data, s, len);
+ str->length = len;
+ return 1;
+}
+
+_TYPE( int )
+cstr_set_length(cstr * str, int len)
+{
+ if(len < str->length) {
+ str->data[len] = 0;
+ str->length = len;
+ return 1;
+ }
+ else if(len > str->length) {
+ if(cstr_alloc(str, len + 1) < 0)
+ return -1;
+ memset(str->data + str->length, 0, len - str->length + 1);
+ str->length = len;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+_TYPE( int )
+cstr_append(cstr * str, const char * s)
+{
+ return cstr_appendn(str, s, strlen(s));
+}
+
+_TYPE( int )
+cstr_appendn(cstr * str, const char * s, int len)
+{
+ if(cstr_alloc(str, str->length + len + 1) < 0)
+ return -1;
+ memcpy(str->data + str->length, s, len);
+ str->length += len;
+ str->data[str->length] = 0;
+ return 1;
+}
+
+_TYPE( int )
+cstr_append_str(cstr * dst, const cstr * src)
+{
+ return cstr_appendn(dst, src->data, src->length);
+}
diff --git a/3rd_party/libsrp6a-sha512/cstr.h b/3rd_party/libsrp6a-sha512/cstr.h
new file mode 100644
index 0000000..7cc019a
--- /dev/null
+++ b/3rd_party/libsrp6a-sha512/cstr.h
@@ -0,0 +1,94 @@
+#ifndef _CSTR_H_
+#define _CSTR_H_
+
+/* A general-purpose string "class" for C */
+
+#if !defined(P)
+#ifdef __STDC__
+#define P(x) x
+#else
+#define P(x) ()
+#endif
+#endif
+
+/* For building dynamic link libraries under windows, windows NT
+ * using MSVC1.5 or MSVC2.0
+ */
+
+#ifndef _DLLDECL
+#define _DLLDECL
+
+#ifdef MSVC15 /* MSVC1.5 support for 16 bit apps */
+#define _MSVC15EXPORT _export
+#define _MSVC20EXPORT
+#define _DLLAPI _export _pascal
+#define _CDECL
+#define _TYPE(a) a _MSVC15EXPORT
+#define DLLEXPORT 1
+
+#elif defined(MSVC20) || (defined(_USRDLL) && defined(SRP_EXPORTS))
+#define _MSVC15EXPORT
+#define _MSVC20EXPORT _declspec(dllexport)
+#define _DLLAPI
+#define _CDECL
+#define _TYPE(a) _MSVC20EXPORT a
+#define DLLEXPORT 1
+
+#else /* Default, non-dll. Use this for Unix or DOS */
+#define _MSVC15DEXPORT
+#define _MSVC20EXPORT
+#define _DLLAPI
+#if defined(WINDOWS) || defined(WIN32)
+#define _CDECL _cdecl
+#else
+#define _CDECL
+#endif
+#define _TYPE(a) a _CDECL
+#endif
+#endif /* _DLLDECL */
+
+#ifdef __cplusplus
+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));
+
+_TYPE( void ) cstr_free P((cstr * str));
+_TYPE( void ) cstr_clear_free P((cstr * str));
+_TYPE( void ) cstr_use P((cstr * str));
+_TYPE( void ) cstr_empty P((cstr * str));
+_TYPE( int ) cstr_copy P((cstr * dst, const cstr * src));
+_TYPE( int ) cstr_set P((cstr * str, const char * s));
+_TYPE( int ) cstr_setn P((cstr * str, const char * s, int len));
+_TYPE( int ) cstr_set_length P((cstr * str, int len));
+_TYPE( int ) cstr_append P((cstr * str, const char * s));
+_TYPE( int ) cstr_appendn P((cstr * str, const char * s, int len));
+_TYPE( int ) cstr_append_str P((cstr * dst, const cstr * src));
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _CSTR_H_ */
diff --git a/3rd_party/libsrp6a-sha512/srp.c b/3rd_party/libsrp6a-sha512/srp.c
new file mode 100644
index 0000000..74e1f98
--- /dev/null
+++ b/3rd_party/libsrp6a-sha512/srp.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 1997-2007 The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Redistributions in source or binary form must retain an intact copy
+ * of this copyright notice.
+ */
+
+#include "t_defines.h"
+#include "srp.h"
+
+static int library_initialized = 0;
+
+_TYPE( SRP_RESULT )
+SRP_initialize_library()
+{
+ if(library_initialized == 0) {
+ BigIntegerInitialize();
+ t_stronginitrand();
+ library_initialized = 1;
+ }
+ return SRP_SUCCESS;
+}
+
+_TYPE( SRP_RESULT )
+SRP_finalize_library()
+{
+ if(library_initialized > 0) {
+ library_initialized = 0;
+ BigIntegerFinalize();
+ }
+ return SRP_SUCCESS;
+}
+
+static int srp_modulus_min_bits = SRP_DEFAULT_MIN_BITS;
+
+_TYPE( SRP_RESULT )
+SRP_set_modulus_min_bits(int minbits)
+{
+ srp_modulus_min_bits = minbits;
+ return SRP_SUCCESS;
+}
+
+_TYPE( int )
+SRP_get_modulus_min_bits()
+{
+ return srp_modulus_min_bits;
+}
+
+static int
+default_secret_bits_cb(int modsize)
+{
+ return 256;
+ /*return modsize;*/ /* Warning: Very Slow */
+}
+
+static SRP_SECRET_BITS_CB srp_sb_cb = default_secret_bits_cb;
+
+_TYPE( SRP_RESULT )
+SRP_set_secret_bits_cb(SRP_SECRET_BITS_CB cb)
+{
+ srp_sb_cb = cb;
+ return SRP_SUCCESS;
+}
+
+_TYPE( int )
+SRP_get_secret_bits(int modsize)
+{
+ return (*srp_sb_cb)(modsize);
+}
+
+_TYPE( SRP * )
+SRP_new(SRP_METHOD * meth)
+{
+ SRP * srp = (SRP *) malloc(sizeof(SRP));
+
+ if(srp == NULL)
+ return NULL;
+
+ srp->flags = 0;
+ srp->username = cstr_new();
+ srp->bctx = BigIntegerCtxNew();
+ srp->modulus = NULL;
+ srp->accel = NULL;
+ srp->generator = NULL;
+ srp->salt = NULL;
+ srp->verifier = NULL;
+ srp->password = NULL;
+ srp->pubkey = NULL;
+ srp->secret = NULL;
+ srp->u = NULL;
+ srp->key = NULL;
+ srp->ex_data = cstr_new();
+ srp->param_cb = NULL;
+ srp->meth = meth;
+ srp->meth_data = NULL;
+ //srp->slu = NULL;
+ if(srp->meth->init == NULL || (*srp->meth->init)(srp) == SRP_SUCCESS)
+ return srp;
+ free(srp);
+ return NULL;
+}
+
+_TYPE( SRP_RESULT )
+SRP_free(SRP * srp)
+{
+ if(srp->meth->finish)
+ (*srp->meth->finish)(srp);
+
+ if(srp->username)
+ cstr_clear_free(srp->username);
+ if(srp->modulus)
+ BigIntegerFree(srp->modulus);
+ if(srp->accel)
+ BigIntegerModAccelFree(srp->accel);
+ if(srp->generator)
+ BigIntegerFree(srp->generator);
+ if(srp->salt)
+ cstr_clear_free(srp->salt);
+ if(srp->verifier)
+ BigIntegerClearFree(srp->verifier);
+ if(srp->password)
+ BigIntegerClearFree(srp->password);
+ if(srp->pubkey)
+ BigIntegerFree(srp->pubkey);
+ if(srp->secret)
+ BigIntegerClearFree(srp->secret);
+ if(srp->u)
+ BigIntegerFree(srp->u);
+ if(srp->key)
+ BigIntegerClearFree(srp->key);
+ if(srp->bctx)
+ BigIntegerCtxFree(srp->bctx);
+ if(srp->ex_data)
+ cstr_clear_free(srp->ex_data);
+ free(srp);
+ return SRP_SUCCESS;
+}
+
+_TYPE( SRP_RESULT )
+SRP_set_client_param_verify_cb(SRP * srp, SRP_CLIENT_PARAM_VERIFY_CB cb)
+{
+ srp->param_cb = cb;
+ return SRP_SUCCESS;
+}
+
+_TYPE( SRP_RESULT )
+SRP_set_username(SRP * srp, const char * username)
+{
+ cstr_set(srp->username, username);
+ return SRP_SUCCESS;
+}
+
+_TYPE( SRP_RESULT )
+SRP_set_user_raw(SRP * srp, const unsigned char * user, int userlen)
+{
+ cstr_setn(srp->username, (const char*)user, userlen);
+ return SRP_SUCCESS;
+}
+
+_TYPE( SRP_RESULT )
+SRP_set_params(SRP * srp, const unsigned char * modulus, int modlen,
+ const unsigned char * generator, int genlen,
+ const unsigned char * salt, int saltlen)
+{
+ SRP_RESULT rc;
+
+ if(modulus == NULL || generator == NULL || salt == NULL)
+ return SRP_ERROR;
+
+ /* Set fields in SRP context */
+ srp->modulus = BigIntegerFromBytes(modulus, modlen);
+ if(srp->flags & SRP_FLAG_MOD_ACCEL)
+ srp->accel = BigIntegerModAccelNew(srp->modulus, srp->bctx);
+ srp->generator = BigIntegerFromBytes(generator, genlen);
+ if(srp->salt == NULL)
+ srp->salt = cstr_new();
+ cstr_setn(srp->salt, (const char*)salt, saltlen);
+
+ /* Now attempt to validate parameters */
+ if(BigIntegerBitLen(srp->modulus) < SRP_get_modulus_min_bits())
+ return SRP_ERROR;
+
+ if(srp->param_cb) {
+ rc = (*srp->param_cb)(srp, modulus, modlen, generator, genlen);
+ if(!SRP_OK(rc))
+ return rc;
+ }
+
+ return (*srp->meth->params)(srp, modulus, modlen, generator, genlen,
+ salt, saltlen);
+}
+
+_TYPE( SRP_RESULT )
+SRP_set_authenticator(SRP * srp, const unsigned char * a, int alen)
+{
+ return (*srp->meth->auth)(srp, a, alen);
+}
+
+_TYPE( SRP_RESULT )
+SRP_set_auth_password(SRP * srp, const char * password)
+{
+ return (*srp->meth->passwd)(srp, (const unsigned char *)password,
+ strlen(password));
+}
+
+_TYPE( SRP_RESULT )
+SRP_set_auth_password_raw(SRP * srp,
+ const unsigned char * password, int passlen)
+{
+ return (*srp->meth->passwd)(srp, password, passlen);
+}
+
+_TYPE( SRP_RESULT )
+SRP_gen_pub(SRP * srp, cstr ** result)
+{
+ return (*srp->meth->genpub)(srp, result);
+}
+
+_TYPE( SRP_RESULT )
+SRP_add_ex_data(SRP * srp, const unsigned char * data, int datalen)
+{
+ cstr_appendn(srp->ex_data, (const char*)data, datalen);
+ return SRP_SUCCESS;
+}
+
+_TYPE( SRP_RESULT )
+SRP_compute_key(SRP * srp, cstr ** result,
+ const unsigned char * pubkey, int pubkeylen)
+{
+ return (*srp->meth->key)(srp, result, pubkey, pubkeylen);
+}
+
+_TYPE( SRP_RESULT )
+SRP_verify(SRP * srp, const unsigned char * proof, int prooflen)
+{
+ return (*srp->meth->verify)(srp, proof, prooflen);
+}
+
+_TYPE( SRP_RESULT )
+SRP_respond(SRP * srp, cstr ** proof)
+{
+ return (*srp->meth->respond)(srp, proof);
+}
+
+_TYPE( SRP_RESULT )
+SRP_use_engine(const char * engine)
+{
+ if(BigIntegerOK(BigIntegerUseEngine(engine)))
+ return SRP_SUCCESS;
+ else
+ return SRP_ERROR;
+}
diff --git a/3rd_party/libsrp6a-sha512/srp.h b/3rd_party/libsrp6a-sha512/srp.h
new file mode 100644
index 0000000..b1d46af
--- /dev/null
+++ b/3rd_party/libsrp6a-sha512/srp.h
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 1997-2007 The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Redistributions in source or binary form must retain an intact copy
+ * of this copyright notice.
+ */
+#ifndef _SRP_H_
+#define _SRP_H_
+
+#include "cstr.h"
+#include "srp_aux.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* SRP library version identification */
+#define SRP_VERSION_MAJOR 2
+#define SRP_VERSION_MINOR 0
+#define SRP_VERSION_PATCHLEVEL 1
+
+typedef int SRP_RESULT;
+/* Returned codes for SRP API functions */
+#define SRP_OK(v) ((v) == SRP_SUCCESS)
+#define SRP_SUCCESS 0
+#define SRP_ERROR -1
+
+/* Set the minimum number of bits acceptable in an SRP modulus */
+#define SRP_DEFAULT_MIN_BITS 512
+_TYPE( SRP_RESULT ) SRP_set_modulus_min_bits P((int minbits));
+_TYPE( int ) SRP_get_modulus_min_bits P((void));
+
+/*
+ * Sets the "secret size callback" function.
+ * This function is called with the modulus size in bits,
+ * and returns the size of the secret exponent in bits.
+ * The default function always returns 256 bits.
+ */
+typedef int (_CDECL * SRP_SECRET_BITS_CB)(int modsize);
+_TYPE( SRP_RESULT ) SRP_set_secret_bits_cb P((SRP_SECRET_BITS_CB cb));
+_TYPE( int ) SRP_get_secret_bits P((int modsize));
+
+typedef struct srp_st SRP;
+
+#if 0
+/* Server Lookup API */
+typedef struct srp_server_lu_st SRP_SERVER_LOOKUP;
+
+typedef struct srp_s_lu_meth_st {
+ const char * name;
+
+ SRP_RESULT (_CDECL * init)(SRP_SERVER_LOOKUP * slu);
+ SRP_RESULT (_CDECL * finish)(SRP_SERVER_LOOKUP * slu);
+
+ SRP_RESULT (_CDECL * lookup)(SRP_SERVER_LOOKUP * slu, SRP * srp, cstr * username);
+
+ void * meth_data;
+} SRP_SERVER_LOOKUP_METHOD;
+
+struct srp_server_lu_st {
+ SRP_SERVER_LOOKUP_METHOD * meth;
+ void * data;
+};
+
+/*
+ * The Server Lookup API deals with the server-side issue of
+ * mapping usernames to verifiers. Given a username, a lookup
+ * mechanism needs to provide parameters (N, g), salt (s), and
+ * password verifier (v) for that user.
+ *
+ * A SRP_SERVER_LOOKUP_METHOD describes the general mechanism
+ * for performing lookups (e.g. files, LDAP, database, etc.)
+ * A SRP_SERVER_LOOKUP is an active "object" that is actually
+ * called to do lookups.
+ */
+_TYPE( SRP_SERVER_LOOKUP * )
+ SRP_SERVER_LOOKUP_new P((SRP_SERVER_LOOKUP_METHOD * meth));
+_TYPE( SRP_RESULT ) SRP_SERVER_LOOKUP_free P((SRP_SERVER_LOOKUP * slu));
+_TYPE( SRP_RESULT ) SRP_SERVER_do_lookup P((SRP_SERVER_LOOKUP * slu,
+ SRP * srp, cstr * username));
+
+/*
+ * SRP_SERVER_system_lookup supercedes SRP_server_init_user.
+ */
+_TYPE( SRP_SERVER_LOOKUP * ) SRP_SERVER_system_lookup P((void));
+#endif
+
+/*
+ * Client Parameter Verification API
+ *
+ * This callback is called from the SRP client when the
+ * parameters (modulus and generator) are set. The callback
+ * should return SRP_SUCCESS if the parameters are okay,
+ * otherwise some error code to indicate that the parameters
+ * should be rejected.
+ */
+typedef SRP_RESULT (_CDECL * SRP_CLIENT_PARAM_VERIFY_CB)(SRP * srp, const unsigned char * mod, int modlen, const unsigned char * gen, int genlen);
+
+#if 0
+/* The default parameter verifier function */
+_TYPE( SRP_RESULT ) SRP_CLIENT_default_param_verify_cb(SRP * srp, const unsigned char * mod, int modlen, const unsigned char * gen, int genlen);
+/* A parameter verifier that only accepts builtin params (no prime test) */
+_TYPE( SRP_RESULT ) SRP_CLIENT_builtin_param_verify_cb(SRP * srp, const unsigned char * mod, int modlen, const unsigned char * gen, int genlen);
+/* The "classic" parameter verifier that accepts either builtin params
+ * immediately, and performs safe-prime tests on N and primitive-root
+ * tests on g otherwise. SECURITY WARNING: This may allow for certain
+ * attacks based on "trapdoor" moduli, so this is not recommended. */
+_TYPE( SRP_RESULT ) SRP_CLIENT_compat_param_verify_cb(SRP * srp, const unsigned char * mod, int modlen, const unsigned char * gen, int genlen);
+
+#endif
+
+/*
+ * Main SRP API - SRP and SRP_METHOD
+ */
+
+/* SRP method definitions */
+typedef struct srp_meth_st {
+ const char * name;
+
+ SRP_RESULT (_CDECL * init)(SRP * srp);
+ SRP_RESULT (_CDECL * finish)(SRP * srp);
+
+ SRP_RESULT (_CDECL * params)(SRP * srp,
+ const unsigned char * modulus, int modlen,
+ const unsigned char * generator, int genlen,
+ const unsigned char * salt, int saltlen);
+ SRP_RESULT (_CDECL * auth)(SRP * srp, const unsigned char * a, int alen);
+ SRP_RESULT (_CDECL * passwd)(SRP * srp,
+ const unsigned char * pass, int passlen);
+ SRP_RESULT (_CDECL * genpub)(SRP * srp, cstr ** result);
+ SRP_RESULT (_CDECL * key)(SRP * srp, cstr ** result,
+ const unsigned char * pubkey, int pubkeylen);
+ SRP_RESULT (_CDECL * verify)(SRP * srp,
+ const unsigned char * proof, int prooflen);
+ SRP_RESULT (_CDECL * respond)(SRP * srp, cstr ** proof);
+
+ void * data;
+} SRP_METHOD;
+
+/* Magic numbers for the SRP context header */
+#define SRP_MAGIC_CLIENT 12
+#define SRP_MAGIC_SERVER 28
+
+/* Flag bits for SRP struct */
+#define SRP_FLAG_MOD_ACCEL 0x1 /* accelerate modexp operations */
+#define SRP_FLAG_LEFT_PAD 0x2 /* left-pad to length-of-N inside hashes */
+
+/*
+ * A hybrid structure that represents either client or server state.
+ */
+struct srp_st {
+ int magic; /* To distinguish client from server (and for sanity) */
+
+ int flags;
+
+ cstr * username;
+
+ BigInteger modulus;
+ BigInteger generator;
+ cstr * salt;
+
+ BigInteger verifier;
+ BigInteger password;
+
+ BigInteger pubkey;
+ BigInteger secret;
+ BigInteger u;
+
+ BigInteger key;
+
+ cstr * ex_data;
+
+ SRP_METHOD * meth;
+ void * meth_data;
+
+ BigIntegerCtx bctx; /* to cache temporaries if available */
+ BigIntegerModAccel accel; /* to accelerate modexp if available */
+
+ SRP_CLIENT_PARAM_VERIFY_CB param_cb; /* to verify params */
+ //SRP_SERVER_LOOKUP * slu; /* to look up users */
+};
+
+/*
+ * Global initialization/de-initialization functions.
+ * Call SRP_initialize_library before using the library,
+ * and SRP_finalize_library when done.
+ */
+_TYPE( SRP_RESULT ) SRP_initialize_library();
+_TYPE( SRP_RESULT ) SRP_finalize_library();
+
+/*
+ * SRP_new() creates a new SRP context object -
+ * the method determines which "sense" (client or server)
+ * the object operates in. SRP_free() frees it.
+ * (See RFC2945 method definitions below.)
+ */
+_TYPE( SRP * ) SRP_new P((SRP_METHOD * meth));
+_TYPE( SRP_RESULT ) SRP_free P((SRP * srp));
+
+#if 0
+/*
+ * Use the supplied lookup object to look up user parameters and
+ * password verifier. The lookup function gets called during
+ * SRP_set_username/SRP_set_user_raw below. Using this function
+ * means that the server can avoid calling SRP_set_params and
+ * SRP_set_authenticator, since the lookup function handles that
+ * internally.
+ */
+_TYPE( SRP_RESULT ) SRP_set_server_lookup P((SRP * srp,
+ SRP_SERVER_LOOKUP * lookup));
+#endif
+
+/*
+ * Use the supplied callback function to verify parameters
+ * (modulus, generator) given to the client.
+ */
+_TYPE( SRP_RESULT )
+ SRP_set_client_param_verify_cb P((SRP * srp,
+ SRP_CLIENT_PARAM_VERIFY_CB cb));
+
+/*
+ * Both client and server must call both SRP_set_username and
+ * SRP_set_params, in that order, before calling anything else.
+ * SRP_set_user_raw is an alternative to SRP_set_username that
+ * accepts an arbitrary length-bounded octet string as input.
+ */
+_TYPE( SRP_RESULT ) SRP_set_username P((SRP * srp, const char * username));
+_TYPE( SRP_RESULT ) SRP_set_user_raw P((SRP * srp, const unsigned char * user,
+ int userlen));
+_TYPE( SRP_RESULT )
+ SRP_set_params P((SRP * srp,
+ const unsigned char * modulus, int modlen,
+ const unsigned char * generator, int genlen,
+ const unsigned char * salt, int saltlen));
+
+/*
+ * On the client, SRP_set_authenticator, SRP_gen_exp, and
+ * SRP_add_ex_data can be called in any order.
+ * On the server, SRP_set_authenticator must come first,
+ * followed by SRP_gen_exp and SRP_add_ex_data in either order.
+ */
+/*
+ * The authenticator is the secret possessed by either side.
+ * For the server, this is the bigendian verifier, as an octet string.
+ * For the client, this is the bigendian raw secret, as an octet string.
+ * The server's authenticator must be the generator raised to the power
+ * of the client's raw secret modulo the common modulus for authentication
+ * to succeed.
+ *
+ * SRP_set_auth_password computes the authenticator from a plaintext
+ * password and then calls SRP_set_authenticator automatically. This is
+ * usually used on the client side, while the server usually uses
+ * SRP_set_authenticator (since it doesn't know the plaintext password).
+ */
+_TYPE( SRP_RESULT )
+ SRP_set_authenticator P((SRP * srp, const unsigned char * a, int alen));
+_TYPE( SRP_RESULT )
+ SRP_set_auth_password P((SRP * srp, const char * password));
+_TYPE( SRP_RESULT )
+ SRP_set_auth_password_raw P((SRP * srp,
+ const unsigned char * password,
+ int passlen));
+
+/*
+ * SRP_gen_pub generates the random exponential residue to send
+ * to the other side. If using SRP-3/RFC2945, the server must
+ * withhold its result until it receives the client's number.
+ * If using SRP-6, the server can send its value immediately
+ * without waiting for the client.
+ *
+ * If "result" points to a NULL pointer, a new cstr object will be
+ * created to hold the result, and "result" will point to it.
+ * If "result" points to a non-NULL cstr pointer, the result will be
+ * placed there.
+ * If "result" itself is NULL, no result will be returned,
+ * although the big integer value will still be available
+ * through srp->pubkey in the SRP struct.
+ */
+_TYPE( SRP_RESULT ) SRP_gen_pub P((SRP * srp, cstr ** result));
+/*
+ * Append the data to the extra data segment. Authentication will
+ * not succeed unless both sides add precisely the same data in
+ * the same order.
+ */
+_TYPE( SRP_RESULT ) SRP_add_ex_data P((SRP * srp, const unsigned char * data,
+ int datalen));
+
+/*
+ * SRP_compute_key must be called after the previous three methods.
+ */
+_TYPE( SRP_RESULT ) SRP_compute_key P((SRP * srp, cstr ** result,
+ const unsigned char * pubkey,
+ int pubkeylen));
+
+/*
+ * On the client, call SRP_respond first to get the response to send
+ * to the server, and call SRP_verify to verify the server's response.
+ * On the server, call SRP_verify first to verify the client's response,
+ * and call SRP_respond ONLY if verification succeeds.
+ *
+ * It is an error to call SRP_respond with a NULL pointer.
+ */
+_TYPE( SRP_RESULT ) SRP_verify P((SRP * srp,
+ const unsigned char * proof, int prooflen));
+_TYPE( SRP_RESULT ) SRP_respond P((SRP * srp, cstr ** response));
+
+/* RFC2945-style SRP authentication */
+
+#define RFC2945_KEY_LEN 40 /* length of session key (bytes) */
+#define RFC2945_RESP_LEN 20 /* length of proof hashes (bytes) */
+
+/*
+ * RFC2945-style SRP authentication methods. Use these like:
+ * SRP * srp = SRP_new(SRP_RFC2945_client_method());
+ */
+_TYPE( SRP_METHOD * ) SRP_RFC2945_client_method P((void));
+_TYPE( SRP_METHOD * ) SRP_RFC2945_server_method P((void));
+
+/*
+ * SRP-6 and SRP-6a authentication methods.
+ * SRP-6a is recommended for better resistance to 2-for-1 attacks.
+ */
+_TYPE( SRP_METHOD * ) SRP6_client_method P((void));
+_TYPE( SRP_METHOD * ) SRP6_server_method P((void));
+_TYPE( SRP_METHOD * ) SRP6a_client_method P((void));
+_TYPE( SRP_METHOD * ) SRP6a_server_method P((void));
+
+_TYPE( SRP_METHOD * ) SRP6a_sha512_client_method P((void));
+
+/*
+ * Convenience function - SRP_server_init_user
+ * Looks up the username from the system EPS configuration and calls
+ * SRP_set_username, SRP_set_params, and SRP_set_authenticator to
+ * initialize server state for that user.
+ *
+ * This is deprecated in favor of SRP_SERVER_system_lookup() and
+ * the Server Lookup API.
+ */
+_TYPE( SRP_RESULT ) SRP_server_init_user P((SRP * srp, const char * username));
+
+/*
+ * Use the named engine for acceleration.
+ */
+_TYPE( SRP_RESULT ) SRP_use_engine P((const char * engine));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SRP_H_ */
diff --git a/3rd_party/libsrp6a-sha512/srp6a_sha512_client.c b/3rd_party/libsrp6a-sha512/srp6a_sha512_client.c
new file mode 100644
index 0000000..db59fe8
--- /dev/null
+++ b/3rd_party/libsrp6a-sha512/srp6a_sha512_client.c
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 1997-2007 The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Redistributions in source or binary form must retain an intact copy
+ * of this copyright notice.
+ */
+#include "t_defines.h"
+#include "srp.h"
+#include "t_sha.h"
+
+/*
+ * SRP-6/6a has two minor refinements relative to SRP-3/RFC2945:
+ * 1. The "g^x" value is multipled by three in the client's
+ * calculation of its session key.
+ * SRP-6a: The "g^x" value is multiplied by the hash of
+ * N and g in the client's session key calculation.
+ * 2. The value of u is taken as the hash of A and B,
+ * instead of the top 32 bits of the hash of B.
+ * This eliminates the old restriction where the
+ * server had to receive A before it could send B.
+ */
+
+/****************************/
+#define SHA512_DIGESTSIZE 64
+#define SRP6_SHA512_KEY_LEN 64
+
+/*
+ * The client keeps track of the running hash
+ * state via SHA512_CTX structures pointed to by the
+ * meth_data pointer. The "hash" member is the hash value that
+ * will be sent to the other side; the "ckhash" member is the
+ * hash value expected from the other side.
+ */
+struct sha512_client_meth_st {
+ SHA512_CTX hash;
+ SHA512_CTX ckhash;
+ unsigned char k[SRP6_SHA512_KEY_LEN];
+};
+
+#define SHA512_CLIENT_CTXP(srp) ((struct sha512_client_meth_st *)(srp)->meth_data)
+
+static SRP_RESULT
+srp6a_sha512_client_init(SRP * srp)
+{
+ srp->magic = SRP_MAGIC_CLIENT;
+ srp->flags = SRP_FLAG_MOD_ACCEL | SRP_FLAG_LEFT_PAD;
+ srp->meth_data = malloc(sizeof(struct sha512_client_meth_st));
+ SHA512Init(&SHA512_CLIENT_CTXP(srp)->hash);
+ SHA512Init(&SHA512_CLIENT_CTXP(srp)->ckhash);
+ return SRP_SUCCESS;
+}
+
+static SRP_RESULT
+srp6_sha512_client_finish(SRP * srp)
+{
+ if(srp->meth_data) {
+ memset(srp->meth_data, 0, sizeof(struct sha512_client_meth_st));
+ free(srp->meth_data);
+ }
+ return SRP_SUCCESS;
+}
+
+static SRP_RESULT
+srp6_sha512_client_params(SRP * srp, const unsigned char * modulus, int modlen,
+ const unsigned char * generator, int genlen,
+ const unsigned char * salt, int saltlen)
+{
+ int i;
+ unsigned char buf1[SHA512_DIGESTSIZE], buf2[SHA512_DIGESTSIZE];
+ SHA512_CTX ctxt;
+
+ /* Fields set by SRP_set_params */
+
+ /* Update hash state */
+ SHA512Init(&ctxt);
+ SHA512Update(&ctxt, modulus, modlen);
+ SHA512Final(buf1, &ctxt); /* buf1 = H(modulus) */
+
+ SHA512Init(&ctxt);
+ SHA512Update(&ctxt, generator, genlen);
+ SHA512Final(buf2, &ctxt); /* buf2 = H(generator) */
+
+ for(i = 0; i < sizeof(buf1); ++i)
+ buf1[i] ^= buf2[i]; /* buf1 = H(modulus) xor H(generator) */
+
+ /* hash: H(N) xor H(g) */
+ SHA512Update(&SHA512_CLIENT_CTXP(srp)->hash, buf1, sizeof(buf1));
+
+ SHA512Init(&ctxt);
+ SHA512Update(&ctxt, srp->username->data, srp->username->length);
+ SHA512Final(buf1, &ctxt); /* buf1 = H(user) */
+
+ /* hash: (H(N) xor H(g)) | H(U) */
+ SHA512Update(&SHA512_CLIENT_CTXP(srp)->hash, buf1, sizeof(buf1));
+
+ /* hash: (H(N) xor H(g)) | H(U) | s */
+ SHA512Update(&SHA512_CLIENT_CTXP(srp)->hash, salt, saltlen);
+
+ return SRP_SUCCESS;
+}
+
+static SRP_RESULT
+srp6_sha512_client_auth(SRP * srp, const unsigned char * a, int alen)
+{
+ /* On the client, the authenticator is the raw password-derived hash */
+ srp->password = BigIntegerFromBytes(a, alen);
+
+ /* verifier = g^x mod N */
+ srp->verifier = BigIntegerFromInt(0);
+ BigIntegerModExp(srp->verifier, srp->generator, srp->password, srp->modulus, srp->bctx, srp->accel);
+
+ return SRP_SUCCESS;
+}
+
+static SRP_RESULT
+srp6_sha512_client_passwd(SRP * srp, const unsigned char * p, int plen)
+{
+ SHA512_CTX ctxt;
+ unsigned char dig[SHA512_DIGESTSIZE];
+ int r;
+
+ SHA512Init(&ctxt);
+ SHA512Update(&ctxt, srp->username->data, srp->username->length);
+ SHA512Update(&ctxt, ":", 1);
+ SHA512Update(&ctxt, p, plen);
+ SHA512Final(dig, &ctxt); /* dig = H(U | ":" | P) */
+
+ SHA512Init(&ctxt);
+ SHA512Update(&ctxt, srp->salt->data, srp->salt->length);
+ SHA512Update(&ctxt, dig, sizeof(dig));
+ SHA512Final(dig, &ctxt); /* dig = H(s | H(U | ":" | P)) */
+ memset(&ctxt, 0, sizeof(ctxt));
+
+ r = SRP_set_authenticator(srp, dig, sizeof(dig));
+ memset(dig, 0, sizeof(dig));
+
+ return r;
+}
+
+static SRP_RESULT
+srp6_sha512_client_genpub(SRP * srp, cstr ** result)
+{
+ cstr * astr;
+ int slen = (SRP_get_secret_bits(BigIntegerBitLen(srp->modulus)) + 7) / 8;
+
+ if(result == NULL)
+ astr = cstr_new();
+ else {
+ if(*result == NULL)
+ *result = cstr_new();
+ astr = *result;
+ }
+
+ cstr_set_length(astr, BigIntegerByteLen(srp->modulus));
+ t_random((unsigned char*)astr->data, slen);
+ srp->secret = BigIntegerFromBytes((const unsigned char*)astr->data, slen);
+ /* Force g^a mod n to "wrap around" by adding log[2](n) to "a". */
+ BigIntegerAddInt(srp->secret, srp->secret, BigIntegerBitLen(srp->modulus));
+ /* A = g^a mod n */
+ srp->pubkey = BigIntegerFromInt(0);
+ BigIntegerModExp(srp->pubkey, srp->generator, srp->secret, srp->modulus, srp->bctx, srp->accel);
+ BigIntegerToCstr(srp->pubkey, astr);
+
+ /* hash: (H(N) xor H(g)) | H(U) | s | A */
+ SHA512Update(&SHA512_CLIENT_CTXP(srp)->hash, astr->data, astr->length);
+ /* ckhash: A */
+ SHA512Update(&SHA512_CLIENT_CTXP(srp)->ckhash, astr->data, astr->length);
+
+ if(result == NULL) /* astr was a temporary */
+ cstr_clear_free(astr);
+
+ return SRP_SUCCESS;
+}
+
+static SRP_RESULT
+srp6_sha512_client_key_ex(SRP * srp, cstr ** result,
+ const unsigned char * pubkey, int pubkeylen, BigInteger k)
+{
+ SHA512_CTX ctxt;
+ unsigned char dig[SHA512_DIGESTSIZE];
+ BigInteger gb, e;
+ cstr * s;
+ int modlen;
+
+ modlen = BigIntegerByteLen(srp->modulus);
+ if(pubkeylen > modlen)
+ return SRP_ERROR;
+
+ /* Compute u from client's and server's values */
+ SHA512Init(&ctxt);
+ /* Use s as a temporary to store client's value */
+ s = cstr_new();
+ if(srp->flags & SRP_FLAG_LEFT_PAD) {
+ BigIntegerToCstrEx(srp->pubkey, s, modlen);
+ SHA512Update(&ctxt, s->data, s->length);
+ if(pubkeylen < modlen) {
+ memcpy(s->data + (modlen - pubkeylen), pubkey, pubkeylen);
+ memset(s->data, 0, modlen - pubkeylen);
+ SHA512Update(&ctxt, s->data, modlen);
+ }
+ else
+ SHA512Update(&ctxt, pubkey, pubkeylen);
+ }
+ else {
+ BigIntegerToCstr(srp->pubkey, s);
+ SHA512Update(&ctxt, s->data, s->length);
+ SHA512Update(&ctxt, pubkey, pubkeylen);
+ }
+ SHA512Final(dig, &ctxt);
+ srp->u = BigIntegerFromBytes(dig, SHA512_DIGESTSIZE);
+
+ /* hash: (H(N) xor H(g)) | H(U) | s | A | B */
+ SHA512Update(&SHA512_CLIENT_CTXP(srp)->hash, pubkey, pubkeylen);
+
+ gb = BigIntegerFromBytes(pubkey, pubkeylen);
+ /* reject B == 0, B >= modulus */
+ if(BigIntegerCmp(gb, srp->modulus) >= 0 || BigIntegerCmpInt(gb, 0) == 0) {
+ BigIntegerFree(gb);
+ cstr_clear_free(s);
+ return SRP_ERROR;
+ }
+ e = BigIntegerFromInt(0);
+ srp->key = BigIntegerFromInt(0);
+ /* unblind g^b (mod N) */
+ BigIntegerSub(srp->key, srp->modulus, srp->verifier);
+ /* use e as temporary, e == -k*v (mod N) */
+ BigIntegerMul(e, k, srp->key, srp->bctx);
+ BigIntegerAdd(e, e, gb);
+ BigIntegerMod(gb, e, srp->modulus, srp->bctx);
+
+ /* compute gb^(a + ux) (mod N) */
+ BigIntegerMul(e, srp->password, srp->u, srp->bctx);
+ BigIntegerAdd(e, e, srp->secret); /* e = a + ux */
+
+ BigIntegerModExp(srp->key, gb, e, srp->modulus, srp->bctx, srp->accel);
+ BigIntegerClearFree(e);
+ BigIntegerClearFree(gb);
+
+ /* convert srp->key into a session key, update hash states */
+ BigIntegerToCstr(srp->key, s);
+ SHA512Init(&ctxt);
+ SHA512Update(&ctxt, s->data, s->length);
+ SHA512Final((unsigned char*)&SHA512_CLIENT_CTXP(srp)->k, &ctxt);
+ cstr_clear_free(s);
+
+ /* hash: (H(N) xor H(g)) | H(U) | s | A | B | K */
+ SHA512Update(&SHA512_CLIENT_CTXP(srp)->hash, SHA512_CLIENT_CTXP(srp)->k, SRP6_SHA512_KEY_LEN);
+ /* hash: (H(N) xor H(g)) | H(U) | s | A | B | K | ex_data */
+ if(srp->ex_data->length > 0)
+ SHA512Update(&SHA512_CLIENT_CTXP(srp)->hash,
+ srp->ex_data->data, srp->ex_data->length);
+ if(result) {
+ if(*result == NULL)
+ *result = cstr_new();
+ cstr_setn(*result, (const char*)SHA512_CLIENT_CTXP(srp)->k, SRP6_SHA512_KEY_LEN);
+ }
+
+ return SRP_SUCCESS;
+}
+
+static SRP_RESULT
+srp6a_sha512_client_key(SRP * srp, cstr ** result,
+ const unsigned char * pubkey, int pubkeylen)
+{
+ SRP_RESULT ret;
+ BigInteger k;
+ cstr * s;
+ SHA512_CTX ctxt;
+ unsigned char dig[SHA512_DIGESTSIZE];
+
+ SHA512Init(&ctxt);
+ s = cstr_new();
+ BigIntegerToCstr(srp->modulus, s);
+ SHA512Update(&ctxt, s->data, s->length);
+ if(srp->flags & SRP_FLAG_LEFT_PAD)
+ BigIntegerToCstrEx(srp->generator, s, s->length);
+ else
+ BigIntegerToCstr(srp->generator, s);
+ SHA512Update(&ctxt, s->data, s->length);
+ SHA512Final(dig, &ctxt);
+ cstr_free(s);
+
+ k = BigIntegerFromBytes(dig, SHA512_DIGESTSIZE);
+ if(BigIntegerCmpInt(k, 0) == 0)
+ ret = SRP_ERROR;
+ else
+ ret = srp6_sha512_client_key_ex(srp, result, pubkey, pubkeylen, k);
+ BigIntegerClearFree(k);
+ return ret;
+}
+
+static SRP_RESULT
+srp6_sha512_client_verify(SRP * srp, const unsigned char * proof, int prooflen)
+{
+ unsigned char expected[SHA512_DIGESTSIZE];
+
+ SHA512Final(expected, &SHA512_CLIENT_CTXP(srp)->ckhash);
+ if(prooflen == SHA512_DIGESTSIZE && memcmp(expected, proof, prooflen) == 0)
+ return SRP_SUCCESS;
+ else
+ return SRP_ERROR;
+}
+
+static SRP_RESULT
+srp6_sha512_client_respond(SRP * srp, cstr ** proof)
+{
+ if(proof == NULL)
+ return SRP_ERROR;
+
+ if(*proof == NULL)
+ *proof = cstr_new();
+
+ /* proof contains client's response */
+ cstr_set_length(*proof, SHA512_DIGESTSIZE);
+ SHA512Final((unsigned char*)(*proof)->data, &SHA512_CLIENT_CTXP(srp)->hash);
+
+ /* ckhash: A | M | K */
+ SHA512Update(&SHA512_CLIENT_CTXP(srp)->ckhash, (*proof)->data, (*proof)->length);
+ SHA512Update(&SHA512_CLIENT_CTXP(srp)->ckhash, SHA512_CLIENT_CTXP(srp)->k, SRP6_SHA512_KEY_LEN);
+ return SRP_SUCCESS;
+}
+
+static SRP_METHOD srp6a_sha512_client_meth = {
+ "SRP-6a sha512 client (tjw)",
+ srp6a_sha512_client_init,
+ srp6_sha512_client_finish,
+ srp6_sha512_client_params,
+ srp6_sha512_client_auth,
+ srp6_sha512_client_passwd,
+ srp6_sha512_client_genpub,
+ srp6a_sha512_client_key,
+ srp6_sha512_client_verify,
+ srp6_sha512_client_respond,
+ NULL
+};
+
+_TYPE( SRP_METHOD * )
+SRP6a_sha512_client_method()
+{
+ return &srp6a_sha512_client_meth;
+}
diff --git a/3rd_party/libsrp6a-sha512/srp_aux.h b/3rd_party/libsrp6a-sha512/srp_aux.h
new file mode 100644
index 0000000..5088f08
--- /dev/null
+++ b/3rd_party/libsrp6a-sha512/srp_aux.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 1997-2007 The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Redistributions in source or binary form must retain an intact copy
+ * of this copyright notice.
+ */
+
+#ifndef SRP_AUX_H
+#define SRP_AUX_H
+
+#include "cstr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* BigInteger abstraction API */
+
+#ifndef MATH_PRIV
+typedef void * BigInteger;
+typedef void * BigIntegerCtx;
+typedef void * BigIntegerModAccel;
+#endif
+
+/*
+ * Some functions return a BigIntegerResult.
+ * Use BigIntegerOK to test for success.
+ */
+#define BIG_INTEGER_SUCCESS 0
+#define BIG_INTEGER_ERROR -1
+#define BigIntegerOK(v) ((v) == BIG_INTEGER_SUCCESS)
+typedef int BigIntegerResult;
+
+_TYPE( BigInteger ) BigIntegerFromInt P((unsigned int number));
+_TYPE( BigInteger ) BigIntegerFromBytes P((const unsigned char * bytes,
+ int length));
+#define BigIntegerByteLen(X) ((BigIntegerBitLen(X)+7)/8)
+_TYPE( int ) BigIntegerToBytes P((BigInteger src,
+ unsigned char * dest, int destlen));
+_TYPE( BigIntegerResult ) BigIntegerToCstr P((BigInteger src, cstr * dest));
+_TYPE( BigIntegerResult ) BigIntegerToCstrEx P((BigInteger src, cstr * dest, int len));
+_TYPE( BigIntegerResult ) BigIntegerToHex P((BigInteger src,
+ char * dest, int destlen));
+_TYPE( BigIntegerResult ) BigIntegerToString P((BigInteger src,
+ char * dest, int destlen,
+ unsigned int radix));
+_TYPE( int ) BigIntegerBitLen P((BigInteger b));
+_TYPE( int ) BigIntegerCmp P((BigInteger c1, BigInteger c2));
+_TYPE( int ) BigIntegerCmpInt P((BigInteger c1, unsigned int c2));
+_TYPE( BigIntegerResult ) BigIntegerLShift P((BigInteger result, BigInteger x,
+ unsigned int bits));
+_TYPE( BigIntegerResult ) BigIntegerAdd P((BigInteger result,
+ BigInteger a1, BigInteger a2));
+_TYPE( BigIntegerResult ) BigIntegerAddInt P((BigInteger result,
+ BigInteger a1, unsigned int a2));
+_TYPE( BigIntegerResult ) BigIntegerSub P((BigInteger result,
+ BigInteger s1, BigInteger s2));
+_TYPE( BigIntegerResult ) BigIntegerSubInt P((BigInteger result,
+ BigInteger s1, unsigned int s2));
+/* For BigIntegerMul{,Int}: result != m1, m2 */
+_TYPE( BigIntegerResult ) BigIntegerMul P((BigInteger result, BigInteger m1,
+ BigInteger m2, BigIntegerCtx ctx));
+_TYPE( BigIntegerResult ) BigIntegerMulInt P((BigInteger result,
+ BigInteger m1, unsigned int m2,
+ BigIntegerCtx ctx));
+_TYPE( BigIntegerResult ) BigIntegerDivInt P((BigInteger result,
+ BigInteger d, unsigned int m,
+ BigIntegerCtx ctx));
+_TYPE( BigIntegerResult ) BigIntegerMod P((BigInteger result, BigInteger d,
+ BigInteger m, BigIntegerCtx ctx));
+_TYPE( unsigned int ) BigIntegerModInt P((BigInteger d, unsigned int m,
+ BigIntegerCtx ctx));
+_TYPE( BigIntegerResult ) BigIntegerModMul P((BigInteger result,
+ BigInteger m1, BigInteger m2,
+ BigInteger m, BigIntegerCtx ctx));
+_TYPE( BigIntegerResult ) BigIntegerModExp P((BigInteger result,
+ BigInteger base, BigInteger expt,
+ BigInteger modulus,
+ BigIntegerCtx ctx,
+ BigIntegerModAccel accel));
+_TYPE( int ) BigIntegerCheckPrime P((BigInteger n, BigIntegerCtx ctx));
+
+_TYPE( BigIntegerResult ) BigIntegerFree P((BigInteger b));
+_TYPE( BigIntegerResult ) BigIntegerClearFree P((BigInteger b));
+
+_TYPE( BigIntegerCtx ) BigIntegerCtxNew();
+_TYPE( BigIntegerResult ) BigIntegerCtxFree P((BigIntegerCtx ctx));
+
+_TYPE( BigIntegerModAccel ) BigIntegerModAccelNew P((BigInteger m,
+ BigIntegerCtx ctx));
+_TYPE( BigIntegerResult ) BigIntegerModAccelFree P((BigIntegerModAccel accel));
+
+_TYPE( BigIntegerResult ) BigIntegerInitialize();
+_TYPE( BigIntegerResult ) BigIntegerFinalize();
+
+_TYPE( BigIntegerResult ) BigIntegerUseEngine P((const char * engine));
+_TYPE( BigIntegerResult ) BigIntegerReleaseEngine();
+
+/* Miscellaneous functions - formerly in t_pwd.h */
+
+/*
+ * "t_random" is a cryptographic random number generator, which is seeded
+ * from various high-entropy sources and uses a one-way hash function
+ * in a feedback configuration.
+ * "t_sessionkey" is the interleaved hash used to generate session keys
+ * from a large integer.
+ * "t_mgf1" is an implementation of MGF1 using SHA1 to generate session
+ * keys from large integers, and is preferred over the older
+ * interleaved hash, and is used with SRP6.
+ * "t_getpass" reads a password from the terminal without echoing.
+ */
+_TYPE( void ) t_random P((unsigned char *, unsigned));
+_TYPE( void ) t_stronginitrand();
+_TYPE( unsigned char * )
+ t_sessionkey P((unsigned char *, unsigned char *, unsigned));
+_TYPE( void ) t_mgf1 P((unsigned char *, unsigned,
+ const unsigned char *, unsigned));
+_TYPE( int ) t_getpass P((char *, unsigned, const char *));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SRP_AUX_H */
diff --git a/3rd_party/libsrp6a-sha512/t_conv.c b/3rd_party/libsrp6a-sha512/t_conv.c
new file mode 100644
index 0000000..76d4e58
--- /dev/null
+++ b/3rd_party/libsrp6a-sha512/t_conv.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 1997-2007 The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Redistributions in source or binary form must retain an intact copy
+ * of this copyright notice.
+ */
+
+/*#define _POSIX_SOURCE*/
+#include <stdio.h>
+#include "t_defines.h"
+#include "cstr.h"
+
+static int
+hexDigitToInt(char c)
+{
+ if(c >= '0' && c <= '9')
+ return c - '0';
+ else if(c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ else if(c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ else
+ return 0;
+}
+
+/*
+ * Convert a hex string to a string of bytes; return size of dst
+ */
+_TYPE( int )
+t_fromhex(char *dst, const char *src)
+{
+ register char *chp = dst;
+ register unsigned size = strlen(src);
+
+ /* FIXME: handle whitespace and non-hex digits by setting size and src
+ appropriately. */
+
+ if(size % 2 == 1) {
+ *chp++ = hexDigitToInt(*src++);
+ --size;
+ }
+ while(size > 0) {
+ *chp++ = (hexDigitToInt(*src) << 4) | hexDigitToInt(*(src + 1));
+ src += 2;
+ size -= 2;
+ }
+ return chp - dst;
+}
+
+/*
+ * Convert a string of bytes to their hex representation
+ */
+_TYPE( char * )
+t_tohex(char *dst, const char *src, unsigned size)
+{
+ int notleading = 0;
+
+ register char *chp = dst;
+ *dst = '\0';
+ if (size != 0) do {
+ if(notleading || *src != '\0') {
+ if(!notleading && (*src & 0xf0) == 0) {
+ sprintf(chp, "%.1X", * (unsigned char *) src);
+ chp += 1;
+ }
+ else {
+ sprintf(chp, "%.2X", * (unsigned char *) src);
+ chp += 2;
+ }
+ notleading = 1;
+ }
+ ++src;
+ } while (--size != 0);
+ return dst;
+}
+
+_TYPE( char * )
+t_tohexcstr(cstr *dst, const char *src, unsigned size)
+{
+ cstr_set_length(dst, 2 * size + 1);
+ return t_tohex(dst->data, src, size);
+}
+
+static char b64table[] =
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./";
+
+/*
+ * Convert a base64 string into raw byte array representation.
+ */
+_TYPE( int )
+t_fromb64(char *dst, const char *src)
+{
+ unsigned char *a;
+ char *loc;
+ int i, j;
+ unsigned int size;
+
+ while(*src && (*src == ' ' || *src == '\t' || *src == '\n'))
+ ++src;
+ size = strlen(src);
+
+ a = malloc((size + 1) * sizeof(unsigned char));
+ if(a == (unsigned char *) 0)
+ return -1;
+
+ i = 0;
+ while(i < size) {
+ loc = strchr(b64table, src[i]);
+ if(loc == (char *) 0)
+ break;
+ else
+ a[i] = loc - b64table;
+ ++i;
+ }
+ size = i;
+
+ i = size - 1;
+ j = size;
+ while(1) {
+ a[j] = a[i];
+ if(--i < 0)
+ break;
+ a[j] |= (a[i] & 3) << 6;
+ --j;
+ a[j] = (unsigned char) ((a[i] & 0x3c) >> 2);
+ if(--i < 0)
+ break;
+ a[j] |= (a[i] & 0xf) << 4;
+ --j;
+ a[j] = (unsigned char) ((a[i] & 0x30) >> 4);
+ if(--i < 0)
+ break;
+ a[j] |= (a[i] << 2);
+
+ a[--j] = 0;
+ if(--i < 0)
+ break;
+ }
+
+ while(a[j] == 0 && j <= size)
+ ++j;
+
+ memcpy(dst, a + j, size - j + 1);
+ free(a);
+ return size - j + 1;
+}
+
+_TYPE( int )
+t_cstrfromb64(cstr *dst, const char *src)
+{
+ int len;
+ cstr_set_length(dst, (strlen(src) * 6 + 7) / 8);
+ len = t_fromb64(dst->data, src);
+ cstr_set_length(dst, len);
+ return len;
+}
+
+/*
+ * Convert a raw byte string into a null-terminated base64 ASCII string.
+ */
+_TYPE( char * )
+t_tob64(char *dst, const char *src, unsigned size)
+{
+ int c, pos = size % 3;
+ unsigned char b0 = 0, b1 = 0, b2 = 0, notleading = 0;
+ char *olddst = dst;
+
+ switch(pos) {
+ case 1:
+ b2 = src[0];
+ break;
+ case 2:
+ b1 = src[0];
+ b2 = src[1];
+ break;
+ }
+
+ while(1) {
+ c = (b0 & 0xfc) >> 2;
+ if(notleading || c != 0) {
+ *dst++ = b64table[c];
+ notleading = 1;
+ }
+ c = ((b0 & 3) << 4) | ((b1 & 0xf0) >> 4);
+ if(notleading || c != 0) {
+ *dst++ = b64table[c];
+ notleading = 1;
+ }
+ c = ((b1 & 0xf) << 2) | ((b2 & 0xc0) >> 6);
+ if(notleading || c != 0) {
+ *dst++ = b64table[c];
+ notleading = 1;
+ }
+ c = b2 & 0x3f;
+ if(notleading || c != 0) {
+ *dst++ = b64table[c];
+ notleading = 1;
+ }
+ if(pos >= size)
+ break;
+ else {
+ b0 = src[pos++];
+ b1 = src[pos++];
+ b2 = src[pos++];
+ }
+ }
+
+ *dst++ = '\0';
+ return olddst;
+}
+
+_TYPE( char * )
+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
new file mode 100644
index 0000000..447263f
--- /dev/null
+++ b/3rd_party/libsrp6a-sha512/t_defines.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 1997-2007 The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Redistributions in source or binary form must retain an intact copy
+ * of this copyright notice.
+ */
+
+#ifndef T_DEFINES_H
+#define T_DEFINES_H
+
+#ifndef P
+#if defined(__STDC__) || defined(__cplusplus)
+#define P(x) x
+#else
+#define P(x) ()
+#endif
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifndef _DLLDECL
+#define _DLLDECL
+
+#ifdef MSVC15 /* MSVC1.5 support for 16 bit apps */
+#define _MSVC15EXPORT _export
+#define _MSVC20EXPORT
+#define _DLLAPI _export _pascal
+#define _CDECL
+#define _TYPE(a) a _MSVC15EXPORT
+#define DLLEXPORT 1
+
+#elif defined(MSVC20) || (defined(_USRDLL) && defined(SRP_EXPORTS))
+#define _MSVC15EXPORT
+#define _MSVC20EXPORT _declspec(dllexport)
+#define _DLLAPI
+#define _CDECL
+#define _TYPE(a) _MSVC20EXPORT a
+#define DLLEXPORT 1
+
+#else /* Default, non-dll. Use this for Unix or DOS */
+#define _MSVC15DEXPORT
+#define _MSVC20EXPORT
+#define _DLLAPI
+#if defined(WINDOWS) || defined(WIN32)
+#define _CDECL _cdecl
+#else
+#define _CDECL
+#endif
+#define _TYPE(a) a _CDECL
+#endif
+#endif
+
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <string.h>
+#else /* not STDC_HEADERS */
+#ifndef HAVE_STRCHR
+#define strchr index
+#define strrchr rindex
+#endif
+char *strchr(), *strrchr(), *strtok();
+#ifndef HAVE_MEMCPY
+#define memcpy(d, s, n) bcopy((s), (d), (n))
+#endif
+#endif /* not STDC_HEADERS */
+
+#include <sys/types.h>
+
+#if TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else /* not TIME_WITH_SYS_TIME */
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif /* not TIME_WITH_SYS_TIME */
+
+#if HAVE_TERMIOS_H
+#include <termios.h>
+#define STTY(fd, termio) tcsetattr(fd, TCSANOW, termio)
+#define GTTY(fd, termio) tcgetattr(fd, termio)
+#define TERMIO struct termios
+#define USE_TERMIOS
+#elif HAVE_TERMIO_H
+#include <sys/ioctl.h>
+#include <termio.h>
+#define STTY(fd, termio) ioctl(fd, TCSETA, termio)
+#define GTTY(fd, termio) ioctl(fd, TCGETA, termio)
+#define TEMRIO struct termio
+#define USE_TERMIO
+#elif HAVE_SGTTY_H
+#include <sgtty.h>
+#define STTY(fd, termio) stty(fd, termio)
+#define GTTY(fd, termio) gtty(fd, termio)
+#define TERMIO struct sgttyb
+#define USE_SGTTY
+#endif
+
+#ifdef WIN32
+#define USE_FTIME 1
+#define USE_RENAME 1
+#define NO_FCHMOD 1
+#endif
+
+#ifdef USE_FTIME
+#include <sys/timeb.h>
+#endif
+
+/* Looking for BigInteger math functions? They've moved to <srp_aux.h>. */
+
+#endif
diff --git a/3rd_party/libsrp6a-sha512/t_math.c b/3rd_party/libsrp6a-sha512/t_math.c
new file mode 100644
index 0000000..037650e
--- /dev/null
+++ b/3rd_party/libsrp6a-sha512/t_math.c
@@ -0,0 +1,964 @@
+/*
+ * Copyright (c) 1997-2007 The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Redistributions in source or binary form must retain an intact copy
+ * of this copyright notice.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "config.h"
+
+#ifdef OPENSSL
+# include "openssl/opensslv.h"
+# include "openssl/bn.h"
+typedef BIGNUM * BigInteger;
+typedef BN_CTX * BigIntegerCtx;
+typedef BN_MONT_CTX * BigIntegerModAccel;
+#include <limits.h>
+#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;
+#elif defined(CRYPTOLIB)
+# include "libcrypt.h"
+typedef BigInt BigInteger;
+typedef void * BigIntegerCtx;
+typedef void * BigIntegerModAccel;
+#elif defined(GNU_MP)
+# include "gmp.h"
+typedef MP_INT * BigInteger;
+typedef void * BigIntegerCtx;
+typedef void * BigIntegerModAccel;
+# if __GNU_MP_VERSION >= 4 || (__GNU_MP_VERSION == 4 && __GNU_MP_VERSION_MINOR >= 1)
+/* GMP 4.1 and up has fast import/export routines for integer conversion */
+# define GMP_IMPEXP 1
+# endif
+#elif defined(TOMMATH)
+# ifdef TOMCRYPT
+ /* as of v0.96 */
+# include "ltc_tommath.h"
+# else
+# include "tommath.h"
+# endif
+typedef mp_int * BigInteger;
+typedef void * BigIntegerCtx;
+typedef void * BigIntegerModAccel;
+#elif defined(GCRYPT)
+# include "gcrypt.h"
+typedef gcry_mpi_t BigInteger;
+typedef void * BigIntegerCtx;
+typedef void * BigIntegerModAccel;
+#elif defined(MPI)
+# include "mpi.h"
+typedef mp_int * BigInteger;
+typedef void * BigIntegerCtx;
+typedef void * BigIntegerModAccel;
+#elif defined(MBEDTLS)
+#include <mbedtls/bignum.h>
+#include <mbedtls/error.h>
+typedef mbedtls_mpi* BigInteger;
+typedef void * BigIntegerCtx;
+typedef void * BigIntegerModAccel;
+#else
+# error "no math library specified"
+#endif
+#define MATH_PRIV
+
+#include "t_defines.h"
+#include "t_pwd.h"
+#include "srp_aux.h"
+
+/* Math library interface stubs */
+
+BigInteger
+BigIntegerFromInt(unsigned int n)
+{
+#ifdef OPENSSL
+ BIGNUM * a = BN_new();
+ if(a)
+ BN_set_word(a, n);
+ return a;
+#elif defined(CRYPTOLIB)
+ return bigInit(n);
+#elif defined(GNU_MP)
+ BigInteger rv = (BigInteger) malloc(sizeof(MP_INT));
+ if(rv)
+ mpz_init_set_ui(rv, n);
+ return rv;
+#elif defined(GCRYPT)
+ BigInteger rv = gcry_mpi_new(32);
+ gcry_mpi_set_ui(rv, n);
+ return rv;
+#elif defined(MPI) || defined(TOMMATH)
+ BigInteger rv = (BigInteger) malloc(sizeof(mp_int));
+ if(rv) {
+ mp_init(rv);
+ mp_set_int(rv, n);
+ }
+ return rv;
+#elif defined(MBEDTLS)
+ mbedtls_mpi* a = (mbedtls_mpi*)malloc(sizeof(mbedtls_mpi));
+ if (a) {
+ mbedtls_mpi_init(a);
+ mbedtls_mpi_lset(a, n);
+ }
+ return a;
+#endif
+}
+
+BigInteger
+BigIntegerFromBytes(const unsigned char *bytes, int length)
+{
+#ifdef OPENSSL
+ BIGNUM * a = BN_new();
+ BN_bin2bn(bytes, length, a);
+ return a;
+#elif defined(CRYPTOLIB)
+ BigInteger rv, t;
+ int i, n;
+
+ rv = bigInit(0);
+ if(rv == NULL)
+ return rv;
+ if(length % 4 == 0)
+ RSA_bufToBig(bytes, length, rv);
+ else { /* Wouldn't need this if cryptolib behaved better */
+ i = length & 0x3;
+ if(length > i)
+ RSA_bufToBig(bytes + i, length - i, rv);
+ for(n = 0; i > 0; --i)
+ n = (n << 8) | *bytes++;
+ t = bigInit(n);
+ bigLeftShift(t, (length & ~0x3) << 3, t);
+ bigAdd(rv, t, rv);
+ freeBignum(t);
+ }
+ return rv;
+#elif defined(GNU_MP)
+ BigInteger rv = (BigInteger) malloc(sizeof(MP_INT));
+
+# ifdef GMP_IMPEXP
+ if(rv) {
+ mpz_init(rv);
+ mpz_import(rv, length, 1, 1, 1, 0, bytes);
+ }
+# else
+ cstr * hexbuf = cstr_new();
+
+ if(hexbuf) {
+ if(rv)
+ mpz_init_set_str(rv, t_tohexcstr(hexbuf, bytes, length), 16);
+ cstr_clear_free(hexbuf);
+ }
+# endif /* GMP_IMPEXP */
+
+ return rv;
+#elif defined(GCRYPT)
+ BigInteger rv;
+ gcry_mpi_scan(&rv, GCRYMPI_FMT_USG, bytes, length, NULL);
+ return rv;
+#elif defined(MPI) || defined(TOMMATH)
+ BigInteger rv = (BigInteger) malloc(sizeof(mp_int));
+ if(rv) {
+ mp_init(rv);
+ mp_read_unsigned_bin(rv, (unsigned char *)bytes, length);
+ }
+ return rv;
+#elif defined(MBEDTLS)
+ mbedtls_mpi* a = (mbedtls_mpi*)malloc(sizeof(mbedtls_mpi));
+ if (a) {
+ mbedtls_mpi_init(a);
+ mbedtls_mpi_read_binary(a, bytes, length);
+ }
+ return a;
+#endif
+}
+
+int
+BigIntegerToBytes(BigInteger src, unsigned char *dest, int destlen)
+{
+#ifdef OPENSSL
+ return BN_bn2bin(src, dest);
+#elif defined(CRYPTOLIB)
+ int i, j;
+ cstr * rawbuf;
+
+ trim(src);
+ i = bigBytes(src);
+ j = (bigBits(src) + 7) / 8;
+ if(i == j)
+ RSA_bigToBuf(src, i, dest);
+ else { /* Wouldn't need this if cryptolib behaved better */
+ rawbuf = cstr_new();
+ cstr_set_length(rawbuf, i);
+ RSA_bigToBuf(src, i, rawbuf->data);
+ memcpy(dest, rawbuf->data + (i-j), j);
+ cstr_clear_free(rawbuf);
+ }
+ return j;
+#elif defined(GNU_MP)
+ size_t r = 0;
+# ifdef GMP_IMPEXP
+ mpz_export(dest, &r, 1, 1, 1, 0, src);
+# else
+ cstr * hexbuf = cstr_new();
+
+ if(hexbuf) {
+ cstr_set_length(hexbuf, mpz_sizeinbase(src, 16) + 1);
+ mpz_get_str(hexbuf->data, 16, src);
+ r = t_fromhex(dest, hexbuf->data);
+ cstr_clear_free(hexbuf);
+ }
+# endif
+ return r;
+#elif defined(GCRYPT)
+ size_t r = 0;
+ gcry_mpi_print(GCRYMPI_FMT_USG, dest, destlen, &r, src);
+ return r;
+#elif defined(MPI) || defined(TOMMATH)
+ mp_to_unsigned_bin(src, dest);
+ return mp_unsigned_bin_size(src);
+#elif defined(MBEDTLS)
+ size_t r = mbedtls_mpi_size(src);
+ mbedtls_mpi_write_binary(src, dest, r);
+ return r;
+#endif
+}
+
+BigIntegerResult
+BigIntegerToCstr(BigInteger x, cstr * out)
+{
+ int n = BigIntegerByteLen(x);
+ if(cstr_set_length(out, n) < 0)
+ return BIG_INTEGER_ERROR;
+ if(cstr_set_length(out, BigIntegerToBytes(x, (unsigned char*)out->data, n)) < 0)
+ return BIG_INTEGER_ERROR;
+ return BIG_INTEGER_SUCCESS;
+}
+
+BigIntegerResult
+BigIntegerToCstrEx(BigInteger x, cstr * out, int len)
+{
+ int n;
+ if(cstr_set_length(out, len) < 0)
+ return BIG_INTEGER_ERROR;
+#if defined(MBEDTLS)
+ /* mbedtls will prefix the output with zeros if the buffer is larger */
+ mbedtls_mpi_write_binary(x, (unsigned char*)out->data, len);
+#else
+ n = BigIntegerToBytes(x, (unsigned char*)out->data, len);
+ if(n < len) {
+ memmove(out->data + (len - n), out->data, n);
+ memset(out->data, 0, len - n);
+ }
+#endif
+ return BIG_INTEGER_SUCCESS;
+}
+
+BigIntegerResult
+BigIntegerToHex(BigInteger src, char *dest, int destlen)
+{
+#ifdef OPENSSL
+ strncpy(dest, BN_bn2hex(src), destlen);
+#elif defined(CRYPTOLIB)
+ trim(src);
+ bigsprint(src, dest);
+#elif defined(GNU_MP)
+ mpz_get_str(dest, 16, src);
+#elif defined(GCRYPT)
+ gcry_mpi_print(GCRYMPI_FMT_HEX, dest, destlen, NULL, src);
+#elif defined(MPI) || defined(TOMMATH)
+ mp_toradix(src, dest, 16);
+#elif defined(MBEDTLS)
+ size_t olen = 0;
+ mbedtls_mpi_write_string(src, 16, dest, destlen, &olen);
+#endif
+ return BIG_INTEGER_SUCCESS;
+}
+
+static char b64table[] =
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./";
+
+BigIntegerResult
+BigIntegerToString(BigInteger src, char *dest, int destlen, unsigned int radix)
+{
+ BigInteger t = BigIntegerFromInt(0);
+ char * p = dest;
+ char c;
+
+ *p++ = b64table[BigIntegerModInt(src, radix, NULL)];
+ BigIntegerDivInt(t, src, radix, NULL);
+ while(BigIntegerCmpInt(t, 0) > 0) {
+ *p++ = b64table[BigIntegerModInt(t, radix, NULL)];
+ BigIntegerDivInt(t, t, radix, NULL);
+ }
+ BigIntegerFree(t);
+ *p-- = '\0';
+ /* reverse the string */
+ while(p > dest) {
+ c = *p;
+ *p-- = *dest;
+ *dest++ = c;
+ }
+ return BIG_INTEGER_SUCCESS;
+}
+
+int
+BigIntegerBitLen(BigInteger b)
+{
+#ifdef OPENSSL
+ return BN_num_bits(b);
+#elif defined(CRYPTOLIB)
+ return bigBits(b);
+#elif defined(GNU_MP)
+ return mpz_sizeinbase(b, 2);
+#elif defined(GCRYPT)
+ return gcry_mpi_get_nbits(b);
+#elif defined(MPI) || defined(TOMMATH)
+ return mp_count_bits(b);
+#elif defined(MBEDTLS)
+ return (int)mbedtls_mpi_bitlen(b);
+#endif
+}
+
+int
+BigIntegerCmp(BigInteger c1, BigInteger c2)
+{
+#ifdef OPENSSL
+ return BN_cmp(c1, c2);
+#elif defined(CRYPTOLIB)
+ return bigCompare(c1, c2);
+#elif defined(GNU_MP)
+ return mpz_cmp(c1, c2);
+#elif defined(GCRYPT)
+ return gcry_mpi_cmp(c1, c2);
+#elif defined(MPI) || defined(TOMMATH)
+ return mp_cmp(c1, c2);
+#elif defined(MBEDTLS)
+ return mbedtls_mpi_cmp_mpi(c1, c2);
+#endif
+}
+
+int
+BigIntegerCmpInt(BigInteger c1, unsigned int c2)
+{
+#ifdef OPENSSL
+ BigInteger bc2 = BigIntegerFromInt(c2);
+ int rv = BigIntegerCmp(c1, bc2);
+ BigIntegerFree(bc2);
+ return rv;
+#elif defined(CRYPTOLIB)
+ BigInteger t;
+ int rv;
+
+ t = bigInit(c2);
+ rv = bigCompare(c1, t);
+ freeBignum(t);
+ return rv;
+#elif defined(GNU_MP)
+ return mpz_cmp_ui(c1, c2);
+#elif defined(TOMMATH)
+ return mp_cmp_d(c1, c2);
+#elif defined(GCRYPT)
+ return gcry_mpi_cmp_ui(c1, c2);
+#elif defined(MPI)
+ return mp_cmp_int(c1, c2);
+#elif defined(MBEDTLS)
+ return mbedtls_mpi_cmp_int(c1, c2);
+#endif
+}
+
+BigIntegerResult
+BigIntegerLShift(BigInteger result, BigInteger x, unsigned int bits)
+{
+#ifdef OPENSSL
+ BN_lshift(result, x, bits);
+#elif defined(CRYPTOLIB)
+ bigLeftShift(x, bits, result);
+#elif defined(GNU_MP)
+ mpz_mul_2exp(result, x, bits);
+#elif defined(GCRYPT)
+ gcry_mpi_mul_2exp(result, x, bits);
+#elif defined(MPI) || defined(TOMMATH)
+ mp_mul_2d(x, bits, result);
+#elif defined(MBEDTLS)
+ mbedtls_mpi_copy(result, x);
+ mbedtls_mpi_shift_l(result, bits);
+#endif
+ return BIG_INTEGER_SUCCESS;
+}
+
+BigIntegerResult
+BigIntegerAdd(BigInteger result, BigInteger a1, BigInteger a2)
+{
+#ifdef OPENSSL
+ BN_add(result, a1, a2);
+#elif defined(CRYPTOLIB)
+ bigAdd(a1, a2, result);
+#elif defined(GNU_MP)
+ mpz_add(result, a1, a2);
+#elif defined(GCRYPT)
+ gcry_mpi_add(result, a1, a2);
+#elif defined(MPI) || defined(TOMMATH)
+ mp_add(a1, a2, result);
+#elif defined(MBEDTLS)
+ mbedtls_mpi_add_mpi(result, a1, a2);
+#endif
+ return BIG_INTEGER_SUCCESS;
+}
+
+BigIntegerResult
+BigIntegerAddInt(BigInteger result, BigInteger a1, unsigned int a2)
+{
+#ifdef OPENSSL
+ if(result != a1)
+ BN_copy(result, a1);
+ BN_add_word(result, a2);
+#elif defined(CRYPTOLIB)
+ BigInteger t;
+
+ t = bigInit(a2);
+ bigAdd(a1, t, result);
+ freeBignum(t);
+#elif defined(GNU_MP)
+ mpz_add_ui(result, a1, a2);
+#elif defined(GCRYPT)
+ gcry_mpi_add_ui(result, a1, a2);
+#elif defined(MPI) || defined(TOMMATH)
+ mp_add_d(a1, a2, result);
+#elif defined(MBEDTLS)
+ mbedtls_mpi_add_int(result, a1, a2);
+#endif
+ return BIG_INTEGER_SUCCESS;
+}
+
+BigIntegerResult
+BigIntegerSub(BigInteger result, BigInteger s1, BigInteger s2)
+{
+#ifdef OPENSSL
+ BN_sub(result, s1, s2);
+#elif defined(CRYPTOLIB)
+ bigSubtract(s1, s2, result);
+#elif defined(GNU_MP)
+ mpz_sub(result, s1, s2);
+#elif defined(GCRYPT)
+ gcry_mpi_sub(result, s1, s2);
+#elif defined(MPI) || defined(TOMMATH)
+ mp_sub(s1, s2, result);
+#elif defined(MBEDTLS)
+ mbedtls_mpi_sub_mpi(result, s1, s2);
+#endif
+ return BIG_INTEGER_SUCCESS;
+}
+
+BigIntegerResult
+BigIntegerSubInt(BigInteger result, BigInteger s1, unsigned int s2)
+{
+#ifdef OPENSSL
+ if(result != s1)
+ BN_copy(result, s1);
+ BN_sub_word(result, s2);
+#elif defined(CRYPTOLIB)
+ BigInteger t;
+
+ t = bigInit(s2);
+ bigSubtract(s1, t, result);
+ freeBignum(t);
+#elif defined(GNU_MP)
+ mpz_sub_ui(result, s1, s2);
+#elif defined(GCRYPT)
+ gcry_mpi_sub_ui(result, s1, s2);
+#elif defined(MPI) || defined(TOMMATH)
+ mp_sub_d(s1, s2, result);
+#elif defined(MBEDTLS)
+ mbedtls_mpi_sub_int(result, s1, s2);
+#endif
+ return BIG_INTEGER_SUCCESS;
+}
+
+BigIntegerResult
+BigIntegerMul(BigInteger result, BigInteger m1, BigInteger m2, BigIntegerCtx c)
+{
+#ifdef OPENSSL
+ BN_CTX * ctx = NULL;
+ if(c == NULL)
+ c = ctx = BN_CTX_new();
+ BN_mul(result, m1, m2, c);
+ if(ctx)
+ BN_CTX_free(ctx);
+#elif defined(CRYPTOLIB)
+ bigMultiply(m1, m2, result);
+#elif defined(GNU_MP)
+ mpz_mul(result, m1, m2);
+#elif defined(GCRYPT)
+ gcry_mpi_mul(result, m1, m2);
+#elif defined(MPI) || defined(TOMMATH)
+ mp_mul(m1, m2, result);
+#elif defined(MBEDTLS)
+ mbedtls_mpi_mul_mpi(result, m1, m2);
+#endif
+ return BIG_INTEGER_SUCCESS;
+}
+
+BigIntegerResult
+BigIntegerMulInt(BigInteger result, BigInteger m1, unsigned int m2, BigIntegerCtx c)
+{
+#ifdef OPENSSL
+ if(result != m1)
+ BN_copy(result, m1);
+ BN_mul_word(result, m2);
+#elif defined(CRYPTOLIB)
+ BigInteger t;
+
+ t = bigInit(m2);
+ bigMultiply(m1, t, result);
+ freeBignum(t);
+#elif defined(GNU_MP)
+ mpz_mul_ui(result, m1, m2);
+#elif defined(GCRYPT)
+ gcry_mpi_mul_ui(result, m1, m2);
+#elif defined(MPI) || defined(TOMMATH)
+ mp_mul_d(m1, m2, result);
+#elif defined(MBEDTLS)
+ mbedtls_mpi_mul_int(result, m1, m2);
+#endif
+ return BIG_INTEGER_SUCCESS;
+}
+
+BigIntegerResult
+BigIntegerDivInt(BigInteger result, BigInteger d, unsigned int m, BigIntegerCtx c)
+{
+#ifdef OPENSSL
+ if(result != d)
+ BN_copy(result, d);
+ BN_div_word(result, m);
+#elif defined(CRYPTOLIB)
+ BigInteger t, u, q;
+
+ t = bigInit(m);
+ u = bigInit(0);
+ /* We use a separate variable q because cryptolib breaks if result == d */
+ q = bigInit(0);
+ bigDivide(d, t, q, u);
+ freeBignum(t);
+ freeBignum(u);
+ bigCopy(q, result);
+ freeBignum(q);
+#elif defined(GNU_MP)
+# ifdef GMP2
+ mpz_fdiv_q_ui(result, d, m);
+# else
+ mpz_div_ui(result, d, m);
+# endif
+#elif defined(GCRYPT)
+ BigInteger t = BigIntegerFromInt(m);
+ gcry_mpi_div(result, NULL, d, t, -1);
+ BigIntegerFree(t);
+#elif defined(MPI) || defined(TOMMATH)
+ mp_div_d(d, m, result, NULL);
+#elif defined(MBEDTLS)
+ mbedtls_mpi_div_int(result, NULL, d, m);
+#endif
+ return BIG_INTEGER_SUCCESS;
+}
+
+BigIntegerResult
+BigIntegerMod(BigInteger result, BigInteger d, BigInteger m, BigIntegerCtx c)
+{
+#ifdef OPENSSL
+ BN_CTX * ctx = NULL;
+ if(c == NULL)
+ c = ctx = BN_CTX_new();
+ BN_mod(result, d, m, c);
+ if(ctx)
+ BN_CTX_free(ctx);
+#elif defined(CRYPTOLIB)
+ bigMod(d, m, result);
+#elif defined(GNU_MP)
+ mpz_mod(result, d, m);
+#elif defined(GCRYPT)
+ gcry_mpi_mod(result, d, m);
+#elif defined(MPI) || defined(TOMMATH)
+ mp_mod(d, m, result);
+#elif defined(MBEDTLS)
+ mbedtls_mpi_mod_mpi(result, d, m);
+#endif
+ return BIG_INTEGER_SUCCESS;
+}
+
+unsigned int
+BigIntegerModInt(BigInteger d, unsigned int m, BigIntegerCtx c)
+{
+#ifdef OPENSSL
+ return BN_mod_word(d, m);
+#elif defined(CRYPTOLIB)
+ BigInteger t, u;
+ unsigned char r[4];
+
+ t = bigInit(m);
+ u = bigInit(0);
+ bigMod(d, t, u);
+ bigToBuf(u, sizeof(r), r);
+ freeBignum(t);
+ freeBignum(u);
+ return r[0] | (r[1] << 8) | (r[2] << 16) | (r[3] << 24);
+#elif defined(GNU_MP)
+ MP_INT result;
+ unsigned int i;
+
+ mpz_init(&result);
+
+/* Define GMP2 if you're using an old gmp.h but want to link against a
+ * newer libgmp.a (e.g. 2.0 or later). */
+
+# ifdef GMP2
+ mpz_fdiv_r_ui(&result, d, m);
+# else
+ mpz_mod_ui(&result, d, m);
+# endif
+ i = mpz_get_ui(&result);
+ mpz_clear(&result);
+ return i;
+#elif defined(GCRYPT)
+ /* TODO: any way to clean this up??? */
+ unsigned char r[4];
+ size_t len, i;
+ unsigned int ret = 0;
+ BigInteger t = BigIntegerFromInt(m);
+ BigInteger a = BigIntegerFromInt(0);
+ gcry_mpi_mod(a, d, t);
+ gcry_mpi_print(GCRYMPI_FMT_USG, r, 4, &len, a);
+ for(i = 0; i < len; ++i)
+ ret = (ret << 8) | r[i];
+ BigIntegerFree(t);
+ BigIntegerFree(a);
+ return ret;
+#elif defined(MPI) || defined(TOMMATH)
+ mp_digit r;
+ mp_mod_d(d, m, &r);
+ return r;
+#elif defined(MBEDTLS)
+ mbedtls_mpi_uint r = 0;
+ mbedtls_mpi_mod_int(&r, d, m);
+ return r;
+#endif
+}
+
+BigIntegerResult
+BigIntegerModMul(BigInteger r, BigInteger m1, BigInteger m2, BigInteger modulus, BigIntegerCtx c)
+{
+#ifdef OPENSSL
+ BN_CTX * ctx = NULL;
+ if(c == NULL)
+ c = ctx = BN_CTX_new();
+ BN_mod_mul(r, m1, m2, modulus, c);
+ if(ctx)
+ BN_CTX_free(ctx);
+#elif defined(CRYPTOLIB)
+ bigMultiply(m1, m2, r);
+ bigMod(r, modulus, r);
+#elif defined(GNU_MP)
+ mpz_mul(r, m1, m2);
+ mpz_mod(r, r, modulus);
+#elif defined(GCRYPT)
+ gcry_mpi_mulm(r, m1, m2, modulus);
+#elif defined(MPI) || defined(TOMMATH)
+ mp_mulmod(m1, m2, modulus, r);
+#elif defined(MBEDTLS)
+ mbedtls_mpi d;
+ mbedtls_mpi_init(&d);
+ mbedtls_mpi_mul_mpi(&d, m1, m2);
+ mbedtls_mpi_mod_mpi(r, &d, modulus);
+ mbedtls_mpi_free(&d);
+#endif
+ return BIG_INTEGER_SUCCESS;
+}
+
+BigIntegerResult
+BigIntegerModExp(BigInteger r, BigInteger b, BigInteger e, BigInteger m, BigIntegerCtx c, BigIntegerModAccel a)
+{
+#ifdef OPENSSL
+#if OPENSSL_VERSION_NUMBER >= 0x00906000
+ BN_ULONG B = BN_get_word(b);
+#endif
+ BN_CTX * ctx = NULL;
+ if(c == NULL)
+ c = ctx = BN_CTX_new();
+ if(default_modexp) {
+ (*default_modexp)(r, b, e, m, c, a);
+ }
+ else if(a == NULL) {
+ BN_mod_exp(r, b, e, m, c);
+ }
+#if OPENSSL_VERSION_NUMBER >= 0x00906000
+ 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);
+ }
+#endif
+ else
+ BN_mod_exp_mont(r, b, e, m, c, a);
+ if(ctx)
+ BN_CTX_free(ctx);
+#elif defined(CRYPTOLIB)
+ bigPow(b, e, m, r);
+#elif defined(GNU_MP)
+ mpz_powm(r, b, e, m);
+#elif defined(GCRYPT)
+ gcry_mpi_powm(r, b, e, m);
+#elif defined(MPI) || defined(TOMMATH)
+ mp_exptmod(b, e, m, r);
+#elif defined(MBEDTLS)
+ mbedtls_mpi_exp_mod(r, b, e, m, NULL);
+#endif
+ return BIG_INTEGER_SUCCESS;
+}
+
+#if defined(MBEDTLS)
+int _mbedtls_f_rng(void* unused, unsigned char *buf, size_t size)
+{
+ t_random(buf, size);
+ return 0;
+}
+#endif
+
+int
+BigIntegerCheckPrime(BigInteger n, BigIntegerCtx c)
+{
+#ifdef OPENSSL
+ int rv;
+ BN_CTX * ctx = NULL;
+ if(c == NULL)
+ c = ctx = BN_CTX_new();
+#if OPENSSL_VERSION_NUMBER >= 0x00908000
+ #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
+ if(ctx)
+ BN_CTX_free(ctx);
+ return rv;
+#elif defined(CRYPTOLIB)
+#if 0
+ /*
+ * Ugh. Not only is cryptolib's bigDivide sensitive to inputs
+ * and outputs being the same, but now the primeTest needs random
+ * numbers, which it gets by calling cryptolib's broken truerand
+ * implementation(!) We have to fake it out by doing our own
+ * seeding explicitly.
+ */
+ static int seeded = 0;
+ static unsigned char seedbuf[64];
+ if(!seeded) {
+ t_random(seedbuf, sizeof(seedbuf));
+ seedDesRandom(seedbuf, sizeof(seedbuf));
+ memset(seedbuf, 0, sizeof(seedbuf));
+ seeded = 1;
+ }
+#endif /* 0 */
+ t_random(NULL, 0);
+ return primeTest(n);
+#elif defined(GNU_MP)
+ return mpz_probab_prime_p(n, 25);
+#elif defined(GCRYPT)
+ return (gcry_prime_check(n, 0) == GPG_ERR_NO_ERROR);
+#elif defined(TOMMATH)
+ int rv;
+ mp_prime_is_prime(n, 25, &rv);
+ return rv;
+#elif defined(MPI)
+ return (mpp_pprime(n, 25) == MP_YES);
+#elif defined(MBEDTLS)
+ return mbedtls_mpi_is_prime_ext(n, 25, _mbedtls_f_rng, NULL);
+#endif
+}
+
+BigIntegerResult
+BigIntegerFree(BigInteger b)
+{
+#ifdef OPENSSL
+ BN_free(b);
+#elif defined(CRYPTOLIB)
+ freeBignum(b);
+#elif defined(GNU_MP)
+ mpz_clear(b);
+ free(b);
+#elif defined(GCRYPT)
+ gcry_mpi_release(b);
+#elif defined(MPI) || defined(TOMMATH)
+ mp_clear(b);
+ free(b);
+#elif defined(MBEDTLS)
+ mbedtls_mpi_free(b);
+ free(b);
+#endif
+ return BIG_INTEGER_SUCCESS;
+}
+
+BigIntegerResult
+BigIntegerClearFree(BigInteger b)
+{
+#ifdef OPENSSL
+ BN_clear_free(b);
+#elif defined(CRYPTOLIB)
+ /* TODO */
+ freeBignum(b);
+#elif defined(GNU_MP)
+ /* TODO */
+ mpz_clear(b);
+ free(b);
+#elif defined(GCRYPT)
+ /* TODO */
+ gcry_mpi_release(b);
+#elif defined(MPI) || defined(TOMMATH)
+ /* TODO */
+ mp_clear(b);
+ free(b);
+#elif defined(MBEDTLS)
+ mbedtls_mpi_free(b);
+ free(b);
+#endif
+ return BIG_INTEGER_SUCCESS;
+}
+
+BigIntegerCtx
+BigIntegerCtxNew()
+{
+#ifdef OPENSSL
+ return BN_CTX_new();
+#else
+ return NULL;
+#endif
+}
+
+BigIntegerResult
+BigIntegerCtxFree(BigIntegerCtx ctx)
+{
+#ifdef OPENSSL
+ if(ctx)
+ BN_CTX_free(ctx);
+#endif
+ return BIG_INTEGER_SUCCESS;
+}
+
+BigIntegerModAccel
+BigIntegerModAccelNew(BigInteger m, BigIntegerCtx c)
+{
+#ifdef OPENSSL
+ BN_CTX * ctx = NULL;
+ BN_MONT_CTX * mctx;
+ if(default_modexp)
+ return NULL;
+ if(c == NULL)
+ c = ctx = BN_CTX_new();
+ mctx = BN_MONT_CTX_new();
+ BN_MONT_CTX_set(mctx, m, c);
+ if(ctx)
+ BN_CTX_free(ctx);
+ return mctx;
+#else
+ return NULL;
+#endif
+}
+
+BigIntegerResult
+BigIntegerModAccelFree(BigIntegerModAccel accel)
+{
+#ifdef OPENSSL
+ if(accel)
+ BN_MONT_CTX_free(accel);
+#endif
+ return BIG_INTEGER_SUCCESS;
+}
+
+BigIntegerResult
+BigIntegerInitialize()
+{
+#if OPENSSL_VERSION_NUMBER >= 0x00907000 && defined(OPENSSL_ENGINE)
+ ENGINE_load_builtin_engines();
+#endif
+ return BIG_INTEGER_SUCCESS;
+}
+
+BigIntegerResult
+BigIntegerFinalize()
+{
+ return BigIntegerReleaseEngine();
+}
+
+BigIntegerResult
+BigIntegerUseEngine(const char * engine)
+{
+#if defined(OPENSSL) && defined(OPENSSL_ENGINE)
+ ENGINE * e = ENGINE_by_id(engine);
+ if(e) {
+ if(ENGINE_init(e) > 0) {
+#if OPENSSL_VERSION_NUMBER >= 0x00907000
+ /* 0.9.7 loses the BN_mod_exp method. Pity. */
+ const RSA_METHOD * rsa = ENGINE_get_RSA(e);
+ if(rsa)
+#if (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x3000000fL) || (!defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100005L)
+ default_modexp = (modexp_meth)RSA_meth_get_bn_mod_exp(rsa);
+#else
+ default_modexp = (modexp_meth)rsa->bn_mod_exp;
+#endif
+#else
+ default_modexp = (modexp_meth)ENGINE_get_BN_mod_exp(e);
+#endif
+ BigIntegerReleaseEngine();
+ default_engine = e;
+ return BIG_INTEGER_SUCCESS;
+ }
+ else
+ ENGINE_free(e);
+ }
+#endif
+ return BIG_INTEGER_ERROR;
+}
+
+BigIntegerResult
+BigIntegerReleaseEngine()
+{
+#if defined(OPENSSL) && defined(OPENSSL_ENGINE)
+ if(default_engine) {
+ ENGINE_finish(default_engine);
+ ENGINE_free(default_engine);
+ default_engine = NULL;
+ default_modexp = NULL;
+ }
+#endif
+ return BIG_INTEGER_SUCCESS;
+}
diff --git a/3rd_party/libsrp6a-sha512/t_misc.c b/3rd_party/libsrp6a-sha512/t_misc.c
new file mode 100644
index 0000000..3a2cda1
--- /dev/null
+++ b/3rd_party/libsrp6a-sha512/t_misc.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 1997-2007 The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Redistributions in source or binary form must retain an intact copy
+ * of this copyright notice.
+ */
+
+#include "t_defines.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifdef WIN32
+#include <process.h>
+#include <io.h>
+#endif
+
+#include "t_sha.h"
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifdef OPENSSL
+#include <openssl/opensslv.h>
+#include <openssl/rand.h>
+#elif defined(TOMCRYPT)
+#include "tomcrypt.h"
+static prng_state g_rng;
+static unsigned char entropy[32];
+#elif defined(CRYPTOLIB)
+# include "libcrypt.h"
+static unsigned char crpool[64];
+#else
+static unsigned char randpool[SHA_DIGESTSIZE], randout[SHA_DIGESTSIZE];
+static unsigned long randcnt = 0;
+static unsigned int outpos = 0;
+SHA1_CTX randctxt;
+#endif /* OPENSSL */
+
+/*
+ * t_envhash - Generate a 160-bit SHA hash of the environment
+ *
+ * This routine performs an SHA hash of all the "name=value" pairs
+ * in the environment concatenated together and dumps them in the
+ * output. While it is true that anyone on the system can see
+ * your environment, someone not on the system will have a very
+ * difficult time guessing it, especially since some systems play
+ * tricks with variable ordering and sometimes define quirky
+ * environment variables like $WINDOWID or $_.
+ */
+extern char ** environ;
+
+static void
+t_envhash(unsigned char * out)
+{
+ char ** ptr;
+ char ebuf[256];
+ SHA1_CTX ctxt;
+
+ SHA1Init(&ctxt);
+ for(ptr = environ; *ptr; ++ptr) {
+ strncpy(ebuf, *ptr, 255);
+ ebuf[255] = '\0';
+ SHA1Update(&ctxt, ebuf, strlen(ebuf));
+ }
+ SHA1Final(out, &ctxt);
+}
+
+/*
+ * t_fshash - Generate a 160-bit SHA hash from the file system
+ *
+ * This routine climbs up the directory tree from the current
+ * directory, running stat() on each directory until it hits the
+ * root directory. This information is sensitive to the last
+ * access/modification times of all the directories above you,
+ * so someone who lists one of those directories injects some
+ * entropy into the system. Obviously, this hash is very sensitive
+ * to your current directory when the program is run.
+ *
+ * For good measure, it also performs an fstat on the standard input,
+ * usually your tty, throws that into the buffer, creates a file in
+ * /tmp (the inode is unpredictable on a busy system), and runs stat()
+ * on that before deleting it.
+ *
+ * The entire buffer is run once through SHA to obtain the final result.
+ */
+static void
+t_fshash(unsigned char * out)
+{
+ char dotpath[128];
+ struct stat st;
+ SHA1_CTX ctxt;
+ int i, pinode;
+ dev_t pdev;
+
+ SHA1Init(&ctxt);
+ if(stat(".", &st) >= 0) {
+ SHA1Update(&ctxt, (unsigned char *) &st, sizeof(st));
+ pinode = st.st_ino;
+ pdev = st.st_dev;
+ strcpy(dotpath, "..");
+ for(i = 0; i < 40; ++i) {
+ if(stat(dotpath, &st) < 0)
+ break;
+ if(st.st_ino == pinode && st.st_dev == pdev)
+ break;
+ SHA1Update(&ctxt, (unsigned char *) &st, sizeof(st));
+ pinode = st.st_ino;
+ pdev = st.st_dev;
+ strcat(dotpath, "/..");
+ }
+ }
+
+ if(fstat(0, &st) >= 0)
+ SHA1Update(&ctxt, (unsigned char *) &st, sizeof(st));
+
+ sprintf(dotpath, "/tmp/rnd.%d", getpid());
+ if(creat(dotpath, 0600) >= 0 && stat(dotpath, &st) >= 0)
+ SHA1Update(&ctxt, (unsigned char *) &st, sizeof(st));
+ unlink(dotpath);
+
+ SHA1Final(out, &ctxt);
+}
+
+/*
+ * Generate a high-entropy seed for the strong random number generator.
+ * This uses a wide variety of quickly gathered and somewhat unpredictable
+ * system information. The 'preseed' structure is assembled from:
+ *
+ * The system time in seconds
+ * The system time in microseconds
+ * The current process ID
+ * The parent process ID
+ * A hash of the user's environment
+ * A hash gathered from the file system
+ * Input from a random device, if available
+ * Timings of system interrupts
+ *
+ * The entire structure (60 bytes on most systems) is fed to SHA to produce
+ * a 160-bit seed for the strong random number generator. It is believed
+ * that in the worst case (on a quiet system with no random device versus
+ * an attacker who has access to the system already), the seed contains at
+ * least about 80 bits of entropy. Versus an attacker who does not have
+ * access to the system, the entropy should be slightly over 128 bits.
+ */
+static char initialized = 0;
+
+static struct {
+ unsigned int trand1;
+ time_t sec;
+ time_t subsec;
+ short pid;
+ short ppid;
+ unsigned char envh[SHA_DIGESTSIZE];
+ unsigned char fsh[SHA_DIGESTSIZE];
+ unsigned char devrand[20];
+ unsigned int trand2;
+} preseed;
+
+unsigned long raw_truerand();
+
+static void
+t_initrand()
+{
+ SHA1_CTX ctxt;
+#ifdef USE_FTIME
+ struct timeb t;
+#else
+ struct timeval t;
+#endif
+ int i, r=0;
+
+ if(initialized)
+ return;
+
+ initialized = 1;
+
+#if defined(OPENSSL) /* OpenSSL has nifty win32 entropy-gathering code */
+#if OPENSSL_VERSION_NUMBER >= 0x00905100
+ r = RAND_status();
+#if defined(WINDOWS) || defined(WIN32)
+ if(r) /* Don't do the Unix-y stuff on Windows if possible */
+ return;
+#else
+#endif
+#endif
+
+#elif defined(TOMCRYPT)
+ yarrow_start(&g_rng);
+ r = rng_get_bytes(entropy, sizeof(entropy), NULL);
+ if(r > 0) {
+ yarrow_add_entropy(entropy, r, &g_rng);
+ memset(entropy, 0, sizeof(entropy));
+# if defined(WINDOWS) || defined(WIN32)
+ /* Don't do the Unix-y stuff on Windows if possible */
+ yarrow_ready(&g_rng);
+ return;
+# endif
+ }
+#endif
+
+#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 */
+
+ /* Resort to truerand only if desperate for some Real entropy */
+ if(r == 0)
+ preseed.trand1 = raw_truerand();
+
+#ifdef USE_FTIME
+ ftime(&t);
+ preseed.sec = t.time;
+ preseed.subsec = t.millitm;
+#else
+ gettimeofday(&t, NULL);
+ preseed.sec = t.tv_sec;
+ preseed.subsec = t.tv_usec;
+#endif
+ preseed.pid = getpid();
+#ifndef WIN32
+ preseed.ppid = getppid();
+#endif
+ t_envhash(preseed.envh);
+ t_fshash(preseed.fsh);
+
+ if(r == 0)
+ preseed.trand2 = raw_truerand();
+
+#ifdef OPENSSL
+ RAND_seed((unsigned char *)&preseed, sizeof(preseed));
+#elif defined(TOMCRYPT)
+ yarrow_add_entropy((unsigned char *)&preseed, sizeof(preseed), &g_rng);
+ yarrow_ready(&g_rng);
+#elif defined(CRYPTOLIB)
+ t_mgf1(crpool, sizeof(crpool), (unsigned char *) &preseed, sizeof(preseed));
+ seedDesRandom(crpool, sizeof(crpool));
+ memset(crpool, 0, sizeof(crpool));
+#elif defined(GCRYPT)
+ gcry_random_add_bytes((unsigned char *)&preseed, sizeof(preseed), -1);
+#else
+ SHA1Init(&ctxt);
+ SHA1Update(&ctxt, (unsigned char *) &preseed, sizeof(preseed));
+ SHA1Final(randpool, &ctxt);
+ memset((unsigned char *) &ctxt, 0, sizeof(ctxt));
+ outpos = 0;
+#endif /* OPENSSL */
+ memset((unsigned char *) &preseed, 0, sizeof(preseed));
+}
+
+#define NUM_RANDOMS 12
+
+_TYPE( void )
+t_stronginitrand()
+{
+#if 1 /* t_initrand() has been improved enough to make this unnecessary */
+ t_initrand();
+#else
+ SHA1_CTX ctxt;
+ unsigned int rawrand[NUM_RANDOMS];
+ int i;
+
+ if(!initialized)
+ t_initrand();
+ for(i = 0; i < NUM_RANDOMS; ++i)
+ rawrand[i] = raw_truerand();
+ SHA1Init(&ctxt);
+ SHA1Update(&ctxt, (unsigned char *) rawrand, sizeof(rawrand));
+ SHA1Final(randkey2, &ctxt);
+ memset(rawrand, 0, sizeof(rawrand));
+#endif
+}
+
+/*
+ * The strong random number generator. This uses a 160-bit seed
+ * and uses SHA-1 in a feedback configuration to generate successive
+ * outputs. If S[0] is set to the initial seed, then:
+ *
+ * S[i+1] = SHA-1(i || S[i])
+ * A[i] = SHA-1(S[i])
+ *
+ * where the A[i] are the output blocks starting with i=0.
+ * Each cycle generates 20 bytes of new output.
+ */
+_TYPE( void )
+t_random(unsigned char * data, unsigned size)
+{
+ if(!initialized)
+ t_initrand();
+
+ if(size <= 0) /* t_random(NULL, 0) forces seed initialization */
+ return;
+
+#ifdef OPENSSL
+ RAND_bytes(data, size);
+#elif defined(TOMCRYPT)
+ yarrow_read(data, size, &g_rng);
+#elif defined(GCRYPT)
+ gcry_randomize(data, size, GCRY_STRONG_RANDOM);
+#elif defined(CRYPTOLIB)
+ randomBytes(data, size, PSEUDO);
+#else
+ while(size > outpos) {
+ if(outpos > 0) {
+ memcpy(data, randout + (sizeof(randout) - outpos), outpos);
+ data += outpos;
+ size -= outpos;
+ }
+
+ /* Recycle */
+ SHA1Init(&randctxt);
+ SHA1Update(&randctxt, randpool, sizeof(randpool));
+ SHA1Final(randout, &randctxt);
+ SHA1Init(&randctxt);
+ SHA1Update(&randctxt, (unsigned char *) &randcnt, sizeof(randcnt));
+ SHA1Update(&randctxt, randpool, sizeof(randpool));
+ SHA1Final(randpool, &randctxt);
+ ++randcnt;
+ outpos = sizeof(randout);
+ }
+
+ if(size > 0) {
+ memcpy(data, randout + (sizeof(randout) - outpos), size);
+ outpos -= size;
+ }
+#endif
+}
+
+/*
+ * The interleaved session-key hash. This separates the even and the odd
+ * bytes of the input (ignoring the first byte if the input length is odd),
+ * hashes them separately, and re-interleaves the two outputs to form a
+ * single 320-bit value.
+ */
+_TYPE( unsigned char * )
+t_sessionkey(unsigned char * key, unsigned char * sk, unsigned sklen)
+{
+ unsigned i, klen;
+ unsigned char * hbuf;
+ unsigned char hout[SHA_DIGESTSIZE];
+ SHA1_CTX ctxt;
+
+ while(sklen > 0 && *sk == 0) { /* Skip leading 0's */
+ --sklen;
+ ++sk;
+ }
+
+ klen = sklen / 2;
+ if((hbuf = malloc(klen * sizeof(char))) == 0)
+ return 0;
+
+ for(i = 0; i < klen; ++i)
+ hbuf[i] = sk[sklen - 2 * i - 1];
+ SHA1Init(&ctxt);
+ SHA1Update(&ctxt, hbuf, klen);
+ SHA1Final(hout, &ctxt);
+ for(i = 0; i < sizeof(hout); ++i)
+ key[2 * i] = hout[i];
+
+ for(i = 0; i < klen; ++i)
+ hbuf[i] = sk[sklen - 2 * i - 2];
+ SHA1Init(&ctxt);
+ SHA1Update(&ctxt, hbuf, klen);
+ SHA1Final(hout, &ctxt);
+ for(i = 0; i < sizeof(hout); ++i)
+ key[2 * i + 1] = hout[i];
+
+ memset(hout, 0, sizeof(hout));
+ memset(hbuf, 0, klen);
+ free(hbuf);
+ return key;
+}
+
+_TYPE( void )
+t_mgf1(unsigned char * mask, unsigned masklen, const unsigned char * seed, unsigned seedlen)
+{
+ SHA1_CTX ctxt;
+ unsigned i = 0;
+ unsigned pos = 0;
+ unsigned char cnt[4];
+ unsigned char hout[SHA_DIGESTSIZE];
+
+ while(pos < masklen) {
+ cnt[0] = (i >> 24) & 0xFF;
+ cnt[1] = (i >> 16) & 0xFF;
+ cnt[2] = (i >> 8) & 0xFF;
+ cnt[3] = i & 0xFF;
+ SHA1Init(&ctxt);
+ SHA1Update(&ctxt, seed, seedlen);
+ SHA1Update(&ctxt, cnt, 4);
+
+ if(pos + SHA_DIGESTSIZE > masklen) {
+ SHA1Final(hout, &ctxt);
+ memcpy(mask + pos, hout, masklen - pos);
+ pos = masklen;
+ }
+ else {
+ SHA1Final(mask + pos, &ctxt);
+ pos += SHA_DIGESTSIZE;
+ }
+
+ ++i;
+ }
+
+ memset(hout, 0, sizeof(hout));
+ memset((unsigned char *)&ctxt, 0, sizeof(ctxt));
+}
diff --git a/3rd_party/libsrp6a-sha512/t_pwd.h b/3rd_party/libsrp6a-sha512/t_pwd.h
new file mode 100644
index 0000000..a90a364
--- /dev/null
+++ b/3rd_party/libsrp6a-sha512/t_pwd.h
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 1997-2007 The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Redistributions in source or binary form must retain an intact copy
+ * of this copyright notice.
+ */
+
+#ifndef T_PWD_H
+#define T_PWD_H
+
+#include <stdio.h>
+#include "cstr.h"
+
+#define MAXPARAMBITS 2048
+#define MAXPARAMLEN ((MAXPARAMBITS + 7) / 8)
+#define MAXB64PARAMLEN ((MAXPARAMBITS + 5) / 6 + 1)
+#define MAXHEXPARAMLEN ((MAXPARAMBITS + 3) / 4 + 1)
+#define MAXOCTPARAMLEN ((MAXPARAMBITS + 2) / 3 + 1)
+
+#define MAXUSERLEN 32
+#define MAXSALTLEN 32
+#define MAXB64SALTLEN 44 /* 256 bits in b64 + null */
+#define SALTLEN 10 /* Normally 80 bits */
+
+#define RESPONSE_LEN 20 /* 160-bit proof hashes */
+#define SESSION_KEY_LEN (2 * RESPONSE_LEN) /* 320-bit session key */
+
+#define DEFAULT_PASSWD "/etc/tpasswd"
+#define DEFAULT_CONF "/etc/tpasswd.conf"
+
+struct t_num { /* Standard byte-oriented integer representation */
+ int len;
+ unsigned char * data;
+};
+
+struct t_preconf { /* Structure returned by t_getpreparam() */
+ char * mod_b64;
+ char * gen_b64;
+ char * comment;
+
+ struct t_num modulus;
+ struct t_num generator;
+};
+
+/*
+ * The built-in (known good) parameters access routines
+ *
+ * "t_getprecount" returns the number of precompiled parameter sets.
+ * "t_getpreparam" returns the indicated parameter set.
+ * Memory is statically allocated - callers need not perform any memory mgmt.
+ */
+_TYPE( int ) t_getprecount();
+_TYPE( struct t_preconf * ) t_getpreparam P((int));
+
+struct t_confent { /* One configuration file entry (index, N, g) */
+ int index;
+ struct t_num modulus;
+ struct t_num generator;
+};
+
+struct t_conf { /* An open configuration file */
+ FILE * instream;
+ char close_on_exit;
+ cstr * modbuf;
+ cstr * genbuf;
+ struct t_confent tcbuf;
+};
+
+/*
+ * The configuration file routines are designed along the lines of the
+ * "getpw" functions in the standard C library.
+ *
+ * "t_openconf" accepts a stdio stream and interprets it as a config file.
+ * "t_openconfbyname" accepts a filename and does the same thing.
+ * "t_closeconf" closes the config file.
+ * "t_getconfent" fetches the next sequential configuration entry.
+ * "t_getconfbyindex" fetches the configuration entry whose index
+ * matches the one supplied, or NULL if one can't be found.
+ * "t_getconflast" fetches the last configuration entry in the file.
+ * "t_makeconfent" generates a set of configuration entry parameters
+ * randomly.
+ * "t_newconfent" returns an empty configuration entry.
+ * "t_cmpconfent" compares two configuration entries a la strcmp.
+ * "t_checkconfent" verifies that a set of configuration parameters
+ * are suitable. N must be prime and should be a safe prime.
+ * "t_putconfent" writes a configuration entry to a stream.
+ */
+_TYPE( struct t_conf * ) t_openconf P((FILE *));
+_TYPE( struct t_conf * ) t_openconfbyname P((const char *));
+_TYPE( void ) t_closeconf P((struct t_conf *));
+_TYPE( void ) t_rewindconf P((struct t_conf *));
+_TYPE( struct t_confent * ) t_getconfent P((struct t_conf *));
+_TYPE( struct t_confent * ) t_getconfbyindex P((struct t_conf *, int));
+_TYPE( struct t_confent * ) t_getconflast P((struct t_conf *));
+_TYPE( struct t_confent * ) t_makeconfent P((struct t_conf *, int));
+_TYPE( struct t_confent * ) t_makeconfent_c P((struct t_conf *, int));
+_TYPE( struct t_confent * ) t_newconfent P((struct t_conf *));
+_TYPE( int ) t_cmpconfent P((const struct t_confent *, const struct t_confent *));
+_TYPE( int ) t_checkconfent P((const struct t_confent *));
+_TYPE( void ) t_putconfent P((const struct t_confent *, FILE *));
+
+/* libc-style system conf file access */
+_TYPE( struct t_confent *) gettcent();
+_TYPE( struct t_confent *) gettcid P((int));
+_TYPE( void ) settcent();
+_TYPE( void ) endtcent();
+
+#ifdef ENABLE_NSW
+extern struct t_confent * _gettcent();
+extern struct t_confent * _gettcid P((int));
+extern void _settcent();
+extern void _endtcent();
+#endif
+
+/* A hack to support '+'-style entries in the passwd file */
+
+typedef enum fstate {
+ FILE_ONLY, /* Ordinary file, don't consult NIS ever */
+ FILE_NIS, /* Currently accessing file, use NIS if encountered */
+ IN_NIS, /* Currently in a '+' entry; use NIS for getXXent */
+} FILE_STATE;
+
+struct t_pwent { /* A single password file entry */
+ char * name;
+ struct t_num password;
+ struct t_num salt;
+ int index;
+};
+
+struct t_pw { /* An open password file */
+ FILE * instream;
+ char close_on_exit;
+ FILE_STATE state;
+ char userbuf[MAXUSERLEN];
+ cstr * pwbuf;
+ unsigned char saltbuf[SALTLEN];
+ struct t_pwent pebuf;
+};
+
+/*
+ * The password manipulation routines are patterned after the getpw*
+ * standard C library function calls.
+ *
+ * "t_openpw" reads a stream as if it were a password file.
+ * "t_openpwbyname" opens the named file as a password file.
+ * "t_closepw" closes an open password file.
+ * "t_rewindpw" starts the internal file pointer from the beginning
+ * of the password file.
+ * "t_getpwent" retrieves the next sequential password entry.
+ * "t_getpwbyname" looks up the password entry corresponding to the
+ * specified user.
+ * "t_makepwent" constructs a password entry from a username, password,
+ * numeric salt, and configuration entry.
+ * "t_putpwent" writes a password entry to a stream.
+ */
+_TYPE( struct t_pw * ) t_newpw();
+_TYPE( struct t_pw * ) t_openpw P((FILE *));
+_TYPE( struct t_pw * ) t_openpwbyname P((const char *));
+_TYPE( void ) t_closepw P((struct t_pw *));
+_TYPE( void ) t_rewindpw P((struct t_pw *));
+_TYPE( struct t_pwent * ) t_getpwent P((struct t_pw *));
+_TYPE( struct t_pwent * ) t_getpwbyname P((struct t_pw *, const char *));
+_TYPE( struct t_pwent * ) t_makepwent P((struct t_pw *, const char *,
+ const char *, const struct t_num *,
+ const struct t_confent *));
+_TYPE( void ) t_putpwent P((const struct t_pwent *, FILE *));
+
+struct t_passwd {
+ struct t_pwent tp;
+ struct t_confent tc;
+};
+
+/* libc-style system password file access */
+_TYPE( struct t_passwd * ) gettpent();
+_TYPE( struct t_passwd * ) gettpnam P((const char *));
+_TYPE( void ) settpent();
+_TYPE( void ) endtpent();
+
+#ifdef ENABLE_NSW
+extern struct t_passwd * _gettpent();
+extern struct t_passwd * _gettpnam P((const char *));
+extern void _settpent();
+extern void _endtpent();
+#endif
+
+/*
+ * Utility functions
+ *
+ * "t_verifypw" accepts a username and password, and checks against the
+ * system password file to see if the password for that user is correct.
+ * Returns > 0 if it is correct, 0 if not, and -1 if some error occurred
+ * (i.e. the user doesn't exist on the system). This is intended ONLY
+ * for local authentication; for remote authentication, look at the
+ * t_client and t_server source. (That's the whole point of SRP!)
+ * "t_changepw" modifies the specified file, substituting the given password
+ * entry for the one already in the file. If no matching entry is found,
+ * the new entry is simply appended to the file.
+ * "t_deletepw" removes the specified user from the specified file.
+ */
+_TYPE( int ) t_verifypw P((const char *, const char *));
+_TYPE( int ) t_changepw P((const char *, const struct t_pwent *));
+_TYPE( int ) t_deletepw P((const char *, const char *));
+
+/* Conversion utilities */
+
+/*
+ * All these calls accept output as the first parameter. In the case of
+ * t_tohex and t_tob64, the last argument is the length of the byte-string
+ * input.
+ */
+_TYPE( char * ) t_tohex P((char *, const char *, unsigned));
+_TYPE( int ) t_fromhex P((char *, const char *));
+_TYPE( char * ) t_tob64 P((char *, const char *, unsigned));
+_TYPE( int ) t_fromb64 P((char *, const char *));
+
+/* These functions put their output in a cstr object */
+_TYPE( char * ) t_tohexcstr P((cstr *, const char *, unsigned));
+_TYPE( int ) t_cstrfromhex P((cstr *, const char *));
+_TYPE( char * ) t_tob64cstr P((cstr *, const char *, unsigned));
+_TYPE( int ) t_cstrfromb64 P((cstr *, const char *));
+
+/* Miscellaneous utilities (moved to t_defines.h) */
+
+#endif
diff --git a/3rd_party/libsrp6a-sha512/t_sha.c b/3rd_party/libsrp6a-sha512/t_sha.c
new file mode 100644
index 0000000..8e54cb6
--- /dev/null
+++ b/3rd_party/libsrp6a-sha512/t_sha.c
@@ -0,0 +1,314 @@
+#include "t_defines.h"
+#include "t_sha.h"
+
+#ifdef CRYPTOLIB_SHA
+
+/* A wrapper around CryptoLib's shsFinal that delivers output in octets */
+void
+shsFinalBytes(unsigned char digest[20], SHS_CTX* context)
+{
+ int i;
+ unsigned long r;
+ unsigned char *p = digest;
+
+ shsFinal(context);
+ for(i = 0; i < 5; ++i) {
+ r = context->h[i];
+ *p++ = (unsigned char)((r >> 24) & 0xff);
+ *p++ = (unsigned char)((r >> 16) & 0xff);
+ *p++ = (unsigned char)((r >> 8) & 0xff);
+ *p++ = (unsigned char)(r & 0xff);
+ }
+}
+
+#elif defined(GCRYPT_SHA)
+/* Wrappers for gcrypt's md interface */
+
+void
+SHA1Init_gcry(SHA1_CTX * ctx)
+{
+ gcry_md_open(ctx, GCRY_MD_SHA1, 0);
+}
+
+void
+SHA1Update_gcry(SHA1_CTX * ctx, const void *data, unsigned int len)
+{
+ gcry_md_write(*ctx, data, len);
+}
+
+void
+SHA1Final_gcry(unsigned char digest[20], SHA1_CTX * ctx)
+{
+ memcpy(digest, gcry_md_read(*ctx, GCRY_MD_SHA1), 20);
+ gcry_md_close(*ctx);
+}
+
+void
+SHA512Init_gcry(SHA512_CTX * ctx)
+{
+ gcry_md_open(ctx, GCRY_MD_SHA512, 0);
+}
+
+void
+SHA512Update_gcry(SHA512_CTX * ctx, const void *data, unsigned int len)
+{
+ gcry_md_write(*ctx, data, len);
+}
+
+void
+SHA512Final_gcry(unsigned char digest[64], SHA512_CTX * ctx)
+{
+ memcpy(digest, gcry_md_read(*ctx, GCRY_MD_SHA512), 64);
+ gcry_md_close(*ctx);
+}
+
+#elif defined(MBEDTLS_SHA)
+/* Wrappers for mbedtls's md interface */
+
+void
+SHA1Init_mbed(SHA1_CTX * ctx)
+{
+ mbedtls_md_init(ctx);
+ mbedtls_md_setup(ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), 0);
+ mbedtls_md_starts(ctx);
+}
+
+void
+SHA1Update_mbed(SHA1_CTX * ctx, const void *data, unsigned int len)
+{
+ mbedtls_md_update(ctx, data, len);
+}
+
+void
+SHA1Final_mbed(unsigned char digest[20], SHA1_CTX * ctx)
+{
+ mbedtls_md_finish(ctx, digest);
+ mbedtls_md_free(ctx);
+}
+
+void
+SHA512Init_mbed(SHA512_CTX * ctx)
+{
+ mbedtls_md_init(ctx);
+ mbedtls_md_setup(ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA512), 0);
+ mbedtls_md_starts(ctx);
+}
+
+void
+SHA512Update_mbed(SHA512_CTX * ctx, const void *data, unsigned int len)
+{
+ mbedtls_md_update(ctx, data, len);
+}
+
+void
+SHA512Final_mbed(unsigned char digest[64], SHA512_CTX * ctx)
+{
+ mbedtls_md_finish(ctx, digest);
+ 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 */
+
+/*
+SHA-1 in C
+By Steve Reid <steve@edmweb.com>
+100% Public Domain
+
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+ A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+ 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+/* #define LITTLE_ENDIAN * This should be #define'd if true. */
+/* #define SHA1HANDSOFF * Copies data before messing with it. */
+
+#include <stdio.h>
+#include <string.h>
+
+static void SHA1Transform(uint32 state[5], const unsigned char buffer[64]);
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+#ifndef WORDS_BIGENDIAN
+#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+ |(rol(block->l[i],8)&0x00FF00FF))
+#else
+#define blk0(i) block->l[i]
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+ ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+static void SHA1Transform(uint32 state[5], const unsigned char buffer[64])
+{
+uint32 a, b, c, d, e;
+typedef union {
+ unsigned char c[64];
+ uint32 l[16];
+} CHAR64LONG16;
+CHAR64LONG16* block;
+#ifdef SHA1HANDSOFF
+static unsigned char workspace[64];
+ block = (CHAR64LONG16*)workspace;
+ memcpy(block, buffer, 64);
+#else
+ block = (CHAR64LONG16*)buffer;
+#endif
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+}
+
+
+/* SHA1Init - Initialize new context */
+
+void SHA1Init(SHA1_CTX* context)
+{
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+
+void SHA1Update(SHA1_CTX* context, const unsigned char* data, unsigned int len)
+{
+unsigned int i, j;
+
+ j = (context->count[0] >> 3) & 63;
+ if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
+ context->count[1] += (len >> 29);
+ if ((j + len) > 63) {
+ memcpy(&context->buffer[j], data, (i = 64-j));
+ SHA1Transform(context->state, context->buffer);
+ for ( ; i + 63 < len; i += 64) {
+ SHA1Transform(context->state, &data[i]);
+ }
+ j = 0;
+ }
+ else i = 0;
+ memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
+{
+uint32 i, j;
+unsigned char finalcount[8];
+
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
+ }
+ SHA1Update(context, (unsigned char *)"\200", 1);
+ while ((context->count[0] & 504) != 448) {
+ SHA1Update(context, (unsigned char *)"\0", 1);
+ }
+ SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
+ for (i = 0; i < 20; i++) {
+ digest[i] = (unsigned char)
+ ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+ /* Wipe variables */
+ i = j = 0;
+ memset(context->buffer, 0, 64);
+ memset(context->state, 0, 20);
+ memset(context->count, 0, 8);
+ memset(&finalcount, 0, 8);
+#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */
+ SHA1Transform(context->state, context->buffer);
+#endif
+}
+#endif
diff --git a/3rd_party/libsrp6a-sha512/t_sha.h b/3rd_party/libsrp6a-sha512/t_sha.h
new file mode 100644
index 0000000..2e38067
--- /dev/null
+++ b/3rd_party/libsrp6a-sha512/t_sha.h
@@ -0,0 +1,147 @@
+#ifndef T_SHA_H
+#define T_SHA_H
+
+#if !defined(P)
+#ifdef __STDC__
+#define P(x) x
+#else
+#define P(x) ()
+#endif
+#endif
+
+#define SHA_DIGESTSIZE 20
+
+#ifdef OPENSSL
+#define OPENSSL_SHA 1
+#endif
+
+#ifdef TOMCRYPT
+# include <tomcrypt.h>
+# ifdef SHA1
+# define TOMCRYPT_SHA 1
+# endif
+#endif
+
+#ifdef CRYPTOLIB
+/* The SHA (shs) implementation in CryptoLib 1.x breaks when Update
+ * is called multiple times, so we still use our own code.
+ * Uncomment below if you think your copy of CryptoLib is fixed. */
+/*#define CRYPTOLIB_SHA 1*/
+#endif
+
+#ifdef GCRYPT
+# define GCRYPT_SHA 1
+#endif
+
+#ifdef MBEDTLS
+# define MBEDTLS_SHA 1
+#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;
+#define SHA1Init SHA1_Init
+#define SHA1Update SHA1_Update
+#define SHA1Final SHA1_Final
+
+#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 */
+
+typedef hash_state SHA1_CTX;
+#define SHA1Init sha1_init
+#define SHA1Update sha1_process
+#define SHA1Final(D,C) sha1_done(C,D)
+
+#elif defined(GCRYPT_SHA)
+#include "gcrypt.h"
+
+typedef gcry_md_hd_t SHA1_CTX;
+#define SHA1Init SHA1Init_gcry
+#define SHA1Update SHA1Update_gcry
+#define SHA1Final SHA1Final_gcry
+typedef gcry_md_hd_t SHA512_CTX;
+#define SHA512Init SHA512Init_gcry
+#define SHA512Update SHA512Update_gcry
+#define SHA512Final SHA512Final_gcry
+
+void SHA1Init_gcry(SHA1_CTX * ctx);
+void SHA1Update_gcry(SHA1_CTX * ctx, const void *data, unsigned int len);
+void SHA1Final_gcry(unsigned char digest[20], SHA1_CTX * ctx);
+
+void SHA512Init_gcry(SHA512_CTX * ctx);
+void SHA512Update_gcry(SHA512_CTX * ctx, const void *data, unsigned int len);
+void SHA512Final_gcry(unsigned char digest[64], SHA512_CTX * ctx);
+
+#elif defined(MBEDTLS_SHA)
+#include <mbedtls/md.h>
+
+typedef mbedtls_md_context_t SHA1_CTX;
+#define SHA1Init SHA1Init_mbed
+#define SHA1Update SHA1Update_mbed
+#define SHA1Final SHA1Final_mbed
+
+typedef mbedtls_md_context_t SHA512_CTX;
+#define SHA512Init SHA512Init_mbed
+#define SHA512Update SHA512Update_mbed
+#define SHA512Final SHA512Final_mbed
+
+void SHA1Init_mbed(SHA1_CTX * ctx);
+void SHA1Update_mbed(SHA1_CTX * ctx, const void *data, unsigned int len);
+void SHA1Final_mbed(unsigned char digest[20], SHA1_CTX * ctx);
+
+void SHA512Init_mbed(SHA512_CTX * ctx);
+void SHA512Update_mbed(SHA512_CTX * ctx, const void *data, unsigned int len);
+void SHA512Final_mbed(unsigned char digest[64], SHA512_CTX * ctx);
+
+#elif defined(CRYPTOLIB_SHA)
+#include "libcrypt.h"
+
+typedef SHS_CTX SHA1_CTX;
+#define SHA1Init shsInit
+#define SHA1Update shsUpdate
+#define SHA1Final shsFinalBytes
+
+void shsFinalBytes P((unsigned char digest[20], SHS_CTX* context));
+
+#else
+typedef unsigned int uint32;
+
+typedef struct {
+ uint32 state[5];
+ uint32 count[2];
+ unsigned char buffer[64];
+} SHA1_CTX;
+
+void SHA1Init P((SHA1_CTX* context));
+void SHA1Update P((SHA1_CTX* context, const unsigned char* data, unsigned int len));
+void SHA1Final P((unsigned char digest[20], SHA1_CTX* context));
+#endif /* !OPENSSL && !CRYPTOLIB */
+
+#endif /* T_SHA_H */
diff --git a/3rd_party/libsrp6a-sha512/t_truerand.c b/3rd_party/libsrp6a-sha512/t_truerand.c
new file mode 100644
index 0000000..f995ed7
--- /dev/null
+++ b/3rd_party/libsrp6a-sha512/t_truerand.c
@@ -0,0 +1,241 @@
+/*
+ * Physically random numbers (very nearly uniform)
+ * D. P. Mitchell
+ * Modified by Matt Blaze 7/95
+ */
+/*
+ * The authors of this software are Don Mitchell and Matt Blaze.
+ * Copyright (c) 1995 by AT&T.
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software and in all copies of the supporting
+ * documentation for such software.
+ *
+ * This software may be subject to United States export controls.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+/*
+ * WARNING: depending on the particular platform, raw_truerand()
+ * output may be biased or correlated. In general, you can expect
+ * about 16 bits of "pseudo-entropy" out of each 32 bit word returned
+ * by truerand(), but it may not be uniformly diffused. You should
+ * raw_therefore run the output through some post-whitening function
+ * (like MD5 or DES or whatever) before using it to generate key
+ * material. (RSAREF's random package does this for you when you feed
+ * raw_truerand() bits to the seed input function.)
+ *
+ * The application interface, for 8, 16, and 32 bit properly "whitened"
+ * random numbers, can be found in trand8(), trand16(), and trand32().
+ * Use those instead of calling raw_truerand() directly.
+ *
+ * The basic idea here is that between clock "skew" and various
+ * hard-to-predict OS event arrivals, counting a tight loop will yield
+ * a little (maybe a third of a bit or so) of "good" randomness per
+ * interval clock tick. This seems to work well even on unloaded
+ * machines. If there is a human operator at the machine, you should
+ * augment truerand with other measure, like keyboard event timing.
+ * On server machines (e.g., when you need to generate a
+ * Diffie-Hellman secret) truerand alone may be good enough.
+ *
+ * Test these assumptions on your own platform before fielding a
+ * system based on this software or these techniques.
+ *
+ * This software seems to work well (at 10 or so bits per
+ * raw_truerand() call) on a Sun Sparc-20 under SunOS 4.1.3 and on a
+ * P100 under BSDI 2.0. You're on your own elsewhere.
+ *
+ */
+
+#include "t_defines.h"
+
+#ifdef WIN32
+
+# ifdef CRYPTOLIB
+
+/* Cryptolib contains its own truerand() on both UNIX and Windows. */
+/* Only use cryptolib's truerand under Windows */
+
+# include "libcrypt.h"
+
+unsigned long
+raw_truerand()
+{
+ return truerand();
+}
+
+# else /* !CRYPTOLIB && WIN32 */
+
+#include <windows.h>
+#include <wtypes.h>
+#include <winbase.h>
+#include <windef.h>
+#include <winnt.h>
+#include <winuser.h>
+#include <process.h>
+
+volatile unsigned long count, ocount, randbuf;
+volatile int dontstop;
+char outbuf[1024], *bufp;
+
+static void counter() {
+ while (dontstop)
+ count++;
+ _endthread();
+}
+
+
+static unsigned long roulette() {
+ unsigned long thread;
+
+ count = 0;
+ dontstop= 1;
+ while ((thread = _beginthread((void *)counter, 1024, NULL)) < 0)
+ ;
+
+ Sleep(16);
+ dontstop = 0;
+ Sleep(1);
+
+ count ^= (count>>3) ^ (count>>6) ^ (ocount);
+ count &= 0x7;
+ ocount = count;
+ randbuf = (randbuf<<3) ^ count;
+ return randbuf;
+}
+
+
+unsigned long
+raw_truerand() {
+
+ roulette();
+ roulette();
+ roulette();
+ roulette();
+ roulette();
+ roulette();
+ roulette();
+ roulette();
+ roulette();
+ roulette();
+ return roulette();
+}
+
+# endif /* CRYPTOLIB */
+
+#else /* !WIN32 */
+
+#include <signal.h>
+#include <setjmp.h>
+#include <sys/time.h>
+#include <math.h>
+#include <stdio.h>
+
+#ifdef OLD_TRUERAND
+static jmp_buf env;
+#endif
+static unsigned volatile count
+#ifndef OLD_TRUERAND
+ , done = 0
+#endif
+;
+
+static unsigned ocount;
+static unsigned buffer;
+
+static void
+tick()
+{
+ struct itimerval it, oit;
+
+ it.it_interval.tv_sec = 0;
+ it.it_interval.tv_usec = 0;
+ it.it_value.tv_sec = 0;
+ it.it_value.tv_usec = 16665;
+ if (setitimer(ITIMER_REAL, &it, &oit) < 0)
+ perror("tick");
+}
+
+static void
+interrupt()
+{
+ if (count) {
+#ifdef OLD_TRUERAND
+ longjmp(env, 1);
+#else
+ ++done;
+ return;
+#endif
+ }
+
+ (void) signal(SIGALRM, interrupt);
+ tick();
+}
+
+static unsigned long
+roulette()
+{
+#ifdef OLD_TRUERAND
+ if (setjmp(env)) {
+ count ^= (count>>3) ^ (count>>6) ^ ocount;
+ count &= 0x7;
+ ocount=count;
+ buffer = (buffer<<3) ^ count;
+ return buffer;
+ }
+#else
+ done = 0;
+#endif
+ (void) signal(SIGALRM, interrupt);
+ count = 0;
+ tick();
+#ifdef OLD_TRUERAND
+ for (;;)
+#else
+ while(done == 0)
+#endif
+ count++; /* about 1 MHz on VAX 11/780 */
+#ifndef OLD_TRUERAND
+ count ^= (count>>3) ^ (count>>6) ^ ocount;
+ count &= 0x7;
+ ocount=count;
+ buffer = (buffer<<3) ^ count;
+ return buffer;
+#endif
+}
+
+unsigned long
+raw_truerand()
+{
+ count=0;
+ (void) roulette();
+ (void) roulette();
+ (void) roulette();
+ (void) roulette();
+ (void) roulette();
+ (void) roulette();
+ (void) roulette();
+ (void) roulette();
+ (void) roulette();
+ (void) roulette();
+ return roulette();
+}
+
+int
+raw_n_truerand(int n)
+{
+ int slop, v;
+
+ slop = 0x7FFFFFFF % n;
+ do {
+ v = raw_truerand() >> 1;
+ } while (v <= slop);
+ return v % n;
+}
+
+#endif /* !CRYPTOLIB || !WIN32 */
diff --git a/Makefile.am b/Makefile.am
index a50777a..b11de57 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,10 +1,14 @@
AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = -I m4
-SUBDIRS = common src include $(CYTHON_SUB) tools docs
+SUBDIRS = 3rd_party common src include $(CYTHON_SUB) tools docs
EXTRA_DIST = \
docs \
- README.md
+ README.md \
+ git-version-gen
+
+dist-hook:
+ echo $(VERSION) > $(distdir)/.tarball-version
docs/html: $(top_builddir)/doxygen.cfg $(top_srcdir)/src/*.c $(top_srcdir)/src/*.h $(top_srcdir)/include/libimobiledevice/*.h
rm -rf docs/html
diff --git a/README.md b/README.md
index ce225ca..89db882 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,8 @@
*A library to communicate with services on iOS devices using native protocols.*
+![](https://github.com/libimobiledevice/libimobiledevice/actions/workflows/build.yml/badge.svg)
+
## Features
libimobiledevice is a cross-platform software library that talks the protocols
@@ -16,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
@@ -55,6 +57,7 @@ First install all required dependencies and build tools:
```shell
sudo apt-get install \
build-essential \
+ pkg-config \
checkinstall \
git \
autoconf \
@@ -62,6 +65,7 @@ sudo apt-get install \
libtool-bin \
libplist-dev \
libusbmuxd-dev \
+ libimobiledevice-glue-dev \
libssl-dev \
usbmuxd
```
@@ -94,10 +98,19 @@ make
sudo make install
```
-By default, OpenSSL will be used. If you prefer GnuTLS, configure with
-`--disable-openssl` like this:
+By default, OpenSSL will be used as TLS/SSL library. If you prefer GnuTLS,
+configure with `--with-gnutls` like this:
+```bash
+./autogen.sh --with-gnutls
+```
+
+MbedTLS is also supported and can be enabled by passing `--with-mbedtls` to
+configure. If mbedTLS is not installed in a default location, you need to set
+the environment variables `mbedtls_INCLUDES` to the path that contains the
+MbedTLS headers and `mbedtls_LIBDIR` to set the library path. Optionally,
+`mbedtls_LIBS` can be used to set the library names directly. Example:
```bash
-./autogen.sh --disable-openssl
+./autogen.sh --with-mbedtls mbedtls_INCLUDES=/opt/local/include mbedtls_LIBDIR=/opt/local/lib
```
## Usage
@@ -115,6 +128,7 @@ The library bundles the following command-line utilities in the tools directory:
| `idevice_id` | List attached devices or print device name of given device |
| `idevicebackup` | Create or restore backup for devices (legacy) |
| `idevicebackup2` | Create or restore backups for devices running iOS 4 or later |
+| `idevicebtlogger` | Capture Bluetooth HCI traffic from a device (requires log profile) |
| `idevicecrashreport` | Retrieve crash reports from a device |
| `idevicedate` | Display the current date or set it on a device |
| `idevicedebug` | Interact with the debugserver service of a device |
@@ -130,6 +144,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:
@@ -151,7 +166,7 @@ ticket first to discuss the idea upfront to ensure less effort for everyone.
Please make sure your contribution adheres to:
* Try to follow the code style of the project
-* Commit messages should describe the change well without being to short
+* Commit messages should describe the change well without being too short
* Try to split larger changes into individual commits of a common domain
* Use your real name and a valid email address for your commits
@@ -179,4 +194,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: 2020-06-12
+README Updated on: 2023-12-30
diff --git a/common/Makefile.am b/common/Makefile.am
index 4e3facb..bd09bad 100644
--- a/common/Makefile.am
+++ b/common/Makefile.am
@@ -4,27 +4,23 @@ AM_CPPFLAGS = \
AM_CFLAGS = \
$(GLOBAL_CFLAGS) \
+ $(ssl_lib_CFLAGS) \
+ $(LFS_CFLAGS) \
$(libusbmuxd_CFLAGS) \
- $(libplist_CFLAGS) \
- $(libgnutls_CFLAGS) \
- $(libtasn1_CFLAGS) \
- $(openssl_CFLAGS) \
- $(LFS_CFLAGS)
+ $(libplist_CFLAGS)
AM_LDFLAGS = \
+ $(ssl_lib_LIBS) \
+ ${libpthread_LIBS} \
$(libusbmuxd_LIBS) \
- $(libplist_LIBS) \
- ${libpthread_LIBS}
+ $(libplist_LIBS)
noinst_LTLIBRARIES = libinternalcommon.la
libinternalcommon_la_LIBADD =
libinternalcommon_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined
libinternalcommon_la_SOURCES = \
- socket.c socket.h \
- thread.c thread.h \
debug.c debug.h \
- userpref.c userpref.h \
- utils.c utils.h
+ userpref.c userpref.h
if WIN32
libinternalcommon_la_LIBADD += -lole32 -lws2_32
diff --git a/common/debug.c b/common/debug.c
index a1c336b..cf1bc2f 100644
--- a/common/debug.c
+++ b/common/debug.c
@@ -31,9 +31,9 @@
#include <stdlib.h>
#include <time.h>
+#include "src/idevice.h"
#include "debug.h"
#include "libimobiledevice/libimobiledevice.h"
-#include "src/idevice.h"
#ifndef STRIP_DEBUG_CODE
#include "asprintf.h"
@@ -46,7 +46,7 @@ void internal_set_debug_level(int level)
debug_level = level;
}
-#define MAX_PRINT_LEN 16*1024
+#define MAX_PRINT_LEN (16*1024)
#ifndef STRIP_DEBUG_CODE
static void debug_print_line(const char *func, const char *file, int line, const char *buffer)
@@ -60,7 +60,7 @@ static void debug_print_line(const char *func, const char *file, int line, const
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);
+ if(asprintf(&header, "%s %s:%d %s()", str_time, file, line, func)<0){}
free (str_time);
/* trim ending newlines */
@@ -86,7 +86,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/socket.c b/common/socket.c
deleted file mode 100644
index 354e6a4..0000000
--- a/common/socket.c
+++ /dev/null
@@ -1,1171 +0,0 @@
-/*
- * socket.c
- *
- * Copyright (C) 2012-2020 Nikias Bassen <nikias@gmx.li>
- * Copyright (C) 2012 Martin Szulecki <m.szulecki@libimobiledevice.org>
- *
- * 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 <stdio.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#ifdef WIN32
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#include <windows.h>
-#ifndef HAVE_GETIFADDRS
-#include <iphlpapi.h>
-#endif
-static int wsa_init = 0;
-#ifndef IFF_RUNNING
-#define IFF_RUNNING IFF_UP
-#endif
-#ifndef AI_NUMERICSERV
-#define AI_NUMERICSERV 0
-#endif
-#else
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <netdb.h>
-#include <arpa/inet.h>
-#include <fcntl.h>
-#ifdef AF_INET6
-#include <net/if.h>
-#include <ifaddrs.h>
-#endif
-#endif
-#include "socket.h"
-
-#define RECV_TIMEOUT 20000
-#define SEND_TIMEOUT 10000
-#define CONNECT_TIMEOUT 5000
-
-#ifndef EAFNOSUPPORT
-#define EAFNOSUPPORT 102
-#endif
-#ifndef ECONNRESET
-#define ECONNRESET 108
-#endif
-#ifndef ETIMEDOUT
-#define ETIMEDOUT 138
-#endif
-
-static int verbose = 0;
-
-void socket_set_verbose(int level)
-{
- verbose = level;
-}
-
-const char *socket_addr_to_string(struct sockaddr *addr, char *addr_out, size_t addr_out_size)
-{
-#ifdef WIN32
- WSADATA wsa_data;
- if (!wsa_init) {
- if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) {
- fprintf(stderr, "WSAStartup failed!\n");
- ExitProcess(-1);
- }
- wsa_init = 1;
- }
- DWORD addr_out_len = addr_out_size;
- DWORD addrlen = 0;
-
- if (addr->sa_family == AF_INET) {
- addrlen = sizeof(struct sockaddr_in);
- }
-#ifdef AF_INET6
- else if (addr->sa_family == AF_INET6) {
- addrlen = sizeof(struct sockaddr_in6);
- }
-#endif
- else {
- errno = EAFNOSUPPORT;
- return NULL;
- }
-
- if (WSAAddressToString(addr, addrlen, NULL, addr_out, &addr_out_len) == 0) {
- return addr_out;
- }
-#else
- const void *addrdata = NULL;
-
- if (addr->sa_family == AF_INET) {
- addrdata = &((struct sockaddr_in*)addr)->sin_addr;
- }
-#ifdef AF_INET6
- else if (addr->sa_family == AF_INET6) {
- addrdata = &((struct sockaddr_in6*)addr)->sin6_addr;
- }
-#endif
- else {
- errno = EAFNOSUPPORT;
- return NULL;
- }
-
- if (inet_ntop(addr->sa_family, addrdata, addr_out, addr_out_size)) {
- return addr_out;
- }
-#endif
- return NULL;
-}
-
-#ifndef WIN32
-int socket_create_unix(const char *filename)
-{
- struct sockaddr_un name;
- int sock;
-#ifdef SO_NOSIGPIPE
- int yes = 1;
-#endif
-
- // remove if still present
- unlink(filename);
-
- /* Create the socket. */
- sock = socket(PF_UNIX, SOCK_STREAM, 0);
- if (sock < 0) {
- perror("socket");
- return -1;
- }
-
-#ifdef SO_NOSIGPIPE
- if (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) {
- perror("setsockopt()");
- socket_close(sock);
- return -1;
- }
-#endif
-
- /* Bind a name to the socket. */
- name.sun_family = AF_UNIX;
- strncpy(name.sun_path, filename, sizeof(name.sun_path));
- name.sun_path[sizeof(name.sun_path) - 1] = '\0';
-
- if (bind(sock, (struct sockaddr*)&name, sizeof(name)) < 0) {
- perror("bind");
- socket_close(sock);
- return -1;
- }
-
- if (listen(sock, 100) < 0) {
- perror("listen");
- socket_close(sock);
- return -1;
- }
-
- return sock;
-}
-
-int socket_connect_unix(const char *filename)
-{
- struct sockaddr_un name;
- int sfd = -1;
- struct stat fst;
-#ifdef SO_NOSIGPIPE
- int yes = 1;
-#endif
- int bufsize = 0x20000;
-
- // check if socket file exists...
- if (stat(filename, &fst) != 0) {
- if (verbose >= 2)
- fprintf(stderr, "%s: stat '%s': %s\n", __func__, filename,
- strerror(errno));
- return -1;
- }
- // ... and if it is a unix domain socket
- if (!S_ISSOCK(fst.st_mode)) {
- if (verbose >= 2)
- fprintf(stderr, "%s: File '%s' is not a socket!\n", __func__,
- filename);
- return -1;
- }
- // make a new socket
- if ((sfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
- if (verbose >= 2)
- fprintf(stderr, "%s: socket: %s\n", __func__, strerror(errno));
- return -1;
- }
-
- if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, (void*)&bufsize, sizeof(int)) == -1) {
- perror("Could not set send buffer for socket");
- }
-
- if (setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, (void*)&bufsize, sizeof(int)) == -1) {
- perror("Could not set receive buffer for socket");
- }
-
-#ifdef SO_NOSIGPIPE
- if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) {
- perror("setsockopt()");
- socket_close(sfd);
- return -1;
- }
-#endif
- // and connect to 'filename'
- name.sun_family = AF_UNIX;
- strncpy(name.sun_path, filename, sizeof(name.sun_path));
- name.sun_path[sizeof(name.sun_path) - 1] = 0;
-
- int flags = fcntl(sfd, F_GETFL, 0);
- fcntl(sfd, F_SETFL, flags | O_NONBLOCK);
-
- do {
- if (connect(sfd, (struct sockaddr*)&name, sizeof(name)) != -1) {
- break;
- }
- if (errno == EINPROGRESS) {
- fd_set fds;
- FD_ZERO(&fds);
- FD_SET(sfd, &fds);
-
- struct timeval timeout;
- timeout.tv_sec = CONNECT_TIMEOUT / 1000;
- timeout.tv_usec = (CONNECT_TIMEOUT - (timeout.tv_sec * 1000)) * 1000;
- if (select(sfd + 1, NULL, &fds, NULL, &timeout) == 1) {
- int so_error;
- socklen_t len = sizeof(so_error);
- getsockopt(sfd, SOL_SOCKET, SO_ERROR, (void*)&so_error, &len);
- if (so_error == 0) {
- break;
- }
- }
- }
- socket_close(sfd);
- sfd = -1;
- } while (0);
-
- if (sfd < 0) {
- if (verbose >= 2)
- fprintf(stderr, "%s: connect: %s\n", __func__, strerror(errno));
- return -1;
- }
-
- return sfd;
-}
-#endif
-
-int socket_create(const char* addr, uint16_t port)
-{
- int sfd = -1;
- int yes = 1;
- struct addrinfo hints;
- struct addrinfo *result, *rp;
- char portstr[8];
- int res;
-#ifdef WIN32
- WSADATA wsa_data;
- if (!wsa_init) {
- if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) {
- fprintf(stderr, "WSAStartup failed!\n");
- ExitProcess(-1);
- }
- wsa_init = 1;
- }
-#endif
-
- memset(&hints, '\0', sizeof(struct addrinfo));
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
- hints.ai_protocol = IPPROTO_TCP;
-
- sprintf(portstr, "%d", port);
-
- if (!addr) {
- addr = "localhost";
- }
- res = getaddrinfo(addr, portstr, &hints, &result);
- if (res != 0) {
- fprintf(stderr, "%s: getaddrinfo: %s\n", __func__, gai_strerror(res));
- return -1;
- }
-
- for (rp = result; rp != NULL; rp = rp->ai_next) {
- sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
- if (sfd == -1) {
- continue;
- }
-
- if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) {
- perror("setsockopt()");
- socket_close(sfd);
- continue;
- }
-
-#ifdef SO_NOSIGPIPE
- if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) {
- perror("setsockopt()");
- socket_close(sfd);
- continue;
- }
-#endif
-
-#if defined(AF_INET6) && defined(IPV6_V6ONLY)
- if (rp->ai_family == AF_INET6) {
- if (setsockopt(sfd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&yes, sizeof(int)) == -1) {
- perror("setsockopt() IPV6_V6ONLY");
- }
- }
-#endif
-
- if (bind(sfd, rp->ai_addr, rp->ai_addrlen) < 0) {
- perror("bind()");
- socket_close(sfd);
- continue;
- }
-
- if (listen(sfd, 100) < 0) {
- perror("listen()");
- socket_close(sfd);
- continue;
- }
- break;
- }
-
- freeaddrinfo(result);
-
- if (rp == NULL) {
- return -1;
- }
-
- return sfd;
-}
-
-#ifdef AF_INET6
-static uint32_t _in6_addr_scope(struct in6_addr* addr)
-{
- uint32_t scope = 0;
-
- if (IN6_IS_ADDR_MULTICAST(addr)) {
- if (IN6_IS_ADDR_MC_NODELOCAL(addr)) {
- scope = 1;
- } else if (IN6_IS_ADDR_MC_LINKLOCAL(addr)) {
- scope = 2;
- } else if (IN6_IS_ADDR_MC_SITELOCAL(addr)) {
- scope = 5;
- }
-
- return scope;
- }
-
- if (IN6_IS_ADDR_LINKLOCAL(addr)) {
- scope = 2;
- } else if (IN6_IS_ADDR_LOOPBACK(addr)) {
- scope = 2;
- } else if (IN6_IS_ADDR_SITELOCAL(addr)) {
- scope = 5;
- } else if (IN6_IS_ADDR_UNSPECIFIED(addr)) {
- scope = 0;
- }
-
- return scope;
-}
-
-#ifndef HAVE_GETIFADDRS
-#ifdef WIN32
-
-struct ifaddrs {
- struct ifaddrs *ifa_next; /* Next item in list */
- char *ifa_name; /* Name of interface */
- unsigned int ifa_flags; /* Flags from SIOCGIFFLAGS */
- struct sockaddr *ifa_addr; /* Address of interface */
- struct sockaddr *ifa_netmask; /* Netmask of interface */
- union {
- struct sockaddr *ifu_broadaddr; /* Broadcast address of interface */
- struct sockaddr *ifu_dstaddr; /* Point-to-point destination address */
- } ifa_ifu;
-#define ifa_broadaddr ifa_ifu.ifu_broadaddr
-#define ifa_dstaddr ifa_ifu.ifu_dstaddr
- void *ifa_data; /* Address-specific data */
-};
-
-#define WORKING_BUFFER_SIZE 15000
-#define MAX_TRIES 3
-
-static void freeifaddrs(struct ifaddrs *ifa)
-{
- if (!ifa) {
- return;
- }
- free(ifa->ifa_name);
- free(ifa->ifa_addr);
- free(ifa->ifa_netmask);
- free(ifa->ifa_dstaddr);
- freeifaddrs(ifa->ifa_next);
- free(ifa);
-}
-
-/*
- * getifaddrs() reference implementation for win32.
- * Heavily based on openpgm's implementation found here:
- * https://github.com/steve-o/openpgm/blob/master/openpgm/pgm/getifaddrs.c
- */
-static int getifaddrs(struct ifaddrs** ifap)
-{
- struct ifaddrs* ifa = NULL;
-
- DWORD dwRetVal = 0;
-
- PIP_ADAPTER_ADDRESSES pAddresses = NULL;
- ULONG outBufLen = 0;
- ULONG Iterations = 0;
-
- ULONG flags = GAA_FLAG_INCLUDE_PREFIX |
- GAA_FLAG_SKIP_ANYCAST |
- GAA_FLAG_SKIP_DNS_SERVER |
- GAA_FLAG_SKIP_FRIENDLY_NAME |
- GAA_FLAG_SKIP_MULTICAST;
-
- PIP_ADAPTER_ADDRESSES adapter = NULL;
-
- if (!ifap) {
- errno = EINVAL;
- return -1;
- }
- *ifap = NULL;
-
- outBufLen = WORKING_BUFFER_SIZE;
- do {
- pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen);
- if (pAddresses == NULL) {
- printf("Memory allocation failed for IP_ADAPTER_ADDRESSES struct\n");
- return -1;
- }
- dwRetVal = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, pAddresses, &outBufLen);
- if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
- free(pAddresses);
- pAddresses = NULL;
- } else {
- break;
- }
- Iterations++;
- } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES));
-
- if (dwRetVal != NO_ERROR) {
- free(pAddresses);
- return -1;
- }
-
- for (adapter = pAddresses; adapter; adapter = adapter->Next) {
- int unicastIndex = 0;
- for (IP_ADAPTER_UNICAST_ADDRESS *unicast = adapter->FirstUnicastAddress; unicast; unicast = unicast->Next, ++unicastIndex) {
- /* ensure IP adapter */
- if (AF_INET != unicast->Address.lpSockaddr->sa_family && AF_INET6 != unicast->Address.lpSockaddr->sa_family) {
- continue;
- }
-
- if (!ifa) {
- ifa = malloc(sizeof(struct ifaddrs));
- if (!ifa) {
- errno = ENOMEM;
- free(pAddresses);
- return -1;
- }
- *ifap = ifa;
- ifa->ifa_next = NULL;
- } else {
- struct ifaddrs* ifanew = malloc(sizeof(struct ifaddrs));
- if (!ifanew) {
- freeifaddrs(*ifap);
- free(pAddresses);
- errno = ENOMEM;
- return -1;
- }
- ifa->ifa_next = ifanew;
- ifa = ifanew;
- ifa->ifa_next = NULL;
- }
-
- /* name */
- ifa->ifa_name = strdup(adapter->AdapterName);
-
- /* flags */
- ifa->ifa_flags = 0;
- if (IfOperStatusUp == adapter->OperStatus)
- ifa->ifa_flags |= IFF_UP;
- if (IF_TYPE_SOFTWARE_LOOPBACK == adapter->IfType)
- ifa->ifa_flags |= IFF_LOOPBACK;
- if (!(adapter->Flags & IP_ADAPTER_NO_MULTICAST))
- ifa->ifa_flags |= IFF_MULTICAST;
-
- /* address */
- ifa->ifa_addr = (struct sockaddr*)malloc(sizeof(struct sockaddr_storage));
- memcpy(ifa->ifa_addr, unicast->Address.lpSockaddr, unicast->Address.iSockaddrLength);
-
- /* netmask */
- ifa->ifa_netmask = (struct sockaddr*)malloc(sizeof(struct sockaddr_storage));
- memset(ifa->ifa_netmask, 0, sizeof(struct sockaddr_storage));
-
-/* pre-Vista must hunt for matching prefix in linked list, otherwise use
- * OnLinkPrefixLength from IP_ADAPTER_UNICAST_ADDRESS structure.
- * FirstPrefix requires Windows XP SP1, from SP1 to pre-Vista provides a
- * single adapter prefix for each IP address. Vista and later provides
- * host IP address prefix, subnet IP address, and subnet broadcast IP
- * address. In addition there is a multicast and broadcast address prefix.
- */
- ULONG prefixLength = 0;
-
-#if defined( _WIN32 ) && ( _WIN32_WINNT >= 0x0600 )
-/* For a unicast IPv4 address, any value greater than 32 is an illegal
- * value. For a unicast IPv6 address, any value greater than 128 is an
- * illegal value. A value of 255 is commonly used to represent an illegal
- * value.
- *
- * Windows 7 SP1 returns 64 for Teredo links which is incorrect.
- */
-
-#define IN6_IS_ADDR_TEREDO(addr) \
- (((const uint32_t *)(addr))[0] == ntohl (0x20010000))
-
- if (AF_INET6 == unicast->Address.lpSockaddr->sa_family &&
-/* TunnelType only applies to one interface on the adapter and no
- * convenient method is provided to determine which.
- */
- TUNNEL_TYPE_TEREDO == adapter->TunnelType &&
-/* Test the interface with the known Teredo network prefix.
- */
- IN6_IS_ADDR_TEREDO( &((struct sockaddr_in6*)(unicast->Address.lpSockaddr))->sin6_addr) &&
-/* Test that this version is actually wrong, subsequent releases from Microsoft
- * may resolve the issue.
- */
- 32 != unicast->OnLinkPrefixLength)
- {
- prefixLength = 32;
- }
- else
- prefixLength = unicast->OnLinkPrefixLength;
-#else
-/* The order of linked IP_ADAPTER_UNICAST_ADDRESS structures pointed to by
- * the FirstUnicastAddress member does not have any relationship with the
- * order of linked IP_ADAPTER_PREFIX structures pointed to by the FirstPrefix
- * member.
- *
- * Example enumeration:
- * [ no subnet ]
- * ::1/128 - address
- * ff00::%1/8 - multicast (no IPv6 broadcast)
- * 127.0.0.0/8 - subnet
- * 127.0.0.1/32 - address
- * 127.255.255.255/32 - subnet broadcast
- * 224.0.0.0/4 - multicast
- * 255.255.255.255/32 - broadcast
- *
- * Which differs from most adapters listing three IPv6:
- * fe80::%10/64 - subnet
- * fe80::51e9:5fe5:4202:325a%10/128 - address
- * ff00::%10/8 - multicast
- *
- * !IfOperStatusUp IPv4 addresses are skipped:
- * fe80::%13/64 - subnet
- * fe80::d530:946d:e8df:8c91%13/128 - address
- * ff00::%13/8 - multicast
- * [ no subnet ]
- * [ no address ]
- * 224.0.0.0/4 - multicast
- * 255.255.255.255/32 - broadcast
- *
- * On PTP links no multicast or broadcast addresses are returned:
- * [ no subnet ]
- * fe80::5efe:10.203.9.30/128 - address
- * [ no multicast ]
- * [ no multicast ]
- * [ no broadcast ]
- *
- * Active primary IPv6 interfaces are a bit overloaded:
- * ::/0 - default route
- * 2001::/32 - global subnet
- * 2001:0:4137:9e76:2443:d6:ba87:1a2a/128 - global address
- * fe80::/64 - link-local subnet
- * fe80::2443:d6:ba87:1a2a/128 - link-local address
- * ff00::/8 - multicast
- */
-
-#define IN_LINKLOCAL(a) ((((uint32_t) (a)) & 0xaffff0000) == 0xa9fe0000)
-
- for (IP_ADAPTER_PREFIX *prefix = adapter->FirstPrefix; prefix; prefix = prefix->Next) {
- LPSOCKADDR lpSockaddr = prefix->Address.lpSockaddr;
- if (lpSockaddr->sa_family != unicast->Address.lpSockaddr->sa_family)
- continue;
-/* special cases */
-/* RFC2863: IPv4 interface not up */
- if (AF_INET == lpSockaddr->sa_family && adapter->OperStatus != IfOperStatusUp) {
-/* RFC3927: link-local IPv4 always has 16-bit CIDR */
- if (IN_LINKLOCAL( ntohl (((struct sockaddr_in*)(unicast->Address.lpSockaddr))->sin_addr.s_addr))) {
- prefixLength = 16;
- }
- break;
- }
-/* default IPv6 route */
- if (AF_INET6 == lpSockaddr->sa_family && 0 == prefix->PrefixLength && IN6_IS_ADDR_UNSPECIFIED( &((struct sockaddr_in6*)(lpSockaddr))->sin6_addr)) {
- continue;
- }
-/* Assume unicast address for first prefix of operational adapter */
- if (AF_INET == lpSockaddr->sa_family)
- if (IN_MULTICAST( ntohl (((struct sockaddr_in*)(lpSockaddr))->sin_addr.s_addr))) {
- fprintf(stderr, "FATAL: first prefix is non a unicast address\n");
- break;
- }
- if (AF_INET6 == lpSockaddr->sa_family)
- if (IN6_IS_ADDR_MULTICAST( &((struct sockaddr_in6*)(lpSockaddr))->sin6_addr)) {
- fprintf(stderr, "FATAL: first prefix is not a unicast address\n");
- break;
- }
-/* Assume subnet or host IP address for XP backward compatibility */
-
- prefixLength = prefix->PrefixLength;
- break;
- }
-#endif /* defined( _WIN32 ) && ( _WIN32_WINNT >= 0x0600 ) */
-
-/* map prefix to netmask */
- ifa->ifa_netmask->sa_family = unicast->Address.lpSockaddr->sa_family;
- switch (unicast->Address.lpSockaddr->sa_family) {
- case AF_INET:
- if (0 == prefixLength || prefixLength > 32) {
- prefixLength = 32;
- }
-#if defined( _WIN32) && ( _WIN32_WINNT >= 0x0600 )
-/* Added in Vista, but no IPv6 equivalent. */
- {
- ULONG Mask;
- ConvertLengthToIpv4Mask (prefixLength, &Mask);
- ((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr = Mask; /* network order */
- }
-#else
-/* NB: left-shift of full bit-width is undefined in C standard. */
- ((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr = htonl( 0xffffffffU << ( 32 - prefixLength ) );
-#endif
- break;
-
- case AF_INET6:
- if (0 == prefixLength || prefixLength > 128) {
- prefixLength = 128;
- }
- for (LONG i = prefixLength, j = 0; i > 0; i -= 8, ++j) {
- ((struct sockaddr_in6*)ifa->ifa_netmask)->sin6_addr.s6_addr[ j ] = i >= 8 ? 0xff : (ULONG)(( 0xffU << ( 8 - i ) ) & 0xffU );
- }
- break;
- default:
- break;
- }
- }
- }
- free(pAddresses);
-
- return 0;
-}
-#else
-#error No reference implementation for getifaddrs available for this platform.
-#endif
-#endif
-
-static int32_t _sockaddr_in6_scope_id(struct sockaddr_in6* addr)
-{
- int32_t res = -1;
- struct ifaddrs *ifaddr = NULL, *ifa = NULL;
- uint32_t addr_scope;
-
- /* get scope for requested address */
- addr_scope = _in6_addr_scope(&addr->sin6_addr);
- if (addr_scope == 0) {
- /* global scope doesn't need a specific scope id */
- return addr_scope;
- }
-
- /* get interfaces */
- if (getifaddrs(&ifaddr) == -1) {
- perror("getifaddrs");
- return res;
- }
-
- /* loop over interfaces */
- for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
- /* skip if no address is available */
- if (ifa->ifa_addr == NULL) {
- continue;
- }
-
- /* skip if wrong family */
- if (ifa->ifa_addr->sa_family != AF_INET6) {
- continue;
- }
-
- /* skip if not up */
- if ((ifa->ifa_flags & IFF_UP) == 0) {
- continue;
- }
-
- /* skip if not running */
- if ((ifa->ifa_flags & IFF_RUNNING) == 0) {
- continue;
- }
-
- struct sockaddr_in6* addr_in = (struct sockaddr_in6*)ifa->ifa_addr;
-
- /* skip if scopes do not match */
- if (_in6_addr_scope(&addr_in->sin6_addr) != addr_scope) {
- continue;
- }
-
- /* use if address is equal */
- if (memcmp(&addr->sin6_addr.s6_addr, &addr_in->sin6_addr.s6_addr, sizeof(addr_in->sin6_addr.s6_addr)) == 0) {
- /* if scope id equals the requested one then assume it was valid */
- if (addr->sin6_scope_id == addr_in->sin6_scope_id) {
- res = addr_in->sin6_scope_id;
- break;
- }
-
- if ((addr_in->sin6_scope_id > addr->sin6_scope_id) && (res >= 0)) {
- // use last valid scope id as we're past the requested scope id
- break;
- }
- res = addr_in->sin6_scope_id;
- continue;
- }
-
- /* skip loopback interface if not already matched exactly above */
- if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) {
- continue;
- }
-
- if ((addr_in->sin6_scope_id > addr->sin6_scope_id) && (res >= 0)) {
- // use last valid scope id as we're past the requested scope id
- break;
- }
-
- res = addr_in->sin6_scope_id;
-
- /* if scope id equals the requested one then assume it was valid */
- if (addr->sin6_scope_id == addr_in->sin6_scope_id) {
- /* set the scope id of this interface as most likely candidate */
- break;
- }
- }
-
- freeifaddrs(ifaddr);
-
- return res;
-}
-#endif
-
-int socket_connect_addr(struct sockaddr* addr, uint16_t port)
-{
- int sfd = -1;
- int yes = 1;
- int bufsize = 0x20000;
- int addrlen = 0;
-#ifdef WIN32
- u_long l_yes = 1;
- WSADATA wsa_data;
- if (!wsa_init) {
- if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) {
- fprintf(stderr, "WSAStartup failed!\n");
- ExitProcess(-1);
- }
- wsa_init = 1;
- }
-#endif
-
- if (addr->sa_family == AF_INET) {
- struct sockaddr_in* addr_in = (struct sockaddr_in*)addr;
- addr_in->sin_port = htons(port);
- addrlen = sizeof(struct sockaddr_in);
- }
-#ifdef AF_INET6
- else if (addr->sa_family == AF_INET6) {
- struct sockaddr_in6* addr_in = (struct sockaddr_in6*)addr;
- addr_in->sin6_port = htons(port);
-
- /*
- * IPv6 Routing Magic:
- *
- * If the scope of the address is a link-local one, IPv6 requires the
- * scope id set to an interface number to allow proper routing. However,
- * as the provided sockaddr might contain a wrong scope id, we must find
- * a scope id from a suitable interface on this system or routing might
- * fail. An IPv6 guru should have another look though...
- */
- addr_in->sin6_scope_id = _sockaddr_in6_scope_id(addr_in);
-
- addrlen = sizeof(struct sockaddr_in6);
- }
-#endif
- else {
- fprintf(stderr, "ERROR: Unsupported address family");
- return -1;
- }
-
- sfd = socket(addr->sa_family, SOCK_STREAM, IPPROTO_TCP);
- if (sfd == -1) {
- perror("socket()");
- return -1;
- }
-
-#ifdef SO_NOSIGPIPE
- if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) {
- perror("setsockopt()");
- socket_close(sfd);
- return -1;
- }
-#endif
-
- if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) {
- perror("setsockopt()");
- socket_close(sfd);
- return -1;
- }
-
-#ifdef WIN32
- ioctlsocket(sfd, FIONBIO, &l_yes);
-#else
- int flags = fcntl(sfd, F_GETFL, 0);
- fcntl(sfd, F_SETFL, flags | O_NONBLOCK);
-#endif
-
- do {
- if (connect(sfd, addr, addrlen) != -1) {
- break;
- }
-#ifdef WIN32
- if (WSAGetLastError() == WSAEWOULDBLOCK)
-#else
- if (errno == EINPROGRESS)
-#endif
- {
- fd_set fds;
- FD_ZERO(&fds);
- FD_SET(sfd, &fds);
-
- struct timeval timeout;
- timeout.tv_sec = CONNECT_TIMEOUT / 1000;
- timeout.tv_usec = (CONNECT_TIMEOUT - (timeout.tv_sec * 1000)) * 1000;
- if (select(sfd + 1, NULL, &fds, NULL, &timeout) == 1) {
- int so_error;
- socklen_t len = sizeof(so_error);
- getsockopt(sfd, SOL_SOCKET, SO_ERROR, (void*)&so_error, &len);
- if (so_error == 0) {
- errno = 0;
- break;
- }
- errno = so_error;
- }
- }
- socket_close(sfd);
- sfd = -1;
- } while (0);
-
- if (sfd < 0) {
- if (verbose >= 2) {
- char addrtxt[48];
- socket_addr_to_string(addr, addrtxt, sizeof(addrtxt));
- fprintf(stderr, "%s: Could not connect to %s port %d\n", __func__, addrtxt, port);
- }
- return -1;
- }
-
- if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (void*)&yes, sizeof(int)) == -1) {
- perror("Could not set TCP_NODELAY on socket");
- }
-
- if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, (void*)&bufsize, sizeof(int)) == -1) {
- perror("Could not set send buffer for socket");
- }
-
- if (setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, (void*)&bufsize, sizeof(int)) == -1) {
- perror("Could not set receive buffer for socket");
- }
-
- return sfd;
-}
-
-int socket_connect(const char *addr, uint16_t port)
-{
- int sfd = -1;
- int yes = 1;
- int bufsize = 0x20000;
- struct addrinfo hints;
- struct addrinfo *result, *rp;
- char portstr[8];
- int res;
-#ifdef WIN32
- u_long l_yes = 1;
- WSADATA wsa_data;
- if (!wsa_init) {
- if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) {
- fprintf(stderr, "WSAStartup failed!\n");
- ExitProcess(-1);
- }
- wsa_init = 1;
- }
-#else
- int flags = 0;
-#endif
-
- if (!addr) {
- errno = EINVAL;
- return -1;
- }
-
- memset(&hints, '\0', sizeof(struct addrinfo));
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = AI_NUMERICSERV;
- hints.ai_protocol = IPPROTO_TCP;
-
- sprintf(portstr, "%d", port);
-
- res = getaddrinfo(addr, portstr, &hints, &result);
- if (res != 0) {
- fprintf(stderr, "%s: getaddrinfo: %s\n", __func__, gai_strerror(res));
- return -1;
- }
-
- for (rp = result; rp != NULL; rp = rp->ai_next) {
- sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
- if (sfd == -1) {
- continue;
- }
-
-#ifdef SO_NOSIGPIPE
- if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) {
- perror("setsockopt()");
- socket_close(sfd);
- return -1;
- }
-#endif
-
- if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) {
- perror("setsockopt()");
- socket_close(sfd);
- continue;
- }
-
-#ifdef WIN32
- ioctlsocket(sfd, FIONBIO, &l_yes);
-#else
- flags = fcntl(sfd, F_GETFL, 0);
- fcntl(sfd, F_SETFL, flags | O_NONBLOCK);
-#endif
-
- if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) {
- break;
- }
-#ifdef WIN32
- if (WSAGetLastError() == WSAEWOULDBLOCK)
-#else
- if (errno == EINPROGRESS)
-#endif
- {
- fd_set fds;
- FD_ZERO(&fds);
- FD_SET(sfd, &fds);
-
- struct timeval timeout;
- timeout.tv_sec = CONNECT_TIMEOUT / 1000;
- timeout.tv_usec = (CONNECT_TIMEOUT - (timeout.tv_sec * 1000)) * 1000;
- if (select(sfd + 1, NULL, &fds, NULL, &timeout) == 1) {
- int so_error;
- socklen_t len = sizeof(so_error);
- getsockopt(sfd, SOL_SOCKET, SO_ERROR, (void*)&so_error, &len);
- if (so_error == 0) {
- break;
- }
- }
- }
- socket_close(sfd);
- }
-
- freeaddrinfo(result);
-
- if (rp == NULL) {
- if (verbose >= 2)
- fprintf(stderr, "%s: Could not connect to %s:%d\n", __func__, addr, port);
- return -1;
- }
-
- if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (void*)&yes, sizeof(int)) == -1) {
- perror("Could not set TCP_NODELAY on socket");
- }
-
- if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, (void*)&bufsize, sizeof(int)) == -1) {
- perror("Could not set send buffer for socket");
- }
-
- if (setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, (void*)&bufsize, sizeof(int)) == -1) {
- perror("Could not set receive buffer for socket");
- }
-
- return sfd;
-}
-
-int socket_check_fd(int fd, fd_mode fdm, unsigned int timeout)
-{
- fd_set fds;
- int sret;
- int eagain;
- struct timeval to;
- struct timeval *pto;
-
- if (fd < 0) {
- if (verbose >= 2)
- fprintf(stderr, "ERROR: invalid fd in check_fd %d\n", fd);
- return -1;
- }
-
- FD_ZERO(&fds);
- FD_SET(fd, &fds);
-
- sret = -1;
-
- do {
- if (timeout > 0) {
- to.tv_sec = (time_t) (timeout / 1000);
- to.tv_usec = (time_t) ((timeout - (to.tv_sec * 1000)) * 1000);
- pto = &to;
- } else {
- pto = NULL;
- }
- eagain = 0;
- switch (fdm) {
- case FDM_READ:
- sret = select(fd + 1, &fds, NULL, NULL, pto);
- break;
- case FDM_WRITE:
- sret = select(fd + 1, NULL, &fds, NULL, pto);
- break;
- case FDM_EXCEPT:
- sret = select(fd + 1, NULL, NULL, &fds, pto);
- break;
- default:
- return -1;
- }
-
- if (sret < 0) {
- switch (errno) {
- case EINTR:
- // interrupt signal in select
- if (verbose >= 2)
- fprintf(stderr, "%s: EINTR\n", __func__);
- eagain = 1;
- break;
- case EAGAIN:
- if (verbose >= 2)
- fprintf(stderr, "%s: EAGAIN\n", __func__);
- break;
- default:
- if (verbose >= 2)
- fprintf(stderr, "%s: select failed: %s\n", __func__,
- strerror(errno));
- return -1;
- }
- } else if (sret == 0) {
- if (verbose >= 2)
- fprintf(stderr, "%s: timeout\n", __func__);
- return -ETIMEDOUT;
- }
- } while (eagain);
-
- return sret;
-}
-
-int socket_accept(int fd, uint16_t port)
-{
-#ifdef WIN32
- int addr_len;
-#else
- socklen_t addr_len;
-#endif
- int result;
- struct sockaddr_storage addr;
- addr_len = sizeof(addr);
-
- result = accept(fd, (struct sockaddr*)&addr, &addr_len);
-
- return result;
-}
-
-int socket_shutdown(int fd, int how)
-{
- return shutdown(fd, how);
-}
-
-int socket_close(int fd) {
-#ifdef WIN32
- return closesocket(fd);
-#else
- return close(fd);
-#endif
-}
-
-int socket_receive(int fd, void *data, size_t length)
-{
- return socket_receive_timeout(fd, data, length, 0, RECV_TIMEOUT);
-}
-
-int socket_peek(int fd, void *data, size_t length)
-{
- return socket_receive_timeout(fd, data, length, MSG_PEEK, RECV_TIMEOUT);
-}
-
-int socket_receive_timeout(int fd, void *data, size_t length, int flags,
- unsigned int timeout)
-{
- int res;
- int result;
-
- // check if data is available
- res = socket_check_fd(fd, FDM_READ, timeout);
- if (res <= 0) {
- return res;
- }
- // if we get here, there _is_ data available
- result = recv(fd, data, length, flags);
- if (res > 0 && result == 0) {
- // but this is an error condition
- if (verbose >= 3)
- fprintf(stderr, "%s: fd=%d recv returned 0\n", __func__, fd);
- return -ECONNRESET;
- }
- if (result < 0) {
- return -errno;
- }
- return result;
-}
-
-int socket_send(int fd, void *data, size_t length)
-{
- int flags = 0;
- int res = socket_check_fd(fd, FDM_WRITE, SEND_TIMEOUT);
- if (res <= 0) {
- return res;
- }
-#ifdef MSG_NOSIGNAL
- flags |= MSG_NOSIGNAL;
-#endif
- return send(fd, data, length, flags);
-}
diff --git a/common/socket.h b/common/socket.h
deleted file mode 100644
index 9567270..0000000
--- a/common/socket.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * socket.h
- *
- * Copyright (C) 2012-2020 Nikias Bassen <nikias@gmx.li>
- * Copyright (C) 2012 Martin Szulecki <m.szulecki@libimobiledevice.org>
- *
- * 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 SOCKET_SOCKET_H
-#define SOCKET_SOCKET_H
-
-#include <stdlib.h>
-#include <stdint.h>
-
-enum fd_mode {
- FDM_READ,
- FDM_WRITE,
- FDM_EXCEPT
-};
-typedef enum fd_mode fd_mode;
-
-#ifdef WIN32
-#include <winsock2.h>
-#define SHUT_RD SD_READ
-#define SHUT_WR SD_WRITE
-#define SHUT_RDWR SD_BOTH
-#else
-#include <sys/socket.h>
-#endif
-
-#ifndef WIN32
-int socket_create_unix(const char *filename);
-int socket_connect_unix(const char *filename);
-#endif
-int socket_create(const char *addr, uint16_t port);
-int socket_connect_addr(struct sockaddr *addr, uint16_t port);
-int socket_connect(const char *addr, uint16_t port);
-int socket_check_fd(int fd, fd_mode fdm, unsigned int timeout);
-int socket_accept(int fd, uint16_t port);
-
-int socket_shutdown(int fd, int how);
-int socket_close(int fd);
-
-int socket_receive(int fd, void *data, size_t length);
-int socket_peek(int fd, void *data, size_t length);
-int socket_receive_timeout(int fd, void *data, size_t length, int flags,
- unsigned int timeout);
-
-int socket_send(int fd, void *data, size_t length);
-
-void socket_set_verbose(int level);
-
-const char *socket_addr_to_string(struct sockaddr *addr, char *addr_out, size_t addr_out_size);
-
-#endif /* SOCKET_SOCKET_H */
diff --git a/common/thread.c b/common/thread.c
deleted file mode 100644
index eb535ab..0000000
--- a/common/thread.c
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * thread.c
- *
- * Copyright (c) 2012-2019 Nikias Bassen, All Rights Reserved.
- * Copyright (c) 2012 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
- * 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 "thread.h"
-
-int thread_new(THREAD_T *thread, thread_func_t thread_func, void* data)
-{
-#ifdef WIN32
- HANDLE th = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread_func, data, 0, NULL);
- if (th == NULL) {
- return -1;
- }
- *thread = th;
- return 0;
-#else
- int res = pthread_create(thread, NULL, thread_func, data);
- return res;
-#endif
-}
-
-void thread_detach(THREAD_T thread)
-{
-#ifdef WIN32
- CloseHandle(thread);
-#else
- pthread_detach(thread);
-#endif
-}
-
-void thread_free(THREAD_T thread)
-{
-#ifdef WIN32
- CloseHandle(thread);
-#endif
-}
-
-int thread_join(THREAD_T thread)
-{
- /* wait for thread to complete */
-#ifdef WIN32
- return (int)WaitForSingleObject(thread, INFINITE);
-#else
- return pthread_join(thread, NULL);
-#endif
-}
-
-int thread_alive(THREAD_T thread)
-{
-#ifdef WIN32
- return WaitForSingleObject(thread, 0) == WAIT_TIMEOUT;
-#else
- return pthread_kill(thread, 0) == 0;
-#endif
-}
-
-int thread_cancel(THREAD_T thread)
-{
-#ifdef WIN32
- return -1;
-#else
-#ifdef HAVE_PTHREAD_CANCEL
- return pthread_cancel(thread);
-#else
- return -1;
-#endif
-#endif
-}
-
-void mutex_init(mutex_t* mutex)
-{
-#ifdef WIN32
- InitializeCriticalSection(mutex);
-#else
- pthread_mutex_init(mutex, NULL);
-#endif
-}
-
-void mutex_destroy(mutex_t* mutex)
-{
-#ifdef WIN32
- DeleteCriticalSection(mutex);
-#else
- pthread_mutex_destroy(mutex);
-#endif
-}
-
-void mutex_lock(mutex_t* mutex)
-{
-#ifdef WIN32
- EnterCriticalSection(mutex);
-#else
- pthread_mutex_lock(mutex);
-#endif
-}
-
-void mutex_unlock(mutex_t* mutex)
-{
-#ifdef WIN32
- LeaveCriticalSection(mutex);
-#else
- pthread_mutex_unlock(mutex);
-#endif
-}
-
-void thread_once(thread_once_t *once_control, void (*init_routine)(void))
-{
-#ifdef WIN32
- while (InterlockedExchange(&(once_control->lock), 1) != 0) {
- Sleep(1);
- }
- if (!once_control->state) {
- once_control->state = 1;
- init_routine();
- }
- InterlockedExchange(&(once_control->lock), 0);
-#else
- pthread_once(once_control, init_routine);
-#endif
-}
diff --git a/common/thread.h b/common/thread.h
deleted file mode 100644
index 23e4510..0000000
--- a/common/thread.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * thread.h
- *
- * Copyright (c) 2012-2019 Nikias Bassen, All Rights Reserved.
- * Copyright (c) 2012 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
- * 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 __THREAD_H
-#define __THREAD_H
-
-#include <stddef.h>
-
-#ifdef WIN32
-#include <windows.h>
-typedef HANDLE THREAD_T;
-typedef CRITICAL_SECTION mutex_t;
-typedef volatile struct {
- LONG lock;
- int state;
-} thread_once_t;
-#define THREAD_ONCE_INIT {0, 0}
-#define THREAD_ID GetCurrentThreadId()
-#define THREAD_T_NULL (THREAD_T)NULL
-#else
-#include <pthread.h>
-#include <signal.h>
-typedef pthread_t THREAD_T;
-typedef pthread_mutex_t mutex_t;
-typedef pthread_once_t thread_once_t;
-#define THREAD_ONCE_INIT PTHREAD_ONCE_INIT
-#define THREAD_ID pthread_self()
-#define THREAD_T_NULL (THREAD_T)NULL
-#endif
-
-typedef void* (*thread_func_t)(void* data);
-
-int thread_new(THREAD_T* thread, thread_func_t thread_func, void* data);
-void thread_detach(THREAD_T thread);
-void thread_free(THREAD_T thread);
-int thread_join(THREAD_T thread);
-int thread_alive(THREAD_T thread);
-
-int thread_cancel(THREAD_T thread);
-
-#ifdef WIN32
-#undef HAVE_THREAD_CLEANUP
-#else
-#ifdef HAVE_PTHREAD_CANCEL
-#define HAVE_THREAD_CLEANUP 1
-#define thread_cleanup_push(routine, arg) pthread_cleanup_push(routine, arg)
-#define thread_cleanup_pop(execute) pthread_cleanup_pop(execute)
-#endif
-#endif
-
-void mutex_init(mutex_t* mutex);
-void mutex_destroy(mutex_t* mutex);
-void mutex_lock(mutex_t* mutex);
-void mutex_unlock(mutex_t* mutex);
-
-void thread_once(thread_once_t *once_control, void (*init_routine)(void));
-
-#endif
diff --git a/common/userpref.c b/common/userpref.c
index a5aa7cb..b64c703 100644
--- a/common/userpref.c
+++ b/common/userpref.c
@@ -2,6 +2,7 @@
* userpref.c
* contains methods to access user specific certificates IDs and more.
*
+ * Copyright (c) 2013-2021 Nikias Bassen, All Rights Reserved.
* Copyright (c) 2013-2014 Martin Szulecki All Rights Reserved.
* Copyright (c) 2008 Jonathan Beck All Rights Reserved.
*
@@ -36,7 +37,7 @@
#endif
#include <unistd.h>
#include <usbmuxd.h>
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL)
#include <openssl/bn.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
@@ -47,12 +48,20 @@
#define X509_set1_notBefore X509_set_notBefore
#define X509_set1_notAfter X509_set_notAfter
#endif
-#else
+#elif defined(HAVE_GNUTLS)
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#include <gnutls/x509.h>
#include <gcrypt.h>
#include <libtasn1.h>
+#elif defined(HAVE_MBEDTLS)
+#include <mbedtls/ssl.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/asn1write.h>
+#include <mbedtls/oid.h>
+#else
+#error No supported TLS/SSL library enabled
#endif
#include <dirent.h>
@@ -64,11 +73,16 @@
#include <shlobj.h>
#endif
+#ifndef ETIMEDOUT
+#define ETIMEDOUT 138
+#endif
+
+#include <libimobiledevice-glue/utils.h>
+
#include "userpref.h"
#include "debug.h"
-#include "utils.h"
-#ifndef HAVE_OPENSSL
+#if defined(HAVE_GNUTLS)
const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = {
{"PKCS1", 536872976, 0},
{0, 1073741836, 0},
@@ -300,8 +314,10 @@ userpref_error_t userpref_save_pair_record(const char *udid, uint32_t device_id,
* @param udid The device UDID as given by the device
* @param pair_record The pair record to read
*
- * @return 1 on success and 0 if no device record is given or if it has already
- * been saved previously.
+ * @return USERPREF_E_SUCCESS on success,
+ * USERPREF_E_NOENT if no pairing record was found,
+ * USERPREF_E_READ_ERROR if retrieving the pairing record from usbmuxd failed,
+ * or USERPREF_E_INVALID_CONF otherwise.
*/
userpref_error_t userpref_read_pair_record(const char *udid, plist_t *pair_record)
{
@@ -309,24 +325,27 @@ userpref_error_t userpref_read_pair_record(const char *udid, plist_t *pair_recor
uint32_t record_size = 0;
int res = usbmuxd_read_pair_record(udid, &record_data, &record_size);
-
if (res < 0) {
- if (record_data)
- free(record_data);
-
- return USERPREF_E_INVALID_CONF;
+ free(record_data);
+ switch (-res) {
+ case ENOENT:
+ return USERPREF_E_NOENT;
+ case ETIMEDOUT:
+ return USERPREF_E_READ_ERROR;
+ default:
+ return USERPREF_E_INVALID_CONF;
+ }
}
*pair_record = NULL;
- if (memcmp(record_data, "bplist00", 8) == 0) {
- plist_from_bin(record_data, record_size, pair_record);
- } else {
- plist_from_xml(record_data, record_size, pair_record);
- }
-
+ plist_from_memory(record_data, record_size, pair_record, NULL);
free(record_data);
- return res == 0 ? USERPREF_E_SUCCESS: USERPREF_E_UNKNOWN_ERROR;
+ if (!*pair_record) {
+ debug_info("Failed to parse pairing record");
+ return USERPREF_E_INVALID_CONF;
+ }
+ return USERPREF_E_SUCCESS;
}
/**
@@ -343,7 +362,7 @@ userpref_error_t userpref_delete_pair_record(const char *udid)
return res == 0 ? USERPREF_E_SUCCESS: USERPREF_E_UNKNOWN_ERROR;
}
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL)
static int X509_add_ext_helper(X509 *cert, int nid, char *value)
{
X509_EXTENSION *ex;
@@ -364,6 +383,31 @@ static int X509_add_ext_helper(X509 *cert, int nid, char *value)
return 1;
}
+#elif defined(HAVE_MBEDTLS)
+static int _mbedtls_x509write_crt_set_basic_constraints_critical(mbedtls_x509write_cert *ctx, int is_ca, int max_pathlen)
+{
+ int ret;
+ unsigned char buf[9];
+ unsigned char *c = buf + sizeof(buf);
+ size_t len = 0;
+
+ memset( buf, 0, sizeof(buf) );
+
+ if (is_ca && max_pathlen > 127)
+ return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
+
+ if (is_ca) {
+ if (max_pathlen >= 0) {
+ MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, max_pathlen ) );
+ }
+ MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_bool( &c, buf, 1 ) );
+ }
+
+ MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
+ MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) );
+
+ return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_BASIC_CONSTRAINTS, MBEDTLS_OID_SIZE( MBEDTLS_OID_BASIC_CONSTRAINTS ), 1, buf + sizeof(buf) - len, len );
+}
#endif
/**
@@ -390,7 +434,11 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da
debug_info("Generating keys and certificates...");
-#ifdef HAVE_OPENSSL
+#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();
@@ -407,6 +455,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();
@@ -517,12 +566,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);
}
@@ -544,10 +603,7 @@ 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");
@@ -574,12 +630,13 @@ 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);
X509_free(host_cert);
X509_free(root_cert);
-#else
+#elif defined(HAVE_GNUTLS)
gnutls_x509_privkey_t root_privkey;
gnutls_x509_crt_t root_cert;
gnutls_x509_privkey_t host_privkey;
@@ -749,6 +806,211 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da
gnutls_free(exponent.data);
gnutls_free(der_pub_key.data);
+#elif defined(HAVE_MBEDTLS)
+ time_t now = time(NULL);
+ struct tm* timestamp = gmtime(&now);
+ char notbefore[16];
+ strftime(notbefore, sizeof(notbefore), "%Y%m%d%H%M%S", timestamp);
+ time_t then = now + 60 * 60 * 24 * 365 * 10;
+ char notafter[16];
+ timestamp = gmtime(&then);
+ strftime(notafter, sizeof(notafter), "%Y%m%d%H%M%S", timestamp);
+
+ mbedtls_mpi sn;
+ mbedtls_mpi_init(&sn);
+ mbedtls_mpi_lset(&sn, 1); /* 0 doesn't work, so we have to use 1 (like GnuTLS) */
+
+ mbedtls_ctr_drbg_context ctr_drbg;
+ mbedtls_ctr_drbg_init(&ctr_drbg);
+
+ mbedtls_pk_context root_pkey;
+ mbedtls_pk_init(&root_pkey);
+
+ mbedtls_pk_context host_pkey;
+ mbedtls_pk_init(&host_pkey);
+
+ mbedtls_pk_context dev_public_key;
+ mbedtls_pk_init(&dev_public_key);
+
+ mbedtls_entropy_context entropy;
+ mbedtls_entropy_init(&entropy);
+
+ mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)"limd", 4);
+
+ /* ----- root key & cert ----- */
+ ret = mbedtls_pk_setup(&root_pkey, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA));
+ if (ret != 0) {
+ debug_info("mbedtls_pk_setup returned -0x%04x", -ret);
+ goto cleanup;
+ }
+
+ ret = mbedtls_rsa_gen_key(mbedtls_pk_rsa(root_pkey), mbedtls_ctr_drbg_random, &ctr_drbg, 2048, 65537);
+ if (ret != 0) {
+ debug_info("mbedtls_rsa_gen_key returned -0x%04x", -ret);
+ goto cleanup;
+ }
+
+ mbedtls_x509write_cert cert;
+ mbedtls_x509write_crt_init(&cert);
+
+ /* set serial number */
+ mbedtls_x509write_crt_set_serial(&cert, &sn);
+
+ /* set version */
+ mbedtls_x509write_crt_set_version(&cert, 2);
+
+ /* set x509v3 basic constraints */
+ _mbedtls_x509write_crt_set_basic_constraints_critical(&cert, 1, -1);
+
+ /* use root public key for root cert */
+ mbedtls_x509write_crt_set_subject_key(&cert, &root_pkey);
+
+ /* set x509v3 subject key identifier */
+ mbedtls_x509write_crt_set_subject_key_identifier(&cert);
+
+ /* set key validity */
+ mbedtls_x509write_crt_set_validity(&cert, notbefore, notafter);
+
+ /* 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);
+
+ unsigned char outbuf[16384];
+
+ /* write root private key */
+ mbedtls_pk_write_key_pem(&root_pkey, outbuf, sizeof(outbuf));
+ root_key_pem.size = strlen((const char*)outbuf);
+ root_key_pem.data = malloc(root_key_pem.size+1);
+ memcpy(root_key_pem.data, outbuf, root_key_pem.size);
+ root_key_pem.data[root_key_pem.size] = '\0';
+
+ /* write root certificate */
+ mbedtls_x509write_crt_pem(&cert, outbuf, sizeof(outbuf), mbedtls_ctr_drbg_random, &ctr_drbg);
+ root_cert_pem.size = strlen((const char*)outbuf);
+ root_cert_pem.data = malloc(root_cert_pem.size+1);
+ memcpy(root_cert_pem.data, outbuf, root_cert_pem.size);
+ root_cert_pem.data[root_cert_pem.size] = '\0';
+
+ mbedtls_x509write_crt_free(&cert);
+
+
+ /* ----- host key & cert ----- */
+ ret = mbedtls_pk_setup(&host_pkey, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA));
+ if (ret != 0) {
+ debug_info("mbedtls_pk_setup returned -0x%04x", -ret);
+ goto cleanup;
+ }
+
+ ret = mbedtls_rsa_gen_key(mbedtls_pk_rsa(host_pkey), mbedtls_ctr_drbg_random, &ctr_drbg, 2048, 65537);
+ if (ret != 0) {
+ debug_info("mbedtls_rsa_gen_key returned -0x%04x", -ret);
+ goto cleanup;
+ }
+
+ mbedtls_x509write_crt_init(&cert);
+
+ /* set serial number */
+ mbedtls_x509write_crt_set_serial(&cert, &sn);
+
+ /* set version */
+ mbedtls_x509write_crt_set_version(&cert, 2);
+
+ /* set x509v3 basic constraints */
+ _mbedtls_x509write_crt_set_basic_constraints_critical(&cert, 0, -1);
+
+ /* use host public key for host cert */
+ mbedtls_x509write_crt_set_subject_key(&cert, &host_pkey);
+
+ /* set x509v3 subject key identifier */
+ mbedtls_x509write_crt_set_subject_key_identifier(&cert);
+
+ /* set x509v3 key usage */
+ mbedtls_x509write_crt_set_key_usage(&cert, MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_KEY_ENCIPHERMENT);
+
+ /* set key validity */
+ mbedtls_x509write_crt_set_validity(&cert, notbefore, notafter);
+
+ /* 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);
+
+ /* write host private key */
+ mbedtls_pk_write_key_pem(&host_pkey, outbuf, sizeof(outbuf));
+ host_key_pem.size = strlen((const char*)outbuf);
+ host_key_pem.data = malloc(host_key_pem.size+1);
+ memcpy(host_key_pem.data, outbuf, host_key_pem.size);
+ host_key_pem.data[host_key_pem.size] = '\0';
+
+ /* write host certificate */
+ mbedtls_x509write_crt_pem(&cert, outbuf, sizeof(outbuf), mbedtls_ctr_drbg_random, &ctr_drbg);
+ host_cert_pem.size = strlen((const char*)outbuf);
+ host_cert_pem.data = malloc(host_cert_pem.size+1);
+ memcpy(host_cert_pem.data, outbuf, host_cert_pem.size);
+ host_cert_pem.data[host_cert_pem.size] = '\0';
+
+ mbedtls_x509write_crt_free(&cert);
+
+
+ /* ----- device certificate ----- */
+ unsigned char* pubkey_data = malloc(public_key.size+1);
+ if (!pubkey_data) {
+ debug_info("malloc() failed\n");
+ goto cleanup;
+ }
+ memcpy(pubkey_data, public_key.data, public_key.size);
+ pubkey_data[public_key.size] = '\0';
+
+ int pr = mbedtls_pk_parse_public_key(&dev_public_key, pubkey_data, public_key.size+1);
+ free(pubkey_data);
+ if (pr != 0) {
+ debug_info("Failed to read device public key: -0x%x\n", -pr);
+ goto cleanup;
+ }
+
+ mbedtls_x509write_crt_init(&cert);
+
+ /* set serial number */
+ mbedtls_x509write_crt_set_serial(&cert, &sn);
+
+ /* set version */
+ mbedtls_x509write_crt_set_version(&cert, 2);
+
+ /* set x509v3 basic constraints */
+ _mbedtls_x509write_crt_set_basic_constraints_critical(&cert, 0, -1);
+
+ /* use root public key for dev cert subject key */
+ mbedtls_x509write_crt_set_subject_key(&cert, &dev_public_key);
+
+ /* set x509v3 subject key identifier */
+ mbedtls_x509write_crt_set_subject_key_identifier(&cert);
+
+ /* set x509v3 key usage */
+ mbedtls_x509write_crt_set_key_usage(&cert, MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_KEY_ENCIPHERMENT);
+
+ /* set key validity */
+ mbedtls_x509write_crt_set_validity(&cert, notbefore, notafter);
+
+ /* 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);
+
+ /* write device certificate */
+ mbedtls_x509write_crt_pem(&cert, outbuf, sizeof(outbuf), mbedtls_ctr_drbg_random, &ctr_drbg);
+ dev_cert_pem.size = strlen((const char*)outbuf);
+ dev_cert_pem.data = malloc(dev_cert_pem.size+1);
+ memcpy(dev_cert_pem.data, outbuf, dev_cert_pem.size);
+ dev_cert_pem.data[dev_cert_pem.size] = '\0';
+
+ mbedtls_x509write_crt_free(&cert);
+
+ /* cleanup */
+cleanup:
+ mbedtls_mpi_free(&sn);
+ mbedtls_pk_free(&dev_public_key);
+ mbedtls_entropy_free(&entropy);
+ mbedtls_pk_free(&host_pkey);
+ mbedtls_pk_free(&root_pkey);
+ mbedtls_ctr_drbg_free(&ctr_drbg);
#endif
/* make sure that we have all we need */
@@ -783,32 +1045,31 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da
*
* @return 1 if the key was successfully imported.
*/
-#ifdef HAVE_OPENSSL
+#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)
-#else
+#elif defined(HAVE_GNUTLS)
userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const char* name, gnutls_x509_privkey_t key)
#endif
{
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS)
if (!key)
return USERPREF_E_SUCCESS;
#endif
userpref_error_t ret = USERPREF_E_INVALID_CONF;
-#ifdef HAVE_OPENSSL
- ret = pair_record_get_item_as_key_data(pair_record, name, key);
-#else
- key_data_t pem = { NULL, 0 };
- ret = pair_record_get_item_as_key_data(pair_record, name, &pem);
- if (ret == USERPREF_E_SUCCESS && GNUTLS_E_SUCCESS == gnutls_x509_privkey_import(key, &pem, GNUTLS_X509_FMT_PEM))
- ret = USERPREF_E_SUCCESS;
- else
- ret = USERPREF_E_SSL_ERROR;
-
- if (pem.data)
- free(pem.data);
-#endif
+#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS)
+ ret = pair_record_get_item_as_key_data(pair_record, name, key);
+#elif defined(HAVE_GNUTLS)
+ key_data_t pem = { NULL, 0 };
+ ret = pair_record_get_item_as_key_data(pair_record, name, &pem);
+ if (ret == USERPREF_E_SUCCESS && GNUTLS_E_SUCCESS == gnutls_x509_privkey_import(key, &pem, GNUTLS_X509_FMT_PEM))
+ ret = USERPREF_E_SUCCESS;
+ else
+ ret = USERPREF_E_SSL_ERROR;
+ if (pem.data)
+ free(pem.data);
+#endif
return ret;
}
@@ -820,32 +1081,31 @@ userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const cha
*
* @return IDEVICE_E_SUCCESS if the certificate was successfully imported.
*/
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS)
userpref_error_t pair_record_import_crt_with_name(plist_t pair_record, const char* name, key_data_t* cert)
#else
userpref_error_t pair_record_import_crt_with_name(plist_t pair_record, const char* name, gnutls_x509_crt_t cert)
#endif
{
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS)
if (!cert)
return USERPREF_E_SUCCESS;
#endif
userpref_error_t ret = USERPREF_E_INVALID_CONF;
-#ifdef HAVE_OPENSSL
- ret = pair_record_get_item_as_key_data(pair_record, name, cert);
-#else
- key_data_t pem = { NULL, 0 };
- ret = pair_record_get_item_as_key_data(pair_record, name, &pem);
- if (ret == USERPREF_E_SUCCESS && GNUTLS_E_SUCCESS == gnutls_x509_crt_import(cert, &pem, GNUTLS_X509_FMT_PEM))
- ret = USERPREF_E_SUCCESS;
- else
- ret = USERPREF_E_SSL_ERROR;
-
- if (pem.data)
- free(pem.data);
-#endif
+#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS)
+ ret = pair_record_get_item_as_key_data(pair_record, name, cert);
+#elif defined(HAVE_GNUTLS)
+ key_data_t pem = { NULL, 0 };
+ ret = pair_record_get_item_as_key_data(pair_record, name, &pem);
+ if (ret == USERPREF_E_SUCCESS && GNUTLS_E_SUCCESS == gnutls_x509_crt_import(cert, &pem, GNUTLS_X509_FMT_PEM))
+ ret = USERPREF_E_SUCCESS;
+ else
+ ret = USERPREF_E_SSL_ERROR;
+ if (pem.data)
+ free(pem.data);
+#endif
return ret;
}
@@ -880,9 +1140,10 @@ userpref_error_t pair_record_get_item_as_key_data(plist_t pair_record, const cha
if (node && plist_get_node_type(node) == PLIST_DATA) {
plist_get_data_val(node, &buffer, &length);
- value->data = (unsigned char*)malloc(length);
+ value->data = (unsigned char*)malloc(length+1);
memcpy(value->data, buffer, length);
- value->size = length;
+ value->data[length] = '\0';
+ value->size = length+1;
free(buffer);
buffer = NULL;
} else {
diff --git a/common/userpref.h b/common/userpref.h
index 4ea630f..75bb8b7 100644
--- a/common/userpref.h
+++ b/common/userpref.h
@@ -27,7 +27,7 @@
#include <config.h>
#endif
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS)
typedef struct {
unsigned char *data;
unsigned int size;
@@ -54,10 +54,11 @@ typedef gnutls_datum_t key_data_t;
typedef enum {
USERPREF_E_SUCCESS = 0,
USERPREF_E_INVALID_ARG = -1,
- USERPREF_E_INVALID_CONF = -2,
- USERPREF_E_SSL_ERROR = -3,
- USERPREF_E_READ_ERROR = -4,
- USERPREF_E_WRITE_ERROR = -5,
+ USERPREF_E_NOENT = -2,
+ USERPREF_E_INVALID_CONF = -3,
+ USERPREF_E_SSL_ERROR = -4,
+ USERPREF_E_READ_ERROR = -5,
+ USERPREF_E_WRITE_ERROR = -6,
USERPREF_E_UNKNOWN_ERROR = -256
} userpref_error_t;
@@ -68,7 +69,7 @@ userpref_error_t userpref_save_pair_record(const char *udid, uint32_t device_id,
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);
-#ifdef HAVE_OPENSSL
+#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);
#else
diff --git a/common/utils.c b/common/utils.c
deleted file mode 100644
index 58dac02..0000000
--- a/common/utils.c
+++ /dev/null
@@ -1,530 +0,0 @@
-/*
- * utils.c
- * Miscellaneous utilities for string manipulation,
- * file I/O and plist helper.
- *
- * Copyright (c) 2014-2019 Nikias Bassen, All Rights Reserved.
- * Copyright (c) 2013-2014 Martin Szulecki, All Rights Reserved.
- * Copyright (c) 2013 Federico Mena Quintero
- *
- * 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 <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <sys/time.h>
-#include <inttypes.h>
-#include <ctype.h>
-
-#include "utils.h"
-
-#ifndef HAVE_STPCPY
-/**
- * Copy characters from one string into another
- *
- * @note: The strings should not overlap, as the behavior is undefined.
- *
- * @s1: The source string.
- * @s2: The destination string.
- *
- * @return a pointer to the terminating `\0' character of @s1,
- * or NULL if @s1 or @s2 is NULL.
- */
-char *stpcpy(char *s1, const char *s2)
-{
- if (s1 == NULL || s2 == NULL)
- return NULL;
-
- strcpy(s1, s2);
-
- return s1 + strlen(s2);
-}
-#endif
-
-/**
- * Concatenate strings into a newly allocated string
- *
- * @note: Specify NULL for the last string in the varargs list
- *
- * @str: The first string in the list
- * @...: Subsequent strings. Use NULL for the last item.
- *
- * @return a newly allocated string, or NULL if @str is NULL. This will also
- * return NULL and set errno to ENOMEM if memory is exhausted.
- */
-char *string_concat(const char *str, ...)
-{
- size_t len;
- va_list args;
- char *s;
- char *result;
- char *dest;
-
- if (!str)
- return NULL;
-
- /* Compute final length */
-
- len = strlen(str) + 1; /* plus 1 for the null terminator */
-
- va_start(args, str);
- s = va_arg(args, char *);
- while (s) {
- len += strlen(s);
- s = va_arg(args, char*);
- }
- va_end(args);
-
- /* Concat each string */
-
- result = malloc(len);
- if (!result)
- return NULL; /* errno remains set */
-
- dest = result;
-
- dest = stpcpy(dest, str);
-
- va_start(args, str);
- s = va_arg(args, char *);
- while (s) {
- dest = stpcpy(dest, s);
- s = va_arg(args, char *);
- }
- va_end(args);
-
- return result;
-}
-
-char *string_append(char* str, ...)
-{
- size_t len = 0;
- size_t slen;
- va_list args;
- char *s;
- char *result;
- char *dest;
-
- /* Compute final length */
-
- if (str) {
- len = strlen(str);
- }
- slen = len;
- len++; /* plus 1 for the null terminator */
-
- va_start(args, str);
- s = va_arg(args, char *);
- while (s) {
- len += strlen(s);
- s = va_arg(args, char*);
- }
- va_end(args);
-
- result = realloc(str, len);
- if (!result)
- return NULL; /* errno remains set */
-
- dest = result + slen;
-
- /* Concat additional strings */
-
- va_start(args, str);
- s = va_arg(args, char *);
- while (s) {
- dest = stpcpy(dest, s);
- s = va_arg(args, char *);
- }
- va_end(args);
-
- return result;
-}
-
-char *string_build_path(const char *elem, ...)
-{
- if (!elem)
- return NULL;
- va_list args;
- int len = strlen(elem)+1;
- va_start(args, elem);
- char *arg = va_arg(args, char*);
- while (arg) {
- len += strlen(arg)+1;
- arg = va_arg(args, char*);
- }
- va_end(args);
-
- char* out = (char*)malloc(len);
- strcpy(out, elem);
-
- va_start(args, elem);
- arg = va_arg(args, char*);
- while (arg) {
- strcat(out, "/");
- strcat(out, arg);
- arg = va_arg(args, char*);
- }
- va_end(args);
- return out;
-}
-
-char *string_format_size(uint64_t size)
-{
- char buf[80];
- double sz;
- if (size >= 1000000000000LL) {
- sz = ((double)size / 1000000000000.0f);
- sprintf(buf, "%0.1f TB", sz);
- } else if (size >= 1000000000LL) {
- sz = ((double)size / 1000000000.0f);
- sprintf(buf, "%0.1f GB", sz);
- } else if (size >= 1000000LL) {
- sz = ((double)size / 1000000.0f);
- sprintf(buf, "%0.1f MB", sz);
- } else if (size >= 1000LL) {
- sz = ((double)size / 1000.0f);
- sprintf(buf, "%0.1f KB", sz);
- } else {
- sprintf(buf, "%d Bytes", (int)size);
- }
- return strdup(buf);
-}
-
-char *string_toupper(char* str)
-{
- char *res = strdup(str);
- unsigned int i;
- for (i = 0; i < strlen(res); i++) {
- res[i] = toupper(res[i]);
- }
- return res;
-}
-
-static int get_rand(int min, int max)
-{
- int retval = (rand() % (max - min)) + min;
- return retval;
-}
-
-char *generate_uuid()
-{
- const char *chars = "ABCDEF0123456789";
- int i = 0;
- char *uuid = (char *) malloc(sizeof(char) * 37);
-
- srand(time(NULL));
-
- for (i = 0; i < 36; i++) {
- if (i == 8 || i == 13 || i == 18 || i == 23) {
- uuid[i] = '-';
- continue;
- } else {
- uuid[i] = chars[get_rand(0, 16)];
- }
- }
-
- /* make it a real string */
- uuid[36] = '\0';
-
- return uuid;
-}
-
-void buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length)
-{
- FILE *f;
- uint64_t size;
-
- *length = 0;
-
- f = fopen(filename, "rb");
- if (!f) {
- return;
- }
-
- fseek(f, 0, SEEK_END);
- size = ftell(f);
- rewind(f);
-
- if (size == 0) {
- fclose(f);
- return;
- }
-
- *buffer = (char*)malloc(sizeof(char)*(size+1));
- if (fread(*buffer, sizeof(char), size, f) != size) {
- fclose(f);
- return;
- }
- fclose(f);
-
- *length = size;
-}
-
-void buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length)
-{
- FILE *f;
-
- f = fopen(filename, "wb");
- if (f) {
- fwrite(buffer, sizeof(char), length, f);
- fclose(f);
- }
-}
-
-int plist_read_from_filename(plist_t *plist, const char *filename)
-{
- char *buffer = NULL;
- uint64_t length;
-
- if (!filename)
- return 0;
-
- buffer_read_from_filename(filename, &buffer, &length);
-
- if (!buffer) {
- return 0;
- }
-
- if ((length > 8) && (memcmp(buffer, "bplist00", 8) == 0)) {
- plist_from_bin(buffer, length, plist);
- } else {
- plist_from_xml(buffer, length, plist);
- }
-
- free(buffer);
-
- return 1;
-}
-
-int plist_write_to_filename(plist_t plist, const char *filename, enum plist_format_t format)
-{
- char *buffer = NULL;
- uint32_t length;
-
- if (!plist || !filename)
- return 0;
-
- if (format == PLIST_FORMAT_XML)
- plist_to_xml(plist, &buffer, &length);
- else if (format == PLIST_FORMAT_BINARY)
- plist_to_bin(plist, &buffer, &length);
- else
- return 0;
-
- buffer_write_to_filename(filename, buffer, length);
-
- free(buffer);
-
- return 1;
-}
-
-static const char base64_str[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-static const char base64_pad = '=';
-
-static char *base64encode(const unsigned char *buf, size_t size)
-{
- if (!buf || !(size > 0)) return NULL;
- int outlen = (size / 3) * 4;
- char *outbuf = (char*)malloc(outlen+5); // 4 spare bytes + 1 for '\0'
- size_t n = 0;
- size_t m = 0;
- unsigned char input[3];
- unsigned int output[4];
- while (n < size) {
- input[0] = buf[n];
- input[1] = (n+1 < size) ? buf[n+1] : 0;
- input[2] = (n+2 < size) ? buf[n+2] : 0;
- output[0] = input[0] >> 2;
- output[1] = ((input[0] & 3) << 4) + (input[1] >> 4);
- output[2] = ((input[1] & 15) << 2) + (input[2] >> 6);
- output[3] = input[2] & 63;
- outbuf[m++] = base64_str[(int)output[0]];
- outbuf[m++] = base64_str[(int)output[1]];
- outbuf[m++] = (n+1 < size) ? base64_str[(int)output[2]] : base64_pad;
- outbuf[m++] = (n+2 < size) ? base64_str[(int)output[3]] : base64_pad;
- n+=3;
- }
- outbuf[m] = 0; // 0-termination!
- return outbuf;
-}
-
-static void plist_node_print_to_stream(plist_t node, int* indent_level, FILE* stream);
-
-static void plist_array_print_to_stream(plist_t node, int* indent_level, FILE* stream)
-{
- /* iterate over items */
- int i, count;
- plist_t subnode = NULL;
-
- count = plist_array_get_size(node);
-
- for (i = 0; i < count; i++) {
- subnode = plist_array_get_item(node, i);
- fprintf(stream, "%*s", *indent_level, "");
- fprintf(stream, "%d: ", i);
- plist_node_print_to_stream(subnode, indent_level, stream);
- }
-}
-
-static void plist_dict_print_to_stream(plist_t node, int* indent_level, FILE* stream)
-{
- /* iterate over key/value pairs */
- plist_dict_iter it = NULL;
-
- char* key = NULL;
- plist_t subnode = NULL;
- plist_dict_new_iter(node, &it);
- plist_dict_next_item(node, it, &key, &subnode);
- while (subnode)
- {
- fprintf(stream, "%*s", *indent_level, "");
- fprintf(stream, "%s", key);
- if (plist_get_node_type(subnode) == PLIST_ARRAY)
- fprintf(stream, "[%d]: ", plist_array_get_size(subnode));
- else
- fprintf(stream, ": ");
- free(key);
- key = NULL;
- plist_node_print_to_stream(subnode, indent_level, stream);
- plist_dict_next_item(node, it, &key, &subnode);
- }
- free(it);
-}
-
-static void plist_node_print_to_stream(plist_t node, int* indent_level, FILE* stream)
-{
- char *s = NULL;
- char *data = NULL;
- double d;
- uint8_t b;
- uint64_t u = 0;
- struct timeval tv = { 0, 0 };
-
- plist_type t;
-
- if (!node)
- return;
-
- t = plist_get_node_type(node);
-
- switch (t) {
- case PLIST_BOOLEAN:
- plist_get_bool_val(node, &b);
- fprintf(stream, "%s\n", (b ? "true" : "false"));
- break;
-
- case PLIST_UINT:
- plist_get_uint_val(node, &u);
- fprintf(stream, "%"PRIu64"\n", u);
- break;
-
- case PLIST_REAL:
- plist_get_real_val(node, &d);
- fprintf(stream, "%f\n", d);
- break;
-
- case PLIST_STRING:
- plist_get_string_val(node, &s);
- fprintf(stream, "%s\n", s);
- free(s);
- break;
-
- case PLIST_KEY:
- plist_get_key_val(node, &s);
- fprintf(stream, "%s: ", s);
- free(s);
- break;
-
- case PLIST_DATA:
- plist_get_data_val(node, &data, &u);
- if (u > 0) {
- s = base64encode((unsigned char*)data, u);
- free(data);
- if (s) {
- fprintf(stream, "%s\n", s);
- free(s);
- } else {
- fprintf(stream, "\n");
- }
- } else {
- fprintf(stream, "\n");
- }
- break;
-
- case PLIST_DATE:
- plist_get_date_val(node, (int32_t*)&tv.tv_sec, (int32_t*)&tv.tv_usec);
- {
- time_t ti = (time_t)tv.tv_sec + MAC_EPOCH;
- struct tm *btime = localtime(&ti);
- if (btime) {
- s = (char*)malloc(24);
- memset(s, 0, 24);
- if (strftime(s, 24, "%Y-%m-%dT%H:%M:%SZ", btime) <= 0) {
- free (s);
- s = NULL;
- }
- }
- }
- if (s) {
- fprintf(stream, "%s\n", s);
- free(s);
- } else {
- fprintf(stream, "\n");
- }
- break;
-
- case PLIST_ARRAY:
- fprintf(stream, "\n");
- (*indent_level)++;
- plist_array_print_to_stream(node, indent_level, stream);
- (*indent_level)--;
- break;
-
- case PLIST_DICT:
- fprintf(stream, "\n");
- (*indent_level)++;
- plist_dict_print_to_stream(node, indent_level, stream);
- (*indent_level)--;
- break;
-
- default:
- break;
- }
-}
-
-void plist_print_to_stream(plist_t plist, FILE* stream)
-{
- int indent = 0;
-
- if (!plist || !stream)
- return;
-
- switch (plist_get_node_type(plist)) {
- case PLIST_DICT:
- plist_dict_print_to_stream(plist, &indent, stream);
- break;
- case PLIST_ARRAY:
- plist_array_print_to_stream(plist, &indent, stream);
- break;
- default:
- plist_node_print_to_stream(plist, &indent, stream);
- }
-}
diff --git a/common/utils.h b/common/utils.h
deleted file mode 100644
index 2c3acec..0000000
--- a/common/utils.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * utils.h
- * Miscellaneous utilities for string manipulation,
- * file I/O and plist helper.
- *
- * Copyright (c) 2014-2019 Nikias Bassen, All Rights Reserved.
- * Copyright (c) 2013-2014 Martin Szulecki, All Rights Reserved.
- * Copyright (c) 2013 Federico Mena Quintero
- *
- * 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 __UTILS_H
-#define __UTILS_H
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#ifdef WIN32
-#include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <plist/plist.h>
-
-#define MAC_EPOCH 978307200
-
-#ifndef HAVE_STPCPY
-char *stpcpy(char *s1, const char *s2);
-#endif
-char *string_concat(const char *str, ...);
-char *string_append(char *str, ...);
-char *string_build_path(const char *elem, ...);
-char *string_format_size(uint64_t size);
-char *string_toupper(char *str);
-char *generate_uuid(void);
-
-void buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length);
-void buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length);
-
-enum plist_format_t {
- PLIST_FORMAT_XML,
- PLIST_FORMAT_BINARY
-};
-
-int plist_read_from_filename(plist_t *plist, const char *filename);
-int plist_write_to_filename(plist_t plist, const char *filename, enum plist_format_t format);
-
-void plist_print_to_stream(plist_t plist, FILE* stream);
-
-#endif
diff --git a/configure.ac b/configure.ac
index 82038e1..9856ae2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,8 +1,8 @@
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
-AC_PREREQ(2.64)
-AC_INIT([libimobiledevice], [1.3.1], [https://github.com/libimobiledevice/libimobiledevice/issues],, [https://libimobiledevice.org])
+AC_PREREQ([2.68])
+AC_INIT([libimobiledevice], [m4_esyscmd(./git-version-gen $RELEASE_VERSION)], [https://github.com/libimobiledevice/libimobiledevice/issues], [], [https://libimobiledevice.org])
AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip check-news])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES])
AC_CONFIG_SRCDIR([src/])
@@ -17,27 +17,47 @@ dnl libtool versioning
# CURRENT : REVISION : AGE
LIBIMOBILEDEVICE_SO_VERSION=6:0:0
+AC_SUBST(LIBIMOBILEDEVICE_SO_VERSION)
+
+# Check if we have a version defined
+if test -z $PACKAGE_VERSION; then
+ AC_MSG_ERROR([PACKAGE_VERSION is not defined. Make sure to configure a source tree checked out from git or that .tarball-version is present.])
+fi
+
dnl Minimum package versions
LIBUSBMUXD_VERSION=2.0.2
-LIBPLIST_VERSION=2.2.0
+LIBPLIST_VERSION=2.3.0
+LIMD_GLUE_VERSION=1.0.0
-AC_SUBST(LIBIMOBILEDEVICE_SO_VERSION)
AC_SUBST(LIBUSBMUXD_VERSION)
AC_SUBST(LIBPLIST_VERSION)
+AC_SUBST(LIMD_GLUE_VERSION)
# Checks for programs.
AC_PROG_CC
AC_PROG_CXX
AM_PROG_CC_C_O
-AC_PROG_LIBTOOL
+LT_INIT
# Checks for libraries.
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)
+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_HEADER_STDC
-AC_CHECK_HEADERS([stdint.h stdlib.h string.h gcrypt.h])
+AC_CHECK_HEADERS([stdint.h stdlib.h string.h sys/time.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
@@ -62,6 +82,8 @@ if test "x$ac_cv_have_endian_h" = "xno"; then
fi
fi
+AC_CHECK_DECL([plist_from_json], [AC_DEFINE([HAVE_PLIST_JSON], [1], [Define if libplist has JSON support])], [], [[#include <plist/plist.h>]])
+
# Check for operating system
AC_MSG_CHECKING([for platform-specific build settings])
case ${host_os} in
@@ -72,6 +94,7 @@ case ${host_os} in
;;
darwin*)
AC_MSG_RESULT([${host_os}])
+ darwin=true
;;
*)
AC_MSG_RESULT([${host_os}])
@@ -80,6 +103,25 @@ case ${host_os} in
;;
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>])
@@ -90,9 +132,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"
@@ -128,44 +170,135 @@ fi
AM_CONDITIONAL([HAVE_CYTHON],[test "x$CYTHON_SUB" = "xcython"])
AC_SUBST([CYTHON_SUB])
-AC_ARG_ENABLE([openssl],
- [AS_HELP_STRING([--disable-openssl],
+default_openssl=yes
+
+AC_ARG_WITH([mbedtls],
+ [AS_HELP_STRING([--without-mbedtls],
+ [Do not look for mbedtls])],
+ [use_mbedtls=$withval],
+ [use_mbedtls=no])
+if test "x$use_mbedtls" = "xyes"; then
+ default_openssl=no
+fi
+AC_ARG_WITH([gnutls],
+ [AS_HELP_STRING([--without-gnutls],
+ [Do not look for GnuTLS])],
+ [use_gnutls=$withval],
+ [use_gnutls=no])
+if test "x$use_gnutls" = "xyes"; then
+ default_openssl=no
+fi
+AC_ARG_WITH([openssl],
+ [AS_HELP_STRING([--without-openssl],
[Do not look for OpenSSL])],
- [use_openssl=$enableval],
- [use_openssl=yes])
-
-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
- if test "x$use_openssl" != "xyes"; then
- enable_openssl=no
- echo "*** Note: OpenSSL support explicitly disabled ***"
+ [use_openssl=$withval],
+ [use_openssl=$default_openssl])
+
+if test "x$use_mbedtls" = "xyes"; then
+ CACHED_CFLAGS="$CFLAGS"
+ conf_mbedtls_CFLAGS=""
+ if test -n "$mbedtls_INCLUDES"; then
+ CFLAGS=" -I$mbedtls_INCLUDES"
+ conf_mbedtls_CFLAGS="-I$mbedtls_INCLUDES"
+ fi
+ conf_mbedtls_LIBS=""
+ if test -n "$mbedtls_LIBDIR"; then
+ conf_mbedtls_LIBS+=" -L$mbedtls_LIBDIR"
+ fi
+ if test -n "$mbedtls_LIBS"; then
+ conf_mbedtls_LIBS+=" $mbedtls_LIBS"
else
- enable_openssl=yes
+ conf_mbedtls_LIBS+=" -lmbedtls -lmbedx509 -lmbedcrypto"
fi
+ AC_CHECK_HEADER(mbedtls/ssl.h, [break], [AC_MSG_ERROR([MbedTLS support explicitly requested, but includes could not be found. Try setting mbedtls_INCLUDES=/path/to/mbedtls/include])])
+ CFLAGS="$CACHED_CFLAGS"
+ AC_DEFINE(HAVE_MBEDTLS, 1, [Define if you have MbedTLS support])
+ ssl_lib_CFLAGS="$conf_mbedtls_CFLAGS"
+ ssl_lib_LIBS="$conf_mbedtls_LIBS"
+ AC_SUBST(ssl_lib_CFLAGS)
+ AC_SUBST(ssl_lib_LIBS)
+ ssl_provider="MbedTLS";
+ ssl_requires=""
+ AC_SUBST(ssl_requires)
else
- if test "x$use_openssl" == "xyes" -a "x$have_openssl" != "xyes"; then
- AC_MSG_ERROR([OpenSSL support explicitly requested but OpenSSL could not be found])
+ 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
+ AC_MSG_ERROR([OpenSSL support explicitly requested but OpenSSL could not be found])
+ else
+ AC_DEFINE(HAVE_OPENSSL, 1, [Define if you have OpenSSL support])
+ ssl_lib_CFLAGS="$openssl_CFLAGS"
+ ssl_lib_LIBS="$openssl_LIBS"
+ AC_SUBST(ssl_lib_CFLAGS)
+ 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
+ pkg_req_gnutls="gnutls >= 2.2.0"
+ pkg_req_libtasn1="libtasn1 >= 1.1"
+ PKG_CHECK_MODULES(libgnutls, $pkg_req_gnutls)
+ AC_CHECK_HEADERS([gcrypt.h])
+ AC_CHECK_LIB(gcrypt, gcry_control, [AC_SUBST(libgcrypt_LIBS,[-lgcrypt])], [AC_MSG_ERROR([libgcrypt is required to build libimobiledevice with GnuTLS])])
+ PKG_CHECK_MODULES(libtasn1, $pkg_req_libtasn1)
+ AC_DEFINE(HAVE_GCRYPT, 1, [Define if you have libgcrypt support])
+ AC_DEFINE(HAVE_GNUTLS, 1, [Define if you have GnuTLS support])
+ ssl_lib_CFLAGS="$libgnutls_CFLAGS $libtasn1_CFLAGS $libgcrypt_CFLAGS"
+ ssl_lib_LIBS="$libgnutls_LIBS $libtasn1_LIBS $libgcrypt_LIBS"
+ AC_SUBST(ssl_lib_CFLAGS)
+ AC_SUBST(ssl_lib_LIBS)
+ ssl_provider="GnuTLS"
+ ssl_requires="$pkg_req_gnutls $pkg_req_libtasn1"
+ AC_SUBST(ssl_requires)
+ else
+ AC_MSG_ERROR([No SSL library configured. $PACKAGE cannot be built without a supported SSL library.])
+ 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")
-if test "x$enable_openssl" = "xyes"; then
- AC_DEFINE(HAVE_OPENSSL, 1, [Define if you have OpenSSL support])
- AC_SUBST(openssl_CFLAGS)
- AC_SUBST(openssl_LIBS)
- ssl_provider="OpenSSL";
- ssl_requires="$pkg_req_openssl"
- AC_SUBST(ssl_requires)
-else
- pkg_req_gnutls="gnutls >= 2.2.0"
- pkg_req_libtasn1="libtasn1 >= 1.1"
- PKG_CHECK_MODULES(libgnutls, $pkg_req_gnutls)
- AC_CHECK_LIB(gcrypt, gcry_control, [AC_SUBST(libgcrypt_LIBS,[-lgcrypt])], [AC_MSG_ERROR([libgcrypt is required to build libimobiledevice with GnuTLS])])
- PKG_CHECK_MODULES(libtasn1, $pkg_req_libtasn1)
- ssl_provider="GnuTLS"
- ssl_requires="$pkg_req_gnutls $pkg_req_libtasn1"
- AC_SUBST(ssl_requires)
+AC_ARG_ENABLE([wireless-pairing],
+ [AS_HELP_STRING([--disable-wireless-pairing],
+ [Do not build with wirless pairing support (default is yes)])])
+if test "$enable_wireless_pairing" != "no"; then
+ AC_DEFINE(HAVE_WIRELESS_PAIRING,1,[Define if building with wireless pairing support])
fi
+AM_CONDITIONAL(HAVE_WIRELESS_PAIRING, test "$enable_wireless_pairing" != "no")
AC_ARG_ENABLE([debug],
[AS_HELP_STRING([--enable-debug],
@@ -180,20 +313,23 @@ 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
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
-AC_OUTPUT([
+AC_CONFIG_FILES([
Makefile
+3rd_party/Makefile
+3rd_party/ed25519/Makefile
+3rd_party/libsrp6a-sha512/Makefile
common/Makefile
src/Makefile
src/libimobiledevice-1.0.pc
@@ -203,6 +339,7 @@ cython/Makefile
docs/Makefile
doxygen.cfg
])
+AC_OUTPUT
echo "
Configuration for $PACKAGE $VERSION:
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/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/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 5ed81fe..4a4c56f 100644
--- a/docs/Makefile.am
+++ b/docs/Makefile.am
@@ -1,6 +1,7 @@
man_MANS = \
idevice_id.1 \
ideviceinfo.1 \
+ idevicebtlogger.1 \
idevicesyslog.1 \
idevicebackup.1 \
idevicebackup2.1 \
@@ -15,6 +16,7 @@ man_MANS = \
idevicecrashreport.1 \
idevicename.1 \
idevicedebug.1 \
+ idevicedevmodectl.1 \
idevicenotificationproxy.1 \
idevicesetlocation.1
diff --git a/docs/afcclient.1 b/docs/afcclient.1
new file mode 100644
index 0000000..ca7cb86
--- /dev/null
+++ b/docs/afcclient.1
@@ -0,0 +1,76 @@
+.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 PATH
+remove item at PATH
+.TP
+.B get 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.
+\f[B]WARNING\f[]: Existing files will be overwritten!
+.TP
+.B put 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.
+\f[B]WARNING\f[]: Existing files will be overwritten!
+.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/idevicebackup.1 b/docs/idevicebackup.1
index 3a40f5f..6f2a8f9 100644
--- a/docs/idevicebackup.1
+++ b/docs/idevicebackup.1
@@ -7,7 +7,7 @@ idevicebackup \- Create or restore backup for devices.
.SH DESCRIPTION
-Create or restore backup from the current or specified directory.
+Create or restore backup in/from the specified directory.
\f[B]NOTE\f[]: This tool is outdated. See idevicebackup2(1) for an updated tool.
diff --git a/docs/idevicebackup2.1 b/docs/idevicebackup2.1
index ba5ef53..79b6dc4 100644
--- a/docs/idevicebackup2.1
+++ b/docs/idevicebackup2.1
@@ -7,7 +7,7 @@ idevicebackup2 \- Create or restore backups for devices running iOS 4 or later.
.SH DESCRIPTION
-Create or restore backup from the current or specified directory.
+Create or restore backup in/from the specified directory.
.SH OPTIONS
.TP
@@ -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.
@@ -62,7 +62,9 @@ remove items which are not being restored.
do not trigger re-installation of apps after restore.
.TP
.B \t\-\-password PWD
-supply the password of the source backup.
+supply the password for the encrypted source backup. If omitted, the password
+will be requested in interactive mode (\f[B]\-i\f[]), or it can be passed using
+the environment variable \f[B]BACKUP_PASSWORD\f[].
.TP
.B info
show details about last completed backup of device.
@@ -74,13 +76,23 @@ list files of last completed backup in CSV format.
unpack a completed backup in DIRECTORY/_unback_/
.TP
.B encryption on|off [PWD]
-enable or disable backup encryption.
+enable or disable backup encryption. The password will be requested in
+interactive mode (\f[B]\-i\f[]) if omitted, or it can be passed using the
+environment variable \f[B]BACKUP_PASSWORD\f[].
.TP
.B changepw [OLD NEW]
-change backup password on target device.
+change backup password on target device. The passwords will be requested in
+interactive mode (\f[B]\-i\f[]) if omitted, or they can be passed using the
+environment variables \f[B]BACKUP_PASSWORD\f[] (old password) and
+\f[B]BACKUP_PASSWORD_NEW\f[] (new password) respectively.
.TP
.B cloud on|off
enable or disable cloud use (requires iCloud account).
+.SH SECURITY CONSIDERATIONS
+Passing passwords on the command line is not advised, since it might reveal
+the backup password to other users via process list or command line history.
+Use interactive mode (\f[B]\-i\f[]) or pass them via environment variable(s)
+as mentioned in the description of the respective commands above.
.SH AUTHORS
Martin Szulecki
diff --git a/docs/idevicebtlogger.1 b/docs/idevicebtlogger.1
new file mode 100644
index 0000000..98a723f
--- /dev/null
+++ b/docs/idevicebtlogger.1
@@ -0,0 +1,60 @@
+.TH "idevicebtlogger" 1
+.SH NAME
+idevicebtlogger \- Capture HCI traffic of a connected device.
+.SH SYNOPSIS
+.B idevicebtlogger
+[OPTIONS]
+<FILE>
+
+.SH DESCRIPTION
+
+Capture HCI traffic of a connected device. Requires Bluetooth logging profile to be installed on device with iOS 13 or higher. See https://www.bluetooth.com/blog/a-new-way-to-debug-iosbluetooth-applications/ for iOS device configuration.
+
+The HCI traffic can be stored in Apple's native PacketLogger format or converted into PCAP format for live feedback in Wireshark.
+
+.SH OPTIONS
+.TP
+.B \-u, \-\-udid UDID
+target specific device by UDID
+.TP
+.B \-n, \-\-network
+connect to network device
+.TP
+.B \-f, \-\-format FORMAT
+set log format: PacketLogger (default), or pcap
+.TP
+.B \-x, \-\-exit
+exit when device disconnects
+.TP
+.B \-d, \-\-debug
+enable communication debugging
+.TP
+.B \-h, \-\-help
+prints usage information
+.TP
+.B \-v, \-\-version
+prints version information.
+
+.SH EXAMPLES
+.TP
+.B idevicebtlogger \-u 00008030\-0000111ABC000DEF
+Capture HCI traffic of device with UDID 00008030-0000111ABC000DEF.
+.TP
+.B idevicebtlogger \-x
+Capture HCI traffic of device and exit when the device is unplugged.
+.TP
+.B idevicebtlogger \-f pcap
+Capture HCI traffic of device in PCAP format.
+.TP
+.B idevicebtlogger -f pcap - | wireshark -k -i -
+Capture HCI traffic and pipe it into Wireshark for live feedback.
+
+.SH AUTHORS
+Geoffrey Kruse
+
+Matthias Ringwald
+
+.SH ON THE WEB
+https://libimobiledevice.org
+
+https://github.com/libimobiledevice/libimobiledevice
diff --git a/docs/idevicecrashreport.1 b/docs/idevicecrashreport.1
index aba806a..6acd6e9 100644
--- a/docs/idevicecrashreport.1
+++ b/docs/idevicecrashreport.1
@@ -30,6 +30,9 @@ copy but do not remove crash reports from device.
.B \-d, \-\-debug
enable communication debugging.
.TP
+.B \-f, \-\-filter NAME
+filter crash reports by NAME (case sensitive)
+.TP
.B \-h, \-\-help
prints usage information.
.TP
diff --git a/docs/idevicedebugserverproxy.1 b/docs/idevicedebugserverproxy.1
index 37502eb..69200ee 100644
--- a/docs/idevicedebugserverproxy.1
+++ b/docs/idevicedebugserverproxy.1
@@ -3,7 +3,7 @@
idevicedebugserverproxy \- Remote debugging proxy.
.SH SYNOPSIS
.B idevicedebugserverproxy
-[OPTIONS] PORT
+[OPTIONS] [PORT]
.SH DESCRIPTION
@@ -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
@@ -35,6 +38,7 @@ prints version information.
.TP
.B PORT
The port under which the proxy should listen for connections from clients.
+If omitted, the next available port will be used and printed to stdout.
.SH AUTHORS
Martin Szulecki
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/idevicepair.1 b/docs/idevicepair.1
index 3576ce9..eb6e7d4 100644
--- a/docs/idevicepair.1
+++ b/docs/idevicepair.1
@@ -13,7 +13,13 @@ Manage host pairings with devices and usbmuxd.
.TP
.B \-u, \-\-udid UDID
target specific device by UDID.
-.TP
+.TP
+.B \-w, \-\-wireless
+perform wireless pairing (\f[B]see NOTE\f[]).
+.TP
+.B \-n, \-\-network
+connect to network device (\f[B]see NOTE\f[]).
+.TP
.B \-d, \-\-debug
enable communication debugging.
.TP
@@ -43,6 +49,24 @@ unpair device with this host.
.B list
list devices paired with this host.
+.SH NOTE
+Pairing over network (wireless pairing) is only supported by Apple TV
+devices. To perform a wireless pairing, you need to use the \f[B]\-w\f[]
+command line switch.
+
+Make sure to put the device into pairing mode first by opening
+Settings > Remotes and Devices > Remote App and Devices.
+
+The pairable device will become visible with a special UDID, and then you
+can run idevicepair like this:
+
+.B idevicepair -u fffc8:ab:cd:12:34:56fff -w pair
+
+idevicepair will then ask for the PIN that the device is displaying and
+continues with the pairing once entered.
+
+Please note that wireless pairing is currently not supported on Linux.
+
.SH AUTHORS
Nikias Bassen
diff --git a/docs/idevicesyslog.1 b/docs/idevicesyslog.1
index b7d4bab..66ae2e4 100644
--- a/docs/idevicesyslog.1
+++ b/docs/idevicesyslog.1
@@ -27,10 +27,17 @@ 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[].
.SH FILTER OPTIONS
.TP
diff --git a/doxygen.cfg.in b/doxygen.cfg.in
index 12b4ea2..4cbbb2d 100644
--- a/doxygen.cfg.in
+++ b/doxygen.cfg.in
@@ -93,14 +93,6 @@ ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English
-# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all generated output in the proper direction.
-# Possible values are: None, LTR, RTL and Context.
-# The default value is: None.
-
-OUTPUT_TEXT_DIRECTION = None
-
# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
# descriptions after the members that are listed in the file and class
# documentation (similar to Javadoc). Set to NO to disable this.
@@ -253,12 +245,6 @@ TAB_SIZE = 8
ALIASES =
-# This tag can be used to specify a number of word-keyword mappings (TCL only).
-# A mapping has the form "name=value". For example adding "class=itcl::class"
-# will allow you to use the command class in the itcl::class meaning.
-
-TCL_SUBST =
-
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
# only. Doxygen will then generate output that is more tailored for C. For
# instance, some of the names that are used will be different. The list of all
@@ -888,7 +874,7 @@ EXCLUDE_PATTERNS =
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories use the pattern */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
@@ -1069,13 +1055,6 @@ VERBATIM_HEADERS = NO
ALPHABETICAL_INDEX = NO
-# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
-# which the alphabetical index list will be split.
-# Minimum value: 1, maximum value: 20, default value: 5.
-# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
-
-COLS_IN_ALPHA_INDEX = 5
-
# 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
@@ -1708,7 +1687,7 @@ COMPACT_LATEX = NO
# The default value is: a4.
# This tag requires that the tag GENERATE_LATEX is set to YES.
-PAPER_TYPE = a4wide
+PAPER_TYPE = a4
# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
# that should be included in the LaTeX output. The package can be specified just
@@ -1801,16 +1780,6 @@ LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
-# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
-# code with syntax highlighting in the LaTeX output.
-#
-# Note that which sources are shown also depends on other settings such as
-# SOURCE_BROWSER.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_SOURCE_CODE = NO
-
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
# bibliography, e.g. plainnat, or ieeetr. See
# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
@@ -1891,16 +1860,6 @@ RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
-# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
-# with syntax highlighting in the RTF output.
-#
-# Note that which sources are shown also depends on other settings such as
-# SOURCE_BROWSER.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_SOURCE_CODE = NO
-
#---------------------------------------------------------------------------
# Configuration options related to the man page output
#---------------------------------------------------------------------------
@@ -1997,15 +1956,6 @@ GENERATE_DOCBOOK = NO
DOCBOOK_OUTPUT = docbook
-# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
-# program listings (including syntax highlighting and cross-referencing
-# information) to the DOCBOOK output. Note that enabling this will significantly
-# increase the size of the DOCBOOK output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
-
-DOCBOOK_PROGRAMLISTING = NO
-
#---------------------------------------------------------------------------
# Configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
@@ -2073,7 +2023,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
@@ -2081,7 +2031,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.
@@ -2122,7 +2072,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
@@ -2233,7 +2183,7 @@ DOT_NUM_THREADS = 0
# The default value is: Helvetica.
# This tag requires that the tag HAVE_DOT is set to YES.
-DOT_FONTNAME = FreeSans
+DOT_FONTNAME =
# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
# dot graphs.
diff --git a/git-version-gen b/git-version-gen
new file mode 100755
index 0000000..d868952
--- /dev/null
+++ b/git-version-gen
@@ -0,0 +1,20 @@
+#!/bin/sh
+SRCDIR=`dirname $0`
+if test -n "$1"; then
+ VER=$1
+else
+ 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`
+ DIRTY=`git diff --quiet HEAD || echo "-dirty"`
+ VER=`sed -n '1,/RE/s/Version \(.*\)/\1/p' ${SRCDIR}/NEWS`-git-${COMMIT}${DIRTY}
+ fi
+ else
+ if test -f "${SRCDIR}/.tarball-version"; then
+ VER=`cat "${SRCDIR}/.tarball-version"`
+ fi
+ fi
+fi
+VER=`printf %s "$VER" | head -n1`
+printf %s "$VER"
diff --git a/include/Makefile.am b/include/Makefile.am
index e23b2a9..2abaf49 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -26,5 +26,6 @@ nobase_include_HEADERS = \
libimobiledevice/mobileactivation.h \
libimobiledevice/preboard.h \
libimobiledevice/companion_proxy.h \
+ libimobiledevice/reverse_proxy.h \
libimobiledevice/property_list_service.h \
libimobiledevice/service.h
diff --git a/include/asprintf.h b/include/asprintf.h
index ce26aed..3ed35be 100644
--- a/include/asprintf.h
+++ b/include/asprintf.h
@@ -5,6 +5,8 @@
#include <config.h>
#endif
+#include <stdio.h>
+
#ifndef HAVE_VASPRINTF
static inline int vasprintf(char **PTR, const char *TEMPLATE, va_list AP)
{
diff --git a/include/endianness.h b/include/endianness.h
index 2d6ad0e..88b63db 100644
--- a/include/endianness.h
+++ b/include/endianness.h
@@ -31,6 +31,18 @@
#define htobe16 be16toh
#endif
+#ifndef le16toh
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define le16toh(x) ((((x) & 0xFF00) >> 8) | (((x) & 0x00FF) << 8))
+#else
+#define le16toh(x) (x)
+#endif
+#endif
+
+#ifndef htole16
+#define htole16 le16toh
+#endif
+
#ifndef __bswap_32
#define __bswap_32(x) ((((x) & 0xFF000000) >> 24) \
| (((x) & 0x00FF0000) >> 8) \
@@ -97,4 +109,15 @@
#define htole64 le64toh
#endif
+#if (defined(__BIG_ENDIAN__) \
+ && !defined(__FLOAT_WORD_ORDER__)) \
+ || (defined(__FLOAT_WORD_ORDER__) \
+ && __FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__)
+#define float_bswap64(x) __bswap_64(x)
+#define float_bswap32(x) __bswap_32(x)
+#else
+#define float_bswap64(x) (x)
+#define float_bswap32(x) (x)
+#endif
+
#endif /* ENDIANNESS_H */
diff --git a/include/libimobiledevice/afc.h b/include/libimobiledevice/afc.h
index b59b070..4ad3dbd 100644
--- a/include/libimobiledevice/afc.h
+++ b/include/libimobiledevice/afc.h
@@ -31,6 +31,7 @@ extern "C" {
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
+/** Service identifier passed to lockdownd_start_service() to start the AFC service */
#define AFC_SERVICE_NAME "com.apple.afc"
/** Error Codes */
@@ -89,7 +90,7 @@ typedef enum {
AFC_LOCK_UN = 8 | 4 /**< unlock */
} afc_lock_op_t;
-typedef struct afc_client_private afc_client_private;
+typedef struct afc_client_private afc_client_private; /**< \private */
typedef afc_client_private *afc_client_t; /**< The client handle. */
/* Interface */
@@ -106,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.
@@ -119,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,
@@ -127,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
@@ -141,7 +142,7 @@ 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);
/**
* Gets a directory listing of the directory requested.
@@ -154,7 +155,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.
@@ -167,7 +168,7 @@ afc_error_t afc_read_directory(afc_client_t client, const char *path, char ***di
*
* @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);
/**
* Opens a file on the device.
@@ -179,7 +180,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.
@@ -187,7 +188,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.
@@ -201,7 +202,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.
@@ -214,7 +215,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.
@@ -227,7 +228,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.
@@ -239,7 +240,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.
@@ -250,7 +251,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.
@@ -264,7 +265,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.
@@ -274,7 +275,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.
@@ -285,7 +286,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.
@@ -296,7 +297,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.
@@ -307,7 +308,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.
@@ -319,7 +320,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.
@@ -330,7 +331,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.
@@ -342,7 +343,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 */
@@ -357,7 +358,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.
@@ -366,7 +367,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
new file mode 100644
index 0000000..590e5c1
--- /dev/null
+++ b/include/libimobiledevice/bt_packet_logger.h
@@ -0,0 +1,156 @@
+/**
+ * @file libimobiledevice/bt_packet_logger.h
+ * @brief Capture the Bluetooth HCI trace from a device
+ * \internal
+ *
+ * Copyright (c) 2021 Geoffrey Kruse, All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef IBT_PACKET_LOGGER_H
+#define IBT_PACKET_LOGGER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libimobiledevice/libimobiledevice.h>
+#include <libimobiledevice/lockdown.h>
+
+#define BT_PACKETLOGGER_SERVICE_NAME "com.apple.bluetooth.BTPacketLogger"
+#define BT_MAX_PACKET_SIZE 65535
+
+/** Error Codes */
+typedef enum {
+ BT_PACKET_LOGGER_E_SUCCESS = 0,
+ BT_PACKET_LOGGER_E_INVALID_ARG = -1,
+ BT_PACKET_LOGGER_E_MUX_ERROR = -2,
+ BT_PACKET_LOGGER_E_SSL_ERROR = -3,
+ BT_PACKET_LOGGER_E_NOT_ENOUGH_DATA = -4,
+ BT_PACKET_LOGGER_E_TIMEOUT = -5,
+ BT_PACKET_LOGGER_E_UNKNOWN_ERROR = -256
+} bt_packet_logger_error_t;
+
+typedef struct {
+ uint32_t length;
+ uint32_t ts_secs;
+ uint32_t ts_usecs;
+} bt_packet_logger_header_t;
+
+typedef struct bt_packet_logger_client_private bt_packet_logger_client_private;
+typedef bt_packet_logger_client_private *bt_packet_logger_client_t; /**< The client handle. */
+
+/** Receives each hci packet received from the device. */
+typedef void (*bt_packet_logger_receive_cb_t)(uint8_t * data, uint16_t len, void *user_data);
+
+/* Interface */
+
+/**
+ * Connects to the bt_packet_logger 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
+ * bt_packet_logger_client_t upon successful return. Must be freed using
+ * bt_packet_logger_client_free() after use.
+ *
+ * @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.
+ */
+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.
+ *
+ * @param device The device to connect to.
+ * @param client Pointer that will point to a newly allocated
+ * bt_packet_logger_client_t upon successful return. Must be freed using
+ * bt_packet_logger_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 BT_PACKET_LOGGER_E_SUCCESS on success, or an BT_PACKET_LOGGER_E_* error
+ * code otherwise.
+ */
+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
+ * bt_packet_logger client data.
+ *
+ * @param client The bt_packet_logger client to disconnect and free.
+ *
+ * @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.
+ */
+LIBIMOBILEDEVICE_API bt_packet_logger_error_t bt_packet_logger_client_free(bt_packet_logger_client_t client);
+
+
+/**
+ * Starts capturing the hci interface from the device using a callback.
+ *
+ * Use bt_packet_logger_stop_capture() to stop receiving hci data.
+ *
+ * @param client The bt_packet_logger client to use
+ * @param callback Callback to receive each packet from the hci interface.
+ * @param user_data Custom pointer passed to the callback function.
+ *
+ * @return BT_PACKET_LOGGER_E_SUCCESS on success,
+ * BT_PACKET_LOGGER_E_INVALID_ARG when one or more parameters are
+ * invalid or BT_PACKET_LOGGER_E_UNKNOWN_ERROR when an unspecified
+ * error occurs or an hci capture has already been started.
+ */
+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.
+ *
+ * Use bt_packet_logger_start_capture() to start receiving the hci data.
+ *
+ * @param client The bt_packet_logger client to use
+ *
+ * @return BT_PACKET_LOGGER_E_SUCCESS on success,
+ * BT_PACKET_LOGGER_E_INVALID_ARG when one or more parameters are
+ * invalid or BT_PACKET_LOGGER_E_UNKNOWN_ERROR when an unspecified
+ * error occurs or an hci capture has already been started.
+ */
+LIBIMOBILEDEVICE_API bt_packet_logger_error_t bt_packet_logger_stop_capture(bt_packet_logger_client_t client);
+
+/* Receiving */
+
+/**
+ * Receives data using the given bt_packet_logger client with specified timeout.
+ *
+ * @param client The bt_packet_logger client to use for receiving
+ * @param data Buffer that will be filled with the data received
+ * @param size Number of bytes to receive
+ * @param received Number of bytes received (can be NULL to ignore)
+ * @param timeout Maximum time in milliseconds to wait for data.
+ *
+ * @return BT_PACKET_LOGGER_E_SUCCESS on success,
+ * BT_PACKET_LOGGER_E_INVALID_ARG when one or more parameters are
+ * invalid, BT_PACKET_LOGGER_E_MUX_ERROR when a communication error
+ * occurs, or BT_PACKET_LOGGER_E_UNKNOWN_ERROR when an unspecified
+ * error occurs.
+ */
+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
+}
+#endif
+
+#endif
diff --git a/include/libimobiledevice/companion_proxy.h b/include/libimobiledevice/companion_proxy.h
index 19c88eb..544322a 100644
--- a/include/libimobiledevice/companion_proxy.h
+++ b/include/libimobiledevice/companion_proxy.h
@@ -30,6 +30,7 @@ extern "C" {
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
+/** Service identifier passed to lockdownd_start_service() to start the companion proxy service */
#define COMPANION_PROXY_SERVICE_NAME "com.apple.companion_proxy"
/** Error Codes */
@@ -48,9 +49,10 @@ typedef enum {
COMPANION_PROXY_E_UNKNOWN_ERROR = -256
} companion_proxy_error_t;
-typedef struct companion_proxy_client_private companion_proxy_client_private;
+typedef struct companion_proxy_client_private companion_proxy_client_private; /**< \private */
typedef companion_proxy_client_private *companion_proxy_client_t; /**< The client handle. */
+/** Callback for companion device events */
typedef void (*companion_proxy_device_event_cb_t) (plist_t event, void* userdata);
/**
@@ -65,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.
@@ -80,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
@@ -91,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.
@@ -102,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.
@@ -113,13 +115,13 @@ 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.
*
* @param client The companion_proxy client
- * @param devices Point that will receive a PLIST_ARRAY with paired device UDIDs
+ * @param paired_devices Point that will receive a PLIST_ARRAY with paired device UDIDs
*
* @note The device closes the connection after sending the reply.
*
@@ -127,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.
@@ -143,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
@@ -153,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.
@@ -161,6 +163,8 @@ companion_proxy_error_t companion_proxy_stop_listening_for_devices(companion_pro
* @param client The companion_proxy client
* @param companion_udid UDID of the (paired) companion device
* @param key The key to retrieve the value for
+ * @param value A pointer to a plist_t that will receive the value for the given key.
+ * The consumer is responsible for freeing the value with plist_free() when no longer needed.
*
* @note The device closes the connection after sending the reply.
*
@@ -169,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.
@@ -186,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.
@@ -199,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 ce8176c..809b97f 100644
--- a/include/libimobiledevice/debugserver.h
+++ b/include/libimobiledevice/debugserver.h
@@ -30,7 +30,9 @@ extern "C" {
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
+/** Service identifier passed to lockdownd_start_service() to start the debugserver service */
#define DEBUGSERVER_SERVICE_NAME "com.apple.debugserver"
+/** Service identifier passed to lockdownd_start_service() to start the secure debugserver service */
#define DEBUGSERVER_SECURE_SERVICE_NAME DEBUGSERVER_SERVICE_NAME ".DVTSecureSocketProxy"
/** Error Codes */
@@ -44,10 +46,10 @@ typedef enum {
DEBUGSERVER_E_UNKNOWN_ERROR = -256
} debugserver_error_t;
-typedef struct debugserver_client_private debugserver_client_private;
+typedef struct debugserver_client_private debugserver_client_private; /**< \private */
typedef debugserver_client_private *debugserver_client_t; /**< The client handle. */
-typedef struct debugserver_command_private debugserver_command_private;
+typedef struct debugserver_command_private debugserver_command_private; /**< \private */
typedef debugserver_command_private *debugserver_command_t; /**< The command handle. */
/* Interface */
@@ -64,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.
@@ -79,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
@@ -90,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.
@@ -105,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.
@@ -119,10 +121,11 @@ debugserver_error_t debugserver_client_send(debugserver_client_t client, const c
* @return DEBUGSERVER_E_SUCCESS on success,
* DEBUGSERVER_E_INVALID_ARG when one or more parameters are
* invalid, DEBUGSERVER_E_MUX_ERROR when a communication error
- * occurs, or DEBUGSERVER_E_UNKNOWN_ERROR when an unspecified
+ * occurs, DEBUGSERVER_E_TIMEOUT when the timeout is reached,
+ * 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.
@@ -136,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.
@@ -149,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.
@@ -161,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.
@@ -175,7 +178,26 @@ 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.
+ *
+ * @see debugserver_client_send_command, debugserver_client_receive_response,
+ * debugserver_client_receive
+ *
+ * @param client The debugserver client
+ * @param cancel_receive A function pointer that will be called approximately
+ * every receive_loop_timeout milliseconds; the function should return a
+ * boolean flag specifying whether to stop waiting for a response. If NULL,
+ * behaves as if it always returns true.
+ * @param receive_loop_timeout Time in milliseconds between calls to
+ * cancel_receive.
+ *
+ * @return DEBUGSERVER_E_SUCCESS on success, or an DEBUGSERVER_E_* error
+ * code otherwise.
+ */
+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.
@@ -188,7 +210,7 @@ debugserver_error_t debugserver_client_set_ack_mode(debugserver_client_t client,
* @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.
@@ -200,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.
@@ -213,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.
@@ -223,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.
@@ -232,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.
@@ -241,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 d37ad74..6ab47a9 100644
--- a/include/libimobiledevice/diagnostics_relay.h
+++ b/include/libimobiledevice/diagnostics_relay.h
@@ -30,6 +30,7 @@ extern "C" {
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
+/** Service identifier passed to lockdownd_start_service() to start the diagnostics relay service */
#define DIAGNOSTICS_RELAY_SERVICE_NAME "com.apple.mobile.diagnostics_relay"
/** Error Codes */
@@ -42,18 +43,19 @@ typedef enum {
DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR = -256
} diagnostics_relay_error_t;
+/** Action type for #diagnostics_relay_restart and #diagnostics_relay_shutdown */
typedef enum {
DIAGNOSTICS_RELAY_ACTION_FLAG_WAIT_FOR_DISCONNECT = 1 << 1,
DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_PASS = 1 << 2,
DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_FAIL = 1 << 3
} diagnostics_relay_action_t;
-#define DIAGNOSTICS_RELAY_REQUEST_TYPE_ALL "All"
-#define DIAGNOSTICS_RELAY_REQUEST_TYPE_WIFI "WiFi"
-#define DIAGNOSTICS_RELAY_REQUEST_TYPE_GAS_GAUGE "GasGauge"
-#define DIAGNOSTICS_RELAY_REQUEST_TYPE_NAND "NAND"
+#define DIAGNOSTICS_RELAY_REQUEST_TYPE_ALL "All" /**< Query all available diagnostics */
+#define DIAGNOSTICS_RELAY_REQUEST_TYPE_WIFI "WiFi" /**< Query WiFi diagnostics */
+#define DIAGNOSTICS_RELAY_REQUEST_TYPE_GAS_GAUGE "GasGauge" /**< Query GasGauge diagnostics */
+#define DIAGNOSTICS_RELAY_REQUEST_TYPE_NAND "NAND" /**< Query NAND diagnostics */
-typedef struct diagnostics_relay_client_private diagnostics_relay_client_private;
+typedef struct diagnostics_relay_client_private diagnostics_relay_client_private; /**< \private */
typedef diagnostics_relay_client_private *diagnostics_relay_client_t; /**< The client handle. */
/**
@@ -68,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.
@@ -83,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
@@ -96,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);
/**
@@ -109,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.
@@ -121,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.
@@ -138,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.
@@ -155,30 +157,69 @@ 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);
/**
- * Shutdown of the device and optionally show a user notification.
+ * Request diagnostics information for a given type.
*
* @param client The diagnostics_relay client
- * @param flags A binary flag combination of
- * DIAGNOSTICS_RELAY_ACTION_FLAG_WAIT_FOR_DISCONNECT to wait until
- * diagnostics_relay_client_free() disconnects before execution and
- * DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_FAIL to show a "FAIL" dialog
- * or DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_PASS to show an "OK" dialog
+ * @param type The type or domain to query for diagnostics. Some known values
+ * are "All", "WiFi", "GasGauge", and "NAND".
+ * @param diagnostics A pointer to plist_t that will receive the diagnostics information.
+ * The consumer has to free the allocated memory with plist_free() when no longer needed.
*
* @return DIAGNOSTICS_RELAY_E_SUCCESS on success,
* DIAGNOSTICS_RELAY_E_INVALID_ARG when client is NULL,
* 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);
-diagnostics_relay_error_t diagnostics_relay_query_mobilegestalt(diagnostics_relay_client_t client, plist_t keys, plist_t* result);
+/**
+ * Query one or multiple MobileGestalt keys.
+ *
+ * @param client The diagnostics_relay client
+ * @param keys A PLIST_ARRAY with the keys to query.
+ * @param result A pointer to plist_t that will receive the result. The consumer
+ * has to free the allocated memory with plist_free() when no longer needed.
+ *
+ * @return DIAGNOSTICS_RELAY_E_SUCCESS on success,
+ * DIAGNOSTICS_RELAY_E_INVALID_ARG when client is NULL,
+ * DIAGNOSTICS_RELAY_E_PLIST_ERROR if the device did not acknowledge the
+ * request
+ */
+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_ioregistry_entry(diagnostics_relay_client_t client, const char* entry_name, const char* entry_class, plist_t* result);
+/**
+ * Query an IORegistry entry of a given class.
+ *
+ * @param client The diagnostics_relay client
+ * @param entry_name The IORegistry entry name to query.
+ * @param entry_class The IORegistry class to query.
+ * @param result A pointer to plist_t that will receive the result. The consumer
+ * has to free the allocated memory with plist_free() when no longer needed.
+ *
+ * @return DIAGNOSTICS_RELAY_E_SUCCESS on success,
+ * DIAGNOSTICS_RELAY_E_INVALID_ARG when client is NULL,
+ * DIAGNOSTICS_RELAY_E_PLIST_ERROR if the device did not acknowledge the
+ * request
+ */
+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_plane(diagnostics_relay_client_t client, const char* plane, plist_t* result);
+/**
+ * Query an IORegistry plane.
+ *
+ * @param client The diagnostics_relay client
+ * @param plane The IORegistry plane name to query.
+ * @param result A pointer to plist_t that will receive the result. The consumer
+ * has to free the allocated memory with plist_free() when no longer needed.
+ *
+ * @return DIAGNOSTICS_RELAY_E_SUCCESS on success,
+ * DIAGNOSTICS_RELAY_E_INVALID_ARG when client is NULL,
+ * DIAGNOSTICS_RELAY_E_PLIST_ERROR if the device did not acknowledge the
+ * request
+ */
+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 e41bb2d..00773b8 100644
--- a/include/libimobiledevice/file_relay.h
+++ b/include/libimobiledevice/file_relay.h
@@ -32,6 +32,7 @@ extern "C" {
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
+/** Service identifier passed to lockdownd_start_service() to start the file relay service */
#define FILE_RELAY_SERVICE_NAME "com.apple.mobile.file_relay"
/** Error Codes */
@@ -46,7 +47,7 @@ typedef enum {
FILE_RELAY_E_UNKNOWN_ERROR = -256
} file_relay_error_t;
-typedef struct file_relay_client_private file_relay_client_private;
+typedef struct file_relay_client_private file_relay_client_private; /**< \private */
typedef file_relay_client_private *file_relay_client_t; /**< The client handle. */
/**
@@ -61,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.
@@ -76,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
@@ -89,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);
/**
@@ -110,8 +111,7 @@ file_relay_error_t file_relay_client_free(file_relay_client_t client);
* data using idevice_connection_receive(). The connection will be closed
* automatically by the device, but use file_relay_client_free() to clean
* up properly.
- * @param timeout Maximum time in milliseconds to wait for data.
- *
+ *
* @note WARNING: Don't call this function without reading the data afterwards.
* A directory mobile_file_relay.XXXX used for creating the archive will
* remain in the /tmp directory otherwise.
@@ -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
@@ -144,6 +144,7 @@ file_relay_error_t file_relay_request_sources(file_relay_client_t client, const
* data using idevice_connection_receive(). The connection will be closed
* automatically by the device, but use file_relay_client_free() to clean
* up properly.
+ * @param timeout Maximum time in milliseconds to wait for data.
*
* @note WARNING: Don't call this function without reading the data afterwards.
* A directory mobile_file_relay.XXXX used for creating the archive will
@@ -156,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 1f5344a..4074b8b 100644
--- a/include/libimobiledevice/heartbeat.h
+++ b/include/libimobiledevice/heartbeat.h
@@ -30,6 +30,7 @@ extern "C" {
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
+/** Service identifier passed to lockdownd_start_service() to start the heartbeat service */
#define HEARTBEAT_SERVICE_NAME "com.apple.mobile.heartbeat"
/** Error Codes */
@@ -44,7 +45,7 @@ typedef enum {
HEARTBEAT_E_UNKNOWN_ERROR = -256
} heartbeat_error_t;
-typedef struct heartbeat_client_private heartbeat_client_private;
+typedef struct heartbeat_client_private heartbeat_client_private; /**< \private */
typedef heartbeat_client_private *heartbeat_client_t; /**< The client handle. */
/**
@@ -59,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.
@@ -74,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
@@ -85,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);
/**
@@ -97,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.
@@ -108,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.
@@ -116,7 +117,7 @@ heartbeat_error_t heartbeat_receive(heartbeat_client_t client, plist_t * plist);
* @param client The heartbeat client to use for receiving
* @param plist pointer to a plist_t that will point to the received plist
* upon successful return
- * @param timeout Maximum time in milliseconds to wait for data.
+ * @param timeout_ms Maximum time in milliseconds to wait for data.
*
* @return HEARTBEAT_E_SUCCESS on success,
* HEARTBEAT_E_INVALID_ARG when client or *plist is NULL,
@@ -127,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 5a42838..f9ba68a 100644
--- a/include/libimobiledevice/house_arrest.h
+++ b/include/libimobiledevice/house_arrest.h
@@ -32,6 +32,7 @@ extern "C" {
#include <libimobiledevice/lockdown.h>
#include <libimobiledevice/afc.h>
+/** Service identifier passed to lockdownd_start_service() to start the house arrest service */
#define HOUSE_ARREST_SERVICE_NAME "com.apple.mobile.house_arrest"
/** Error Codes */
@@ -44,7 +45,7 @@ typedef enum {
HOUSE_ARREST_E_UNKNOWN_ERROR = -256
} house_arrest_error_t;
-typedef struct house_arrest_client_private house_arrest_client_private;
+typedef struct house_arrest_client_private house_arrest_client_private; /**< \private */
typedef house_arrest_client_private *house_arrest_client_t; /**< The client handle. */
/* Interface */
@@ -60,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.
@@ -75,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
@@ -91,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);
/**
@@ -111,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.
@@ -132,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.
@@ -148,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);
/**
@@ -170,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 e96e224..44331aa 100644
--- a/include/libimobiledevice/installation_proxy.h
+++ b/include/libimobiledevice/installation_proxy.h
@@ -33,6 +33,7 @@ extern "C" {
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
+/** Service identifier passed to lockdownd_start_service() to start the installation proxy service */
#define INSTPROXY_SERVICE_NAME "com.apple.mobile.installation_proxy"
/** Error Codes */
@@ -107,7 +108,7 @@ typedef enum {
INSTPROXY_E_UNKNOWN_ERROR = -256
} instproxy_error_t;
-typedef struct instproxy_client_private instproxy_client_private;
+typedef struct instproxy_client_private instproxy_client_private; /**< \private */
typedef instproxy_client_private *instproxy_client_t; /**< The client handle. */
/** Reports the status response of the given command */
@@ -126,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.
@@ -141,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
@@ -152,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.
@@ -170,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.
@@ -189,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.
@@ -205,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.
@@ -231,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
@@ -259,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.
@@ -280,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.
@@ -296,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.
@@ -322,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.
@@ -346,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.
@@ -369,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.
@@ -385,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 */
@@ -395,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.
@@ -403,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.
@@ -419,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.
@@ -434,24 +435,24 @@ 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);
/**
* Gets progress in percentage from a status if available.
*
* @param status The dictionary status response to use.
- * @param name Pointer to store the progress in percent (0-100) or -1 if not
- * progress was found in the status.
+ * @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.
@@ -463,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.
@@ -473,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.
@@ -481,13 +482,13 @@ 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.
*
* @param client The connected installation proxy client.
- * @param appid ApplicationIdentifier of app to retrieve the path for.
+ * @param bundle_id ApplicationIdentifier of app to retrieve the path for.
* @param path Pointer to store the device path for the application
* which is set to NULL if it could not be determined.
*
@@ -495,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 e0aa518..a9d270b 100644
--- a/include/libimobiledevice/libimobiledevice.h
+++ b/include/libimobiledevice/libimobiledevice.h
@@ -35,6 +35,16 @@ extern "C" {
#include <sys/stat.h>
#include <plist/plist.h>
+#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,
@@ -42,14 +52,15 @@ typedef enum {
IDEVICE_E_UNKNOWN_ERROR = -2,
IDEVICE_E_NO_DEVICE = -3,
IDEVICE_E_NOT_ENOUGH_DATA = -4,
+ IDEVICE_E_CONNREFUSED = -5,
IDEVICE_E_SSL_ERROR = -6,
IDEVICE_E_TIMEOUT = -7
} idevice_error_t;
-typedef struct idevice_private idevice_private;
+typedef struct idevice_private idevice_private; /**< \private */
typedef idevice_private *idevice_t; /**< The device handle. */
-typedef struct idevice_connection_private idevice_connection_private;
+typedef struct idevice_connection_private idevice_connection_private; /**< \private */
typedef idevice_connection_private *idevice_connection_t; /**< The connection handle. */
/** Options for idevice_new_with_options() */
@@ -61,23 +72,24 @@ enum idevice_options {
/** Type of connection a device is available on */
enum idevice_connection_type {
- CONNECTION_USBMUXD = 1,
- CONNECTION_NETWORK
+ CONNECTION_USBMUXD = 1, /**< device is available via USBMUX */
+ CONNECTION_NETWORK /**< device is available via network */
};
+/** Device information returned by #idevice_get_device_list_extended API */
struct idevice_info {
- char *udid;
- enum idevice_connection_type conn_type;
- void* conn_data;
+ char *udid; /**< UDID of the device */
+ enum idevice_connection_type conn_type; /**< Type of connection the device is available on */
+ void* conn_data; /**< Connection data, depending on the connection type */
};
typedef struct idevice_info* idevice_info_t;
/* discovery (events/asynchronous) */
/** The event type for device add or removal */
enum idevice_event_type {
- IDEVICE_DEVICE_ADD = 1,
- IDEVICE_DEVICE_REMOVE,
- IDEVICE_DEVICE_PAIRED
+ IDEVICE_DEVICE_ADD = 1, /**< device was added */
+ IDEVICE_DEVICE_REMOVE, /**< device was removed */
+ IDEVICE_DEVICE_PAIRED /**< device completed pairing process */
};
/* event data structure */
@@ -92,6 +104,9 @@ typedef struct {
/** Callback to notifiy if a device was added or removed. */
typedef void (*idevice_event_cb_t) (const idevice_event_t *event, void *user_data);
+/** Event subscription context type */
+typedef struct idevice_subscription_context* idevice_subscription_context_t;
+
/* functions */
/**
@@ -99,27 +114,56 @@ typedef void (*idevice_event_cb_t) (const idevice_event_t *event, void *user_dat
*
* @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);
/**
- * Register a callback function that will be called when device add/remove
+ * Subscribe a callback function that will be called when device add/remove
* events occur.
*
+ * @param context A pointer to a idevice_subscription_context_t that will be
+ * set upon creation of the subscription. The returned context must be
+ * passed to idevice_events_unsubscribe() to unsubscribe the callback.
* @param callback Callback function to call.
* @param user_data Application-specific data passed as parameter
* to the registered callback function.
*
* @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_events_subscribe(idevice_subscription_context_t *context, idevice_event_cb_t callback, void *user_data);
/**
- * Release the event callback function that has been registered with
+ * Unsubscribe the event callback function that has been registered with
+ * idevice_events_subscribe().
+ *
+ * @param context A valid context as returned from idevice_events_subscribe().
+ *
+ * @return IDEVICE_E_SUCCESS on success or an error value when an error occurred.
+ */
+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
+ * events occur.
+ *
+ * @deprecated Use idevice_events_subscribe() instead.
+ *
+ * @param callback Callback function to call.
+ * @param user_data Application-specific data passed as parameter
+ * to the registered callback function.
+ *
+ * @return IDEVICE_E_SUCCESS on success or an error value when an error occurred.
+ */
+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
* idevice_event_subscribe().
*
+ * @deprecated Use idevice_events_unsubscribe() instead.
+ *
* @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) */
@@ -136,7 +180,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.
@@ -145,7 +189,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
@@ -156,7 +200,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().
@@ -165,7 +209,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 */
@@ -186,7 +230,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,
@@ -209,14 +253,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 */
@@ -230,7 +274,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.
@@ -239,7 +283,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 */
@@ -254,7 +298,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.
@@ -271,7 +315,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.
@@ -286,7 +330,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.
@@ -297,7 +341,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.
@@ -308,7 +352,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.
@@ -321,7 +365,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);
/**
@@ -332,19 +376,36 @@ 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 */
/**
- * Gets the handle or (usbmux device id) of the device.
+ * Gets the handle or (USBMUX device id) of the device.
+ *
+ * @param device The device to get the USBMUX device id for.
+ * @param handle Pointer to a uint32_t that will be set to the USBMUX handle value.
+ *
+ * @return IDEVICE_E_SUCCESS on success, otherwise an error code.
+ */
+LIBIMOBILEDEVICE_API idevice_error_t idevice_get_handle(idevice_t device, uint32_t *handle);
+
+/**
+ * Gets the Unique Device ID for the device.
+ *
+ * @param device The device to get the Unique Device ID for.
+ * @param udid Pointer that will be set to an allocated buffer with the device UDID. The consumer is responsible for releasing the allocated memory.
+ *
+ * @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_udid(idevice_t device, char **udid);
/**
- * Gets the unique id for the device.
+ * Returns a static string of the libimobiledevice version.
+ *
+ * @return The libimobiledevice version as static ascii string
*/
-idevice_error_t idevice_get_udid(idevice_t device, char **udid);
+LIBIMOBILEDEVICE_API const char* libimobiledevice_version();
#ifdef __cplusplus
}
diff --git a/include/libimobiledevice/lockdown.h b/include/libimobiledevice/lockdown.h
index c35e5e9..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 {
@@ -80,7 +79,7 @@ typedef enum {
LOCKDOWN_E_UNKNOWN_ERROR = -256
} lockdownd_error_t;
-typedef struct lockdownd_client_private lockdownd_client_private;
+typedef struct lockdownd_client_private lockdownd_client_private; /**< \private */
typedef lockdownd_client_private *lockdownd_client_t; /**< The client handle. */
struct lockdownd_pair_record {
@@ -88,18 +87,32 @@ struct lockdownd_pair_record {
char *host_certificate; /**< The host certificate */
char *root_certificate; /**< The root certificate */
char *host_id; /**< A unique HostID for the host computer */
- char *system_buid; /**< A unique system id */
+ char *system_buid; /**< A unique system id */
};
-/** A pair record holding device, host and root certificates along the host_id */
-typedef struct lockdownd_pair_record *lockdownd_pair_record_t;
+/** pair record holding device, host and root certificates along the host_id */
+typedef struct lockdownd_pair_record *lockdownd_pair_record_t; /**< pair record */
+/** service descriptor */
struct lockdownd_service_descriptor {
- uint16_t port;
- uint8_t ssl_enabled;
- char* identifier;
+ uint16_t port; /**< port number the service was started on */
+ uint8_t ssl_enabled; /**< an indicator if the service requires SSL */
+ char* identifier; /**< identifier of the service */
};
typedef struct lockdownd_service_descriptor *lockdownd_service_descriptor_t;
+/** Callback types used in #lockdownd_cu_pairing_cb_t */
+typedef enum {
+ LOCKDOWN_CU_PAIRING_PIN_REQUESTED, /**< PIN requested: data_ptr is a char* buffer, and data_size points to the size of this buffer that must not be exceeded and has to be updated to the actual number of characters filled into the buffer. */
+ LOCKDOWN_CU_PAIRING_DEVICE_INFO, /**< device information available: data_ptr is a plist_t, and data_size is ignored. The plist_t has to be copied if required, since it is freed when the callback function returns. */
+ LOCKDOWN_CU_PAIRING_ERROR /**< pairing error message available: data_ptr is a NULL-terminated char* buffer containing the error message, and data_size is ignored. Buffer needs to be copied if it shall persist outside the callback. */
+} lockdownd_cu_pairing_cb_type_t;
+
+/* CU pairing callback function prototype */
+/** Callback used to supply the pairing PIN during a CU pairing session,
+ * and to report device information and pairing error messages. */
+typedef void (*lockdownd_cu_pairing_cb_t) (lockdownd_cu_pairing_cb_type_t cb_type, void *user_data, void* data_ptr, unsigned int* data_size);
+
+
/* Interface */
/**
@@ -117,7 +130,7 @@ typedef struct lockdownd_service_descriptor *lockdownd_service_descriptor_t;
*
* @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.
@@ -136,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
@@ -146,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);
/**
@@ -158,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.
@@ -170,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.
@@ -183,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.
@@ -196,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.
@@ -210,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.
@@ -226,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.
@@ -241,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.
@@ -253,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.
@@ -267,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.
@@ -278,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.
@@ -294,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.
@@ -313,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
@@ -332,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
@@ -348,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.
@@ -365,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”
@@ -377,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.
@@ -386,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.
@@ -397,7 +410,90 @@ 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.
+ * This is required to allow lockdownd_cu_send_request_and_get_reply(),
+ * lockdownd_get_value_cu() and lockdonwd_pair_cu() requests, and eventually
+ * allows to perform an actual wireless pairing.
+ *
+ * Through the callback function, the PIN displayed on the device has to be
+ * supplied during the process. Currently, only AppleTV devices have this
+ * capability.
+ *
+ * @param client The lockdown client to perform the CU pairing for
+ * @param pairing_callback Callback function that is used to supply the PIN
+ * for the pairing process, but also to receive device information or
+ * pairing error messages.
+ * @param cb_user_data User data that will be passed as additional argument
+ * to the callback function.
+ * @param host_info (Optional) A dictionary containing host information to
+ * send to the device when finalizing the CU pairing. The supplied
+ * values will override the default values gathered for the current host.
+ * @param acl (Optional) A dictionary containing ACL information. Currently
+ * only com.apple.ScreenCapture:true and com.apple.developer:true are known
+ * valid ACL values, which are used as default when NULL is passed.
+ *
+ * @return LOCKDOWN_E_SUCCESS on success, LOCKDOWN_E_INVALID_ARG if one of the
+ * parameters is invalid, LOCKDOWN_E_PAIRING_FAILED if the pairing failed,
+ * or a LOCKDOWN_E_* error code otherwise.
+ */
+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
+ * and attempts to retrieve a reply. This function is used internally
+ * by lockdownd_get_value_cu() and lockdownd_pair_cu(), but exposed here to
+ * allow custom requests being sent and their replies being received.
+ *
+ * @param client A lockdown client with an established CU pairing.
+ * @param request The request to perform.
+ * @param request_payload The payload for the request.
+ * @param reply (Optional) If not NULL, the plist_t will be set to the reply
+ * dictionary that has been received. Consumer is responsible to free it
+ * using plist_free() when no longer required.
+ *
+ * @return LOCKDOWN_E_SUCCESS on success, LOCKDOWN_E_INVALID_ARG if one of the
+ * parameters is invalid, LOCKDOWN_E_NO_RUNNING_SESSION if the current
+ * lockdown client does not have an established CU pairing session,
+ * or a LOCKDOWN_E_* error code otherwise.
+ */
+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
+ * client with established CU pairing session.
+ *
+ * This is used to retrieve values that are only accessible after a CU pairing
+ * has been established, and would otherwise only be accessible with a valid
+ * device pairing.
+ *
+ * @param client A lockdown client with an established CU pairing.
+ * @param domain The domain to query on or NULL for global domain
+ * @param key The key name to request or NULL to query for all keys
+ * @param value A plist node representing the result value node
+ *
+ * @return LOCKDOWN_E_SUCCESS on success, LOCKDOWN_E_INVALID_ARG if one of the
+ * parameters is invalid, LOCKDOWN_E_NO_RUNNING_SESSION if the current
+ * lockdown client does not have an established CU pairing session,
+ * or a LOCKDOWN_E_* error code otherwise.
+ */
+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
+ * CU pairing session.
+ *
+ * @param client A lockdown client with an established CU pairing.
+ *
+ * @return LOCKDOWN_E_SUCCESS on success, LOCKDOWN_E_INVALID_ARG when client
+ * is NULL, LOCKDOWN_E_NO_RUNNING_SESSION if the current lockdown client
+ * does not have an established CU pairing session, or a LOCKDOWN_E_* error
+ * code otherwise.
+ */
+LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_pair_cu(lockdownd_client_t client);
+
/* Helper */
@@ -408,7 +504,7 @@ lockdownd_error_t lockdownd_goodbye(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.
@@ -419,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.
@@ -430,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.
@@ -445,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()
@@ -454,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()
@@ -463,16 +559,16 @@ 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.
*
- * @params err A lockdownd error code
+ * @param err A lockdownd error code
*
* @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 09af57a..7981a8b 100644
--- a/include/libimobiledevice/misagent.h
+++ b/include/libimobiledevice/misagent.h
@@ -31,6 +31,7 @@ extern "C" {
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
+/** Service identifier passed to lockdownd_start_service() to start the misagent service */
#define MISAGENT_SERVICE_NAME "com.apple.misagent"
/** Error Codes */
@@ -43,7 +44,7 @@ typedef enum {
MISAGENT_E_UNKNOWN_ERROR = -256
} misagent_error_t;
-typedef struct misagent_client_private misagent_client_private;
+typedef struct misagent_client_private misagent_client_private; /**< \private */
typedef misagent_client_private *misagent_client_t; /**< The client handle. */
/* Interface */
@@ -59,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.
@@ -74,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
@@ -85,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);
/**
@@ -98,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).
@@ -117,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).
@@ -136,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.
@@ -149,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.
@@ -158,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 e185ad5..d4fc3f4 100644
--- a/include/libimobiledevice/mobile_image_mounter.h
+++ b/include/libimobiledevice/mobile_image_mounter.h
@@ -31,6 +31,7 @@ extern "C" {
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
+/** Service identifier passed to lockdownd_start_service() to start the mobile image mounter service */
#define MOBILE_IMAGE_MOUNTER_SERVICE_NAME "com.apple.mobile.mobile_image_mounter"
/** Error Codes */
@@ -44,7 +45,7 @@ typedef enum {
MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR = -256
} mobile_image_mounter_error_t;
-typedef struct mobile_image_mounter_client_private mobile_image_mounter_client_private;
+typedef struct mobile_image_mounter_client_private mobile_image_mounter_client_private; /**< \private */
typedef mobile_image_mounter_client_private *mobile_image_mounter_client_t; /**< The client handle. */
/** callback for image upload */
@@ -65,7 +66,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.
@@ -80,7 +81,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
@@ -91,7 +92,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);
/**
@@ -107,7 +108,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.
@@ -126,7 +127,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 char *signature, uint16_t signature_size, mobile_image_mounter_upload_cb_t upload_cb, void* userdata);
/**
* Mounts an image on the device.
@@ -149,7 +150,7 @@ mobile_image_mounter_error_t mobile_image_mounter_upload_image(mobile_image_moun
* 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(mobile_image_mounter_client_t client, const char *image_path, const char *signature, uint16_t signature_size, const char *image_type, plist_t *result);
/**
* Hangs up the connection to the mobile_image_mounter service.
@@ -162,7 +163,7 @@ 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);
#ifdef __cplusplus
}
diff --git a/include/libimobiledevice/mobileactivation.h b/include/libimobiledevice/mobileactivation.h
index 51de205..8e036a8 100644
--- a/include/libimobiledevice/mobileactivation.h
+++ b/include/libimobiledevice/mobileactivation.h
@@ -30,6 +30,7 @@ extern "C" {
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
+/** Service identifier passed to lockdownd_start_service() to start the mobile activation service */
#define MOBILEACTIVATION_SERVICE_NAME "com.apple.mobileactivationd"
/** Error Codes */
@@ -43,7 +44,7 @@ typedef enum {
MOBILEACTIVATION_E_UNKNOWN_ERROR = -256
} mobileactivation_error_t;
-typedef struct mobileactivation_client_private mobileactivation_client_private;
+typedef struct mobileactivation_client_private mobileactivation_client_private; /**< \private */
typedef mobileactivation_client_private *mobileactivation_client_t; /**< The client handle. */
/**
@@ -58,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.
@@ -73,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
@@ -86,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);
/**
@@ -101,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.
@@ -115,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.
@@ -129,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'
@@ -138,7 +139,7 @@ mobileactivation_error_t mobileactivation_create_activation_info(mobileactivatio
* provided by mobileactivation_create_activation_session_info().
*
* @param client The mobileactivation client
- * @aram handshake_response The handshake response returned from drmHandshake
+ * @param handshake_response The handshake response returned from drmHandshake
* @param info Pointer to a plist_t variable that will be set to the
* activation info created by the mobileactivation service. The
* consumer is responsible for freeing the returned object using
@@ -147,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.
@@ -160,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.
@@ -175,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 f22150d..2ecb60c 100644
--- a/include/libimobiledevice/mobilebackup.h
+++ b/include/libimobiledevice/mobilebackup.h
@@ -31,6 +31,7 @@ extern "C" {
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
+/** Service identifier passed to lockdownd_start_service() to start the mobilebackup service */
#define MOBILEBACKUP_SERVICE_NAME "com.apple.mobilebackup"
/** Error Codes */
@@ -46,9 +47,10 @@ typedef enum {
MOBILEBACKUP_E_UNKNOWN_ERROR = -256
} mobilebackup_error_t;
-typedef struct mobilebackup_client_private mobilebackup_client_private;
+typedef struct mobilebackup_client_private mobilebackup_client_private; /**< \private */
typedef mobilebackup_client_private *mobilebackup_client_t; /**< The client handle. */
+/** Available flags passed to #mobilebackup_request_restore */
typedef enum {
MB_RESTORE_NOTIFY_SPRINGBOARD = 1 << 0,
MB_RESTORE_PRESERVE_SETTINGS = 1 << 1,
@@ -67,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.
@@ -82,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
@@ -93,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);
/**
@@ -104,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
@@ -117,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.
@@ -136,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.
@@ -147,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.
@@ -170,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
@@ -190,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
@@ -210,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
@@ -223,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.
@@ -235,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 239c807..2e9222d 100644
--- a/include/libimobiledevice/mobilebackup2.h
+++ b/include/libimobiledevice/mobilebackup2.h
@@ -31,6 +31,7 @@ extern "C" {
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
+/** Service identifier passed to lockdownd_start_service() to start the mobilebackup2 service */
#define MOBILEBACKUP2_SERVICE_NAME "com.apple.mobilebackup2"
/** Error Codes */
@@ -47,7 +48,7 @@ typedef enum {
MOBILEBACKUP2_E_UNKNOWN_ERROR = -256
} mobilebackup2_error_t;
-typedef struct mobilebackup2_client_private mobilebackup2_client_private;
+typedef struct mobilebackup2_client_private mobilebackup2_client_private; /**< \private */
typedef mobilebackup2_client_private *mobilebackup2_client_t; /**< The client handle. */
@@ -63,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.
@@ -78,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
@@ -89,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);
/**
@@ -104,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.
@@ -124,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.
@@ -142,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.
@@ -156,13 +157,13 @@ mobilebackup2_error_t mobilebackup2_send_raw(mobilebackup2_client_t client, cons
* @param data Pointer to a buffer that will be filled with the received data.
* @param length Number of bytes to receive. The data buffer needs to be large
* enough to store this amount of data.
- * @paran bytes Number of bytes actually received.
+ * @param bytes Number of bytes actually received.
*
* @return MOBILEBACKUP2_E_SUCCESS if any or no data was received,
* 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.
@@ -175,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.
@@ -190,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.
@@ -204,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 005ef3f..c3bc53d 100644
--- a/include/libimobiledevice/mobilesync.h
+++ b/include/libimobiledevice/mobilesync.h
@@ -34,6 +34,7 @@ extern "C" {
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
+/** Service identifier passed to lockdownd_start_service() to start the mobilesync service */
#define MOBILESYNC_SERVICE_NAME "com.apple.mobilesync"
/** Error Codes */
@@ -59,14 +60,16 @@ typedef enum {
MOBILESYNC_SYNC_TYPE_RESET /**< Reset-sync signals that the computer should send all data again. */
} mobilesync_sync_type_t;
-typedef struct mobilesync_client_private mobilesync_client_private;
+typedef struct mobilesync_client_private mobilesync_client_private; /**< \private */
typedef mobilesync_client_private *mobilesync_client_t; /**< The client handle */
+/** Anchors used by the device and computer (structure) */
typedef struct {
- char *device_anchor;
- char *computer_anchor;
+ char *device_anchor; /**< device anchor */
+ char *computer_anchor; /**< computer anchor */
} mobilesync_anchors;
-typedef mobilesync_anchors *mobilesync_anchors_t; /**< Anchors used by the device and computer. */
+/** Anchors used by the device and computer */
+typedef mobilesync_anchors *mobilesync_anchors_t;
/* Interface */
@@ -83,7 +86,7 @@ typedef mobilesync_anchors *mobilesync_anchors_t; /**< Anchors used by the devic
* @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.
@@ -98,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
@@ -109,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);
/**
@@ -120,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
@@ -133,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);
/**
@@ -156,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.
@@ -167,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.
@@ -180,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);
/**
@@ -193,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.
@@ -205,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
@@ -218,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);
/**
@@ -234,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
@@ -244,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);
/**
@@ -264,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);
/**
@@ -281,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.
@@ -298,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 */
@@ -311,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);
/**
@@ -326,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.
@@ -340,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 a9d2d3f..f4f090b 100644
--- a/include/libimobiledevice/notification_proxy.h
+++ b/include/libimobiledevice/notification_proxy.h
@@ -31,6 +31,7 @@ extern "C" {
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
+/** Service identifier passed to lockdownd_start_service() to start the notification proxy service */
#define NP_SERVICE_NAME "com.apple.mobile.notification_proxy"
/** Error Codes */
@@ -43,22 +44,26 @@ typedef enum {
} np_error_t;
/**
- * @name Notifications that can be send
+ * @name Notifications that can be sent
*
* For use with np_post_notification() (client --> device)
*/
+/**@{*/
+//! @cond
#define NP_SYNC_WILL_START "com.apple.itunes-mobdev.syncWillStart"
#define NP_SYNC_DID_START "com.apple.itunes-mobdev.syncDidStart"
#define NP_SYNC_DID_FINISH "com.apple.itunes-mobdev.syncDidFinish"
#define NP_SYNC_LOCK_REQUEST "com.apple.itunes-mobdev.syncLockRequest"
-/*@}*/
+//! @endcond
+/**@}*/
/**
* @name Notifications that can be received
*
* For use with np_observe_notification() (device --> client)
*/
-/*@{*/
+/**@{*/
+//! @cond
#define NP_SYNC_CANCEL_REQUEST "com.apple.itunes-client.syncCancelRequest"
#define NP_SYNC_SUSPEND_REQUEST "com.apple.itunes-client.syncSuspendRequest"
#define NP_SYNC_RESUME_REQUEST "com.apple.itunes-client.syncResumeRequest"
@@ -81,12 +86,13 @@ typedef enum {
#define NP_ITDBPREP_DID_END "com.apple.itdbprep.notification.didEnd"
#define NP_LANGUAGE_CHANGED "com.apple.language.changed"
#define NP_ADDRESS_BOOK_PREF_CHANGED "com.apple.AddressBook.PreferenceChanged"
-/*@}*/
+//! @endcond
+/**@}*/
-typedef struct np_client_private np_client_private;
+typedef struct np_client_private np_client_private; /**< \private */
typedef np_client_private *np_client_t; /**< The client handle. */
-/** Reports which notification was received. */
+/** Callback function that reports which notification was received. */
typedef void (*np_notify_cb_t) (const char *notification, void *user_data);
/* Interface */
@@ -103,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.
@@ -118,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
@@ -128,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);
/**
@@ -139,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.
@@ -150,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.
@@ -163,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
@@ -187,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 *userdata);
+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/preboard.h b/include/libimobiledevice/preboard.h
index 60b8e26..0d89eb4 100644
--- a/include/libimobiledevice/preboard.h
+++ b/include/libimobiledevice/preboard.h
@@ -30,6 +30,7 @@ extern "C" {
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
+/** Service identifier passed to lockdownd_start_service() to start the preboard service */
#define PREBOARD_SERVICE_NAME "com.apple.preboardservice_v2"
/** Error Codes */
@@ -45,7 +46,7 @@ typedef enum {
PREBOARD_E_UNKNOWN_ERROR = -256
} preboard_error_t;
-typedef struct preboard_client_private preboard_client_private;
+typedef struct preboard_client_private preboard_client_private; /**< \private */
typedef preboard_client_private *preboard_client_t; /**< The client handle. */
/** Reports the status response of the given command */
@@ -63,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.
@@ -78,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
@@ -89,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.
@@ -101,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.
@@ -114,20 +115,21 @@ 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.
*
* @param client The preboard client
* @param plist Pointer to a plist_t what will be set to the received plist
+ * @param timeout_ms Timeout in milliseconds
*
* @return PREBOARD_E_SUCCESS on success,
* PREBOARD_E_INVALID_ARG when client or plist is NULL,
* 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
@@ -148,14 +150,14 @@ preboard_error_t preboard_receive_with_timeout(preboard_client_t client, plist_t
* { Timeout: true }
* followed by { HideDialog: true }
* If the user aborts the passcode entry, the device sends a dictionary:
- * { Error: 1, ErrorString: <error string> }
+ * { Error: 1, ErrorString: \<error string\> }
* followed by { HideDialog: true }
*
* @return PREBOARD_E_SUCCESS if the command was successfully submitted,
* 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.
@@ -170,13 +172,13 @@ preboard_error_t preboard_create_stashbag(preboard_client_t client, plist_t mani
* receive a dictionary with:
* { StashbagCommitComplete: true }
* or in case of an error:
- * { StashbagCommitComplete: 0, Error: 1, <optional> ErrorString: <error string> }
+ * { StashbagCommitComplete: 0, Error: 1, \<optional\> ErrorString: \<error string\> }
*
* @return PREBOARD_E_SUCCESS if the command was successfully submitted,
* 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 031d6f8..e6b26a3 100644
--- a/include/libimobiledevice/property_list_service.h
+++ b/include/libimobiledevice/property_list_service.h
@@ -29,8 +29,9 @@ extern "C" {
#endif
#include <libimobiledevice/lockdown.h>
+#include <libimobiledevice/service.h>
-/* Error Codes */
+/** Error Codes */
typedef enum {
PROPERTY_LIST_SERVICE_E_SUCCESS = 0,
PROPERTY_LIST_SERVICE_E_INVALID_ARG = -1,
@@ -42,7 +43,7 @@ typedef enum {
PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR = -256
} property_list_service_error_t;
-typedef struct property_list_service_client_private property_list_service_private;
+typedef struct property_list_service_client_private property_list_service_private; /**< \private */
typedef property_list_service_private* property_list_service_client_t; /**< The client handle. */
/* Interface */
@@ -59,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.
@@ -70,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.
@@ -83,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.
@@ -96,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
@@ -115,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.
@@ -138,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.
@@ -147,11 +148,11 @@ property_list_service_error_t property_list_service_receive_plist(property_list_
* should be enabled.
*
* @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
- * PROPERTY_LIST_SERVICE_E_INVALID_ARG if client or client->connection is
- * NULL, PROPERTY_LIST_SERVICE_E_SSL_ERROR when SSL could not be enabled,
+ * PROPERTY_LIST_SERVICE_E_INVALID_ARG if one or more of the arguments are invalid,
+ * 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.
@@ -160,10 +161,21 @@ property_list_service_error_t property_list_service_enable_ssl(property_list_ser
* should be disabled.
*
* @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
- * PROPERTY_LIST_SERVICE_E_INVALID_ARG if client or client->connection is
- * NULL, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR otherwise.
+ * PROPERTY_LIST_SERVICE_E_INVALID_ARG if one or more of the arguments are invalid,
+ * or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR otherwise.
+ */
+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.
+ *
+ * @param client The property list service client
+ * @param service_client Pointer to be assigned to the parent #service_client_t
+ *
+ * @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_disable_ssl(property_list_service_client_t 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 950f8fd..859dc98 100644
--- a/include/libimobiledevice/restore.h
+++ b/include/libimobiledevice/restore.h
@@ -42,7 +42,7 @@ typedef enum {
RESTORE_E_UNKNOWN_ERROR = -256
} restored_error_t;
-typedef struct restored_client_private restored_client_private;
+typedef struct restored_client_private restored_client_private; /**< \private */
typedef restored_client_private *restored_client_t; /**< The client handle. */
/* Interface */
@@ -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
new file mode 100644
index 0000000..5e2f54b
--- /dev/null
+++ b/include/libimobiledevice/reverse_proxy.h
@@ -0,0 +1,213 @@
+/**
+ * @file libimobiledevice/reverse_proxy.h
+ * @brief Provide a reverse proxy to allow the device to communicate through,
+ * which is used during firmware restore.
+ * \internal
+ *
+ * Copyright (c) 2021 Nikias Bassen, All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef IREVERSE_PROXY_H
+#define IREVERSE_PROXY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libimobiledevice/libimobiledevice.h>
+
+#define REVERSE_PROXY_DEFAULT_PORT 1082 /**< default port the reverse proxy is listening on */
+
+/** Error Codes */
+typedef enum {
+ REVERSE_PROXY_E_SUCCESS = 0,
+ REVERSE_PROXY_E_INVALID_ARG = -1,
+ REVERSE_PROXY_E_PLIST_ERROR = -2,
+ REVERSE_PROXY_E_MUX_ERROR = -3,
+ REVERSE_PROXY_E_SSL_ERROR = -4,
+ REVERSE_PROXY_E_NOT_ENOUGH_DATA = -5,
+ REVERSE_PROXY_E_TIMEOUT = -6,
+ REVERSE_PROXY_E_UNKNOWN_ERROR = -256
+} reverse_proxy_error_t;
+
+typedef struct reverse_proxy_client_private reverse_proxy_client_private; /**< \private */
+typedef reverse_proxy_client_private *reverse_proxy_client_t; /**< The client handle. */
+
+/** reverse proxy client type */
+typedef enum {
+ RP_TYPE_CTRL = 1, /**< control connection */
+ RP_TYPE_CONN /**< proxy connection */
+} reverse_proxy_client_type_t;
+
+/** reverse proxy status for reverse_proxy_status_cb_t callback */
+typedef enum {
+ RP_STATUS_READY = 1, /**< proxy is ready */
+ RP_STATUS_TERMINATE, /**< proxy terminated */
+ RP_STATUS_CONNECT_REQ, /**< connection request received (only RP_TYPE_CTRL) */
+ RP_STATUS_SHUTDOWN_REQ, /**< shutdown request received (only RP_TYPE_CTRL) */
+ RP_STATUS_CONNECTED, /**< connection established (only RP_TYPE_CONN) */
+ RP_STATUS_DISCONNECTED, /**< connection closed (only RP_TYPE_CONN) */
+} reverse_proxy_status_t;
+
+/** reverse proxy data direction passed to reverse_proxy_data_cb_t callback */
+typedef enum {
+ RP_DATA_DIRECTION_OUT = 1, /**< data going out to remote host */
+ RP_DATA_DIRECTION_IN /**< data coming in from remote host */
+} reverse_proxy_data_direction_t;
+
+/**
+ * Log callback function prototype.
+ *
+ * @param client The client that called the callback function
+ * @param log_msg The log message
+ * @param user_data The user_data pointer that was set when registering the callback
+ */
+typedef void (*reverse_proxy_log_cb_t) (reverse_proxy_client_t client, const char* log_msg, void* user_data);
+
+/**
+ * Data callback function prototype.
+ *
+ * @param client The client that called the callback function
+ * @param direction The direction of the data, either RP_DATA_DIRECTION_OUT or RP_DATA_DIRECTION_IN
+ * @param buffer The data buffer
+ * @param length The length of the data buffer
+ * @param user_data The user_data pointer that was set when registering the callback
+ */
+typedef void (*reverse_proxy_data_cb_t) (reverse_proxy_client_t client, reverse_proxy_data_direction_t direction, const char* buffer, uint32_t length, void* user_data);
+
+/**
+ * Status callback function prototype.
+ *
+ * @param client The client that called the callback function
+ * @param status The status the client is reporting
+ * @param status_msg A status message the client reports along with the status
+ * @param user_data The user_data pointer that was set when registering the callback
+ */
+typedef void (*reverse_proxy_status_cb_t) (reverse_proxy_client_t client, reverse_proxy_status_t status, const char* status_msg, void* user_data);
+
+/**
+ * Create a reverse proxy client using com.apple.PurpleReverseProxy.Ctrl and
+ * com.apple.PurpleReverseProxy.Conn lockdown services. This will open a port
+ * 1083 on the device that iOS apps could connect to; \b however that is
+ * only allowed if an app has the com.apple.private.PurpleReverseProxy.allowed
+ * entitlement, which currently only \c /usr/libexec/fdrhelper holds.
+ *
+ * @note This function only creates and initializes the reverse proxy;
+ * to make it operational, call reverse_proxy_client_start_proxy().
+ *
+ * @param device The device to connect to.
+ * @param client Pointer that will be set to a newly allocated #reverse_proxy_client_t
+ * upon successful return.
+ * @param label A label to pass to lockdownd when creating the service
+ * connections, usually the program name.
+ *
+ * @return REVERSE_PROXY_E_SUCCESS on success,
+ * or a REVERSE_PROXY_E_* error code otherwise.
+ */
+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
+ * used during firmware restores with the default port REVERSE_PROXY_DEFAULT_PORT (1082).
+ *
+ * @note This function only creates and initializes the reverse proxy;
+ * to make it operational, call reverse_proxy_client_start_proxy().
+ *
+ * @param device The device to connect to.
+ * @param client Pointer that will be set to a newly allocated reverse_proxy_client_t
+ * upon successful return.
+ * @param device_port An open port on the device. Unless it's being used for
+ * a custom implementation, pass REVERSE_PROXY_DEFAULT_PORT here.
+ *
+ * @return REVERSE_PROXY_E_SUCCESS on success,
+ * or a REVERSE_PROXY_E_* error code otherwise.
+ */
+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.
+ */
+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.
+ *
+ * @param client The reverse proxy client to start.
+ * @param control_protocol_version The control protocol version to use.
+ * This is either 1 or 2. Recent devices use 2.
+ *
+ * @return REVERSE_PROXY_E_SUCCESS on success,
+ * or a REVERSE_PROXY_E_* error code otherwise.
+ */
+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
+ * reverse proxy, like Ready, Connect Request, Connected, etc.
+ *
+ * @note Set the callback before calling reverse_proxy_client_start_proxy().
+ *
+ * @param client The reverse proxy client
+ * @param callback The status callback function that will be called
+ * when the status of the reverse proxy changes.
+ * @param user_data A pointer that will be passed to the callback function.
+ */
+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.
+ *
+ * @note Set the callback before calling reverse_proxy_client_start_proxy().
+ *
+ * @param client The reverse proxy client
+ * @param callback The log callback function that will be called
+ * when the reverse proxy logs something.
+ * @param user_data A pointer that will be passed to the callback function.
+ */
+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.
+ *
+ * @note Set the callback before calling reverse_proxy_client_start_proxy().
+ *
+ * @param client The reverse proxy client
+ * @param callback The status callback function that will be called
+ * when the status of the reverse proxy changes.
+ * @param user_data A pointer that will be passed to the callback function.
+ */
+
+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
+ * is either RP_TYPE_CTRL or RP_TYPE_CONN. Useful for callback functions.
+ * @see reverse_proxy_client_type_t
+ *
+ * @param client The reverse proxy client
+ *
+ * @return The type of the rerverse proxy client
+ */
+LIBIMOBILEDEVICE_API reverse_proxy_client_type_t reverse_proxy_get_type(reverse_proxy_client_t client);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/libimobiledevice/sbservices.h b/include/libimobiledevice/sbservices.h
index 0259d97..7435947 100644
--- a/include/libimobiledevice/sbservices.h
+++ b/include/libimobiledevice/sbservices.h
@@ -31,6 +31,7 @@ extern "C" {
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
+/** Service identifier passed to lockdownd_start_service() to start the springboardservices service */
#define SBSERVICES_SERVICE_NAME "com.apple.springboardservices"
/** Error Codes */
@@ -42,8 +43,7 @@ typedef enum {
SBSERVICES_E_UNKNOWN_ERROR = -256
} sbservices_error_t;
-/** @name Orientation of the user interface on the device */
-/*@{*/
+/** Orientation of the user interface on the device */
typedef enum {
SBSERVICES_INTERFACE_ORIENTATION_UNKNOWN = 0,
SBSERVICES_INTERFACE_ORIENTATION_PORTRAIT = 1,
@@ -51,9 +51,8 @@ typedef enum {
SBSERVICES_INTERFACE_ORIENTATION_LANDSCAPE_RIGHT = 3,
SBSERVICES_INTERFACE_ORIENTATION_LANDSCAPE_LEFT = 4
} sbservices_interface_orientation_t;
-/*@}*/
-typedef struct sbservices_client_private sbservices_client_private;
+typedef struct sbservices_client_private sbservices_client_private; /**< \private */
typedef sbservices_client_private *sbservices_client_t; /**< The client handle. */
/* Interface */
@@ -69,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.
@@ -84,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
@@ -95,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);
/**
@@ -112,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.
@@ -123,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.
@@ -140,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.
@@ -151,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.
@@ -167,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 83ca96b..db3c969 100644
--- a/include/libimobiledevice/screenshotr.h
+++ b/include/libimobiledevice/screenshotr.h
@@ -32,6 +32,7 @@ extern "C" {
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
+/** Service identifier passed to lockdownd_start_service() to start the screenshotr service */
#define SCREENSHOTR_SERVICE_NAME "com.apple.mobile.screenshotr"
/** Error Codes */
@@ -46,7 +47,7 @@ typedef enum {
SCREENSHOTR_E_UNKNOWN_ERROR = -256
} screenshotr_error_t;
-typedef struct screenshotr_client_private screenshotr_client_private;
+typedef struct screenshotr_client_private screenshotr_client_private; /**< \private */
typedef screenshotr_client_private *screenshotr_client_t; /**< The client handle. */
@@ -65,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.
@@ -80,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
@@ -91,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);
/**
@@ -108,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 13d0e15..f31ada4 100644
--- a/include/libimobiledevice/service.h
+++ b/include/libimobiledevice/service.h
@@ -42,9 +42,10 @@ typedef enum {
SERVICE_E_UNKNOWN_ERROR = -256
} service_error_t;
-typedef struct service_client_private service_client_private;
+typedef struct service_client_private service_client_private; /**< \private */
typedef service_client_private* service_client_t; /**< The client handle. */
+/** service constructor cast */
#define SERVICE_CONSTRUCTOR(x) (int32_t (*)(idevice_t, lockdownd_service_descriptor_t, void**))(x)
/* Interface */
@@ -61,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
@@ -74,11 +75,13 @@ service_error_t service_client_new(idevice_t device, lockdownd_service_descripto
* use.
* @param label The label to use for communication. Usually the program name.
* Pass NULL to disable sending the label in requests to lockdownd.
+ * @param constructor_func Constructor function for the service client to create (e.g. afc_client_new())
+ * @param error_code Pointer to an int32_t that will receive the service start error code.
*
* @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.
@@ -89,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);
/**
@@ -105,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.
@@ -122,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.
@@ -140,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);
/**
@@ -155,29 +158,42 @@ 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.
*
- * @param client The connected service client for that SSL should be disabled.
+ * @param client The connected service client for which SSL should be disabled.
*
* @return SERVICE_E_SUCCESS on success,
* 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 without sending SSL terminate messages.
+ * Disable SSL for the given service client, optionally without sending SSL terminate messages.
*
- * @param client The connected service client for that SSL should be disabled.
+ * @param client The connected service client for which SSL should be disabled.
+ * @param sslBypass A boolean value indicating wether to disable SSL with a proper
+ * SSL shutdown (0), or bypass the shutdown (1).
*
* @return SERVICE_E_SUCCESS on success,
* 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.
+ *
+ * @param client The service client
+ * @param connection Pointer to be assigned to the #idevice_connection_t.
+ *
+ * @return SERVICE_E_SUCCESS on success,
+ * SERVICE_E_INVALID_ARG if one or more of the arguments are invalid.
+ */
+LIBIMOBILEDEVICE_API service_error_t service_get_connection(service_client_t client, idevice_connection_t *connection);
#ifdef __cplusplus
}
diff --git a/include/libimobiledevice/syslog_relay.h b/include/libimobiledevice/syslog_relay.h
index 89d9489..0f6487a 100644
--- a/include/libimobiledevice/syslog_relay.h
+++ b/include/libimobiledevice/syslog_relay.h
@@ -31,6 +31,7 @@ extern "C" {
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
+/** Service identifier passed to lockdownd_start_service() to start the syslog relay service */
#define SYSLOG_RELAY_SERVICE_NAME "com.apple.syslog_relay"
/** Error Codes */
@@ -44,7 +45,7 @@ typedef enum {
SYSLOG_RELAY_E_UNKNOWN_ERROR = -256
} syslog_relay_error_t;
-typedef struct syslog_relay_client_private syslog_relay_client_private;
+typedef struct syslog_relay_client_private syslog_relay_client_private; /**< \private */
typedef syslog_relay_client_private *syslog_relay_client_t; /**< The client handle. */
/** Receives each character received from the device. */
@@ -64,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.
@@ -79,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
@@ -90,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);
/**
@@ -107,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.
@@ -128,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.
@@ -142,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 */
@@ -161,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.
@@ -170,12 +171,11 @@ syslog_relay_error_t syslog_relay_receive_with_timeout(syslog_relay_client_t cli
* @param data Buffer that will be filled with the data received
* @param size Number of bytes to receive
* @param received Number of bytes received (can be NULL to ignore)
- * @param timeout Maximum time in milliseconds to wait for data.
*
* @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 da0759c..16d2ca2 100644
--- a/include/libimobiledevice/webinspector.h
+++ b/include/libimobiledevice/webinspector.h
@@ -31,6 +31,7 @@ extern "C" {
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
+/** Service identifier passed to lockdownd_start_service() to start the webinspector service */
#define WEBINSPECTOR_SERVICE_NAME "com.apple.webinspector"
/** Error Codes */
@@ -45,7 +46,7 @@ typedef enum {
WEBINSPECTOR_E_UNKNOWN_ERROR = -256
} webinspector_error_t;
-typedef struct webinspector_client_private webinspector_client_private;
+typedef struct webinspector_client_private webinspector_client_private; /**< \private */
typedef webinspector_client_private *webinspector_client_t; /**< The client handle. */
@@ -61,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.
@@ -76,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
@@ -87,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);
/**
@@ -99,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.
@@ -110,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.
@@ -118,7 +119,7 @@ webinspector_error_t webinspector_receive(webinspector_client_t client, plist_t
* @param client The webinspector client to use for receiving
* @param plist pointer to a plist_t that will point to the received plist
* upon successful return
- * @param timeout Maximum time in milliseconds to wait for data.
+ * @param timeout_ms Maximum time in milliseconds to wait for data.
*
* @return WEBINSPECTOR_E_SUCCESS on success,
* WEBINSPECTOR_E_INVALID_ARG when client or *plist is NULL,
@@ -127,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/ac_pkg_cython.m4 b/m4/ac_pkg_cython.m4
index 123f2dc..e0af96a 100644
--- a/m4/ac_pkg_cython.m4
+++ b/m4/ac_pkg_cython.m4
@@ -1,8 +1,8 @@
AC_DEFUN([AC_PROG_CYTHON],[
- AC_PATH_PROG([CYTHON],[cython])
+ AC_PATH_PROGS([CYTHON],[cython cython3])
if test -z "$CYTHON" ; then
- AC_MSG_WARN([Unable to find 'cython' program. You should look at http://www.cython.org] or install your distribution specific cython package.)
+ AC_MSG_WARN([Unable to find 'cython' or 'cython3' program. You should look at https://cython.org or install your distribution specific cython package.])
CYTHON=false
elif test -n "$1" ; then
AC_MSG_CHECKING([for Cython version])
diff --git a/m4/as-compiler-flag.m4 b/m4/as-compiler-flag.m4
index 0f660cf..baab5d9 100644
--- a/m4/as-compiler-flag.m4
+++ b/m4/as-compiler-flag.m4
@@ -18,7 +18,7 @@ AC_DEFUN([AS_COMPILER_FLAG],
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $1"
- AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])], [flag_ok=yes], [flag_ok=no])
CFLAGS="$save_CFLAGS"
if test "X$flag_ok" = Xyes ; then
@@ -44,7 +44,7 @@ AC_DEFUN([AS_COMPILER_FLAGS],
do
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $each"
- AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])], [flag_ok=yes], [flag_ok=no])
CFLAGS="$save_CFLAGS"
if test "X$flag_ok" = Xyes ; then
diff --git a/m4/ax_pthread.m4 b/m4/ax_pthread.m4
index 4c4051e..9f35d13 100644
--- a/m4/ax_pthread.m4
+++ b/m4/ax_pthread.m4
@@ -1,5 +1,5 @@
# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_pthread.html
+# https://www.gnu.org/software/autoconf-archive/ax_pthread.html
# ===========================================================================
#
# SYNOPSIS
@@ -14,20 +14,24 @@
# flags that are needed. (The user can also force certain compiler
# flags/libs to be tested by setting these environment variables.)
#
-# Also sets PTHREAD_CC to any special C compiler that is needed for
-# multi-threaded programs (defaults to the value of CC otherwise). (This
-# is necessary on AIX to use the special cc_r compiler alias.)
+# Also sets PTHREAD_CC and PTHREAD_CXX to any special C compiler that is
+# needed for multi-threaded programs (defaults to the value of CC
+# respectively CXX otherwise). (This is necessary on e.g. AIX to use the
+# special cc_r/CC_r compiler alias.)
#
# NOTE: You are assumed to not only compile your program with these flags,
# but also to link with them as well. For example, you might link with
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
+# $PTHREAD_CXX $CXXFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
#
# If you are only building threaded programs, you may wish to use these
# variables in your default LIBS, CFLAGS, and CC:
#
# LIBS="$PTHREAD_LIBS $LIBS"
# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+# CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS"
# CC="$PTHREAD_CC"
+# CXX="$PTHREAD_CXX"
#
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to
@@ -55,6 +59,7 @@
#
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
# Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG>
+# Copyright (c) 2019 Marc Stevens <marc.stevens@cwi.nl>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
@@ -67,7 +72,7 @@
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
-# with this program. If not, see <http://www.gnu.org/licenses/>.
+# with this program. If not, see <https://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
@@ -82,7 +87,7 @@
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
-#serial 23
+#serial 31
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
AC_DEFUN([AX_PTHREAD], [
@@ -104,6 +109,7 @@ if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then
ax_pthread_save_CFLAGS="$CFLAGS"
ax_pthread_save_LIBS="$LIBS"
AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"])
+ AS_IF([test "x$PTHREAD_CXX" != "x"], [CXX="$PTHREAD_CXX"])
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS])
@@ -123,10 +129,12 @@ fi
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
# libraries is broken (non-POSIX).
-# Create a list of thread flags to try. Items starting with a "-" are
-# C compiler flags, and other items are library names, except for "none"
-# which indicates that we try without any flags at all, and "pthread-config"
-# which is a program returning the flags for the Pth emulation library.
+# Create a list of thread flags to try. Items with a "," contain both
+# C compiler flags (before ",") and linker flags (after ","). Other items
+# starting with a "-" are C compiler flags, and remaining items are
+# library names, except for "none" which indicates that we try without
+# any flags at all, and "pthread-config" which is a program returning
+# the flags for the Pth emulation library.
ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
@@ -194,14 +202,47 @@ case $host_os in
# that too in a future libc.) So we'll check first for the
# standard Solaris way of linking pthreads (-mt -lpthread).
- ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags"
+ ax_pthread_flags="-mt,-lpthread pthread $ax_pthread_flags"
;;
esac
+# Are we compiling with Clang?
+
+AC_CACHE_CHECK([whether $CC is Clang],
+ [ax_cv_PTHREAD_CLANG],
+ [ax_cv_PTHREAD_CLANG=no
+ # Note that Autoconf sets GCC=yes for Clang as well as GCC
+ if test "x$GCC" = "xyes"; then
+ AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG],
+ [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
+# if defined(__clang__) && defined(__llvm__)
+ AX_PTHREAD_CC_IS_CLANG
+# endif
+ ],
+ [ax_cv_PTHREAD_CLANG=yes])
+ fi
+ ])
+ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
+
+
# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)
+# Note that for GCC and Clang -pthread generally implies -lpthread,
+# except when -nostdlib is passed.
+# This is problematic using libtool to build C++ shared libraries with pthread:
+# [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25460
+# [2] https://bugzilla.redhat.com/show_bug.cgi?id=661333
+# [3] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=468555
+# To solve this, first try -pthread together with -lpthread for GCC
+
AS_IF([test "x$GCC" = "xyes"],
- [ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"])
+ [ax_pthread_flags="-pthread,-lpthread -pthread -pthreads $ax_pthread_flags"])
+
+# Clang takes -pthread (never supported any other flag), but we'll try with -lpthread first
+
+AS_IF([test "x$ax_pthread_clang" = "xyes"],
+ [ax_pthread_flags="-pthread,-lpthread -pthread"])
+
# The presence of a feature test macro requesting re-entrant function
# definitions is, on some systems, a strong hint that pthreads support is
@@ -224,25 +265,86 @@ AS_IF([test "x$ax_pthread_check_macro" = "x--"],
[ax_pthread_check_cond=0],
[ax_pthread_check_cond="!defined($ax_pthread_check_macro)"])
-# Are we compiling with Clang?
-AC_CACHE_CHECK([whether $CC is Clang],
- [ax_cv_PTHREAD_CLANG],
- [ax_cv_PTHREAD_CLANG=no
- # Note that Autoconf sets GCC=yes for Clang as well as GCC
- if test "x$GCC" = "xyes"; then
- AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG],
- [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
-# if defined(__clang__) && defined(__llvm__)
- AX_PTHREAD_CC_IS_CLANG
-# endif
- ],
- [ax_cv_PTHREAD_CLANG=yes])
- fi
- ])
-ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
+if test "x$ax_pthread_ok" = "xno"; then
+for ax_pthread_try_flag in $ax_pthread_flags; do
+
+ case $ax_pthread_try_flag in
+ none)
+ AC_MSG_CHECKING([whether pthreads work without any flags])
+ ;;
+
+ *,*)
+ PTHREAD_CFLAGS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\1/"`
+ PTHREAD_LIBS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\2/"`
+ AC_MSG_CHECKING([whether pthreads work with "$PTHREAD_CFLAGS" and "$PTHREAD_LIBS"])
+ ;;
+
+ -*)
+ AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag])
+ PTHREAD_CFLAGS="$ax_pthread_try_flag"
+ ;;
+
+ pthread-config)
+ AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
+ AS_IF([test "x$ax_pthread_config" = "xno"], [continue])
+ PTHREAD_CFLAGS="`pthread-config --cflags`"
+ PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+ ;;
+
+ *)
+ AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag])
+ PTHREAD_LIBS="-l$ax_pthread_try_flag"
+ ;;
+ esac
+
+ ax_pthread_save_CFLAGS="$CFLAGS"
+ ax_pthread_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+
+ # Check for various functions. We must include pthread.h,
+ # since some functions may be macros. (On the Sequent, we
+ # need a special flag -Kthread to make this header compile.)
+ # We check for pthread_join because it is in -lpthread on IRIX
+ # while pthread_create is in libc. We check for pthread_attr_init
+ # due to DEC craziness with -lpthreads. We check for
+ # pthread_cleanup_push because it is one of the few pthread
+ # functions on Solaris that doesn't have a non-functional libc stub.
+ # We try pthread_create on general principles.
+
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
+# if $ax_pthread_check_cond
+# error "$ax_pthread_check_macro must be defined"
+# endif
+ static void *some_global = NULL;
+ static void routine(void *a)
+ {
+ /* To avoid any unused-parameter or
+ unused-but-set-parameter warning. */
+ some_global = a;
+ }
+ static void *start_routine(void *a) { return a; }],
+ [pthread_t th; pthread_attr_t attr;
+ pthread_create(&th, 0, start_routine, 0);
+ pthread_join(th, 0);
+ pthread_attr_init(&attr);
+ pthread_cleanup_push(routine, 0);
+ pthread_cleanup_pop(0) /* ; */])],
+ [ax_pthread_ok=yes],
+ [])
+
+ CFLAGS="$ax_pthread_save_CFLAGS"
+ LIBS="$ax_pthread_save_LIBS"
+
+ AC_MSG_RESULT([$ax_pthread_ok])
+ AS_IF([test "x$ax_pthread_ok" = "xyes"], [break])
+
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+done
+fi
-ax_pthread_clang_warning=no
# Clang needs special handling, because older versions handle the -pthread
# option in a rather... idiosyncratic way
@@ -261,11 +363,6 @@ if test "x$ax_pthread_clang" = "xyes"; then
# -pthread does define _REENTRANT, and while the Darwin headers
# ignore this macro, third-party headers might not.)
- PTHREAD_CFLAGS="-pthread"
- PTHREAD_LIBS=
-
- ax_pthread_ok=yes
-
# However, older versions of Clang make a point of warning the user
# that, in an invocation where only linking and no compilation is
# taking place, the -pthread option has no effect ("argument unused
@@ -294,7 +391,7 @@ if test "x$ax_pthread_clang" = "xyes"; then
# step
ax_pthread_save_ac_link="$ac_link"
ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
- ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"`
+ ax_pthread_link_step=`AS_ECHO(["$ac_link"]) | sed "$ax_pthread_sed"`
ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
ax_pthread_save_CFLAGS="$CFLAGS"
for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
@@ -320,78 +417,7 @@ if test "x$ax_pthread_clang" = "xyes"; then
fi # $ax_pthread_clang = yes
-if test "x$ax_pthread_ok" = "xno"; then
-for ax_pthread_try_flag in $ax_pthread_flags; do
-
- case $ax_pthread_try_flag in
- none)
- AC_MSG_CHECKING([whether pthreads work without any flags])
- ;;
-
- -mt,pthread)
- AC_MSG_CHECKING([whether pthreads work with -mt -lpthread])
- PTHREAD_CFLAGS="-mt"
- PTHREAD_LIBS="-lpthread"
- ;;
-
- -*)
- AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag])
- PTHREAD_CFLAGS="$ax_pthread_try_flag"
- ;;
- pthread-config)
- AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
- AS_IF([test "x$ax_pthread_config" = "xno"], [continue])
- PTHREAD_CFLAGS="`pthread-config --cflags`"
- PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
- ;;
-
- *)
- AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag])
- PTHREAD_LIBS="-l$ax_pthread_try_flag"
- ;;
- esac
-
- ax_pthread_save_CFLAGS="$CFLAGS"
- ax_pthread_save_LIBS="$LIBS"
- CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
- LIBS="$PTHREAD_LIBS $LIBS"
-
- # Check for various functions. We must include pthread.h,
- # since some functions may be macros. (On the Sequent, we
- # need a special flag -Kthread to make this header compile.)
- # We check for pthread_join because it is in -lpthread on IRIX
- # while pthread_create is in libc. We check for pthread_attr_init
- # due to DEC craziness with -lpthreads. We check for
- # pthread_cleanup_push because it is one of the few pthread
- # functions on Solaris that doesn't have a non-functional libc stub.
- # We try pthread_create on general principles.
-
- AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
-# if $ax_pthread_check_cond
-# error "$ax_pthread_check_macro must be defined"
-# endif
- static void routine(void *a) { a = 0; }
- static void *start_routine(void *a) { return a; }],
- [pthread_t th; pthread_attr_t attr;
- pthread_create(&th, 0, start_routine, 0);
- pthread_join(th, 0);
- pthread_attr_init(&attr);
- pthread_cleanup_push(routine, 0);
- pthread_cleanup_pop(0) /* ; */])],
- [ax_pthread_ok=yes],
- [])
-
- CFLAGS="$ax_pthread_save_CFLAGS"
- LIBS="$ax_pthread_save_LIBS"
-
- AC_MSG_RESULT([$ax_pthread_ok])
- AS_IF([test "x$ax_pthread_ok" = "xyes"], [break])
-
- PTHREAD_LIBS=""
- PTHREAD_CFLAGS=""
-done
-fi
# Various other checks:
if test "x$ax_pthread_ok" = "xyes"; then
@@ -438,7 +464,8 @@ if test "x$ax_pthread_ok" = "xyes"; then
AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
[ax_cv_PTHREAD_PRIO_INHERIT],
[AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
- [[int i = PTHREAD_PRIO_INHERIT;]])],
+ [[int i = PTHREAD_PRIO_INHERIT;
+ return i;]])],
[ax_cv_PTHREAD_PRIO_INHERIT=yes],
[ax_cv_PTHREAD_PRIO_INHERIT=no])
])
@@ -460,18 +487,28 @@ if test "x$ax_pthread_ok" = "xyes"; then
[#handle absolute path differently from PATH based program lookup
AS_CASE(["x$CC"],
[x/*],
- [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
- [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
+ [
+ AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])
+ AS_IF([test "x${CXX}" != "x"], [AS_IF([AS_EXECUTABLE_P([${CXX}_r])],[PTHREAD_CXX="${CXX}_r"])])
+ ],
+ [
+ AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])
+ AS_IF([test "x${CXX}" != "x"], [AC_CHECK_PROGS([PTHREAD_CXX],[${CXX}_r],[$CXX])])
+ ]
+ )
+ ])
;;
esac
fi
fi
test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
+test -n "$PTHREAD_CXX" || PTHREAD_CXX="$CXX"
AC_SUBST([PTHREAD_LIBS])
AC_SUBST([PTHREAD_CFLAGS])
AC_SUBST([PTHREAD_CC])
+AC_SUBST([PTHREAD_CXX])
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
if test "x$ax_pthread_ok" = "xyes"; then
diff --git a/src/Makefile.am b/src/Makefile.am
index 1ef47fc..58cf07c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,35 +1,41 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/include \
+ -I$(top_srcdir)/3rd_party/libsrp6a-sha512 \
+ -I$(top_srcdir)/3rd_party/ed25519 \
-I$(top_srcdir)
AM_CFLAGS = \
$(GLOBAL_CFLAGS) \
+ $(ssl_lib_CFLAGS) \
+ $(LFS_CFLAGS) \
+ $(PTHREAD_CFLAGS) \
$(libusbmuxd_CFLAGS) \
- $(libgnutls_CFLAGS) \
- $(libtasn1_CFLAGS) \
$(libplist_CFLAGS) \
- $(LFS_CFLAGS) \
- $(openssl_CFLAGS) \
- $(PTHREAD_CFLAGS)
+ $(limd_glue_CFLAGS)
AM_LDFLAGS = \
- $(libgnutls_LIBS) \
- $(libtasn1_LIBS) \
- $(libplist_LIBS) \
+ $(ssl_lib_LIBS) \
+ $(PTHREAD_LIBS) \
$(libusbmuxd_LIBS) \
- $(libgcrypt_LIBS) \
- $(openssl_LIBS) \
- $(PTHREAD_LIBS)
+ $(libplist_LIBS) \
+ $(limd_glue_LIBS)
lib_LTLIBRARIES = libimobiledevice-1.0.la
libimobiledevice_1_0_la_LIBADD = $(top_builddir)/common/libinternalcommon.la
+if HAVE_WIRELESS_PAIRING
+libimobiledevice_1_0_la_LIBADD += $(top_builddir)/3rd_party/ed25519/libed25519.la $(top_builddir)/3rd_party/libsrp6a-sha512/libsrp6a-sha512.la
+endif
libimobiledevice_1_0_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(LIBIMOBILEDEVICE_SO_VERSION) -no-undefined
+if DARWIN
+libimobiledevice_1_0_la_LDFLAGS += -framework CoreFoundation -framework SystemConfiguration
+endif
libimobiledevice_1_0_la_SOURCES = \
idevice.c idevice.h \
service.c service.h \
property_list_service.c property_list_service.h \
device_link_service.c device_link_service.h \
lockdown.c lockdown.h \
+ lockdown-cu.c \
afc.c afc.h \
file_relay.c file_relay.h \
notification_proxy.c notification_proxy.h \
@@ -50,7 +56,9 @@ libimobiledevice_1_0_la_SOURCES = \
mobileactivation.c mobileactivation.h \
preboard.c preboard.h \
companion_proxy.c companion_proxy.h \
- syslog_relay.c syslog_relay.h
+ reverse_proxy.c reverse_proxy.h \
+ syslog_relay.c syslog_relay.h \
+ bt_packet_logger.c bt_packet_logger.h
if WIN32
libimobiledevice_1_0_la_LDFLAGS += -avoid-version -static-libgcc
diff --git a/src/afc.c b/src/afc.c
index 4b8436e..1b4070b 100644
--- a/src/afc.c
+++ b/src/afc.c
@@ -29,8 +29,8 @@
#include <unistd.h>
#include <string.h>
-#include "afc.h"
#include "idevice.h"
+#include "afc.h"
#include "common/debug.h"
#include "endianness.h"
@@ -68,7 +68,7 @@ static void afc_unlock(afc_client_t client)
* invalid, or AFC_E_NO_MEM if there is a memory allocation problem.
*/
-LIBIMOBILEDEVICE_API afc_error_t afc_client_new_with_service_client(service_client_t service_client, afc_client_t *client)
+afc_error_t afc_client_new_with_service_client(service_client_t service_client, afc_client_t *client)
{
if (!service_client)
return AFC_E_INVALID_ARG;
@@ -94,7 +94,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_client_new_with_service_client(service_clie
return AFC_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API afc_error_t afc_client_new(idevice_t device, lockdownd_service_descriptor_t service, afc_client_t * client)
+afc_error_t afc_client_new(idevice_t device, lockdownd_service_descriptor_t service, afc_client_t * client)
{
if (!device || !service || service->port == 0)
return AFC_E_INVALID_ARG;
@@ -113,14 +113,14 @@ LIBIMOBILEDEVICE_API afc_error_t afc_client_new(idevice_t device, lockdownd_serv
return err;
}
-LIBIMOBILEDEVICE_API afc_error_t afc_client_start_service(idevice_t device, afc_client_t * client, const char* label)
+afc_error_t afc_client_start_service(idevice_t device, afc_client_t * client, const char* label)
{
afc_error_t err = AFC_E_UNKNOWN_ERROR;
service_client_factory_start_service(device, AFC_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(afc_client_new), &err);
return err;
}
-LIBIMOBILEDEVICE_API afc_error_t afc_client_free(afc_client_t client)
+afc_error_t afc_client_free(afc_client_t client)
{
if (!client || !client->afc_packet)
return AFC_E_INVALID_ARG;
@@ -213,7 +213,8 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t
uint32_t this_len = 0;
uint32_t current_count = 0;
uint64_t param1 = -1;
- char* dump_here = NULL;
+ char *buf = NULL;
+ uint32_t recv_len = 0;
if (bytes_recv) {
*bytes_recv = 0;
@@ -223,18 +224,20 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t
}
/* first, read the AFC header */
- service_receive(client->parent, (char*)&header, sizeof(AFCPacket), bytes_recv);
+ service_receive(client->parent, (char*)&header, sizeof(AFCPacket), &recv_len);
AFCPacket_from_LE(&header);
- if (*bytes_recv == 0) {
+ if (recv_len == 0) {
debug_info("Just didn't get enough.");
return AFC_E_MUX_ERROR;
- } else if (*bytes_recv < sizeof(AFCPacket)) {
+ }
+
+ if (recv_len < sizeof(AFCPacket)) {
debug_info("Did not even get the AFCPacket header");
return AFC_E_MUX_ERROR;
}
/* check if it's a valid AFC header */
- if (strncmp(header.magic, AFC_MAGIC, AFC_MAGIC_LEN)) {
+ if (strncmp(header.magic, AFC_MAGIC, AFC_MAGIC_LEN) != 0) {
debug_info("Invalid AFC packet received (magic != " AFC_MAGIC ")!");
}
@@ -249,15 +252,14 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t
if (header.this_length < sizeof(AFCPacket)) {
debug_info("Invalid AFCPacket header received!");
return AFC_E_OP_HEADER_INVALID;
- } else if ((header.this_length == header.entire_length)
- && header.entire_length == sizeof(AFCPacket)) {
+ }
+ if ((header.this_length == header.entire_length)
+ && header.entire_length == sizeof(AFCPacket)) {
debug_info("Empty AFCPacket received!");
- *bytes_recv = 0;
if (header.operation == AFC_OP_DATA) {
return AFC_E_SUCCESS;
- } else {
- return AFC_E_IO_ERROR;
}
+ return AFC_E_IO_ERROR;
}
debug_info("received AFC packet, full len=%lld, this len=%lld, operation=0x%llx", header.entire_length, header.this_length, header.operation);
@@ -265,15 +267,17 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t
entire_len = (uint32_t)header.entire_length - sizeof(AFCPacket);
this_len = (uint32_t)header.this_length - sizeof(AFCPacket);
- dump_here = (char*)malloc(entire_len);
+ buf = (char*)malloc(entire_len);
if (this_len > 0) {
- service_receive(client->parent, dump_here, this_len, bytes_recv);
- if (*bytes_recv <= 0) {
- free(dump_here);
+ recv_len = 0;
+ service_receive(client->parent, buf, this_len, &recv_len);
+ if (recv_len <= 0) {
+ free(buf);
debug_info("Did not get packet contents!");
return AFC_E_NOT_ENOUGH_DATA;
- } else if (*bytes_recv < this_len) {
- free(dump_here);
+ }
+ if (recv_len < this_len) {
+ free(buf);
debug_info("Could not receive this_len=%d bytes", this_len);
return AFC_E_NOT_ENOUGH_DATA;
}
@@ -283,12 +287,13 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t
if (entire_len > this_len) {
while (current_count < entire_len) {
- service_receive(client->parent, dump_here+current_count, entire_len - current_count, bytes_recv);
- if (*bytes_recv <= 0) {
- debug_info("Error receiving data (recv returned %d)", *bytes_recv);
+ recv_len = 0;
+ service_receive(client->parent, buf+current_count, entire_len - current_count, &recv_len);
+ if (recv_len <= 0) {
+ debug_info("Error receiving data (recv returned %d)", recv_len);
break;
}
- current_count += *bytes_recv;
+ current_count += recv_len;
}
if (current_count < entire_len) {
debug_info("WARNING: could not receive full packet (read %s, size %d)", current_count, entire_len);
@@ -296,16 +301,16 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t
}
if (current_count >= sizeof(uint64_t)) {
- param1 = le64toh(*(uint64_t*)(dump_here));
+ param1 = le64toh(*(uint64_t*)(buf));
}
debug_info("packet data size = %i", current_count);
if (current_count > 256) {
debug_info("packet data follows (256/%u)", current_count);
- debug_buffer(dump_here, 256);
+ debug_buffer(buf, 256);
} else {
debug_info("packet data follows");
- debug_buffer(dump_here, current_count);
+ debug_buffer(buf, current_count);
}
/* check operation types */
@@ -316,7 +321,7 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t
if (param1 != AFC_E_SUCCESS) {
/* error status */
/* free buffer */
- free(dump_here);
+ free(buf);
return (afc_error_t)param1;
}
} else if (header.operation == AFC_OP_DATA) {
@@ -330,8 +335,7 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t
debug_info("got a tell response, position=%lld", param1);
} else {
/* unknown operation code received */
- free(dump_here);
- *bytes_recv = 0;
+ free(buf);
debug_info("WARNING: Unknown operation code received 0x%llx param1=%lld", header.operation, param1);
#ifndef WIN32
@@ -342,9 +346,9 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t
}
if (bytes) {
- *bytes = dump_here;
+ *bytes = buf;
} else {
- free(dump_here);
+ free(buf);
}
*bytes_recv = current_count;
@@ -354,7 +358,7 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t
/**
* Returns counts of null characters within a string.
*/
-static uint32_t count_nullspaces(char *string, uint32_t number)
+static uint32_t count_nullspaces(const char *string, uint32_t number)
{
uint32_t i = 0, nulls = 0;
@@ -410,7 +414,7 @@ static int _afc_check_packet_buffer(afc_client_t client, uint32_t data_len)
#define AFC_PACKET_DATA_PTR ((char*)client->afc_packet + sizeof(AFCPacket))
-LIBIMOBILEDEVICE_API afc_error_t afc_read_directory(afc_client_t client, const char *path, char ***directory_information)
+afc_error_t afc_read_directory(afc_client_t client, const char *path, char ***directory_information)
{
uint32_t bytes = 0;
char *data = NULL, **list_loc = NULL;
@@ -454,7 +458,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_read_directory(afc_client_t client, const c
return ret;
}
-LIBIMOBILEDEVICE_API afc_error_t afc_get_device_info(afc_client_t client, char ***device_information)
+afc_error_t afc_get_device_info(afc_client_t client, char ***device_information)
{
uint32_t bytes = 0;
char *data = NULL, **list = NULL;
@@ -491,7 +495,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_get_device_info(afc_client_t client, char *
return ret;
}
-LIBIMOBILEDEVICE_API afc_error_t afc_get_device_info_key(afc_client_t client, const char *key, char **value)
+afc_error_t afc_get_device_info_key(afc_client_t client, const char *key, char **value)
{
afc_error_t ret = AFC_E_INTERNAL_ERROR;
char **kvps, **ptr;
@@ -518,7 +522,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_get_device_info_key(afc_client_t client, co
return ret;
}
-LIBIMOBILEDEVICE_API afc_error_t afc_remove_path(afc_client_t client, const char *path)
+afc_error_t afc_remove_path(afc_client_t client, const char *path)
{
uint32_t bytes = 0;
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
@@ -554,7 +558,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_remove_path(afc_client_t client, const char
return ret;
}
-LIBIMOBILEDEVICE_API afc_error_t afc_rename_path(afc_client_t client, const char *from, const char *to)
+afc_error_t afc_rename_path(afc_client_t client, const char *from, const char *to)
{
if (!client || !from || !to || !client->afc_packet || !client->parent)
return AFC_E_INVALID_ARG;
@@ -590,7 +594,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_rename_path(afc_client_t client, const char
return ret;
}
-LIBIMOBILEDEVICE_API afc_error_t afc_make_directory(afc_client_t client, const char *path)
+afc_error_t afc_make_directory(afc_client_t client, const char *path)
{
uint32_t bytes = 0;
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
@@ -622,7 +626,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_make_directory(afc_client_t client, const c
return ret;
}
-LIBIMOBILEDEVICE_API afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***file_information)
+afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***file_information)
{
char *received = NULL;
uint32_t bytes = 0;
@@ -662,7 +666,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_get_file_info(afc_client_t client, const ch
return ret;
}
-LIBIMOBILEDEVICE_API afc_error_t afc_file_open(afc_client_t client, const char *filename, afc_file_mode_t file_mode, uint64_t *handle)
+afc_error_t afc_file_open(afc_client_t client, const char *filename, afc_file_mode_t file_mode, uint64_t *handle)
{
if (!client || !client->parent || !client->afc_packet)
return AFC_E_INVALID_ARG;
@@ -714,7 +718,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_open(afc_client_t client, const char *
return ret;
}
-LIBIMOBILEDEVICE_API afc_error_t afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length, uint32_t *bytes_read)
+afc_error_t afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length, uint32_t *bytes_read)
{
char *input = NULL;
uint32_t current_count = 0, bytes_loc = 0;
@@ -748,28 +752,29 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_read(afc_client_t client, uint64_t han
if (ret != AFC_E_SUCCESS) {
afc_unlock(client);
return ret;
- } else if (bytes_loc == 0) {
+ }
+ if (bytes_loc == 0) {
if (input)
free(input);
afc_unlock(client);
*bytes_read = current_count;
/* FIXME: check that's actually a success */
return ret;
- } else {
- if (input) {
- debug_info("%d", bytes_loc);
- memcpy(data + current_count, input, (bytes_loc > length) ? length : bytes_loc);
- free(input);
- input = NULL;
- current_count += (bytes_loc > length) ? length : bytes_loc;
- }
}
+ if (input) {
+ debug_info("%d", bytes_loc);
+ memcpy(data + current_count, input, (bytes_loc > length) ? length : bytes_loc);
+ free(input);
+ input = NULL;
+ current_count += (bytes_loc > length) ? length : bytes_loc;
+ }
+
afc_unlock(client);
*bytes_read = current_count;
return ret;
}
-LIBIMOBILEDEVICE_API afc_error_t afc_file_write(afc_client_t client, uint64_t handle, const char *data, uint32_t length, uint32_t *bytes_written)
+afc_error_t afc_file_write(afc_client_t client, uint64_t handle, const char *data, uint32_t length, uint32_t *bytes_written)
{
uint32_t current_count = 0;
uint32_t bytes_loc = 0;
@@ -798,13 +803,13 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_write(afc_client_t client, uint64_t ha
ret = afc_receive_data(client, NULL, &bytes_loc);
afc_unlock(client);
if (ret != AFC_E_SUCCESS) {
- debug_info("uh oh?");
+ debug_info("Failed to receive reply (%d)", ret);
}
*bytes_written = current_count;
return ret;
}
-LIBIMOBILEDEVICE_API afc_error_t afc_file_close(afc_client_t client, uint64_t handle)
+afc_error_t afc_file_close(afc_client_t client, uint64_t handle)
{
uint32_t bytes = 0;
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
@@ -835,7 +840,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_close(afc_client_t client, uint64_t ha
return ret;
}
-LIBIMOBILEDEVICE_API afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t operation)
+afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t operation)
{
uint32_t bytes = 0;
struct lockinfo {
@@ -869,7 +874,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_lock(afc_client_t client, uint64_t han
return ret;
}
-LIBIMOBILEDEVICE_API afc_error_t afc_file_seek(afc_client_t client, uint64_t handle, int64_t offset, int whence)
+afc_error_t afc_file_seek(afc_client_t client, uint64_t handle, int64_t offset, int whence)
{
uint32_t bytes = 0;
struct seekinfo {
@@ -903,7 +908,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_seek(afc_client_t client, uint64_t han
return ret;
}
-LIBIMOBILEDEVICE_API afc_error_t afc_file_tell(afc_client_t client, uint64_t handle, uint64_t *position)
+afc_error_t afc_file_tell(afc_client_t client, uint64_t handle, uint64_t *position)
{
char *buffer = NULL;
uint32_t bytes = 0;
@@ -938,7 +943,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_tell(afc_client_t client, uint64_t han
return ret;
}
-LIBIMOBILEDEVICE_API afc_error_t afc_file_truncate(afc_client_t client, uint64_t handle, uint64_t newsize)
+afc_error_t afc_file_truncate(afc_client_t client, uint64_t handle, uint64_t newsize)
{
uint32_t bytes = 0;
struct truncinfo {
@@ -970,7 +975,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_truncate(afc_client_t client, uint64_t
return ret;
}
-LIBIMOBILEDEVICE_API afc_error_t afc_truncate(afc_client_t client, const char *path, uint64_t newsize)
+afc_error_t afc_truncate(afc_client_t client, const char *path, uint64_t newsize)
{
if (!client || !path || !client->afc_packet || !client->parent)
return AFC_E_INVALID_ARG;
@@ -1003,13 +1008,12 @@ 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;
uint32_t bytes = 0;
- uint64_t type = htole64(linktype);
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
size_t target_len = strlen(target);
@@ -1024,7 +1028,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_make_link(afc_client_t client, afc_link_typ
return AFC_E_NO_MEM;
}
- debug_info("link type: %lld", type);
+ debug_info("link type: %lld", htole64(linktype));
debug_info("target: %s, length:%d", target, target_len);
debug_info("linkname: %s, length:%d", linkname, link_len);
@@ -1045,7 +1049,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_make_link(afc_client_t client, afc_link_typ
return ret;
}
-LIBIMOBILEDEVICE_API afc_error_t afc_set_file_time(afc_client_t client, const char *path, uint64_t mtime)
+afc_error_t afc_set_file_time(afc_client_t client, const char *path, uint64_t mtime)
{
if (!client || !path || !client->afc_packet || !client->parent)
return AFC_E_INVALID_ARG;
@@ -1078,7 +1082,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_set_file_time(afc_client_t client, const ch
return ret;
}
-LIBIMOBILEDEVICE_API afc_error_t afc_remove_path_and_contents(afc_client_t client, const char *path)
+afc_error_t afc_remove_path_and_contents(afc_client_t client, const char *path)
{
uint32_t bytes = 0;
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
@@ -1110,7 +1114,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_remove_path_and_contents(afc_client_t clien
return ret;
}
-LIBIMOBILEDEVICE_API afc_error_t afc_dictionary_free(char **dictionary)
+afc_error_t afc_dictionary_free(char **dictionary)
{
int i = 0;
@@ -1124,3 +1128,70 @@ LIBIMOBILEDEVICE_API afc_error_t afc_dictionary_free(char **dictionary)
return AFC_E_SUCCESS;
}
+
+const char* afc_strerror(afc_error_t err)
+{
+ switch (err) {
+ case AFC_E_SUCCESS:
+ return "Success";
+ case AFC_E_UNKNOWN_ERROR:
+ return "Unknown Error";
+ case AFC_E_OP_HEADER_INVALID:
+ return "Operation header invalid";
+ case AFC_E_NO_RESOURCES:
+ return "No resources";
+ case AFC_E_READ_ERROR:
+ return "Read error";
+ case AFC_E_WRITE_ERROR:
+ return "Write error";
+ case AFC_E_UNKNOWN_PACKET_TYPE:
+ return "Unknown packet type";
+ case AFC_E_INVALID_ARG:
+ return "Invalid argument";
+ case AFC_E_OBJECT_NOT_FOUND:
+ return "Not found";
+ case AFC_E_OBJECT_IS_DIR:
+ return "Object is a directory";
+ case AFC_E_PERM_DENIED:
+ return "Permission denied";
+ case AFC_E_SERVICE_NOT_CONNECTED:
+ return "Service not connected";
+ case AFC_E_OP_TIMEOUT:
+ return "Timeout";
+ case AFC_E_TOO_MUCH_DATA:
+ return "Too much data";
+ case AFC_E_END_OF_DATA:
+ return "End of data";
+ case AFC_E_OP_NOT_SUPPORTED:
+ return "Operation not supported";
+ case AFC_E_OBJECT_EXISTS:
+ return "Object exists";
+ case AFC_E_OBJECT_BUSY:
+ return "Object busy";
+ case AFC_E_NO_SPACE_LEFT:
+ return "No space left on device";
+ case AFC_E_OP_WOULD_BLOCK:
+ return "Operation would block";
+ case AFC_E_IO_ERROR:
+ return "I/O error";
+ case AFC_E_OP_INTERRUPTED:
+ return "Operation interrupted";
+ case AFC_E_OP_IN_PROGRESS:
+ return "Operation on progress";
+ case AFC_E_INTERNAL_ERROR:
+ return "Internal error";
+ case AFC_E_MUX_ERROR:
+ return "MUX error";
+ case AFC_E_NO_MEM:
+ return "Out of memory";
+ case AFC_E_NOT_ENOUGH_DATA:
+ return "Not enough data";
+ case AFC_E_DIR_NOT_EMPTY:
+ return "Directory not empty";
+ case AFC_E_FORCE_SIGNED_TYPE:
+ return "Force signed type";
+ default:
+ break;
+ }
+ return "Unknown Error";
+}
diff --git a/src/afc.h b/src/afc.h
index 3e4ef67..6bfdf56 100644
--- a/src/afc.h
+++ b/src/afc.h
@@ -28,7 +28,7 @@
#include "libimobiledevice/afc.h"
#include "service.h"
#include "endianness.h"
-#include "common/thread.h"
+#include <libimobiledevice-glue/thread.h>
#define AFC_MAGIC "CFA6LPAA"
#define AFC_MAGIC_LEN (8)
diff --git a/src/bt_packet_logger.c b/src/bt_packet_logger.c
new file mode 100644
index 0000000..937747c
--- /dev/null
+++ b/src/bt_packet_logger.c
@@ -0,0 +1,231 @@
+/*
+ * bt_packet_logger.c
+ * com.apple.bluetooth.BTPacketLogger service implementation.
+ *
+ * Copyright (c) 2021 Geoffrey Kruse, All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <string.h>
+#include <stdlib.h>
+
+#include "bt_packet_logger.h"
+#include "lockdown.h"
+#include "common/debug.h"
+
+struct bt_packet_logger_worker_thread {
+ bt_packet_logger_client_t client;
+ bt_packet_logger_receive_cb_t cbfunc;
+ void *user_data;
+ uint8_t rxbuff[BT_MAX_PACKET_SIZE];
+};
+
+#define SZ_READ_TIMEOUT 100
+#define PAYLOAD_READ_TIMEOUT 500
+
+/**
+ * Convert a service_error_t value to a bt_packet_logger_error_t value.
+ * Used internally to get correct error codes.
+ *
+ * @param err An service_error_t error code
+ *
+ * @return A matching bt_packet_logger_error_t error code,
+ * BT_PACKET_LOGGER_E_UNKNOWN_ERROR otherwise.
+ */
+static bt_packet_logger_error_t bt_packet_logger_error(service_error_t err)
+{
+ switch (err) {
+ case SERVICE_E_SUCCESS:
+ return BT_PACKET_LOGGER_E_SUCCESS;
+ case SERVICE_E_INVALID_ARG:
+ return BT_PACKET_LOGGER_E_INVALID_ARG;
+ case SERVICE_E_MUX_ERROR:
+ return BT_PACKET_LOGGER_E_MUX_ERROR;
+ case SERVICE_E_SSL_ERROR:
+ return BT_PACKET_LOGGER_E_SSL_ERROR;
+ case SERVICE_E_NOT_ENOUGH_DATA:
+ return BT_PACKET_LOGGER_E_NOT_ENOUGH_DATA;
+ case SERVICE_E_TIMEOUT:
+ return BT_PACKET_LOGGER_E_TIMEOUT;
+ default:
+ break;
+ }
+ return BT_PACKET_LOGGER_E_UNKNOWN_ERROR;
+}
+
+bt_packet_logger_error_t bt_packet_logger_client_new(idevice_t device, lockdownd_service_descriptor_t service, bt_packet_logger_client_t * client)
+{
+ if (!device || !service || service->port == 0 || !client || *client) {
+ debug_info("Incorrect parameter passed to bt_packet_logger_client_new.");
+ return BT_PACKET_LOGGER_E_INVALID_ARG;
+ }
+
+ debug_info("Creating bt_packet_logger_client, port = %d.", service->port);
+
+ service_client_t parent = NULL;
+ bt_packet_logger_error_t ret = bt_packet_logger_error(service_client_new(device, service, &parent));
+ if (ret != BT_PACKET_LOGGER_E_SUCCESS) {
+ debug_info("Creating base service client failed. Error: %i", ret);
+ return ret;
+ }
+
+ bt_packet_logger_client_t client_loc = (bt_packet_logger_client_t) malloc(sizeof(struct bt_packet_logger_client_private));
+ client_loc->parent = parent;
+ client_loc->worker = THREAD_T_NULL;
+
+ *client = client_loc;
+
+ debug_info("bt_packet_logger_client successfully created.");
+ return 0;
+}
+
+bt_packet_logger_error_t bt_packet_logger_client_start_service(idevice_t device, bt_packet_logger_client_t * client, const char* label)
+{
+ bt_packet_logger_error_t err = BT_PACKET_LOGGER_E_UNKNOWN_ERROR;
+ service_client_factory_start_service(device, BT_PACKETLOGGER_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(bt_packet_logger_client_new), &err);
+ return err;
+}
+
+bt_packet_logger_error_t bt_packet_logger_client_free(bt_packet_logger_client_t client)
+{
+ if (!client)
+ return BT_PACKET_LOGGER_E_INVALID_ARG;
+ bt_packet_logger_stop_capture(client);
+ bt_packet_logger_error_t err = bt_packet_logger_error(service_client_free(client->parent));
+ free(client);
+
+ return err;
+}
+
+bt_packet_logger_error_t bt_packet_logger_receive_with_timeout(bt_packet_logger_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout)
+{
+ bt_packet_logger_error_t res = BT_PACKET_LOGGER_E_UNKNOWN_ERROR;
+ int bytes = 0;
+
+ if (!client || !data || (size == 0)) {
+ return BT_PACKET_LOGGER_E_INVALID_ARG;
+ }
+
+ res = bt_packet_logger_error(service_receive_with_timeout(client->parent, data, size, (uint32_t*)&bytes, timeout));
+ if (res != BT_PACKET_LOGGER_E_SUCCESS && res != BT_PACKET_LOGGER_E_TIMEOUT && res != BT_PACKET_LOGGER_E_NOT_ENOUGH_DATA) {
+ debug_info("Could not read data, error %d", res);
+ }
+ if (received) {
+ *received = (uint32_t)bytes;
+ }
+
+ return res;
+}
+
+void *bt_packet_logger_worker(void *arg)
+{
+ bt_packet_logger_error_t ret = BT_PACKET_LOGGER_E_UNKNOWN_ERROR;
+ struct bt_packet_logger_worker_thread *btwt = (struct bt_packet_logger_worker_thread*)arg;
+
+ if (!btwt) {
+ return NULL;
+ }
+
+ debug_info("Running");
+
+ while (btwt->client->parent) {
+ uint32_t bytes = 0;
+ uint16_t len;
+
+ ret = bt_packet_logger_receive_with_timeout(btwt->client, (char*)&len, 2, &bytes, SZ_READ_TIMEOUT);
+
+ if (ret == BT_PACKET_LOGGER_E_TIMEOUT || ret == BT_PACKET_LOGGER_E_NOT_ENOUGH_DATA || ((bytes == 0) && (ret == BT_PACKET_LOGGER_E_SUCCESS))) {
+ continue;
+ } else if (ret < 0) {
+ debug_info("Connection to bt packet logger interrupted");
+ break;
+ }
+
+ // sanity check received length
+ if(bytes > 0 && len > sizeof(bt_packet_logger_header_t)) {
+ debug_info("Reading %u bytes\n", len);
+ ret = bt_packet_logger_receive_with_timeout(btwt->client, (char *)btwt->rxbuff, len, &bytes, PAYLOAD_READ_TIMEOUT);
+
+ if(len != bytes) {
+ debug_info("Failed Read Expected %u, Received %u\n", len, bytes);
+ continue;
+ }
+
+ if (ret == BT_PACKET_LOGGER_E_TIMEOUT || ret == BT_PACKET_LOGGER_E_NOT_ENOUGH_DATA || ((bytes == 0) && (ret == BT_PACKET_LOGGER_E_SUCCESS))) {
+ continue;
+ } else if (ret < 0) {
+ debug_info("Connection to bt packet logger interrupted");
+ break;
+ }
+
+ btwt->cbfunc(btwt->rxbuff, len, btwt->user_data);
+ }
+ }
+
+ // null check performed above
+ free(btwt);
+
+ debug_info("Exiting");
+
+ return NULL;
+}
+
+bt_packet_logger_error_t bt_packet_logger_start_capture(bt_packet_logger_client_t client, bt_packet_logger_receive_cb_t callback, void* user_data)
+{
+ if (!client || !callback)
+ return BT_PACKET_LOGGER_E_INVALID_ARG;
+
+ bt_packet_logger_error_t res = BT_PACKET_LOGGER_E_UNKNOWN_ERROR;
+
+ if (client->worker) {
+ debug_info("Another syslog capture thread appears to be running already.");
+ return res;
+ }
+
+ /* start worker thread */
+ struct bt_packet_logger_worker_thread *btwt = (struct bt_packet_logger_worker_thread*)malloc(sizeof(struct bt_packet_logger_worker_thread));
+ if (btwt) {
+ btwt->client = client;
+ btwt->cbfunc = callback;
+ btwt->user_data = user_data;
+
+ if (thread_new(&client->worker, bt_packet_logger_worker, btwt) == 0) {
+ res = BT_PACKET_LOGGER_E_SUCCESS;
+ }
+ }
+
+ return res;
+}
+
+
+bt_packet_logger_error_t bt_packet_logger_stop_capture(bt_packet_logger_client_t client)
+{
+ if (client->worker) {
+ /* notify thread to finish */
+ service_client_t parent = client->parent;
+ client->parent = NULL;
+ /* join thread to make it exit */
+ thread_join(client->worker);
+ thread_free(client->worker);
+ client->worker = THREAD_T_NULL;
+ client->parent = parent;
+ }
+
+ return BT_PACKET_LOGGER_E_SUCCESS;
+}
diff --git a/src/bt_packet_logger.h b/src/bt_packet_logger.h
new file mode 100644
index 0000000..620555e
--- /dev/null
+++ b/src/bt_packet_logger.h
@@ -0,0 +1,37 @@
+/*
+ * bt_packet_logger.h
+ * com.apple.bluetooth.BTPacketLogger service header file.
+ *
+ * Copyright (c) 2021 Geoffrey Kruse, All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _BR_PACKET_LOGGER_H
+#define _BR_PACKET_LOGGER_H
+
+#include "idevice.h"
+#include "libimobiledevice/bt_packet_logger.h"
+#include "service.h"
+#include <libimobiledevice-glue/thread.h>
+
+struct bt_packet_logger_client_private {
+ service_client_t parent;
+ THREAD_T worker;
+};
+
+void *bt_packet_logger_worker(void *arg);
+
+#endif
diff --git a/src/companion_proxy.c b/src/companion_proxy.c
index f09b416..421fa9a 100644
--- a/src/companion_proxy.c
+++ b/src/companion_proxy.c
@@ -29,7 +29,6 @@
#include "companion_proxy.h"
#include "lockdown.h"
#include "common/debug.h"
-#include "common/thread.h"
/**
* Convert a property_list_service_error_t value to a companion_proxy_error_t value.
@@ -63,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;
@@ -91,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;
@@ -117,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;
@@ -130,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;
@@ -144,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;
@@ -227,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;
@@ -253,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;
@@ -267,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;
@@ -311,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;
@@ -326,7 +325,7 @@ LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_start_forwarding_se
plist_dict_set_item(dict, "IsServiceLowPriority", plist_new_bool(0));
plist_dict_set_item(dict, "PreferWifi", plist_new_bool(0));
if (options) {
- plist_dict_merge(dict, options);
+ plist_dict_merge(&dict, options);
}
companion_proxy_error_t res = companion_proxy_send(client, dict);
@@ -354,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 0314b67..e36932a 100644
--- a/src/companion_proxy.h
+++ b/src/companion_proxy.h
@@ -22,9 +22,10 @@
#ifndef __COMPANION_PROXY_H
#define __COMPANION_PROXY_H
+#include "idevice.h"
#include "libimobiledevice/companion_proxy.h"
#include "property_list_service.h"
-#include "common/thread.h"
+#include <libimobiledevice-glue/thread.h>
struct companion_proxy_client_private {
property_list_service_client_t parent;
diff --git a/src/debugserver.c b/src/debugserver.c
index cc0e73f..74ade8a 100644
--- a/src/debugserver.c
+++ b/src/debugserver.c
@@ -29,10 +29,11 @@
#define __USE_GNU 1
#include <stdio.h>
+#include <libimobiledevice-glue/utils.h>
+
#include "debugserver.h"
#include "lockdown.h"
#include "common/debug.h"
-#include "common/utils.h"
#include "asprintf.h"
/**
@@ -63,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;
@@ -88,6 +89,8 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_new(idevice_t device
debugserver_client_t client_loc = (debugserver_client_t) malloc(sizeof(struct debugserver_client_private));
client_loc->parent = parent;
client_loc->noack_mode = 0;
+ client_loc->cancel_receive = NULL;
+ client_loc->receive_loop_timeout = 1000;
*client = client_loc;
@@ -95,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);
@@ -106,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;
@@ -118,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;
@@ -139,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;
@@ -149,22 +152,27 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive_with_timeout
}
res = debugserver_error(service_receive_with_timeout(client->parent, data, size, (uint32_t*)&bytes, timeout));
- if (bytes <= 0) {
+ if (bytes <= 0 && res != DEBUGSERVER_E_TIMEOUT) {
debug_info("Could not read data, error %d", res);
}
if (received) {
*received = (uint32_t)bytes;
}
- return res;
+ return (bytes > 0) ? DEBUGSERVER_E_SUCCESS : res;
}
-LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive(debugserver_client_t client, char* data, uint32_t size, uint32_t *received)
+debugserver_error_t debugserver_client_receive(debugserver_client_t client, char* data, uint32_t size, uint32_t *received)
{
- return debugserver_client_receive_with_timeout(client, data, size, received, 1000);
+ debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR;
+ do {
+ /* Is this allowed to return DEBUGSERVER_E_TIMEOUT and also set data and received? */
+ res = debugserver_client_receive_with_timeout(client, data, size, received, client->receive_loop_timeout);
+ } while (res == DEBUGSERVER_E_TIMEOUT && client->cancel_receive != NULL && !client->cancel_receive());
+ return res;
}
-LIBIMOBILEDEVICE_API debugserver_error_t debugserver_command_new(const char* name, int argc, char* argv[], debugserver_command_t* command)
+debugserver_error_t debugserver_command_new(const char* name, int argc, char* argv[], debugserver_command_t* command)
{
int i;
debugserver_command_t tmp = (debugserver_command_t) malloc(sizeof(struct debugserver_command_private));
@@ -189,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;
@@ -231,10 +239,10 @@ static char debugserver_int2hex(int x)
return hexchars[x];
}
-#define DEBUGSERVER_HEX_ENCODE_FIRST_BYTE(byte) debugserver_int2hex((byte >> 0x4) & 0xf)
-#define DEBUGSERVER_HEX_ENCODE_SECOND_BYTE(byte) debugserver_int2hex(byte & 0xf)
-#define DEBUGSERVER_HEX_DECODE_FIRST_BYTE(byte) ((byte >> 0x4) & 0xf)
-#define DEBUGSERVER_HEX_DECODE_SECOND_BYTE(byte) (byte & 0xf)
+#define DEBUGSERVER_HEX_ENCODE_FIRST_BYTE(byte) debugserver_int2hex(((byte) >> 0x4) & 0xf)
+#define DEBUGSERVER_HEX_ENCODE_SECOND_BYTE(byte) debugserver_int2hex((byte) & 0xf)
+#define DEBUGSERVER_HEX_DECODE_FIRST_BYTE(byte) (((byte) >> 0x4) & 0xf)
+#define DEBUGSERVER_HEX_DECODE_SECOND_BYTE(byte) ((byte) & 0xf)
static uint32_t debugserver_get_checksum_for_buffer(const char* buffer, uint32_t size)
{
@@ -267,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;
@@ -283,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;
@@ -342,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;
@@ -354,130 +362,137 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_ack_mode(debugse
return DEBUGSERVER_E_SUCCESS;
}
-static int debugserver_client_receive_internal_check(debugserver_client_t client, char* received_char)
+debugserver_error_t debugserver_client_set_receive_params(debugserver_client_t client, int (*cancel_receive)(), int receive_loop_timeout)
+{
+ if (!client)
+ return DEBUGSERVER_E_INVALID_ARG;
+
+ client->cancel_receive = cancel_receive;
+ client->receive_loop_timeout = receive_loop_timeout;
+
+ debug_info("receive params: cancel_receive %s, receive_loop_timeout %dms", (client->cancel_receive == NULL ? "unset": "set"), client->receive_loop_timeout);
+
+ return DEBUGSERVER_E_SUCCESS;
+}
+
+static debugserver_error_t debugserver_client_receive_internal_char(debugserver_client_t client, char* received_char)
{
debugserver_error_t res = DEBUGSERVER_E_SUCCESS;
- int did_receive_char = 0;
- char buffer = 0;
uint32_t bytes = 0;
/* we loop here as we expect an answer */
- res = debugserver_client_receive_with_timeout(client, &buffer, sizeof(char), &bytes, 1000);
- if (res == DEBUGSERVER_E_SUCCESS && received_char[0] != 0) {
- if (memcmp(&buffer, received_char, sizeof(char)) == 0) {
- did_receive_char = 1;
- }
- } else {
- did_receive_char = 0;
+ res = debugserver_client_receive(client, received_char, sizeof(char), &bytes);
+ if (res != DEBUGSERVER_E_SUCCESS) {
+ return res;
}
-
- if (!did_receive_char) {
- memcpy(received_char, &buffer, sizeof(char));
+ if (bytes != 1) {
+ debug_info("received %d bytes when asking for %d!", bytes, sizeof(char));
+ return DEBUGSERVER_E_UNKNOWN_ERROR;
}
-
- return did_receive_char;
+ return res;
}
-LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive_response(debugserver_client_t client, char** response, size_t* response_size)
+debugserver_error_t debugserver_client_receive_response(debugserver_client_t client, char** response, size_t* response_size)
{
debugserver_error_t res = DEBUGSERVER_E_SUCCESS;
- int should_receive = 1;
+ char data = '\0';
int skip_prefix = 0;
- char* command_prefix = strdup("$");
- char* buffer = NULL;
+ char* buffer = malloc(1024);
uint32_t buffer_size = 0;
- uint32_t buffer_capacity = 0;
+ uint32_t buffer_capacity = 1024;
if (response)
*response = NULL;
if (!client->noack_mode) {
- char ack[2] = {'+', '\0'};
- debug_info("attempting to receive ACK %c", *ack);
- should_receive = debugserver_client_receive_internal_check(client, ack);
- debug_info("received char: %c", *ack);
- if (strncmp(ack, command_prefix, sizeof(char)) == 0) {
- should_receive = 1;
+ debug_info("attempting to receive ACK (+)");
+ res = debugserver_client_receive_internal_char(client, &data);
+ if (res != DEBUGSERVER_E_SUCCESS) {
+ goto cleanup;
+ }
+ if (data == '+') {
+ debug_info("received ACK (+)");
+ } else if (data == '$') {
+ debug_info("received prefix ($)");
+ buffer[0] = '$';
+ buffer_size = 1;
skip_prefix = 1;
- buffer = malloc(1024);
- buffer_capacity = 1024;
- strcpy(buffer, command_prefix);
- buffer_size += sizeof(char);
- debug_info("received ACK");
+ } else {
+ debug_info("unrecognized response when looking for ACK: %c", data);
+ goto cleanup;
}
}
- debug_info("should_receive: %d, skip_prefix: %d", should_receive, skip_prefix);
-
- if (should_receive && !skip_prefix) {
- debug_info("attempting to receive prefix");
- should_receive = debugserver_client_receive_internal_check(client, command_prefix);
- debug_info("received command_prefix: %c", *command_prefix);
- if (should_receive) {
- if (buffer) {
- strcpy(buffer, command_prefix);
- } else {
- buffer = malloc(1024);
- buffer_capacity = 1024;
- strcpy(buffer, command_prefix);
- buffer_size += sizeof(char);
- }
+ debug_info("skip_prefix: %d", skip_prefix);
+
+ if (!skip_prefix) {
+ debug_info("attempting to receive prefix ($)");
+ res = debugserver_client_receive_internal_char(client, &data);
+ if (res != DEBUGSERVER_E_SUCCESS) {
+ goto cleanup;
+ }
+ if (data == '$') {
+ debug_info("received prefix ($)");
+ buffer[0] = '$';
+ buffer_size = 1;
+ } else {
+ debug_info("unrecognized response when looking for prefix: %c", data);
+ goto cleanup;
}
}
- debug_info("buffer: %*s, should_receive: %d, skip_prefix: %d", buffer_size, buffer, should_receive, skip_prefix);
-
- if (should_receive) {
- uint32_t checksum_length = DEBUGSERVER_CHECKSUM_HASH_LENGTH;
- int receiving_checksum_response = 0;
- debug_info("attempting to read up response until checksum");
+ uint32_t checksum_length = DEBUGSERVER_CHECKSUM_HASH_LENGTH;
+ int receiving_checksum_response = 0;
+ debug_info("attempting to read up response until checksum");
- while ((checksum_length > 0)) {
- char data[2] = {'#', '\0'};
- if (debugserver_client_receive_internal_check(client, data)) {
- receiving_checksum_response = 1;
- }
- if (receiving_checksum_response) {
- checksum_length--;
- }
- if (buffer_size + 1 >= buffer_capacity) {
- char* newbuffer = realloc(buffer, buffer_capacity+1024);
- if (!newbuffer) {
- return DEBUGSERVER_E_UNKNOWN_ERROR;
- }
- buffer = newbuffer;
- buffer[buffer_capacity] = '\0';
- buffer_capacity += 1024;
- }
- strcat(buffer, data);
- buffer_size += sizeof(char);
+ while ((checksum_length > 0)) {
+ res = debugserver_client_receive_internal_char(client, &data);
+ if (res != DEBUGSERVER_E_SUCCESS) {
+ goto cleanup;
}
- debug_info("validating response checksum...");
- if (client->noack_mode || debugserver_response_is_checksum_valid(buffer, buffer_size)) {
- if (response) {
- /* assemble response string */
- uint32_t resp_size = sizeof(char) * (buffer_size - DEBUGSERVER_CHECKSUM_HASH_LENGTH - 1);
- *response = (char*)malloc(resp_size + 1);
- memcpy(*response, buffer + 1, resp_size);
- (*response)[resp_size] = '\0';
- if (response_size) *response_size = resp_size;
- }
- if (!client->noack_mode) {
- /* confirm valid command */
- debugserver_client_send_ack(client);
- }
- } else {
- /* response was invalid */
- res = DEBUGSERVER_E_RESPONSE_ERROR;
- if (!client->noack_mode) {
- /* report invalid command */
- debugserver_client_send_noack(client);
+ if (data == '#') {
+ receiving_checksum_response = 1;
+ }
+ if (receiving_checksum_response) {
+ checksum_length--;
+ }
+ if (buffer_size + 1 >= buffer_capacity) {
+ char* newbuffer = realloc(buffer, buffer_capacity+1024);
+ if (!newbuffer) {
+ return DEBUGSERVER_E_UNKNOWN_ERROR;
}
+ buffer = newbuffer;
+ buffer_capacity += 1024;
+ }
+ buffer[buffer_size] = data;
+ buffer_size += sizeof(char);
+ }
+ debug_info("validating response checksum...");
+ if (client->noack_mode || debugserver_response_is_checksum_valid(buffer, buffer_size)) {
+ if (response) {
+ /* assemble response string */
+ uint32_t resp_size = sizeof(char) * (buffer_size - DEBUGSERVER_CHECKSUM_HASH_LENGTH - 1);
+ *response = (char*)malloc(resp_size + 1);
+ memcpy(*response, buffer + 1, resp_size);
+ (*response)[resp_size] = '\0';
+ if (response_size) *response_size = resp_size;
+ }
+ if (!client->noack_mode) {
+ /* confirm valid command */
+ debugserver_client_send_ack(client);
+ }
+ } else {
+ /* response was invalid */
+ res = DEBUGSERVER_E_RESPONSE_ERROR;
+ if (!client->noack_mode) {
+ /* report invalid command */
+ debugserver_client_send_noack(client);
}
}
+cleanup:
if (response) {
debug_info("response: %s", *response);
}
@@ -485,13 +500,10 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive_response(deb
if (buffer)
free(buffer);
- if (command_prefix)
- free(command_prefix);
-
return res;
}
-LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_send_command(debugserver_client_t client, debugserver_command_t command, char** response, size_t* response_size)
+debugserver_error_t debugserver_client_send_command(debugserver_client_t client, debugserver_command_t command, char** response, size_t* response_size)
{
debugserver_error_t res = DEBUGSERVER_E_SUCCESS;
int i;
@@ -547,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;
@@ -566,21 +578,25 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_environment_hex_
return result;
}
-LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_argv(debugserver_client_t client, int argc, char* argv[], char** response)
+debugserver_error_t debugserver_client_set_argv(debugserver_client_t client, int argc, char* argv[], char** response)
{
if (!client || !argc)
return DEBUGSERVER_E_INVALID_ARG;
debugserver_error_t result = DEBUGSERVER_E_UNKNOWN_ERROR;
char *pkt = NULL;
- int pkt_len = 0;
+ size_t pkt_len = 0;
int i = 0;
/* calculate total length */
while (i < argc && argv && argv[i]) {
char *prefix = NULL;
- asprintf(&prefix, ",%d,%d,", (int)strlen(argv[i]) * 2, i);
- pkt_len += (int)strlen(prefix) + (int)strlen(argv[i]) * 2;
+ int ret = asprintf(&prefix, ",%zu,%d,", strlen(argv[i]) * 2, i);
+ if (ret < 0 || prefix == NULL) {
+ debug_info("asprintf failed, out of memory?");
+ return DEBUGSERVER_E_UNKNOWN_ERROR;
+ }
+ pkt_len += strlen(prefix) + strlen(argv[i]) * 2;
free(prefix);
i++;
}
@@ -597,10 +613,14 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_argv(debugserver
char *prefix = NULL;
char *m = NULL;
- int arg_len = strlen(argv[i]);
- int arg_hexlen = arg_len * 2;
+ size_t arg_len = strlen(argv[i]);
+ size_t arg_hexlen = arg_len * 2;
- asprintf(&prefix, ",%d,%d,", arg_hexlen, i);
+ int ret = asprintf(&prefix, ",%zu,%d,", arg_hexlen, i);
+ if (ret < 0 || prefix == NULL) {
+ debug_info("asprintf failed, out of memory?");
+ return DEBUGSERVER_E_UNKNOWN_ERROR;
+ }
m = (char *) malloc(arg_hexlen);
char *p = m;
diff --git a/src/debugserver.h b/src/debugserver.h
index 05cd97b..ce9c255 100644
--- a/src/debugserver.h
+++ b/src/debugserver.h
@@ -22,6 +22,7 @@
#ifndef _DEBUGSERVER_H
#define _DEBUGSERVER_H
+#include "idevice.h"
#include "libimobiledevice/debugserver.h"
#include "service.h"
@@ -30,6 +31,8 @@
struct debugserver_client_private {
service_client_t parent;
int noack_mode;
+ int (*cancel_receive)();
+ int receive_loop_timeout;
};
struct debugserver_command_private {
diff --git a/src/device_link_service.c b/src/device_link_service.c
index 6daf84d..66c2461 100644
--- a/src/device_link_service.c
+++ b/src/device_link_service.c
@@ -83,7 +83,7 @@ static int device_link_service_get_message(plist_t dl_msg, char **message)
return 0;
}
- if ((strlen(cmd_str) < 9) || (strncmp(cmd_str, "DL", 2))) {
+ if ((strlen(cmd_str) < 9) || (strncmp(cmd_str, "DL", 2) != 0)) {
free(cmd_str);
return 0;
}
@@ -184,7 +184,7 @@ device_link_service_error_t device_link_service_version_exchange(device_link_ser
goto leave;
}
device_link_service_get_message(array, &msg);
- if (!msg || strcmp(msg, "DLMessageVersionExchange")) {
+ if (!msg || strcmp(msg, "DLMessageVersionExchange") != 0) {
debug_info("Did not receive DLMessageVersionExchange from device!");
err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
goto leave;
@@ -239,7 +239,7 @@ device_link_service_error_t device_link_service_version_exchange(device_link_ser
goto leave;
}
device_link_service_get_message(array, &msg);
- if (!msg || strcmp(msg, "DLMessageDeviceReady")) {
+ if (!msg || strcmp(msg, "DLMessageDeviceReady") != 0) {
debug_info("Did not get DLMessageDeviceReady!");
err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
goto leave;
@@ -403,7 +403,7 @@ device_link_service_error_t device_link_service_receive_process_message(device_l
char *msg = NULL;
device_link_service_get_message(pmsg, &msg);
- if (!msg || strcmp(msg, "DLMessageProcessMessage")) {
+ if (!msg || strcmp(msg, "DLMessageProcessMessage") != 0) {
debug_info("Did not receive DLMessageProcessMessage as expected!");
err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
goto leave;
diff --git a/src/device_link_service.h b/src/device_link_service.h
index eae912a..0255b21 100644
--- a/src/device_link_service.h
+++ b/src/device_link_service.h
@@ -22,6 +22,7 @@
#ifndef __DEVICE_LINK_SERVICE_H
#define __DEVICE_LINK_SERVICE_H
+#include "idevice.h"
#include "property_list_service.h"
/* Error Codes */
diff --git a/src/diagnostics_relay.c b/src/diagnostics_relay.c
index b6cf4d9..6ee3150 100644
--- a/src/diagnostics_relay.c
+++ b/src/diagnostics_relay.c
@@ -73,7 +73,7 @@ static int diagnostics_relay_check_result(plist_t dict)
return ret;
}
-LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, diagnostics_relay_client_t *client)
+diagnostics_relay_error_t diagnostics_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, diagnostics_relay_client_t *client)
{
if (!device || !service || service->port == 0 || !client || *client) {
return DIAGNOSTICS_RELAY_E_INVALID_ARG;
@@ -93,14 +93,14 @@ LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_client_new(idev
return DIAGNOSTICS_RELAY_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_client_start_service(idevice_t device, diagnostics_relay_client_t * client, const char* label)
+diagnostics_relay_error_t diagnostics_relay_client_start_service(idevice_t device, diagnostics_relay_client_t * client, const char* label)
{
diagnostics_relay_error_t err = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
service_client_factory_start_service(device, DIAGNOSTICS_RELAY_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(diagnostics_relay_client_new), &err);
return err;
}
-LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_client_free(diagnostics_relay_client_t client)
+diagnostics_relay_error_t diagnostics_relay_client_free(diagnostics_relay_client_t client)
{
if (!client)
return DIAGNOSTICS_RELAY_E_INVALID_ARG;
@@ -167,7 +167,7 @@ static diagnostics_relay_error_t diagnostics_relay_send(diagnostics_relay_client
return ret;
}
-LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_goodbye(diagnostics_relay_client_t client)
+diagnostics_relay_error_t diagnostics_relay_goodbye(diagnostics_relay_client_t client)
{
if (!client)
return DIAGNOSTICS_RELAY_E_INVALID_ARG;
@@ -201,7 +201,7 @@ LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_goodbye(diagnos
return ret;
}
-LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_sleep(diagnostics_relay_client_t client)
+diagnostics_relay_error_t diagnostics_relay_sleep(diagnostics_relay_client_t client)
{
if (!client)
return DIAGNOSTICS_RELAY_E_INVALID_ARG;
@@ -277,17 +277,17 @@ static diagnostics_relay_error_t internal_diagnostics_relay_action(diagnostics_r
return ret;
}
-LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_restart(diagnostics_relay_client_t client, diagnostics_relay_action_t flags)
+diagnostics_relay_error_t diagnostics_relay_restart(diagnostics_relay_client_t client, diagnostics_relay_action_t flags)
{
return internal_diagnostics_relay_action(client, "Restart", flags);
}
-LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_shutdown(diagnostics_relay_client_t client, diagnostics_relay_action_t flags)
+diagnostics_relay_error_t diagnostics_relay_shutdown(diagnostics_relay_client_t client, diagnostics_relay_action_t flags)
{
return internal_diagnostics_relay_action(client, "Shutdown", flags);
}
-LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_request_diagnostics(diagnostics_relay_client_t client, const char* type, plist_t* diagnostics)
+diagnostics_relay_error_t diagnostics_relay_request_diagnostics(diagnostics_relay_client_t client, const char* type, plist_t* diagnostics)
{
if (!client || diagnostics == NULL)
return DIAGNOSTICS_RELAY_E_INVALID_ARG;
@@ -299,6 +299,9 @@ LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_request_diagnos
ret = diagnostics_relay_send(client, dict);
plist_free(dict);
dict = NULL;
+ if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
+ return ret;
+ }
ret = diagnostics_relay_receive(client, &dict);
if (!dict) {
@@ -328,7 +331,7 @@ LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_request_diagnos
return ret;
}
-LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_query_mobilegestalt(diagnostics_relay_client_t client, plist_t keys, plist_t* result)
+diagnostics_relay_error_t diagnostics_relay_query_mobilegestalt(diagnostics_relay_client_t client, plist_t keys, plist_t* result)
{
if (!client || plist_get_node_type(keys) != PLIST_ARRAY || result == NULL)
return DIAGNOSTICS_RELAY_E_INVALID_ARG;
@@ -341,6 +344,9 @@ LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_query_mobileges
ret = diagnostics_relay_send(client, dict);
plist_free(dict);
dict = NULL;
+ if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
+ return ret;
+ }
ret = diagnostics_relay_receive(client, &dict);
if (!dict) {
@@ -370,7 +376,7 @@ LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_query_mobileges
return ret;
}
-LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_query_ioregistry_entry(diagnostics_relay_client_t client, const char* entry_name, const char* entry_class, plist_t* result)
+diagnostics_relay_error_t diagnostics_relay_query_ioregistry_entry(diagnostics_relay_client_t client, const char* entry_name, const char* entry_class, plist_t* result)
{
if (!client || (entry_name == NULL && entry_class == NULL) || result == NULL)
return DIAGNOSTICS_RELAY_E_INVALID_ARG;
@@ -386,6 +392,9 @@ LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_query_ioregistr
ret = diagnostics_relay_send(client, dict);
plist_free(dict);
dict = NULL;
+ if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
+ return ret;
+ }
ret = diagnostics_relay_receive(client, &dict);
if (!dict) {
@@ -415,7 +424,7 @@ LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_query_ioregistr
return ret;
}
-LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_query_ioregistry_plane(diagnostics_relay_client_t client, const char* plane, plist_t* result)
+diagnostics_relay_error_t diagnostics_relay_query_ioregistry_plane(diagnostics_relay_client_t client, const char* plane, plist_t* result)
{
if (!client || plane == NULL || result == NULL)
return DIAGNOSTICS_RELAY_E_INVALID_ARG;
diff --git a/src/diagnostics_relay.h b/src/diagnostics_relay.h
index 6d11ea1..3bb543a 100644
--- a/src/diagnostics_relay.h
+++ b/src/diagnostics_relay.h
@@ -22,6 +22,7 @@
#ifndef __DIAGNOSTICS_RELAY_H
#define __DIAGNOSTICS_RELAY_H
+#include "idevice.h"
#include "libimobiledevice/diagnostics_relay.h"
#include "property_list_service.h"
diff --git a/src/file_relay.c b/src/file_relay.c
index e304d31..fbe7cbf 100644
--- a/src/file_relay.c
+++ b/src/file_relay.c
@@ -28,7 +28,7 @@
#include "property_list_service.h"
#include "common/debug.h"
-LIBIMOBILEDEVICE_API file_relay_error_t file_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, file_relay_client_t *client)
+file_relay_error_t file_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, file_relay_client_t *client)
{
if (!device || !service || service->port == 0 || !client || *client) {
return FILE_RELAY_E_INVALID_ARG;
@@ -48,14 +48,14 @@ LIBIMOBILEDEVICE_API file_relay_error_t file_relay_client_new(idevice_t device,
return FILE_RELAY_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API file_relay_error_t file_relay_client_start_service(idevice_t device, file_relay_client_t * client, const char* label)
+file_relay_error_t file_relay_client_start_service(idevice_t device, file_relay_client_t * client, const char* label)
{
file_relay_error_t err = FILE_RELAY_E_UNKNOWN_ERROR;
service_client_factory_start_service(device, FILE_RELAY_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(file_relay_client_new), &err);
return err;
}
-LIBIMOBILEDEVICE_API file_relay_error_t file_relay_client_free(file_relay_client_t client)
+file_relay_error_t file_relay_client_free(file_relay_client_t client)
{
if (!client)
return FILE_RELAY_E_INVALID_ARG;
@@ -67,7 +67,7 @@ LIBIMOBILEDEVICE_API file_relay_error_t file_relay_client_free(file_relay_client
return FILE_RELAY_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API file_relay_error_t file_relay_request_sources_timeout(file_relay_client_t client, const char **sources, idevice_connection_t *connection, unsigned int timeout)
+file_relay_error_t file_relay_request_sources_timeout(file_relay_client_t client, const char **sources, idevice_connection_t *connection, unsigned int timeout)
{
if (!client || !client->parent || !sources || !sources[0]) {
return FILE_RELAY_E_INVALID_ARG;
@@ -143,7 +143,7 @@ LIBIMOBILEDEVICE_API file_relay_error_t file_relay_request_sources_timeout(file_
goto leave;
}
- if (strcmp(ack, "Acknowledged")) {
+ if (strcmp(ack, "Acknowledged") != 0) {
debug_info("ERROR: Did not receive 'Acknowledged' but '%s'", ack);
goto leave;
}
@@ -159,7 +159,7 @@ leave:
return err;
}
-LIBIMOBILEDEVICE_API file_relay_error_t file_relay_request_sources(file_relay_client_t client, const char **sources, idevice_connection_t *connection)
+file_relay_error_t file_relay_request_sources(file_relay_client_t client, const char **sources, idevice_connection_t *connection)
{
return file_relay_request_sources_timeout(client, sources, connection, 60000);
}
diff --git a/src/file_relay.h b/src/file_relay.h
index 626fab8..65bf460 100644
--- a/src/file_relay.h
+++ b/src/file_relay.h
@@ -22,6 +22,7 @@
#ifndef __FILE_RELAY_H
#define __FILE_RELAY_H
+#include "idevice.h"
#include "libimobiledevice/file_relay.h"
#include "property_list_service.h"
diff --git a/src/heartbeat.c b/src/heartbeat.c
index 9a527cc..3945d73 100644
--- a/src/heartbeat.c
+++ b/src/heartbeat.c
@@ -62,7 +62,7 @@ static heartbeat_error_t heartbeat_error(property_list_service_error_t err)
return HEARTBEAT_E_UNKNOWN_ERROR;
}
-LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_client_new(idevice_t device, lockdownd_service_descriptor_t service, heartbeat_client_t * client)
+heartbeat_error_t heartbeat_client_new(idevice_t device, lockdownd_service_descriptor_t service, heartbeat_client_t * client)
{
*client = NULL;
@@ -89,14 +89,14 @@ LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_client_new(idevice_t device, lo
return 0;
}
-LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_client_start_service(idevice_t device, heartbeat_client_t * client, const char* label)
+heartbeat_error_t heartbeat_client_start_service(idevice_t device, heartbeat_client_t * client, const char* label)
{
heartbeat_error_t err = HEARTBEAT_E_UNKNOWN_ERROR;
service_client_factory_start_service(device, HEARTBEAT_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(heartbeat_client_new), &err);
return err;
}
-LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_client_free(heartbeat_client_t client)
+heartbeat_error_t heartbeat_client_free(heartbeat_client_t client)
{
if (!client)
return HEARTBEAT_E_INVALID_ARG;
@@ -107,7 +107,7 @@ LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_client_free(heartbeat_client_t
return err;
}
-LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_send(heartbeat_client_t client, plist_t plist)
+heartbeat_error_t heartbeat_send(heartbeat_client_t client, plist_t plist)
{
heartbeat_error_t res = HEARTBEAT_E_UNKNOWN_ERROR;
@@ -122,12 +122,12 @@ LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_send(heartbeat_client_t client,
return res;
}
-LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_receive(heartbeat_client_t client, plist_t * plist)
+heartbeat_error_t heartbeat_receive(heartbeat_client_t client, plist_t * plist)
{
return heartbeat_receive_with_timeout(client, plist, 1000);
}
-LIBIMOBILEDEVICE_API heartbeat_error_t heartbeat_receive_with_timeout(heartbeat_client_t client, plist_t * plist, uint32_t timeout_ms)
+heartbeat_error_t heartbeat_receive_with_timeout(heartbeat_client_t client, plist_t * plist, uint32_t timeout_ms)
{
heartbeat_error_t res = HEARTBEAT_E_UNKNOWN_ERROR;
plist_t outplist = NULL;
diff --git a/src/heartbeat.h b/src/heartbeat.h
index f648681..379ecc1 100644
--- a/src/heartbeat.h
+++ b/src/heartbeat.h
@@ -22,6 +22,7 @@
#ifndef __HEARTBEAT_H
#define __HEARTBEAT_H
+#include "idevice.h"
#include "libimobiledevice/heartbeat.h"
#include "property_list_service.h"
diff --git a/src/house_arrest.c b/src/house_arrest.c
index ac92130..caad731 100644
--- a/src/house_arrest.c
+++ b/src/house_arrest.c
@@ -58,7 +58,7 @@ static house_arrest_error_t house_arrest_error(property_list_service_error_t err
return HOUSE_ARREST_E_UNKNOWN_ERROR;
}
-LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_client_new(idevice_t device, lockdownd_service_descriptor_t service, house_arrest_client_t *client)
+house_arrest_error_t house_arrest_client_new(idevice_t device, lockdownd_service_descriptor_t service, house_arrest_client_t *client)
{
property_list_service_client_t plistclient = NULL;
house_arrest_error_t err = house_arrest_error(property_list_service_client_new(device, service, &plistclient));
@@ -74,14 +74,14 @@ LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_client_new(idevice_t devi
return HOUSE_ARREST_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_client_start_service(idevice_t device, house_arrest_client_t * client, const char* label)
+house_arrest_error_t house_arrest_client_start_service(idevice_t device, house_arrest_client_t * client, const char* label)
{
house_arrest_error_t err = HOUSE_ARREST_E_UNKNOWN_ERROR;
service_client_factory_start_service(device, HOUSE_ARREST_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(house_arrest_client_new), &err);
return err;
}
-LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_client_free(house_arrest_client_t client)
+house_arrest_error_t house_arrest_client_free(house_arrest_client_t client)
{
if (!client)
return HOUSE_ARREST_E_INVALID_ARG;
@@ -96,7 +96,7 @@ LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_client_free(house_arrest_
return err;
}
-LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_send_request(house_arrest_client_t client, plist_t dict)
+house_arrest_error_t house_arrest_send_request(house_arrest_client_t client, plist_t dict)
{
if (!client || !client->parent || !dict)
return HOUSE_ARREST_E_INVALID_ARG;
@@ -112,7 +112,7 @@ LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_send_request(house_arrest
return res;
}
-LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_send_command(house_arrest_client_t client, const char *command, const char *appid)
+house_arrest_error_t house_arrest_send_command(house_arrest_client_t client, const char *command, const char *appid)
{
if (!client || !client->parent || !command || !appid)
return HOUSE_ARREST_E_INVALID_ARG;
@@ -132,7 +132,7 @@ LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_send_command(house_arrest
return res;
}
-LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_get_result(house_arrest_client_t client, plist_t *dict)
+house_arrest_error_t house_arrest_get_result(house_arrest_client_t client, plist_t *dict)
{
if (!client || !client->parent)
return HOUSE_ARREST_E_INVALID_ARG;
@@ -150,7 +150,7 @@ LIBIMOBILEDEVICE_API house_arrest_error_t house_arrest_get_result(house_arrest_c
return res;
}
-LIBIMOBILEDEVICE_API afc_error_t afc_client_new_from_house_arrest_client(house_arrest_client_t client, afc_client_t *afc_client)
+afc_error_t afc_client_new_from_house_arrest_client(house_arrest_client_t client, afc_client_t *afc_client)
{
if (!client || !client->parent || (client->mode == HOUSE_ARREST_CLIENT_MODE_AFC)) {
return AFC_E_INVALID_ARG;
diff --git a/src/house_arrest.h b/src/house_arrest.h
index 387594f..5612a29 100644
--- a/src/house_arrest.h
+++ b/src/house_arrest.h
@@ -22,6 +22,7 @@
#ifndef __HOUSE_ARREST_H
#define __HOUSE_ARREST_H
+#include "idevice.h"
#include "libimobiledevice/house_arrest.h"
#include "property_list_service.h"
diff --git a/src/idevice.c b/src/idevice.c
index c71c49b..b9bbb1f 100644
--- a/src/idevice.c
+++ b/src/idevice.c
@@ -2,7 +2,7 @@
* idevice.c
* Device discovery and communication interface.
*
- * Copyright (c) 2009-2019 Nikias Bassen. All Rights Reserved.
+ * Copyright (c) 2009-2021 Nikias Bassen. All Rights Reserved.
* Copyright (c) 2014 Martin Szulecki All Rights Reserved.
* Copyright (c) 2008 Zach C. All Rights Reserved.
*
@@ -30,29 +30,49 @@
#include <errno.h>
#include <time.h>
+#ifdef WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <windows.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif
+
#include <usbmuxd.h>
-#ifdef HAVE_OPENSSL
+
+#if defined(HAVE_OPENSSL)
#include <openssl/err.h>
#include <openssl/rsa.h>
#include <openssl/ssl.h>
-#else
+#elif defined(HAVE_GNUTLS)
#include <gnutls/gnutls.h>
+#elif defined(HAVE_MBEDTLS)
+#include <mbedtls/rsa.h>
+#include <mbedtls/ssl.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/debug.h>
+#else
+#error No supported TLS/SSL library enabled
#endif
+#include <libimobiledevice-glue/socket.h>
+#include <libimobiledevice-glue/thread.h>
+
#include "idevice.h"
+#include "lockdown.h"
#include "common/userpref.h"
-#include "common/socket.h"
-#include "common/thread.h"
#include "common/debug.h"
-#ifdef WIN32
-#include <windows.h>
+#ifndef ECONNREFUSED
+#define ECONNREFUSED 107
#endif
-
#ifndef ETIMEDOUT
#define ETIMEDOUT 138
#endif
+
#ifdef HAVE_OPENSSL
#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
@@ -106,7 +126,7 @@ static void id_function(CRYPTO_THREADID *thread)
static void internal_idevice_init(void)
{
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL)
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
int i;
SSL_library_init();
@@ -124,14 +144,16 @@ static void internal_idevice_init(void)
#endif
CRYPTO_set_locking_callback(locking_function);
#endif
-#else
+#elif defined(HAVE_GNUTLS)
gnutls_global_init();
+#elif defined(HAVE_MBEDTLS)
+ // NO-OP
#endif
}
static void internal_idevice_deinit(void)
{
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL)
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
int i;
if (mutex_buf) {
@@ -152,15 +174,33 @@ static void internal_idevice_deinit(void)
SSL_COMP_free_compression_methods();
openssl_remove_thread_state();
#endif
-#else
+#elif defined(HAVE_GNUTLS)
gnutls_global_deinit();
+#elif defined(HAVE_MBEDTLS)
+ // NO-OP
#endif
}
static thread_once_t init_once = THREAD_ONCE_INIT;
static thread_once_t deinit_once = THREAD_ONCE_INIT;
-#ifdef WIN32
+#ifndef HAVE_ATTRIBUTE_CONSTRUCTOR
+ #if defined(__llvm__) || defined(__GNUC__)
+ #define HAVE_ATTRIBUTE_CONSTRUCTOR
+ #endif
+#endif
+
+#ifdef HAVE_ATTRIBUTE_CONSTRUCTOR
+static void __attribute__((constructor)) libimobiledevice_initialize(void)
+{
+ thread_once(&init_once, internal_idevice_init);
+}
+
+static void __attribute__((destructor)) libimobiledevice_deinitialize(void)
+{
+ thread_once(&deinit_once, internal_idevice_deinit);
+}
+#elif defined(WIN32)
BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason) {
@@ -176,21 +216,28 @@ BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
return 1;
}
#else
-static void __attribute__((constructor)) libimobiledevice_initialize(void)
-{
- thread_once(&init_once, internal_idevice_init);
-}
+#warning No compiler support for constructor/destructor attributes, some features might not be available.
+#endif
-static void __attribute__((destructor)) libimobiledevice_deinitialize(void)
+const char* libimobiledevice_version()
{
- thread_once(&deinit_once, internal_idevice_deinit);
-}
+#ifndef PACKAGE_VERSION
+#error PACKAGE_VERSION is not defined!
#endif
+ return PACKAGE_VERSION;
+}
+
+struct idevice_subscription_context {
+ idevice_event_cb_t callback;
+ void *user_data;
+ usbmuxd_subscription_context_t ctx;
+};
-static idevice_event_cb_t event_cb = NULL;
+static idevice_subscription_context_t event_ctx = NULL;
static void usbmux_event_cb(const usbmuxd_event_t *event, void *user_data)
{
+ idevice_subscription_context_t context = (idevice_subscription_context_t)user_data;
idevice_event_t ev;
ev.event = event->event;
@@ -204,35 +251,68 @@ static void usbmux_event_cb(const usbmuxd_event_t *event, void *user_data)
debug_info("Unknown connection type %d", event->device.conn_type);
}
- if (event_cb) {
- event_cb(&ev, user_data);
+ if (context->callback) {
+ context->callback(&ev, context->user_data);
}
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_event_subscribe(idevice_event_cb_t callback, void *user_data)
+idevice_error_t idevice_events_subscribe(idevice_subscription_context_t *context, idevice_event_cb_t callback, void *user_data)
{
- event_cb = callback;
- int res = usbmuxd_subscribe(usbmux_event_cb, user_data);
+ if (!context || !callback) {
+ return IDEVICE_E_INVALID_ARG;
+ }
+ *context = malloc(sizeof(struct idevice_subscription_context));
+ if (!*context) {
+ debug_info("ERROR: %s: Failed to allocate subscription context\n", __func__);
+ return IDEVICE_E_UNKNOWN_ERROR;
+ }
+ (*context)->callback = callback;
+ (*context)->user_data = user_data;
+ int res = usbmuxd_events_subscribe(&(*context)->ctx, usbmux_event_cb, *context);
if (res != 0) {
- event_cb = NULL;
+ free(*context);
+ *context = NULL;
debug_info("ERROR: usbmuxd_subscribe() returned %d!", res);
return IDEVICE_E_UNKNOWN_ERROR;
}
return IDEVICE_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_event_unsubscribe(void)
+idevice_error_t idevice_events_unsubscribe(idevice_subscription_context_t context)
{
- event_cb = NULL;
- int res = usbmuxd_unsubscribe();
+ if (!context) {
+ return IDEVICE_E_INVALID_ARG;
+ }
+ int res = usbmuxd_events_unsubscribe(context->ctx);
if (res != 0) {
debug_info("ERROR: usbmuxd_unsubscribe() returned %d!", res);
return IDEVICE_E_UNKNOWN_ERROR;
}
+ if (context == event_ctx) {
+ event_ctx = NULL;
+ }
+ free(context);
return IDEVICE_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_get_device_list_extended(idevice_info_t **devices, int *count)
+idevice_error_t idevice_event_subscribe(idevice_event_cb_t callback, void *user_data)
+{
+ if (event_ctx) {
+ idevice_events_unsubscribe(event_ctx);
+ }
+ return idevice_events_subscribe(&event_ctx, callback, user_data);
+}
+
+idevice_error_t idevice_event_unsubscribe(void)
+{
+ if (!event_ctx) {
+ return IDEVICE_E_SUCCESS;
+ }
+ event_ctx->callback = NULL;
+ return idevice_events_unsubscribe(event_ctx);
+}
+
+idevice_error_t idevice_get_device_list_extended(idevice_info_t **devices, int *count)
{
usbmuxd_device_info_t *dev_list;
@@ -256,7 +336,21 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_get_device_list_extended(idevice_in
newlist[newcount]->conn_data = NULL;
} else if (dev_list[i].conn_type == CONNECTION_TYPE_NETWORK) {
newlist[newcount]->conn_type = CONNECTION_NETWORK;
- size_t addrlen = dev_list[i].conn_data[0];
+ struct sockaddr* saddr = (struct sockaddr*)(dev_list[i].conn_data);
+ size_t addrlen = 0;
+ switch (saddr->sa_family) {
+ case AF_INET:
+ addrlen = sizeof(struct sockaddr_in);
+ break;
+#ifdef AF_INET6
+ case AF_INET6:
+ addrlen = sizeof(struct sockaddr_in6);
+ break;
+#endif
+ default:
+ debug_info("Unsupported address family 0x%02x\n", saddr->sa_family);
+ continue;
+ }
newlist[newcount]->conn_data = malloc(addrlen);
memcpy(newlist[newcount]->conn_data, dev_list[i].conn_data, addrlen);
}
@@ -273,7 +367,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_get_device_list_extended(idevice_in
return IDEVICE_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_device_list_extended_free(idevice_info_t *devices)
+idevice_error_t idevice_device_list_extended_free(idevice_info_t *devices)
{
if (devices) {
int i = 0;
@@ -288,7 +382,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_device_list_extended_free(idevice_i
return IDEVICE_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_get_device_list(char ***devices, int *count)
+idevice_error_t idevice_get_device_list(char ***devices, int *count)
{
usbmuxd_device_info_t *dev_list;
@@ -320,7 +414,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_get_device_list(char ***devices, in
return IDEVICE_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_device_list_free(char **devices)
+idevice_error_t idevice_device_list_free(char **devices)
{
if (devices) {
int i = 0;
@@ -333,7 +427,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_device_list_free(char **devices)
return IDEVICE_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API void idevice_set_debug_level(int level)
+void idevice_set_debug_level(int level)
{
internal_set_debug_level(level);
}
@@ -350,6 +444,7 @@ static idevice_t idevice_from_mux_device(usbmuxd_device_info_t *muxdev)
device->udid = strdup(muxdev->udid);
device->mux_id = muxdev->handle;
device->version = 0;
+ device->device_class = 0;
switch (muxdev->conn_type) {
case CONNECTION_TYPE_USB:
device->conn_type = CONNECTION_USBMUXD;
@@ -357,9 +452,25 @@ static idevice_t idevice_from_mux_device(usbmuxd_device_info_t *muxdev)
break;
case CONNECTION_TYPE_NETWORK:
device->conn_type = CONNECTION_NETWORK;
- size_t len = ((uint8_t*)muxdev->conn_data)[0];
- device->conn_data = malloc(len);
- memcpy(device->conn_data, muxdev->conn_data, len);
+ struct sockaddr* saddr = (struct sockaddr*)(muxdev->conn_data);
+ size_t addrlen = 0;
+ switch (saddr->sa_family) {
+ case AF_INET:
+ addrlen = sizeof(struct sockaddr_in);
+ break;
+#ifdef AF_INET6
+ case AF_INET6:
+ addrlen = sizeof(struct sockaddr_in6);
+ break;
+#endif
+ default:
+ debug_info("Unsupported address family 0x%02x\n", saddr->sa_family);
+ free(device->udid);
+ free(device);
+ return NULL;
+ }
+ device->conn_data = malloc(addrlen);
+ memcpy(device->conn_data, muxdev->conn_data, addrlen);
break;
default:
device->conn_type = 0;
@@ -369,7 +480,7 @@ static idevice_t idevice_from_mux_device(usbmuxd_device_info_t *muxdev)
return device;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_new_with_options(idevice_t * device, const char *udid, enum idevice_options options)
+idevice_error_t idevice_new_with_options(idevice_t * device, const char *udid, enum idevice_options options)
{
usbmuxd_device_info_t muxdev;
int usbmux_options = 0;
@@ -393,12 +504,12 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_new_with_options(idevice_t * device
return IDEVICE_E_NO_DEVICE;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_new(idevice_t * device, const char *udid)
+idevice_error_t idevice_new(idevice_t * device, const char *udid)
{
return idevice_new_with_options(device, udid, 0);
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_free(idevice_t device)
+idevice_error_t idevice_free(idevice_t device)
{
if (!device)
return IDEVICE_E_INVALID_ARG;
@@ -415,7 +526,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_free(idevice_t device)
return ret;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_connect(idevice_t device, uint16_t port, idevice_connection_t *connection)
+idevice_error_t idevice_connect(idevice_t device, uint16_t port, idevice_connection_t *connection)
{
if (!device) {
return IDEVICE_E_INVALID_ARG;
@@ -424,7 +535,15 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connect(idevice_t device, uint16_t
if (device->conn_type == CONNECTION_USBMUXD) {
int sfd = usbmuxd_connect(device->mux_id, port);
if (sfd < 0) {
- debug_info("ERROR: Connecting to usbmuxd failed: %d (%s)", sfd, strerror(-sfd));
+ debug_info("ERROR: Connecting to usbmux device failed: %d (%s)", sfd, strerror(-sfd));
+ switch (-sfd) {
+ case ECONNREFUSED:
+ return IDEVICE_E_CONNREFUSED;
+ case ENODEV:
+ return IDEVICE_E_NO_DEVICE;
+ default:
+ break;
+ }
return IDEVICE_E_UNKNOWN_ERROR;
}
idevice_connection_t new_connection = (idevice_connection_t)malloc(sizeof(struct idevice_connection_private));
@@ -432,30 +551,22 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connect(idevice_t device, uint16_t
new_connection->data = (void*)(long)sfd;
new_connection->ssl_data = NULL;
new_connection->device = device;
+ new_connection->ssl_recv_timeout = (unsigned int)-1;
+ new_connection->status = IDEVICE_E_SUCCESS;
*connection = new_connection;
return IDEVICE_E_SUCCESS;
- } else if (device->conn_type == CONNECTION_NETWORK) {
- struct sockaddr_storage saddr_storage;
- struct sockaddr* saddr = (struct sockaddr*)&saddr_storage;
-
- /* FIXME: Improve handling of this platform/host dependent connection data */
- if (((char*)device->conn_data)[1] == 0x02) { // AF_INET
- saddr->sa_family = AF_INET;
- memcpy(&saddr->sa_data[0], (char*)device->conn_data + 2, 14);
- }
- else if (((char*)device->conn_data)[1] == 0x1E) { // AF_INET6 (bsd)
+ }
+ if (device->conn_type == CONNECTION_NETWORK) {
+ struct sockaddr* saddr = (struct sockaddr*)(device->conn_data);
+ switch (saddr->sa_family) {
+ case AF_INET:
#ifdef AF_INET6
- saddr->sa_family = AF_INET6;
- /* copy the address and the host dependent scope id */
- memcpy(&saddr->sa_data[0], (char*)device->conn_data + 2, 26);
-#else
- debug_info("ERROR: Got an IPv6 address but this system doesn't support IPv6");
- return IDEVICE_E_UNKNOWN_ERROR;
+ case AF_INET6:
#endif
- }
- else {
- debug_info("Unsupported address family 0x%02x", ((char*)device->conn_data)[1]);
- return IDEVICE_E_UNKNOWN_ERROR;
+ break;
+ default:
+ debug_info("Unsupported address family 0x%02x", saddr->sa_family);
+ return IDEVICE_E_UNKNOWN_ERROR;
}
char addrtxt[48];
@@ -469,7 +580,14 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connect(idevice_t device, uint16_t
int sfd = socket_connect_addr(saddr, port);
if (sfd < 0) {
- debug_info("ERROR: Connecting to network device failed: %d (%s)", errno, strerror(errno));
+ int result = errno;
+ debug_info("ERROR: Connecting to network device failed: %d (%s)", result, strerror(result));
+ switch (result) {
+ case ECONNREFUSED:
+ return IDEVICE_E_CONNREFUSED;
+ default:
+ break;
+ }
return IDEVICE_E_NO_DEVICE;
}
@@ -478,18 +596,18 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connect(idevice_t device, uint16_t
new_connection->data = (void*)(long)sfd;
new_connection->ssl_data = NULL;
new_connection->device = device;
+ new_connection->ssl_recv_timeout = (unsigned int)-1;
*connection = new_connection;
return IDEVICE_E_SUCCESS;
- } else {
- debug_info("Unknown connection type %d", device->conn_type);
}
+ debug_info("Unknown connection type %d", device->conn_type);
return IDEVICE_E_UNKNOWN_ERROR;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_disconnect(idevice_connection_t connection)
+idevice_error_t idevice_disconnect(idevice_connection_t connection)
{
if (!connection) {
return IDEVICE_E_INVALID_ARG;
@@ -536,7 +654,8 @@ static idevice_error_t internal_connection_send(idevice_connection_t connection,
return IDEVICE_E_UNKNOWN_ERROR;
}
return IDEVICE_E_SUCCESS;
- } else if (connection->type == CONNECTION_NETWORK) {
+ }
+ if (connection->type == CONNECTION_NETWORK) {
int s = socket_send((int)(long)connection->data, (void*)data, len);
if (s < 0) {
*sent_bytes = 0;
@@ -544,29 +663,28 @@ static idevice_error_t internal_connection_send(idevice_connection_t connection,
}
*sent_bytes = s;
return IDEVICE_E_SUCCESS;
- } else {
- debug_info("Unknown connection type %d", connection->type);
}
+
+ debug_info("Unknown connection type %d", connection->type);
return IDEVICE_E_UNKNOWN_ERROR;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_send(idevice_connection_t connection, const char *data, uint32_t len, uint32_t *sent_bytes)
+idevice_error_t idevice_connection_send(idevice_connection_t connection, const char *data, uint32_t len, uint32_t *sent_bytes)
{
- if (!connection || !data || (connection->ssl_data && !connection->ssl_data->session)) {
+ if (!connection || !data
+#if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS)
+ || (connection->ssl_data && !connection->ssl_data->session)
+#endif
+ ) {
return IDEVICE_E_INVALID_ARG;
}
if (connection->ssl_data) {
+ connection->status = IDEVICE_E_SUCCESS;
uint32_t sent = 0;
while (sent < len) {
-#ifdef HAVE_OPENSSL
- int c = socket_check_fd((int)(long)connection->data, FDM_WRITE, 100);
- if (c == 0 || c == -ETIMEDOUT || c == -EAGAIN) {
- continue;
- } else if (c < 0) {
- break;
- }
+#if defined(HAVE_OPENSSL)
int s = SSL_write(connection->ssl_data->session, (const void*)(data+sent), (int)(len-sent));
if (s <= 0) {
int sslerr = SSL_get_error(connection->ssl_data->session, s);
@@ -575,8 +693,10 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_send(idevice_connection_
}
break;
}
-#else
+#elif defined(HAVE_GNUTLS)
ssize_t s = gnutls_record_send(connection->ssl_data->session, (void*)(data+sent), (size_t)(len-sent));
+#elif defined(HAVE_MBEDTLS)
+ int s = mbedtls_ssl_write(&connection->ssl_data->ctx, (const unsigned char*)(data+sent), (size_t)(len-sent));
#endif
if (s < 0) {
break;
@@ -586,36 +706,42 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_send(idevice_connection_
debug_info("SSL_write %d, sent %d", len, sent);
if (sent < len) {
*sent_bytes = 0;
- return IDEVICE_E_SSL_ERROR;
+ return connection->status == IDEVICE_E_SUCCESS ? IDEVICE_E_SSL_ERROR : connection->status;
}
*sent_bytes = sent;
return IDEVICE_E_SUCCESS;
- } else {
- uint32_t sent = 0;
- while (sent < len) {
- uint32_t bytes = 0;
- int s = internal_connection_send(connection, data+sent, len-sent, &bytes);
- if (s < 0) {
- break;
- }
- sent += bytes;
- }
- debug_info("internal_connection_send %d, sent %d", len, sent);
- if (sent < len) {
- *sent_bytes = 0;
- return IDEVICE_E_NOT_ENOUGH_DATA;
+ }
+ uint32_t sent = 0;
+ while (sent < len) {
+ uint32_t bytes = 0;
+ int s = internal_connection_send(connection, data+sent, len-sent, &bytes);
+ if (s < 0) {
+ break;
}
+ sent += bytes;
+ }
+ debug_info("internal_connection_send %d, sent %d", len, sent);
+ if (sent < len) {
*sent_bytes = sent;
- return IDEVICE_E_SUCCESS;
+ if (sent == 0) {
+ return IDEVICE_E_UNKNOWN_ERROR;
+ }
+ return IDEVICE_E_NOT_ENOUGH_DATA;
}
+ *sent_bytes = sent;
+ return IDEVICE_E_SUCCESS;
}
-static idevice_error_t socket_recv_to_idevice_error(int conn_error, uint32_t len, uint32_t received)
+static inline idevice_error_t socket_recv_to_idevice_error(int conn_error, uint32_t len, uint32_t received)
{
if (conn_error < 0) {
switch (conn_error) {
case -EAGAIN:
- debug_info("ERROR: received partial data %d/%d (%s)", received, len, strerror(-conn_error));
+ if (len) {
+ debug_info("ERROR: received partial data %d/%d (%s)", received, len, strerror(-conn_error));
+ } else {
+ debug_info("ERROR: received partial data (%s)", strerror(-conn_error));
+ }
return IDEVICE_E_NOT_ENOUGH_DATA;
case -ETIMEDOUT:
return IDEVICE_E_TIMEOUT;
@@ -623,7 +749,6 @@ static idevice_error_t socket_recv_to_idevice_error(int conn_error, uint32_t len
return IDEVICE_E_UNKNOWN_ERROR;
}
}
-
return IDEVICE_E_SUCCESS;
}
@@ -640,55 +765,50 @@ 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);
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));
}
-
return error;
- } else if (connection->type == CONNECTION_NETWORK) {
+ }
+ if (connection->type == CONNECTION_NETWORK) {
int res = socket_receive_timeout((int)(long)connection->data, data, len, 0, timeout);
- if (res < 0) {
- debug_info("ERROR: socket_receive_timeout failed: %d (%s)", res, strerror(-res));
- return (res == -EAGAIN ? IDEVICE_E_NOT_ENOUGH_DATA : IDEVICE_E_UNKNOWN_ERROR);
+ idevice_error_t error = socket_recv_to_idevice_error(res, 0, 0);
+ if (error == IDEVICE_E_SUCCESS) {
+ *recv_bytes = (uint32_t)res;
+ } else if (error == IDEVICE_E_UNKNOWN_ERROR) {
+ debug_info("ERROR: socket_receive_timeout returned %d (%s)", res, strerror(-res));
}
- *recv_bytes = (uint32_t)res;
- return IDEVICE_E_SUCCESS;
- } else {
- debug_info("Unknown connection type %d", connection->type);
+ return error;
}
+
+ debug_info("Unknown connection type %d", connection->type);
return IDEVICE_E_UNKNOWN_ERROR;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive_timeout(idevice_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout)
+idevice_error_t idevice_connection_receive_timeout(idevice_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout)
{
- if (!connection || (connection->ssl_data && !connection->ssl_data->session) || len == 0) {
+ if (!connection
+#if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS)
+ || (connection->ssl_data && !connection->ssl_data->session)
+#endif
+ || len == 0
+ ) {
return IDEVICE_E_INVALID_ARG;
}
if (connection->ssl_data) {
uint32_t received = 0;
- int do_select = 1;
- while (received < len) {
-#ifdef HAVE_OPENSSL
- do_select = (SSL_pending(connection->ssl_data->session) == 0);
-#endif
- if (do_select) {
- int conn_error = socket_check_fd((int)(long)connection->data, FDM_READ, timeout);
- idevice_error_t error = socket_recv_to_idevice_error(conn_error, len, received);
-
- switch (error) {
- case IDEVICE_E_SUCCESS:
- break;
- case IDEVICE_E_UNKNOWN_ERROR:
- default:
- debug_info("ERROR: socket_check_fd returned %d (%s)", conn_error, strerror(-conn_error));
- return error;
- }
- }
+ if (connection->ssl_recv_timeout != (unsigned int)-1) {
+ debug_info("WARNING: ssl_recv_timeout was not properly reset in idevice_connection_receive_timeout");
+ }
-#ifdef HAVE_OPENSSL
+ // this should be reset after the SSL_read call on all codepaths, as
+ // the supplied timeout should only apply to the current read.
+ connection->ssl_recv_timeout = timeout;
+ connection->status = IDEVICE_E_SUCCESS;
+ while (received < len) {
+#if defined(HAVE_OPENSSL)
int r = SSL_read(connection->ssl_data->session, (void*)((char*)(data+received)), (int)len-received);
if (r > 0) {
received += r;
@@ -696,23 +816,35 @@ 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;
}
-#else
+#elif defined(HAVE_GNUTLS)
ssize_t r = gnutls_record_recv(connection->ssl_data->session, (void*)(data+received), (size_t)len-received);
if (r > 0) {
received += r;
} else {
break;
}
+#elif defined(HAVE_MBEDTLS)
+ int r = mbedtls_ssl_read(&connection->ssl_data->ctx, (void*)(data+received), (size_t)len-received);
+ if (r > 0) {
+ received += r;
+ } else {
+ break;
+ }
#endif
}
+ connection->ssl_recv_timeout = (unsigned int)-1;
debug_info("SSL_read %d, received %d", len, received);
if (received < len) {
- *recv_bytes = 0;
- return IDEVICE_E_SSL_ERROR;
+ *recv_bytes = received;
+ return connection->status == IDEVICE_E_SUCCESS ? IDEVICE_E_SSL_ERROR : connection->status;
}
*recv_bytes = received;
@@ -737,7 +869,8 @@ static idevice_error_t internal_connection_receive(idevice_connection_t connecti
return IDEVICE_E_UNKNOWN_ERROR;
}
return IDEVICE_E_SUCCESS;
- } else if (connection->type == CONNECTION_NETWORK) {
+ }
+ if (connection->type == CONNECTION_NETWORK) {
int res = socket_receive((int)(long)connection->data, data, len);
if (res < 0) {
debug_info("ERROR: socket_receive returned %d (%s)", res, strerror(-res));
@@ -745,24 +878,34 @@ static idevice_error_t internal_connection_receive(idevice_connection_t connecti
}
*recv_bytes = (uint32_t)res;
return IDEVICE_E_SUCCESS;
- } else {
- debug_info("Unknown connection type %d", connection->type);
}
+
+ debug_info("Unknown connection type %d", connection->type);
return IDEVICE_E_UNKNOWN_ERROR;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive(idevice_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes)
+idevice_error_t idevice_connection_receive(idevice_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes)
{
- if (!connection || (connection->ssl_data && !connection->ssl_data->session)) {
+ if (!connection
+#if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS)
+ || (connection->ssl_data && !connection->ssl_data->session)
+#endif
+ ) {
return IDEVICE_E_INVALID_ARG;
}
if (connection->ssl_data) {
-#ifdef HAVE_OPENSSL
+ if (connection->ssl_recv_timeout != (unsigned int)-1) {
+ debug_info("WARNING: ssl_recv_timeout was not properly reset in idevice_connection_receive_timeout");
+ connection->ssl_recv_timeout = (unsigned int)-1;
+ }
+#if defined(HAVE_OPENSSL)
int received = SSL_read(connection->ssl_data->session, (void*)data, (int)len);
debug_info("SSL_read %d, received %d", len, received);
-#else
+#elif defined(HAVE_GNUTLS)
ssize_t received = gnutls_record_recv(connection->ssl_data->session, (void*)data, (size_t)len);
+#elif defined(HAVE_MBEDTLS)
+ int received = mbedtls_ssl_read(&connection->ssl_data->ctx, (unsigned char*)data, (size_t)len);
#endif
if (received > 0) {
*recv_bytes = received;
@@ -774,26 +917,26 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive(idevice_connecti
return internal_connection_receive(connection, data, len, recv_bytes);
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_get_fd(idevice_connection_t connection, int *fd)
+idevice_error_t idevice_connection_get_fd(idevice_connection_t connection, int *fd)
{
if (!connection || !fd) {
return IDEVICE_E_INVALID_ARG;
}
- idevice_error_t result = IDEVICE_E_UNKNOWN_ERROR;
if (connection->type == CONNECTION_USBMUXD) {
*fd = (int)(long)connection->data;
- result = IDEVICE_E_SUCCESS;
- } else if (connection->type == CONNECTION_NETWORK) {
+ return IDEVICE_E_SUCCESS;
+ }
+ if (connection->type == CONNECTION_NETWORK) {
*fd = (int)(long)connection->data;
- result = IDEVICE_E_SUCCESS;
- } else {
- debug_info("Unknown connection type %d", connection->type);
+ return IDEVICE_E_SUCCESS;
}
- return result;
+
+ debug_info("Unknown connection type %d", connection->type);
+ return IDEVICE_E_UNKNOWN_ERROR;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_get_handle(idevice_t device, uint32_t *handle)
+idevice_error_t idevice_get_handle(idevice_t device, uint32_t *handle)
{
if (!device || !handle)
return IDEVICE_E_INVALID_ARG;
@@ -802,78 +945,80 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_get_handle(idevice_t device, uint32
return IDEVICE_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_get_udid(idevice_t device, char **udid)
+idevice_error_t idevice_get_udid(idevice_t device, char **udid)
{
if (!device || !udid)
return IDEVICE_E_INVALID_ARG;
- *udid = strdup(device->udid);
+ if (device->udid) {
+ *udid = strdup(device->udid);
+ }
return IDEVICE_E_SUCCESS;
}
-#ifndef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS)
+typedef ssize_t ssl_cb_ret_type_t;
+#elif defined(HAVE_MBEDTLS)
+typedef int ssl_cb_ret_type_t;
+#endif
+
/**
- * Internally used gnutls callback function for receiving encrypted data.
+ * Internally used SSL callback function for receiving encrypted data.
*/
-static ssize_t internal_ssl_read(gnutls_transport_ptr_t transport, char *buffer, size_t length)
+static ssl_cb_ret_type_t internal_ssl_read(idevice_connection_t connection, char *buffer, size_t length)
{
- int bytes = 0, pos_start_fill = 0;
- size_t tbytes = 0;
- int this_len = length;
+ uint32_t bytes = 0;
+ uint32_t pos = 0;
idevice_error_t res;
- idevice_connection_t connection = (idevice_connection_t)transport;
- char *recv_buffer;
+ unsigned int timeout = connection->ssl_recv_timeout;
- debug_info("pre-read client wants %zi bytes", length);
-
- recv_buffer = (char *)malloc(sizeof(char) * this_len);
+ debug_info("pre-read length = %zi bytes", length);
/* repeat until we have the full data or an error occurs */
do {
- if ((res = internal_connection_receive(connection, recv_buffer, this_len, (uint32_t*)&bytes)) != IDEVICE_E_SUCCESS) {
- debug_info("ERROR: idevice_connection_receive returned %d", res);
- return res;
+ bytes = 0;
+ if (timeout == (unsigned int)-1) {
+ res = internal_connection_receive(connection, buffer + pos, (uint32_t)length - pos, &bytes);
+ } else {
+ res = internal_connection_receive_timeout(connection, buffer + pos, (uint32_t)length - pos, &bytes, (unsigned int)timeout);
+ }
+ if (res != IDEVICE_E_SUCCESS) {
+ if (res != IDEVICE_E_TIMEOUT) {
+ debug_info("ERROR: %s returned %d", (timeout == (unsigned int)-1) ? "internal_connection_receive" : "internal_connection_receive_timeout", res);
+ }
+ connection->status = res;
+ return -1;
}
- debug_info("post-read we got %i bytes", bytes);
+ debug_info("read %i bytes", bytes);
/* increase read count */
- tbytes += bytes;
-
- /* fill the buffer with what we got right now */
- memcpy(buffer + pos_start_fill, recv_buffer, bytes);
- pos_start_fill += bytes;
-
- if (tbytes >= length) {
- break;
+ pos += bytes;
+ if (pos < (uint32_t)length) {
+ debug_info("re-read trying to read missing %i bytes", (uint32_t)length - pos);
}
+ } while (pos < (uint32_t)length);
- this_len = length - tbytes;
- debug_info("re-read trying to read missing %i bytes", this_len);
- } while (tbytes < length);
+ debug_info("post-read received %i bytes", pos);
- if (recv_buffer) {
- free(recv_buffer);
- }
- return tbytes;
+ return pos;
}
/**
- * Internally used gnutls callback function for sending encrypted data.
+ * Internally used SSL callback function for sending encrypted data.
*/
-static ssize_t internal_ssl_write(gnutls_transport_ptr_t transport, char *buffer, size_t length)
+static ssl_cb_ret_type_t internal_ssl_write(idevice_connection_t connection, const char *buffer, size_t length)
{
uint32_t bytes = 0;
idevice_error_t res;
- idevice_connection_t connection = (idevice_connection_t)transport;
- debug_info("pre-send length = %zi", length);
+ debug_info("pre-send length = %zi bytes", length);
if ((res = internal_connection_send(connection, buffer, length, &bytes)) != IDEVICE_E_SUCCESS) {
debug_info("ERROR: internal_connection_send returned %d", res);
+ connection->status = res;
return -1;
}
debug_info("post-send sent %i bytes", bytes);
return bytes;
}
-#endif
/**
* Internally used function for cleaning up SSL stuff.
@@ -883,14 +1028,14 @@ static void internal_ssl_cleanup(ssl_data_t ssl_data)
if (!ssl_data)
return;
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL)
if (ssl_data->session) {
SSL_free(ssl_data->session);
}
if (ssl_data->ctx) {
SSL_CTX_free(ssl_data->ctx);
}
-#else
+#elif defined(HAVE_GNUTLS)
if (ssl_data->session) {
gnutls_deinit(ssl_data->session);
}
@@ -909,10 +1054,62 @@ static void internal_ssl_cleanup(ssl_data_t ssl_data)
if (ssl_data->host_privkey) {
gnutls_x509_privkey_deinit(ssl_data->host_privkey);
}
+#elif defined(HAVE_MBEDTLS)
+ mbedtls_pk_free(&ssl_data->root_privkey);
+ mbedtls_x509_crt_free(&ssl_data->certificate);
+ mbedtls_entropy_free(&ssl_data->entropy);
+ mbedtls_ctr_drbg_free(&ssl_data->ctr_drbg);
+ mbedtls_ssl_config_free(&ssl_data->config);
+ mbedtls_ssl_free(&ssl_data->ctx);
#endif
}
#ifdef HAVE_OPENSSL
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+static long ssl_idevice_bio_callback(BIO *b, int oper, const char *argp, size_t len, int argi, long argl, int retvalue, size_t *processed)
+#else
+static long ssl_idevice_bio_callback(BIO *b, int oper, const char *argp, int argi, long argl, long retvalue)
+#endif
+{
+ ssize_t bytes = 0;
+ idevice_connection_t conn = (idevice_connection_t)BIO_get_callback_arg(b);
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+ size_t len = (size_t)argi;
+ size_t *processed = (size_t*)&bytes;
+#endif
+ switch (oper) {
+ case (BIO_CB_READ|BIO_CB_RETURN):
+ if (argp) {
+ bytes = internal_ssl_read(conn, (char *)argp, len);
+ *processed = bytes;
+ return (long)bytes;
+ }
+ return 0;
+ case (BIO_CB_PUTS|BIO_CB_RETURN):
+ len = strlen(argp);
+ // fallthrough
+ case (BIO_CB_WRITE|BIO_CB_RETURN):
+ bytes = internal_ssl_write(conn, argp, len);
+ *processed = bytes;
+ return (long)bytes;
+ default:
+ return retvalue;
+ }
+}
+
+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;
+}
+
static int ssl_verify_callback(int ok, X509_STORE_CTX *ctx)
{
return 1;
@@ -947,7 +1144,7 @@ static const char *ssl_error_to_string(int e)
#endif
#endif
-#ifndef HAVE_OPENSSL
+#if defined(HAVE_GNUTLS)
/**
* Internally used gnutls callback function that gets called during handshake.
*/
@@ -978,9 +1175,26 @@ static int internal_cert_callback(gnutls_session_t session, const gnutls_datum_t
}
return res;
}
+#elif defined(HAVE_MBEDTLS)
+static void _mbedtls_log_cb(void* ctx, int level, const char* filename, int line, const char* message)
+{
+ fprintf(stderr, "[mbedtls][%d] %s:%d => %s", level, filename, line, message);
+}
+
+static int cert_verify_cb(void* ctx, mbedtls_x509_crt* cert, int depth, uint32_t *flags)
+{
+ *flags = 0;
+ return 0;
+}
+
+static int _mbedtls_f_rng(void* p_rng, unsigned char* buf, size_t len)
+{
+ memset(buf, 4, len);
+ return 0;
+}
#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;
@@ -988,13 +1202,13 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_conne
idevice_error_t ret = IDEVICE_E_SSL_ERROR;
plist_t pair_record = NULL;
- userpref_read_pair_record(connection->device->udid, &pair_record);
- if (!pair_record) {
- debug_info("ERROR: Failed enabling SSL. Unable to read pair record for udid %s.", connection->device->udid);
+ userpref_error_t uerr = userpref_read_pair_record(connection->device->udid, &pair_record);
+ if (uerr != USERPREF_E_SUCCESS) {
+ debug_info("ERROR: Failed enabling SSL. Unable to read pair record for udid %s (%d)", connection->device->udid, uerr);
return ret;
}
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL)
key_data_t root_cert = { NULL, 0 };
key_data_t root_privkey = { NULL, 0 };
@@ -1004,12 +1218,11 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_conne
if (pair_record)
plist_free(pair_record);
- BIO *ssl_bio = BIO_new(BIO_s_socket());
+ BIO *ssl_bio = ssl_idevice_bio_new(connection);
if (!ssl_bio) {
debug_info("ERROR: Could not create SSL bio.");
return ret;
}
- BIO_set_fd(ssl_bio, (int)(long)connection->data, BIO_NOCLOSE);
SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_method());
if (ssl_ctx == NULL) {
@@ -1018,7 +1231,8 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_conne
return ret;
}
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) || \
+ (defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER >= 0x3060000fL))
SSL_CTX_set_security_level(ssl_ctx, 0);
#endif
@@ -1027,23 +1241,52 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_conne
/* force use of TLSv1 for older devices */
if (connection->device->version < DEVICE_VERSION(10,0,0)) {
#ifdef SSL_OP_NO_TLSv1_1
- long opts = SSL_CTX_get_options(ssl_ctx);
- opts |= SSL_OP_NO_TLSv1_1;
+ SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_1);
+#endif
#ifdef SSL_OP_NO_TLSv1_2
- opts |= SSL_OP_NO_TLSv1_2;
+ SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_2);
#endif
#ifdef SSL_OP_NO_TLSv1_3
- opts |= SSL_OP_NO_TLSv1_3;
-#endif
- SSL_CTX_set_options(ssl_ctx, opts);
+ SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_3);
#endif
}
#else
SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_VERSION);
if (connection->device->version < DEVICE_VERSION(10,0,0)) {
SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_VERSION);
+ if (connection->device->version == 0) {
+ /*
+ iOS 1 doesn't understand TLS1_VERSION, it can only speak SSL3_VERSION.
+ However, modern OpenSSL is usually compiled without SSLv3 support.
+ So if we set min_proto_version to SSL3_VERSION on an OpenSSL instance which doesn't support it,
+ it will just ignore min_proto_version altogether and fall back to an even higher version.
+ To avoid accidentally breaking iOS 2.0+, we set min version to 0 instead.
+ Here is what documentation says:
+ Setting the minimum or maximum version to 0,
+ will enable protocol versions down to the lowest version,
+ or up to the highest version supported by the library, respectively.
+ */
+ SSL_CTX_set_min_proto_version(ssl_ctx, 0);
+ }
}
#endif
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#if defined(SSL_OP_IGNORE_UNEXPECTED_EOF)
+ /*
+ * For OpenSSL 3 and later, mark close_notify alerts as optional.
+ * For prior versions of OpenSSL we check for SSL_ERROR_SYSCALL when
+ * reading instead (this error changes to SSL_ERROR_SSL in OpenSSL 3).
+ */
+ SSL_CTX_set_options(ssl_ctx, SSL_OP_IGNORE_UNEXPECTED_EOF);
+#endif
+#if defined(SSL_OP_LEGACY_SERVER_CONNECT)
+ /*
+ * Without setting SSL_OP_LEGACY_SERVER_CONNECT, OpenSSL 3 fails with
+ * error "unsafe legacy renegotiation disabled" when talking to iOS 5
+ */
+ SSL_CTX_set_options(ssl_ctx, SSL_OP_LEGACY_SERVER_CONNECT);
+#endif
+#endif
BIO* membp;
X509* rootCert = NULL;
@@ -1056,6 +1299,16 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_conne
X509_free(rootCert);
free(root_cert.data);
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_PKEY* rootPrivKey = NULL;
+ membp = BIO_new_mem_buf(root_privkey.data, root_privkey.size);
+ PEM_read_bio_PrivateKey(membp, &rootPrivKey, NULL, NULL);
+ BIO_free(membp);
+ if (SSL_CTX_use_PrivateKey(ssl_ctx, rootPrivKey) != 1) {
+ debug_info("WARNING: Could not load RootPrivateKey");
+ }
+ EVP_PKEY_free(rootPrivKey);
+#else
RSA* rootPrivKey = NULL;
membp = BIO_new_mem_buf(root_privkey.data, root_privkey.size);
PEM_read_bio_RSAPrivateKey(membp, &rootPrivKey, NULL, NULL);
@@ -1064,6 +1317,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_conne
debug_info("WARNING: Could not load RootPrivateKey");
}
RSA_free(rootPrivKey);
+#endif
free(root_privkey.data);
SSL *ssl = SSL_new(ssl_ctx);
@@ -1105,7 +1359,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_conne
}
/* required for proper multi-thread clean up to prevent leaks */
openssl_remove_thread_state();
-#else
+#elif defined(HAVE_GNUTLS)
ssl_data_t ssl_data_loc = (ssl_data_t)malloc(sizeof(struct ssl_data_private));
/* Set up GnuTLS... */
@@ -1163,16 +1417,92 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_conne
ret = IDEVICE_E_SUCCESS;
debug_info("SSL mode enabled");
}
+#elif defined(HAVE_MBEDTLS)
+ key_data_t root_cert = { NULL, 0 };
+ key_data_t root_privkey = { NULL, 0 };
+
+ pair_record_import_crt_with_name(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, &root_cert);
+ pair_record_import_key_with_name(pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY, &root_privkey);
+
+ plist_free(pair_record);
+
+ ssl_data_t ssl_data_loc = (ssl_data_t)malloc(sizeof(struct ssl_data_private));
+
+ mbedtls_ssl_init(&ssl_data_loc->ctx);
+ mbedtls_ssl_config_init(&ssl_data_loc->config);
+ mbedtls_entropy_init(&ssl_data_loc->entropy);
+ mbedtls_ctr_drbg_init(&ssl_data_loc->ctr_drbg);
+
+ int r = mbedtls_ctr_drbg_seed(&ssl_data_loc->ctr_drbg, mbedtls_entropy_func, &ssl_data_loc->entropy, NULL, 0);
+ if (r != 0) {
+ debug_info("ERROR: [mbedtls] mbedtls_ctr_drbg_seed failed: %d", r);
+ return ret;
+ }
+
+ if (mbedtls_ssl_config_defaults(&ssl_data_loc->config, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT) != 0) {
+ debug_info("ERROR: [mbedtls] Failed to set config defaults");
+ return ret;
+ }
+
+ mbedtls_ssl_conf_rng(&ssl_data_loc->config, mbedtls_ctr_drbg_random, &ssl_data_loc->ctr_drbg);
+
+ mbedtls_ssl_conf_dbg(&ssl_data_loc->config, _mbedtls_log_cb, NULL);
+
+ mbedtls_ssl_conf_verify(&ssl_data_loc->config, cert_verify_cb, NULL);
+
+ mbedtls_ssl_setup(&ssl_data_loc->ctx, &ssl_data_loc->config);
+
+ mbedtls_ssl_set_bio(&ssl_data_loc->ctx, connection, (mbedtls_ssl_send_t*)&internal_ssl_write, (mbedtls_ssl_recv_t*)&internal_ssl_read, NULL);
+
+ mbedtls_x509_crt_init(&ssl_data_loc->certificate);
+
+ int crterr = mbedtls_x509_crt_parse(&ssl_data_loc->certificate, root_cert.data, root_cert.size);
+ if (crterr < 0) {
+ debug_info("ERROR: [mbedtls] parsing root cert failed: %d", crterr);
+ return ret;
+ }
+
+ mbedtls_ssl_conf_ca_chain(&ssl_data_loc->config, &ssl_data_loc->certificate, NULL);
+
+ mbedtls_pk_init(&ssl_data_loc->root_privkey);
+
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+ int pkerr = mbedtls_pk_parse_key(&ssl_data_loc->root_privkey, root_privkey.data, root_privkey.size, NULL, 0, &_mbedtls_f_rng, NULL);
+#else
+ int pkerr = mbedtls_pk_parse_key(&ssl_data_loc->root_privkey, root_privkey.data, root_privkey.size, NULL, 0);
+#endif
+ if (pkerr < 0) {
+ debug_info("ERROR: [mbedtls] parsing private key failed: %d (size=%d)", pkerr, root_privkey.size);
+ return ret;
+ }
+
+ mbedtls_ssl_conf_own_cert(&ssl_data_loc->config, &ssl_data_loc->certificate, &ssl_data_loc->root_privkey);
+
+ int return_me = 0;
+ do {
+ return_me = mbedtls_ssl_handshake(&ssl_data_loc->ctx);
+ } while (return_me == MBEDTLS_ERR_SSL_WANT_READ || return_me == MBEDTLS_ERR_SSL_WANT_WRITE);
+
+ if (return_me != 0) {
+ debug_info("ERROR during SSL handshake: %d", return_me);
+ internal_ssl_cleanup(ssl_data_loc);
+ free(ssl_data_loc);
+ } else {
+ connection->ssl_data = ssl_data_loc;
+ ret = IDEVICE_E_SUCCESS;
+ debug_info("SSL mode enabled, %s, cipher: %s", mbedtls_ssl_get_version(&ssl_data_loc->ctx), mbedtls_ssl_get_ciphersuite(&ssl_data_loc->ctx));
+ debug_info("SSL mode enabled");
+ }
#endif
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;
@@ -1184,7 +1514,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_disable_bypass_ssl(idevi
// some services require plain text communication after SSL handshake
// sending out SSL_shutdown will cause bytes
if (!sslBypass) {
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL)
if (connection->ssl_data->session) {
/* see: https://www.openssl.org/docs/ssl/SSL_shutdown.html#RETURN_VALUES */
if (SSL_shutdown(connection->ssl_data->session) == 0) {
@@ -1193,14 +1523,16 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_disable_bypass_ssl(idevi
if ((ssl_error = SSL_get_error(connection->ssl_data->session, 0)) == SSL_ERROR_NONE) {
SSL_shutdown(connection->ssl_data->session);
} else {
- debug_info("Skipping bidirectional SSL shutdown. SSL error code: %i\n", ssl_error);
+ debug_info("Skipping bidirectional SSL shutdown. SSL error code: %i", ssl_error);
}
}
}
-#else
+#elif defined(HAVE_GNUTLS)
if (connection->ssl_data->session) {
gnutls_bye(connection->ssl_data->session, GNUTLS_SHUT_RDWR);
}
+#elif defined(HAVE_MBEDTLS)
+ mbedtls_ssl_close_notify(&connection->ssl_data->ctx);
#endif
}
diff --git a/src/idevice.h b/src/idevice.h
index 8709c9a..dd72f9d 100644
--- a/src/idevice.h
+++ b/src/idevice.h
@@ -26,21 +26,27 @@
#include <config.h>
#endif
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL)
#include <openssl/ssl.h>
-#else
+#elif defined(HAVE_GNUTLS)
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
+#elif defined(HAVE_MBEDTLS)
+#include <mbedtls/ssl.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/ctr_drbg.h>
#endif
-#ifdef WIN32
-#define LIBIMOBILEDEVICE_API __declspec( dllexport )
-#else
-#ifdef HAVE_FVISIBILITY
-#define LIBIMOBILEDEVICE_API __attribute__((visibility("default")))
+#ifdef LIBIMOBILEDEVICE_STATIC
+ #define LIBIMOBILEDEVICE_API
+#elif defined(_WIN32)
+ #define LIBIMOBILEDEVICE_API __declspec( dllexport )
#else
-#define LIBIMOBILEDEVICE_API
-#endif
+ #if __GNUC__ >= 4
+ #define LIBIMOBILEDEVICE_API __attribute__((visibility("default")))
+ #else
+ #define LIBIMOBILEDEVICE_API
+ #endif
#endif
#include "common/userpref.h"
@@ -48,17 +54,31 @@
#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
+#define DEVICE_CLASS_APPLETV 4
+#define DEVICE_CLASS_WATCH 5
+#define DEVICE_CLASS_UNKNOWN 255
+
struct ssl_data_private {
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL)
SSL *session;
SSL_CTX *ctx;
-#else
+#elif defined(HAVE_GNUTLS)
gnutls_certificate_credentials_t certificate;
gnutls_session_t session;
gnutls_x509_privkey_t root_privkey;
gnutls_x509_crt_t root_cert;
gnutls_x509_privkey_t host_privkey;
gnutls_x509_crt_t host_cert;
+#elif defined(HAVE_MBEDTLS)
+ mbedtls_ssl_context ctx;
+ mbedtls_ssl_config config;
+ mbedtls_entropy_context entropy;
+ mbedtls_ctr_drbg_context ctr_drbg;
+ mbedtls_x509_crt certificate;
+ mbedtls_pk_context root_privkey;
#endif
};
typedef struct ssl_data_private *ssl_data_t;
@@ -68,6 +88,8 @@ struct idevice_connection_private {
enum idevice_connection_type type;
void *data;
ssl_data_t ssl_data;
+ unsigned int ssl_recv_timeout;
+ idevice_error_t status;
};
struct idevice_private {
@@ -76,6 +98,7 @@ struct idevice_private {
enum idevice_connection_type conn_type;
void *conn_data;
int version;
+ int device_class;
};
#endif
diff --git a/src/installation_proxy.c b/src/installation_proxy.c
index 9a6f1ab..ec19da0 100644
--- a/src/installation_proxy.c
+++ b/src/installation_proxy.c
@@ -232,7 +232,7 @@ static instproxy_error_t instproxy_error(property_list_service_error_t err)
return INSTPROXY_E_UNKNOWN_ERROR;
}
-LIBIMOBILEDEVICE_API instproxy_error_t instproxy_client_new(idevice_t device, lockdownd_service_descriptor_t service, instproxy_client_t *client)
+instproxy_error_t instproxy_client_new(idevice_t device, lockdownd_service_descriptor_t service, instproxy_client_t *client)
{
property_list_service_client_t plistclient = NULL;
instproxy_error_t err = instproxy_error(property_list_service_client_new(device, service, &plistclient));
@@ -249,14 +249,14 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_client_new(idevice_t device, lo
return INSTPROXY_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API instproxy_error_t instproxy_client_start_service(idevice_t device, instproxy_client_t * client, const char* label)
+instproxy_error_t instproxy_client_start_service(idevice_t device, instproxy_client_t * client, const char* label)
{
instproxy_error_t err = INSTPROXY_E_UNKNOWN_ERROR;
service_client_factory_start_service(device, INSTPROXY_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(instproxy_client_new), &err);
return err;
}
-LIBIMOBILEDEVICE_API instproxy_error_t instproxy_client_free(instproxy_client_t client)
+instproxy_error_t instproxy_client_free(instproxy_client_t client)
{
if (!client)
return INSTPROXY_E_INVALID_ARG;
@@ -282,9 +282,6 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_client_free(instproxy_client_t
*
* @param client The connected installation_proxy client.
* @param command The command to execute. Required.
- * @param client_options The client options to use, as PLIST_DICT, or NULL.
- * @param appid The ApplicationIdentifier to add or NULL if not required.
- * @param package_path The installation package path or NULL if not required.
*
* @return INSTPROXY_E_SUCCESS on success or an INSTPROXY_E_* error value if
* an error occurred.
@@ -367,17 +364,14 @@ static instproxy_error_t instproxy_receive_status_loop(instproxy_client_t client
/* check status from response */
instproxy_status_get_name(node, &status_name);
if (!status_name) {
- debug_info("failed to retrieve name from status response with error %d.", res);
- complete = 1;
- }
-
- if (status_name) {
+ debug_info("ignoring message without Status key:");
+ debug_plist(node);
+ } else {
if (!strcmp(status_name, "Complete")) {
complete = 1;
} else {
res = INSTPROXY_E_OP_IN_PROGRESS;
}
-
#ifndef STRIP_DEBUG_CODE
percent_complete = -1;
instproxy_status_get_percent_complete(node, &percent_complete);
@@ -531,7 +525,7 @@ static instproxy_error_t instproxy_perform_command(instproxy_client_t client, pl
return res;
}
-LIBIMOBILEDEVICE_API instproxy_error_t instproxy_browse_with_callback(instproxy_client_t client, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data)
+instproxy_error_t instproxy_browse_with_callback(instproxy_client_t client, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data)
{
if (!client || !client->parent || !status_cb)
return INSTPROXY_E_INVALID_ARG;
@@ -572,7 +566,7 @@ static void instproxy_append_current_list_to_result_cb(plist_t command, plist_t
plist_free(current_list);
}
-LIBIMOBILEDEVICE_API instproxy_error_t instproxy_browse(instproxy_client_t client, plist_t client_options, plist_t *result)
+instproxy_error_t instproxy_browse(instproxy_client_t client, plist_t client_options, plist_t *result)
{
if (!client || !client->parent || !result)
return INSTPROXY_E_INVALID_ARG;
@@ -609,7 +603,7 @@ static void instproxy_copy_lookup_result_cb(plist_t command, plist_t status, voi
}
}
-LIBIMOBILEDEVICE_API instproxy_error_t instproxy_lookup(instproxy_client_t client, const char** appids, plist_t client_options, plist_t *result)
+instproxy_error_t instproxy_lookup(instproxy_client_t client, const char** appids, plist_t client_options, plist_t *result)
{
instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR;
int i = 0;
@@ -656,7 +650,7 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_lookup(instproxy_client_t clien
return res;
}
-LIBIMOBILEDEVICE_API instproxy_error_t instproxy_install(instproxy_client_t client, const char *pkg_path, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data)
+instproxy_error_t instproxy_install(instproxy_client_t client, const char *pkg_path, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data)
{
instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR;
@@ -666,14 +660,14 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_install(instproxy_client_t clie
plist_dict_set_item(command, "ClientOptions", plist_copy(client_options));
plist_dict_set_item(command, "PackagePath", plist_new_string(pkg_path));
- res = instproxy_perform_command(client, command, INSTPROXY_COMMAND_TYPE_ASYNC, status_cb, user_data);
+ res = instproxy_perform_command(client, command, status_cb == NULL ? INSTPROXY_COMMAND_TYPE_SYNC : INSTPROXY_COMMAND_TYPE_ASYNC, status_cb, user_data);
plist_free(command);
return res;
}
-LIBIMOBILEDEVICE_API instproxy_error_t instproxy_upgrade(instproxy_client_t client, const char *pkg_path, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data)
+instproxy_error_t instproxy_upgrade(instproxy_client_t client, const char *pkg_path, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data)
{
instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR;
@@ -683,14 +677,14 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_upgrade(instproxy_client_t clie
plist_dict_set_item(command, "ClientOptions", plist_copy(client_options));
plist_dict_set_item(command, "PackagePath", plist_new_string(pkg_path));
- res = instproxy_perform_command(client, command, INSTPROXY_COMMAND_TYPE_ASYNC, status_cb, user_data);
+ res = instproxy_perform_command(client, command, status_cb == NULL ? INSTPROXY_COMMAND_TYPE_SYNC : INSTPROXY_COMMAND_TYPE_ASYNC, status_cb, user_data);
plist_free(command);
return res;
}
-LIBIMOBILEDEVICE_API instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data)
+instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data)
{
instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR;
@@ -700,14 +694,14 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_uninstall(instproxy_client_t cl
plist_dict_set_item(command, "ClientOptions", plist_copy(client_options));
plist_dict_set_item(command, "ApplicationIdentifier", plist_new_string(appid));
- res = instproxy_perform_command(client, command, INSTPROXY_COMMAND_TYPE_ASYNC, status_cb, user_data);
+ res = instproxy_perform_command(client, command, status_cb == NULL ? INSTPROXY_COMMAND_TYPE_SYNC : INSTPROXY_COMMAND_TYPE_ASYNC, status_cb, user_data);
plist_free(command);
return res;
}
-LIBIMOBILEDEVICE_API instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist_t client_options, plist_t *result)
+instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist_t client_options, plist_t *result)
{
instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR;
@@ -723,7 +717,7 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_lookup_archives(instproxy_clien
return res;
}
-LIBIMOBILEDEVICE_API instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data)
+instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data)
{
instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR;
@@ -733,14 +727,14 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_archive(instproxy_client_t clie
plist_dict_set_item(command, "ClientOptions", plist_copy(client_options));
plist_dict_set_item(command, "ApplicationIdentifier", plist_new_string(appid));
- res = instproxy_perform_command(client, command, INSTPROXY_COMMAND_TYPE_ASYNC, status_cb, user_data);
+ res = instproxy_perform_command(client, command, status_cb == NULL ? INSTPROXY_COMMAND_TYPE_SYNC : INSTPROXY_COMMAND_TYPE_ASYNC, status_cb, user_data);
plist_free(command);
return res;
}
-LIBIMOBILEDEVICE_API instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data)
+instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data)
{
instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR;
@@ -750,14 +744,14 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_restore(instproxy_client_t clie
plist_dict_set_item(command, "ClientOptions", plist_copy(client_options));
plist_dict_set_item(command, "ApplicationIdentifier", plist_new_string(appid));
- res = instproxy_perform_command(client, command, INSTPROXY_COMMAND_TYPE_ASYNC, status_cb, user_data);
+ res = instproxy_perform_command(client, command, status_cb == NULL ? INSTPROXY_COMMAND_TYPE_SYNC : INSTPROXY_COMMAND_TYPE_ASYNC, status_cb, user_data);
plist_free(command);
return res;
}
-LIBIMOBILEDEVICE_API instproxy_error_t instproxy_remove_archive(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data)
+instproxy_error_t instproxy_remove_archive(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data)
{
instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR;
@@ -767,14 +761,14 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_remove_archive(instproxy_client
plist_dict_set_item(command, "ClientOptions", plist_copy(client_options));
plist_dict_set_item(command, "ApplicationIdentifier", plist_new_string(appid));
- res = instproxy_perform_command(client, command, INSTPROXY_COMMAND_TYPE_ASYNC, status_cb, user_data);
+ res = instproxy_perform_command(client, command, status_cb == NULL ? INSTPROXY_COMMAND_TYPE_SYNC : INSTPROXY_COMMAND_TYPE_ASYNC, status_cb, user_data);
plist_free(command);
return res;
}
-LIBIMOBILEDEVICE_API instproxy_error_t instproxy_check_capabilities_match(instproxy_client_t client, const char** capabilities, plist_t client_options, plist_t *result)
+instproxy_error_t instproxy_check_capabilities_match(instproxy_client_t client, const char** capabilities, plist_t client_options, plist_t *result)
{
if (!client || !capabilities || !result)
return INSTPROXY_E_INVALID_ARG;
@@ -811,7 +805,7 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_check_capabilities_match(instpr
return res;
}
-LIBIMOBILEDEVICE_API instproxy_error_t instproxy_status_get_error(plist_t status, char **name, char** description, uint64_t* code)
+instproxy_error_t instproxy_status_get_error(plist_t status, char **name, char** description, uint64_t* code)
{
instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR;
@@ -849,7 +843,7 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_status_get_error(plist_t status
return res;
}
-LIBIMOBILEDEVICE_API void instproxy_status_get_name(plist_t status, char **name)
+void instproxy_status_get_name(plist_t status, char **name)
{
if (name) {
plist_t node = plist_dict_get_item(status, "Status");
@@ -861,7 +855,7 @@ LIBIMOBILEDEVICE_API void instproxy_status_get_name(plist_t status, char **name)
}
}
-LIBIMOBILEDEVICE_API void instproxy_status_get_percent_complete(plist_t status, int *percent)
+void instproxy_status_get_percent_complete(plist_t status, int *percent)
{
uint64_t val = 0;
if (percent) {
@@ -873,7 +867,7 @@ LIBIMOBILEDEVICE_API void instproxy_status_get_percent_complete(plist_t status,
}
}
-LIBIMOBILEDEVICE_API void instproxy_status_get_current_list(plist_t status, uint64_t* total, uint64_t* current_index, uint64_t* current_amount, plist_t* list)
+void instproxy_status_get_current_list(plist_t status, uint64_t* total, uint64_t* current_index, uint64_t* current_amount, plist_t* list)
{
plist_t node = NULL;
@@ -910,7 +904,7 @@ LIBIMOBILEDEVICE_API void instproxy_status_get_current_list(plist_t status, uint
}
}
-LIBIMOBILEDEVICE_API void instproxy_command_get_name(plist_t command, char** name)
+void instproxy_command_get_name(plist_t command, char** name)
{
if (name) {
plist_t node = plist_dict_get_item(command, "Command");
@@ -922,12 +916,12 @@ LIBIMOBILEDEVICE_API void instproxy_command_get_name(plist_t command, char** nam
}
}
-LIBIMOBILEDEVICE_API plist_t instproxy_client_options_new(void)
+plist_t instproxy_client_options_new(void)
{
return plist_new_dict();
}
-LIBIMOBILEDEVICE_API void instproxy_client_options_add(plist_t client_options, ...)
+void instproxy_client_options_add(plist_t client_options, ...)
{
if (!client_options)
return;
@@ -940,7 +934,7 @@ LIBIMOBILEDEVICE_API void instproxy_client_options_add(plist_t client_options, .
if (!strcmp(key, "SkipUninstall")) {
int intval = va_arg(args, int);
plist_dict_set_item(client_options, key, plist_new_bool(intval));
- } else if (!strcmp(key, "ApplicationSINF") || !strcmp(key, "iTunesMetadata") || !strcmp(key, "ReturnAttributes")) {
+ } else if (!strcmp(key, "ApplicationSINF") || !strcmp(key, "iTunesMetadata") || !strcmp(key, "ReturnAttributes") || !strcmp(key, "BundleIDs")) {
plist_t plistval = va_arg(args, plist_t);
if (!plistval) {
free(key);
@@ -961,7 +955,7 @@ LIBIMOBILEDEVICE_API void instproxy_client_options_add(plist_t client_options, .
va_end(args);
}
-LIBIMOBILEDEVICE_API void instproxy_client_options_set_return_attributes(plist_t client_options, ...)
+void instproxy_client_options_set_return_attributes(plist_t client_options, ...)
{
if (!client_options)
return;
@@ -982,16 +976,16 @@ LIBIMOBILEDEVICE_API void instproxy_client_options_set_return_attributes(plist_t
plist_dict_set_item(client_options, "ReturnAttributes", return_attributes);
}
-LIBIMOBILEDEVICE_API void instproxy_client_options_free(plist_t client_options)
+void instproxy_client_options_free(plist_t client_options)
{
if (client_options) {
plist_free(client_options);
}
}
-LIBIMOBILEDEVICE_API instproxy_error_t instproxy_client_get_path_for_bundle_identifier(instproxy_client_t client, const char* appid, char** path)
+instproxy_error_t instproxy_client_get_path_for_bundle_identifier(instproxy_client_t client, const char* bundle_id, char** path)
{
- if (!client || !client->parent || !appid)
+ if (!client || !client->parent || !bundle_id)
return INSTPROXY_E_INVALID_ARG;
plist_t apps = NULL;
@@ -1004,7 +998,7 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_client_get_path_for_bundle_iden
instproxy_client_options_set_return_attributes(client_opts, "CFBundleIdentifier", "CFBundleExecutable", "Path", NULL);
// only query for specific appid
- const char* appids[] = {appid, NULL};
+ const char* appids[] = {bundle_id, NULL};
// query device for list of apps
instproxy_error_t ierr = instproxy_lookup(client, appids, client_opts, &apps);
@@ -1015,7 +1009,7 @@ LIBIMOBILEDEVICE_API instproxy_error_t instproxy_client_get_path_for_bundle_iden
return ierr;
}
- plist_t app_found = plist_access_path(apps, 1, appid);
+ plist_t app_found = plist_access_path(apps, 1, bundle_id);
if (!app_found) {
if (apps)
plist_free(apps);
diff --git a/src/installation_proxy.h b/src/installation_proxy.h
index 66dd5d0..5bdbb71 100644
--- a/src/installation_proxy.h
+++ b/src/installation_proxy.h
@@ -23,9 +23,10 @@
#ifndef __INSTALLATION_PROXY_H
#define __INSTALLATION_PROXY_H
+#include "idevice.h"
#include "libimobiledevice/installation_proxy.h"
#include "property_list_service.h"
-#include "common/thread.h"
+#include <libimobiledevice-glue/thread.h>
struct instproxy_client_private {
property_list_service_client_t parent;
diff --git a/src/libimobiledevice-1.0.pc.in b/src/libimobiledevice-1.0.pc.in
index c37654b..f00c392 100644
--- a/src/libimobiledevice-1.0.pc.in
+++ b/src/libimobiledevice-1.0.pc.in
@@ -9,4 +9,4 @@ Version: @PACKAGE_VERSION@
Libs: -L${libdir} -limobiledevice-1.0
Cflags: -I${includedir}
Requires: libplist-2.0 >= @LIBPLIST_VERSION@
-Requires.private: libusbmuxd-2.0 >= @LIBUSBMUXD_VERSION@ @ssl_requires@
+Requires.private: libusbmuxd-2.0 >= @LIBUSBMUXD_VERSION@ libimobiledevice-glue-1.0 >= @LIMD_GLUE_VERSION@ @ssl_requires@
diff --git a/src/lockdown-cu.c b/src/lockdown-cu.c
new file mode 100644
index 0000000..1afc2c5
--- /dev/null
+++ b/src/lockdown-cu.c
@@ -0,0 +1,1193 @@
+/*
+ * lockdown-cu.c
+ * com.apple.mobile.lockdownd service CU additions
+ *
+ * Copyright (c) 2021 Nikias Bassen, All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#define _GNU_SOURCE 1
+#define __USE_GNU 1
+#include <stdio.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <plist/plist.h>
+
+#include "idevice.h"
+#include "lockdown.h"
+#include "common/debug.h"
+
+#ifdef HAVE_WIRELESS_PAIRING
+
+#include <libimobiledevice-glue/utils.h>
+#include <libimobiledevice-glue/socket.h>
+#include <libimobiledevice-glue/opack.h>
+#include <libimobiledevice-glue/tlv.h>
+
+#if defined(HAVE_OPENSSL)
+#include <openssl/hmac.h>
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+#if defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x2030200fL)
+#include <openssl/chacha.h>
+#include <openssl/poly1305.h>
+#endif
+#elif defined(HAVE_GCRYPT)
+#include <gcrypt.h>
+#elif defined(HAVE_MBEDTLS)
+#include <mbedtls/md.h>
+#include <mbedtls/chachapoly.h>
+#endif
+
+#ifdef __APPLE__
+#include <sys/sysctl.h>
+#include <SystemConfiguration/SystemConfiguration.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <TargetConditionals.h>
+#endif
+
+#include "property_list_service.h"
+#include "common/userpref.h"
+
+#include "endianness.h"
+
+#include "srp.h"
+#include "ed25519.h"
+
+/* {{{ SRP6a parameters */
+static const unsigned char kSRPModulus3072[384] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34,
+ 0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74,
+ 0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd,
+ 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14, 0x37,
+ 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6,
+ 0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x37, 0xed, 0x6b, 0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed,
+ 0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5, 0xae, 0x9f, 0x24, 0x11, 0x7c, 0x4b, 0x1f, 0xe6,
+ 0x49, 0x28, 0x66, 0x51, 0xec, 0xe4, 0x5b, 0x3d, 0xc2, 0x00, 0x7c, 0xb8, 0xa1, 0x63, 0xbf, 0x05,
+ 0x98, 0xda, 0x48, 0x36, 0x1c, 0x55, 0xd3, 0x9a, 0x69, 0x16, 0x3f, 0xa8, 0xfd, 0x24, 0xcf, 0x5f,
+ 0x83, 0x65, 0x5d, 0x23, 0xdc, 0xa3, 0xad, 0x96, 0x1c, 0x62, 0xf3, 0x56, 0x20, 0x85, 0x52, 0xbb,
+ 0x9e, 0xd5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6d, 0x67, 0x0c, 0x35, 0x4e, 0x4a, 0xbc, 0x98, 0x04,
+ 0xf1, 0x74, 0x6c, 0x08, 0xca, 0x18, 0x21, 0x7c, 0x32, 0x90, 0x5e, 0x46, 0x2e, 0x36, 0xce, 0x3b,
+ 0xe3, 0x9e, 0x77, 0x2c, 0x18, 0x0e, 0x86, 0x03, 0x9b, 0x27, 0x83, 0xa2, 0xec, 0x07, 0xa2, 0x8f,
+ 0xb5, 0xc5, 0x5d, 0xf0, 0x6f, 0x4c, 0x52, 0xc9, 0xde, 0x2b, 0xcb, 0xf6, 0x95, 0x58, 0x17, 0x18,
+ 0x39, 0x95, 0x49, 0x7c, 0xea, 0x95, 0x6a, 0xe5, 0x15, 0xd2, 0x26, 0x18, 0x98, 0xfa, 0x05, 0x10,
+ 0x15, 0x72, 0x8e, 0x5a, 0x8a, 0xaa, 0xc4, 0x2d, 0xad, 0x33, 0x17, 0x0d, 0x04, 0x50, 0x7a, 0x33,
+ 0xa8, 0x55, 0x21, 0xab, 0xdf, 0x1c, 0xba, 0x64, 0xec, 0xfb, 0x85, 0x04, 0x58, 0xdb, 0xef, 0x0a,
+ 0x8a, 0xea, 0x71, 0x57, 0x5d, 0x06, 0x0c, 0x7d, 0xb3, 0x97, 0x0f, 0x85, 0xa6, 0xe1, 0xe4, 0xc7,
+ 0xab, 0xf5, 0xae, 0x8c, 0xdb, 0x09, 0x33, 0xd7, 0x1e, 0x8c, 0x94, 0xe0, 0x4a, 0x25, 0x61, 0x9d,
+ 0xce, 0xe3, 0xd2, 0x26, 0x1a, 0xd2, 0xee, 0x6b, 0xf1, 0x2f, 0xfa, 0x06, 0xd9, 0x8a, 0x08, 0x64,
+ 0xd8, 0x76, 0x02, 0x73, 0x3e, 0xc8, 0x6a, 0x64, 0x52, 0x1f, 0x2b, 0x18, 0x17, 0x7b, 0x20, 0x0c,
+ 0xbb, 0xe1, 0x17, 0x57, 0x7a, 0x61, 0x5d, 0x6c, 0x77, 0x09, 0x88, 0xc0, 0xba, 0xd9, 0x46, 0xe2,
+ 0x08, 0xe2, 0x4f, 0xa0, 0x74, 0xe5, 0xab, 0x31, 0x43, 0xdb, 0x5b, 0xfc, 0xe0, 0xfd, 0x10, 0x8e,
+ 0x4b, 0x82, 0xd1, 0x20, 0xa9, 0x3a, 0xd2, 0xca, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+
+static const unsigned char kSRPGenerator5 = 5;
+/* }}} */
+
+/* {{{ HKDF */
+#if defined(HAVE_OPENSSL)
+#define MD_ALGO_SHA512 EVP_sha512()
+typedef const EVP_MD* MD_ALGO_TYPE_T;
+#define MD_ALGO_DIGEST_SIZE EVP_MD_size
+#define MD_MAX_DIGEST_SIZE EVP_MAX_MD_SIZE
+
+#elif defined(HAVE_GCRYPT)
+#define MD_ALGO_SHA512 GCRY_MD_SHA512
+typedef int MD_ALGO_TYPE_T;
+#define MD_ALGO_DIGEST_SIZE gcry_md_get_algo_dlen
+#define MD_MAX_DIGEST_SIZE 64
+
+static void HMAC(MD_ALGO_TYPE_T md, unsigned char* key, unsigned int key_len, unsigned char* data, unsigned int data_len, unsigned char* out, unsigned int* out_len)
+{
+ gcry_md_hd_t hd;
+ if (gcry_md_open(&hd, md, GCRY_MD_FLAG_HMAC)) {
+ debug_info("gcry_md_open() failed");
+ return;
+ }
+ if (gcry_md_setkey(hd, key, key_len)) {
+ gcry_md_close (hd);
+ debug_info("gcry_md_setkey() failed");
+ return;
+ }
+ gcry_md_write(hd, data, data_len);
+
+ unsigned char* digest = gcry_md_read(hd, md);
+ if (!digest) {
+ gcry_md_close(hd);
+ debug_info("gcry_md_read() failed");
+ return;
+ }
+
+ *out_len = gcry_md_get_algo_dlen(md);
+ memcpy(out, digest, *out_len);
+ gcry_md_close(hd);
+}
+#elif defined(HAVE_MBEDTLS)
+#define MD_ALGO_SHA512 MBEDTLS_MD_SHA512
+typedef mbedtls_md_type_t MD_ALGO_TYPE_T;
+#define MD_ALGO_DIGEST_SIZE(x) mbedtls_md_get_size(mbedtls_md_info_from_type(x))
+#define MD_MAX_DIGEST_SIZE MBEDTLS_MD_MAX_SIZE
+
+static void HMAC(MD_ALGO_TYPE_T md, unsigned char* key, unsigned int key_len, unsigned char* data, unsigned int data_len, unsigned char* out, unsigned int* out_len)
+{
+ mbedtls_md_context_t mdctx;
+ mbedtls_md_init(&mdctx);
+ int mr = mbedtls_md_setup(&mdctx, mbedtls_md_info_from_type(md), 1);
+ if (mr != 0) {
+ debug_info("mbedtls_md_setup() failed: %d", mr);
+ return;
+ }
+
+ mr = mbedtls_md_hmac_starts(&mdctx, key, key_len);
+ if (mr != 0) {
+ mbedtls_md_free(&mdctx);
+ debug_info("mbedtls_md_hmac_starts() failed: %d", mr);
+ return;
+ }
+
+ mbedtls_md_hmac_update(&mdctx, data, data_len);
+
+ mr = mbedtls_md_hmac_finish(&mdctx, out);
+ if (mr == 0) {
+ *out_len = mbedtls_md_get_size(mbedtls_md_info_from_type(md));
+ } else {
+ debug_info("mbedtls_md_hmac_finish() failed: %d", mr);
+ }
+ mbedtls_md_free(&mdctx);
+}
+#endif
+
+static void hkdf_md_extract(MD_ALGO_TYPE_T md, unsigned char* salt, unsigned int salt_len, unsigned char* input_key_material, unsigned int input_key_material_len, unsigned char* out, unsigned int* out_len)
+{
+ unsigned char empty_salt[MD_MAX_DIGEST_SIZE];
+ if (!md || !out || !out_len || !*out_len) return;
+ if (salt_len == 0) {
+ salt_len = MD_ALGO_DIGEST_SIZE(md);
+ salt = (unsigned char*)empty_salt;
+ }
+ HMAC(md, salt, salt_len, input_key_material, input_key_material_len, out, out_len);
+}
+
+static void hkdf_md_expand(MD_ALGO_TYPE_T md, unsigned char* prk, unsigned int prk_len, unsigned char* info, unsigned int info_len, unsigned char* out, unsigned int* out_len)
+{
+ if (!md || !out || !out_len || !*out_len) return;
+ unsigned int md_size = MD_ALGO_DIGEST_SIZE(md);
+ if (*out_len > 255 * md_size) {
+ *out_len = 0;
+ return;
+ }
+ int blocks_needed = (*out_len) / md_size;
+ if (((*out_len) % md_size) != 0) blocks_needed++;
+ unsigned int okm_len = 0;
+ unsigned char okm_block[MD_MAX_DIGEST_SIZE];
+ unsigned int okm_block_len = 0;
+ int i;
+ for (i = 0; i < blocks_needed; i++) {
+ unsigned int output_block_len = okm_block_len + info_len + 1;
+ unsigned char* output_block = malloc(output_block_len);
+ if (okm_block_len > 0) {
+ memcpy(output_block, okm_block, okm_block_len);
+ }
+ memcpy(output_block + okm_block_len, info, info_len);
+ output_block[okm_block_len + info_len] = (uint8_t)(i+1);
+
+ HMAC(md, prk, prk_len, output_block, output_block_len, okm_block, &okm_block_len);
+ if (okm_len < *out_len) {
+ memcpy(out + okm_len, okm_block, (okm_len + okm_block_len > *out_len) ? *out_len - okm_len : okm_block_len);
+ }
+ okm_len += okm_block_len;
+ free(output_block);
+ }
+}
+
+static void hkdf_md(MD_ALGO_TYPE_T md, unsigned char* salt, unsigned int salt_len, unsigned char* info, unsigned int info_len, unsigned char* initial_key_material, unsigned int initial_key_material_size, unsigned char* out, unsigned int *out_len)
+{
+ if (!md || !initial_key_material || !out || !out_len || !*out_len) return;
+
+ unsigned char prk[MD_MAX_DIGEST_SIZE];
+ unsigned int prk_len = MD_ALGO_DIGEST_SIZE(md);
+
+ hkdf_md_extract(md, salt, salt_len, initial_key_material, initial_key_material_size, prk, &prk_len);
+ if (prk_len > 0) {
+ hkdf_md_expand(md, prk, prk_len, info, info_len, out, out_len);
+ } else {
+ *out_len = 0;
+ }
+}
+/* }}} */
+
+/* {{{ chacha20 poly1305 encryption/decryption */
+#if defined(HAVE_OPENSSL) && defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x2030200fL)
+/* {{{ From: OpenBSD's e_chacha20poly1305.c */
+/*
+ * Copyright (c) 2015 Reyk Floter <reyk@openbsd.org>
+ * Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+static void
+poly1305_update_with_length(poly1305_state *poly1305,
+ const unsigned char *data, size_t data_len)
+{
+ size_t j = data_len;
+ unsigned char length_bytes[8];
+ unsigned i;
+
+ for (i = 0; i < sizeof(length_bytes); i++) {
+ length_bytes[i] = j;
+ j >>= 8;
+ }
+
+ if (data != NULL)
+ CRYPTO_poly1305_update(poly1305, data, data_len);
+ CRYPTO_poly1305_update(poly1305, length_bytes, sizeof(length_bytes));
+}
+
+static void
+poly1305_update_with_pad16(poly1305_state *poly1305,
+ const unsigned char *data, size_t data_len)
+{
+ static const unsigned char zero_pad16[16];
+ size_t pad_len;
+
+ CRYPTO_poly1305_update(poly1305, data, data_len);
+
+ /* pad16() is defined in RFC 7539 2.8.1. */
+ if ((pad_len = data_len % 16) == 0)
+ return;
+
+ CRYPTO_poly1305_update(poly1305, zero_pad16, 16 - pad_len);
+}
+/* }}} */
+#endif
+
+static void chacha20_poly1305_encrypt_96(unsigned char* key, unsigned char* nonce, unsigned char* ad, size_t ad_len, unsigned char* in, size_t in_len, unsigned char* out, size_t* out_len)
+{
+#if defined(HAVE_OPENSSL)
+#if defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x3050000fL)
+#if (LIBRESSL_VERSION_NUMBER >= 0x2040000fL)
+ const EVP_AEAD *aead = EVP_aead_chacha20_poly1305();
+ EVP_AEAD_CTX ctx;
+ EVP_AEAD_CTX_init(&ctx, aead, key, EVP_AEAD_key_length(aead), EVP_AEAD_DEFAULT_TAG_LENGTH, NULL);
+ EVP_AEAD_CTX_seal(&ctx, out, out_len, *out_len, nonce, 12, in, in_len, ad, ad_len);
+#else
+ unsigned char poly1305_key[32];
+ poly1305_state poly1305;
+ uint64_t ctr = (uint64_t)(nonce[0] | nonce[1] << 8 | nonce[2] << 16 | nonce[3] << 24) << 32;
+ const unsigned char* iv = nonce + 4;
+
+ memset(poly1305_key, 0, sizeof(poly1305_key));
+ CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key), key, iv, ctr);
+
+ CRYPTO_poly1305_init(&poly1305, poly1305_key);
+ poly1305_update_with_pad16(&poly1305, ad, ad_len);
+ CRYPTO_chacha_20(out, in, in_len, key, iv, ctr + 1);
+ poly1305_update_with_pad16(&poly1305, out, in_len);
+ poly1305_update_with_length(&poly1305, NULL, ad_len);
+ poly1305_update_with_length(&poly1305, NULL, in_len);
+
+ CRYPTO_poly1305_finish(&poly1305, out + in_len);
+
+ *out_len = in_len + 16;
+#endif
+#elif defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+ int outl = 0;
+ EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
+ EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), NULL, key, nonce);
+ EVP_EncryptUpdate(ctx, out, &outl, in, in_len);
+ *out_len = outl;
+ outl = 0;
+ EVP_EncryptFinal_ex(ctx, out + *out_len, &outl);
+ *out_len += outl;
+ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, out + *out_len);
+ EVP_CIPHER_CTX_free(ctx);
+ *out_len += 16;
+#else
+#error Please use a newer version of OpenSSL (>= 1.1.0)
+#endif
+#elif defined(HAVE_GCRYPT)
+#if defined(GCRYPT_VERSION_NUMBER) && (GCRYPT_VERSION_NUMBER >= 0x010700)
+ gcry_cipher_hd_t hd;
+ if (gcry_cipher_open(&hd, GCRY_CIPHER_CHACHA20, GCRY_CIPHER_MODE_POLY1305, 0)) {
+ debug_info("gcry_cipher_open() failed");
+ return;
+ }
+ gcry_cipher_setkey(hd, key, 32);
+ gcry_cipher_setiv(hd, nonce, 12);
+ gcry_cipher_authenticate(hd, ad, ad_len);
+ *out_len = in_len + 16;
+ if (gcry_cipher_encrypt(hd, out, *out_len, in, in_len)) {
+ *out_len = 0;
+ }
+ gcry_cipher_gettag(hd, out+in_len, 16);
+ gcry_cipher_close(hd);
+#else
+#error Please use a newer version of libgcrypt (>= 1.7.0)
+#endif
+#elif defined (HAVE_MBEDTLS)
+ mbedtls_chachapoly_context ctx;
+ mbedtls_chachapoly_init(&ctx);
+ mbedtls_chachapoly_setkey(&ctx, key);
+ if (mbedtls_chachapoly_encrypt_and_tag(&ctx, in_len, nonce, ad, ad_len, in, out, out+in_len) != 0) {
+ *out_len = 0;
+ }
+ mbedtls_chachapoly_free(&ctx);
+#else
+#error chacha20_poly1305_encrypt_96 is not implemented
+#endif
+}
+
+static void chacha20_poly1305_encrypt_64(unsigned char* key, unsigned char* nonce, unsigned char* ad, size_t ad_len, unsigned char* in, size_t in_len, unsigned char* out, size_t* out_len)
+{
+ unsigned char _nonce[12];
+ *(uint32_t*)(&_nonce[0]) = 0;
+ memcpy(&_nonce[4], nonce, 8);
+ chacha20_poly1305_encrypt_96(key, _nonce, ad, ad_len, in, in_len, out, out_len);
+}
+
+static void chacha20_poly1305_decrypt_96(unsigned char* key, unsigned char* nonce, unsigned char* ad, size_t ad_len, unsigned char* in, size_t in_len, unsigned char* out, size_t* out_len)
+{
+#if defined(HAVE_OPENSSL)
+#if defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x3050000fL)
+#if (LIBRESSL_VERSION_NUMBER >= 0x2040000fL)
+ const EVP_AEAD *aead = EVP_aead_chacha20_poly1305();
+ EVP_AEAD_CTX ctx;
+ EVP_AEAD_CTX_init(&ctx, aead, key, EVP_AEAD_key_length(aead), EVP_AEAD_DEFAULT_TAG_LENGTH, NULL);
+ EVP_AEAD_CTX_open(&ctx, out, out_len, *out_len, nonce, 12, in, in_len, ad, ad_len);
+#else
+ unsigned char mac[16];
+ unsigned char poly1305_key[32];
+ poly1305_state poly1305;
+ size_t plaintext_len = in_len - 16;
+ uint64_t ctr = (uint64_t)(nonce[0] | nonce[1] << 8 | nonce[2] << 16 | nonce[3] << 24) << 32;
+ const unsigned char *iv = nonce + 4;
+
+ memset(poly1305_key, 0, sizeof(poly1305_key));
+ CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key), key, iv, ctr);
+
+ CRYPTO_poly1305_init(&poly1305, poly1305_key);
+ poly1305_update_with_pad16(&poly1305, ad, ad_len);
+ poly1305_update_with_pad16(&poly1305, in, plaintext_len);
+ poly1305_update_with_length(&poly1305, NULL, ad_len);
+ poly1305_update_with_length(&poly1305, NULL, plaintext_len);
+
+ CRYPTO_poly1305_finish(&poly1305, mac);
+
+ if (memcmp(mac, in + plaintext_len, 16) != 0) {
+ *out_len = 0;
+ return;
+ }
+
+ CRYPTO_chacha_20(out, in, plaintext_len, key, iv, ctr + 1);
+ *out_len = plaintext_len;
+#endif
+#elif defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+ int outl = 0;
+ size_t plaintext_len = in_len - 16;
+ EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
+ EVP_DecryptInit_ex(ctx, EVP_chacha20_poly1305(), NULL, key, nonce);
+ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, in + plaintext_len);
+ EVP_DecryptUpdate(ctx, out, &outl, in, plaintext_len);
+ *out_len = outl;
+ outl = 0;
+ if (EVP_DecryptFinal_ex(ctx, out + *out_len, &outl) == 1) {
+ *out_len += outl;
+ } else {
+ *out_len = 0;
+ }
+ EVP_CIPHER_CTX_free(ctx);
+#else
+#error Please use a newer version of OpenSSL (>= 1.1.0)
+#endif
+#elif defined(HAVE_GCRYPT)
+#if defined(GCRYPT_VERSION_NUMBER) && (GCRYPT_VERSION_NUMBER >= 0x010700)
+ gcry_cipher_hd_t hd;
+ if (gcry_cipher_open(&hd, GCRY_CIPHER_CHACHA20, GCRY_CIPHER_MODE_POLY1305, 0)) {
+ debug_info("gcry_cipher_open() failed");
+ return;
+ }
+ gcry_cipher_setkey(hd, key, 32);
+ gcry_cipher_setiv(hd, nonce, 12);
+ gcry_cipher_authenticate(hd, ad, ad_len);
+ unsigned int plaintext_len = in_len - 16;
+ gcry_cipher_decrypt(hd, out, *out_len, in, plaintext_len);
+ if (gcry_cipher_checktag(hd, in + plaintext_len, 16) == 0) {
+ *out_len = plaintext_len;
+ } else {
+ *out_len = 0;
+ }
+ gcry_cipher_close(hd);
+#else
+#error Please use a newer version of libgcrypt (>= 1.7.0)
+#endif
+#elif defined(HAVE_MBEDTLS)
+ mbedtls_chachapoly_context ctx;
+ mbedtls_chachapoly_init(&ctx);
+ mbedtls_chachapoly_setkey(&ctx, key);
+ unsigned int plaintext_len = in_len - 16;
+ if (mbedtls_chachapoly_auth_decrypt(&ctx, plaintext_len, nonce, ad, ad_len, in + plaintext_len, in, out) == 0) {
+ *out_len = plaintext_len;
+ } else {
+ *out_len = 0;
+ }
+ mbedtls_chachapoly_free(&ctx);
+#else
+#error chacha20_poly1305_decrypt_96 is not implemented
+#endif
+}
+
+static void chacha20_poly1305_decrypt_64(unsigned char* key, unsigned char* nonce, unsigned char* ad, size_t ad_len, unsigned char* in, size_t in_len, unsigned char* out, size_t* out_len)
+{
+ unsigned char _nonce[12];
+ *(uint32_t*)(&_nonce[0]) = 0;
+ memcpy(&_nonce[4], nonce, 8);
+ chacha20_poly1305_decrypt_96(key, _nonce, ad, ad_len, in, in_len, out, out_len);
+}
+/* }}} */
+
+#define PAIRING_ERROR(x) \
+ debug_info(x); \
+ if (pairing_callback) { \
+ pairing_callback(LOCKDOWN_CU_PAIRING_ERROR, cb_user_data, (char*)x, NULL); \
+ }
+
+#define PAIRING_ERROR_FMT(...) \
+ sprintf(tmp, __VA_ARGS__); \
+ debug_info(tmp); \
+ if (pairing_callback) { \
+ pairing_callback(LOCKDOWN_CU_PAIRING_ERROR, cb_user_data, tmp, NULL); \
+ }
+
+#endif /* HAVE_WIRELESS_PAIRING */
+
+lockdownd_error_t lockdownd_cu_pairing_create(lockdownd_client_t client, lockdownd_cu_pairing_cb_t pairing_callback, void* cb_user_data, plist_t host_info, plist_t acl)
+{
+#ifdef HAVE_WIRELESS_PAIRING
+ if (!client || !pairing_callback || (host_info && plist_get_node_type(host_info) != PLIST_DICT) || (acl && plist_get_node_type(acl) != PLIST_DICT))
+ return LOCKDOWN_E_INVALID_ARG;
+
+ lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
+
+ if (client->device && client->device->version == 0) {
+ plist_t p_version = NULL;
+ if (lockdownd_get_value(client, NULL, "ProductVersion", &p_version) == LOCKDOWN_E_SUCCESS) {
+ int vers[3] = {0, 0, 0};
+ char *s_version = NULL;
+ plist_get_string_val(p_version, &s_version);
+ if (s_version && sscanf(s_version, "%d.%d.%d", &vers[0], &vers[1], &vers[2]) >= 2) {
+ client->device->version = DEVICE_VERSION(vers[0], vers[1], vers[2]);
+ }
+ free(s_version);
+ }
+ plist_free(p_version);
+ }
+
+ char* pairing_uuid = NULL;
+ if (host_info) {
+ plist_t accountid = plist_dict_get_item(host_info, "accountID");
+ if (accountid && plist_get_node_type(accountid) == PLIST_STRING) {
+ plist_get_string_val(accountid, &pairing_uuid);
+ }
+ }
+ if (!pairing_uuid) {
+ userpref_read_system_buid(&pairing_uuid);
+ }
+ if (!pairing_uuid) {
+ pairing_uuid = generate_uuid();
+ }
+ unsigned int pairing_uuid_len = strlen(pairing_uuid);
+
+ SRP_initialize_library();
+
+ SRP* srp = SRP_new(SRP6a_sha512_client_method());
+ if (!srp) {
+ PAIRING_ERROR("Failed to initialize SRP")
+ return LOCKDOWN_E_UNKNOWN_ERROR;
+ }
+
+ char tmp[256];
+ plist_t dict = NULL;
+ uint8_t current_state = 0;
+ uint8_t final_state = 6;
+
+ unsigned char* salt = NULL;
+ unsigned int salt_size = 0;
+ unsigned char* pubkey = NULL;
+ unsigned int pubkey_size = 0;
+
+ unsigned char setup_encryption_key[32];
+
+ cstr *thekey = NULL;
+
+ do {
+ current_state++;
+
+ dict = plist_new_dict();
+ plist_dict_set_item(dict, "Request", plist_new_string("CUPairingCreate"));
+ if (current_state == 1) {
+ plist_dict_set_item(dict, "Flags", plist_new_uint(1));
+ } else {
+ plist_dict_set_item(dict, "Flags", plist_new_uint(0));
+ }
+
+ tlv_buf_t tlv = tlv_buf_new();
+
+ if (current_state == 1) {
+ /* send method */
+ tlv_buf_append(tlv, 0x00, 1, (void*)"\x00"); // 0x00 (Method), 1 bytes, 00
+ } else if (current_state == 3) {
+ /* generate public key */
+ cstr* own_pub = NULL;
+ SRP_gen_pub(srp, &own_pub);
+
+ if (!own_pub) {
+ PAIRING_ERROR("[SRP] Failed to generate public key")
+ ret = LOCKDOWN_E_PAIRING_FAILED;
+ break;
+ }
+
+ /* compute key from remote's public key */
+ if (SRP_compute_key(srp, &thekey, pubkey, pubkey_size) != 0) {
+ cstr_free(own_pub);
+ PAIRING_ERROR("[SRP] Failed to compute key")
+ ret = LOCKDOWN_E_PAIRING_FAILED;
+ break;
+ }
+
+ /* compute response */
+ cstr *response = NULL;
+ SRP_respond(srp, &response);
+
+ /* send our public key + response */
+ tlv_buf_append(tlv, 0x03, own_pub->length, own_pub->data);
+ tlv_buf_append(tlv, 0x04, response->length, response->data);
+ cstr_free(response);
+ cstr_free(own_pub);
+ } else if (current_state == 5) {
+ /* send encrypted info */
+
+ static const char PAIR_SETUP_ENCRYPT_SALT[] = "Pair-Setup-Encrypt-Salt";
+ static const char PAIR_SETUP_ENCRYPT_INFO[] = "Pair-Setup-Encrypt-Info";
+ static const char PAIR_SETUP_CONTROLLER_SIGN_SALT[] = "Pair-Setup-Controller-Sign-Salt";
+ static const char PAIR_SETUP_CONTROLLER_SIGN_INFO[] = "Pair-Setup-Controller-Sign-Info";
+
+ // HKDF with above computed key (SRP_compute_key) + Pair-Setup-Encrypt-Salt + Pair-Setup-Encrypt-Info
+ // result used as key for chacha20-poly1305
+ unsigned int setup_encryption_key_len = sizeof(setup_encryption_key);
+ hkdf_md(MD_ALGO_SHA512, (unsigned char*)PAIR_SETUP_ENCRYPT_SALT, sizeof(PAIR_SETUP_ENCRYPT_SALT)-1, (unsigned char*)PAIR_SETUP_ENCRYPT_INFO, sizeof(PAIR_SETUP_ENCRYPT_INFO)-1, (unsigned char*)thekey->data, thekey->length, setup_encryption_key, &setup_encryption_key_len);
+
+ unsigned char ed25519_pubkey[32];
+ unsigned char ed25519_privkey[64];
+ unsigned char ed25519seed[32];
+ ed25519_create_seed(ed25519seed);
+
+ ed25519_create_keypair(ed25519_pubkey, ed25519_privkey, ed25519seed);
+
+ unsigned int signbuf_len = pairing_uuid_len + 64;
+ unsigned char* signbuf = malloc(signbuf_len);
+ unsigned int hkdf_len = 32;
+ // HKDF with above computed key (SRP_compute_key) + Pair-Setup-Controller-Sign-Salt + Pair-Setup-Controller-Sign-Info
+ hkdf_md(MD_ALGO_SHA512, (unsigned char*)PAIR_SETUP_CONTROLLER_SIGN_SALT, sizeof(PAIR_SETUP_CONTROLLER_SIGN_SALT)-1, (unsigned char*)PAIR_SETUP_CONTROLLER_SIGN_INFO, sizeof(PAIR_SETUP_CONTROLLER_SIGN_INFO)-1, (unsigned char*)thekey->data, thekey->length, signbuf, &hkdf_len);
+
+ memcpy(signbuf + 32, pairing_uuid, pairing_uuid_len);
+ memcpy(signbuf + 32 + pairing_uuid_len, ed25519_pubkey, 32);
+
+ unsigned char ed_sig[64];
+ ed25519_sign(ed_sig, signbuf, 0x64, ed25519_pubkey, ed25519_privkey);
+
+ tlv_buf_t tlvbuf = tlv_buf_new();
+ tlv_buf_append(tlvbuf, 0x01, pairing_uuid_len, (void*)pairing_uuid);
+ tlv_buf_append(tlvbuf, 0x03, sizeof(ed25519_pubkey), ed25519_pubkey);
+ tlv_buf_append(tlvbuf, 0x0a, sizeof(ed_sig), ed_sig);
+
+ /* ACL */
+ unsigned char* odata = NULL;
+ unsigned int olen = 0;
+ if (acl) {
+ opack_encode_from_plist(acl, &odata, &olen);
+ } else {
+ /* defaut ACL */
+ plist_t acl_plist = plist_new_dict();
+ plist_dict_set_item(acl_plist, "com.apple.ScreenCapture", plist_new_bool(1));
+ plist_dict_set_item(acl_plist, "com.apple.developer", plist_new_bool(1));
+ opack_encode_from_plist(acl_plist, &odata, &olen);
+ plist_free(acl_plist);
+ }
+ tlv_buf_append(tlvbuf, 0x12, olen, odata);
+ free(odata);
+
+ /* HOST INFORMATION */
+ char hostname[256];
+#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE)
+ CFStringRef cname = SCDynamicStoreCopyComputerName(NULL, NULL);
+ CFStringGetCString(cname, hostname, sizeof(hostname), kCFStringEncodingUTF8);
+ CFRelease(cname);
+#else
+#ifdef WIN32
+ DWORD hostname_len = sizeof(hostname);
+ GetComputerName(hostname, &hostname_len);
+#else
+ gethostname(hostname, sizeof(hostname));
+#endif
+#endif
+
+ char modelname[256];
+ modelname[0] = '\0';
+#ifdef __APPLE__
+ size_t len = sizeof(modelname);
+ sysctlbyname("hw.model", &modelname, &len, NULL, 0);
+#endif
+ if (strlen(modelname) == 0) {
+ strcpy(modelname, "HackbookPro13,37");
+ }
+
+ unsigned char primary_mac_addr[6] = { 0, 0, 0, 0, 0, 0 };
+ if (get_primary_mac_address(primary_mac_addr) != 0) {
+ debug_info("Failed to get primary mac address");
+ }
+ debug_info("Primary mac address: %02x:%02x:%02x:%02x:%02x:%02x\n", primary_mac_addr[0], primary_mac_addr[1], primary_mac_addr[2], primary_mac_addr[3], primary_mac_addr[4], primary_mac_addr[5]);
+
+ // "OPACK" encoded device info
+ plist_t info_plist = plist_new_dict();
+ //plist_dict_set_item(info_plist, "altIRK", plist_new_data((char*)altIRK, 16));
+ plist_dict_set_item(info_plist, "accountID", plist_new_string(pairing_uuid));
+ plist_dict_set_item(info_plist, "model", plist_new_string(modelname));
+ plist_dict_set_item(info_plist, "name", plist_new_string(hostname));
+ plist_dict_set_item(info_plist, "mac", plist_new_data((char*)primary_mac_addr, 6));
+ if (host_info) {
+ plist_dict_merge(&info_plist, host_info);
+ }
+ opack_encode_from_plist(info_plist, &odata, &olen);
+ plist_free(info_plist);
+ tlv_buf_append(tlvbuf, 0x11, olen, odata);
+ free(odata);
+
+ size_t encrypted_len = tlvbuf->length + 16;
+ unsigned char* encrypted_buf = (unsigned char*)malloc(encrypted_len);
+
+ chacha20_poly1305_encrypt_64(setup_encryption_key, (unsigned char*)"PS-Msg05", NULL, 0, tlvbuf->data, tlvbuf->length, encrypted_buf, &encrypted_len);
+
+ tlv_buf_free(tlvbuf);
+
+ tlv_buf_append(tlv, 0x05, encrypted_len, encrypted_buf);
+ free(encrypted_buf);
+ } else {
+ tlv_buf_free(tlv);
+ PAIRING_ERROR("[SRP] Invalid state");
+ ret = LOCKDOWN_E_PAIRING_FAILED;
+ break;
+ }
+ tlv_buf_append(tlv, 0x06, 1, &current_state);
+ plist_dict_set_item(dict, "Payload", plist_new_data((char*)tlv->data, tlv->length));
+ tlv_buf_free(tlv);
+
+ plist_dict_set_item(dict, "Label", plist_new_string(client->label));
+ plist_dict_set_item(dict, "ProtocolVersion", plist_new_uint(2));
+
+ ret = lockdownd_send(client, dict);
+ plist_free(dict);
+ dict = NULL;
+
+ if (ret != LOCKDOWN_E_SUCCESS) {
+ break;
+ }
+
+ current_state++;
+
+ ret = lockdownd_receive(client, &dict);
+ if (ret != LOCKDOWN_E_SUCCESS) {
+ break;
+ }
+ ret = lockdown_check_result(dict, "CUPairingCreate");
+ if (ret != LOCKDOWN_E_SUCCESS) {
+ break;
+ }
+
+ plist_t extresp = plist_dict_get_item(dict, "ExtendedResponse");
+ if (!extresp) {
+ ret = LOCKDOWN_E_PLIST_ERROR;
+ break;
+ }
+ plist_t blob = plist_dict_get_item(extresp, "Payload");
+ if (!blob) {
+ ret = LOCKDOWN_E_PLIST_ERROR;
+ break;
+ }
+ uint64_t data_len = 0;
+ const char* data = plist_get_data_ptr(blob, &data_len);
+
+ uint8_t state = 0;
+ if (!tlv_data_get_uint8(data, data_len, 0x06, &state)) {
+ PAIRING_ERROR("[SRP] ERROR: Could not find state in response");
+ ret = LOCKDOWN_E_PAIRING_FAILED;
+ break;
+ }
+ if (state != current_state) {
+ PAIRING_ERROR_FMT("[SRP] ERROR: Unexpected state %d, expected %d", state, current_state);
+ ret = LOCKDOWN_E_PAIRING_FAILED;
+ break;
+ }
+
+ unsigned int errval = 0;
+ uint64_t u64val = 0;
+ tlv_data_get_uint(data, data_len, 0x07, &u64val);
+debug_buffer(data, data_len);
+ errval = (unsigned int)u64val;
+ if (errval > 0) {
+ if (errval == 3) {
+ u64val = 0;
+ tlv_data_get_uint(data, data_len, 0x08, &u64val);
+ if (u64val > 0) {
+ uint32_t retry_delay = (uint32_t)u64val;
+ PAIRING_ERROR_FMT("[SRP] Pairing is blocked for another %u seconds", retry_delay)
+ ret = LOCKDOWN_E_PAIRING_FAILED;
+ break;
+ }
+ } else if (errval == 2 && state == 4) {
+ PAIRING_ERROR_FMT("[SRP] Invalid PIN")
+ ret = LOCKDOWN_E_PAIRING_FAILED;
+ break;
+ } else {
+ PAIRING_ERROR_FMT("[SRP] Received error %u in state %d.", errval, state);
+ ret = LOCKDOWN_E_PAIRING_FAILED;
+ break;
+ }
+ }
+
+ if (state == 2) {
+ /* receive salt and public key */
+ if (!tlv_data_copy_data(data, data_len, 0x02, (void**)&salt, &salt_size)) {
+ PAIRING_ERROR("[SRP] ERROR: Could not find salt in response");
+ ret = LOCKDOWN_E_PAIRING_FAILED;
+ break;
+ }
+ if (!tlv_data_copy_data(data, data_len, 0x03, (void**)&pubkey, &pubkey_size)) {
+ PAIRING_ERROR("[SRP] ERROR: Could not find public key in response");
+
+ ret = LOCKDOWN_E_PAIRING_FAILED;
+ break;
+ }
+
+ const char PAIR_SETUP[] = "Pair-Setup";
+ if (SRP_set_user_raw(srp, (const unsigned char*)PAIR_SETUP, sizeof(PAIR_SETUP)-1) != 0) {
+ PAIRING_ERROR("[SRP] Failed to set SRP user");
+ ret = LOCKDOWN_E_PAIRING_FAILED;
+ break;
+ }
+
+ /* kSRPParameters_3072_SHA512 */
+ if (SRP_set_params(srp, kSRPModulus3072, sizeof(kSRPModulus3072), &kSRPGenerator5, 1, salt, salt_size) != 0) {
+ PAIRING_ERROR("[SRP] Failed to set SRP parameters");
+ ret = LOCKDOWN_E_PAIRING_FAILED;
+ break;
+
+ }
+
+ if (pairing_callback) {
+ char pin[64];
+ unsigned int pin_len = sizeof(pin);
+ pairing_callback(LOCKDOWN_CU_PAIRING_PIN_REQUESTED, cb_user_data, pin, &pin_len);
+
+ SRP_set_auth_password_raw(srp, (const unsigned char*)pin, pin_len);
+ }
+ } else if (state == 4) {
+ /* receive proof */
+ unsigned char* proof = NULL;
+ unsigned int proof_len = 0;
+
+ if (!tlv_data_copy_data(data, data_len, 0x04, (void**)&proof, &proof_len)) {
+ PAIRING_ERROR("[SRP] ERROR: Could not find proof data in response");
+ ret = LOCKDOWN_E_PAIRING_FAILED;
+ break;
+ }
+
+ /* verify */
+ int vrfy_result = SRP_verify(srp, proof, proof_len);
+ free(proof);
+
+ if (vrfy_result == 0) {
+ debug_info("[SRP] PIN verified successfully");
+ } else {
+ PAIRING_ERROR("[SRP] PIN verification failure");
+ ret = LOCKDOWN_E_PAIRING_FAILED;
+ break;
+ }
+
+ } else if (state == 6) {
+ int srp_pair_success = 0;
+ plist_t node = plist_dict_get_item(extresp, "doSRPPair");
+ if (node) {
+ const char* strv = plist_get_string_ptr(node, NULL);
+ if (strcmp(strv, "succeed") == 0) {
+ srp_pair_success = 1;
+ }
+ }
+ if (!srp_pair_success) {
+ PAIRING_ERROR("SRP Pairing failed");
+ ret = LOCKDOWN_E_PAIRING_FAILED;
+ break;
+ }
+
+ /* receive encrypted info */
+ unsigned char* encrypted_buf = NULL;
+ unsigned int enc_len = 0;
+ if (!tlv_data_copy_data(data, data_len, 0x05, (void**)&encrypted_buf, &enc_len)) {
+ PAIRING_ERROR("[SRP] ERROR: Could not find encrypted data in response");
+ ret = LOCKDOWN_E_PAIRING_FAILED;
+ break;
+ }
+ size_t plain_len = enc_len-16;
+ unsigned char* plain_buf = malloc(plain_len);
+ chacha20_poly1305_decrypt_64(setup_encryption_key, (unsigned char*)"PS-Msg06", NULL, 0, encrypted_buf, enc_len, plain_buf, &plain_len);
+ free(encrypted_buf);
+
+ unsigned char* dev_info = NULL;
+ unsigned int dev_info_len = 0;
+ int res = tlv_data_copy_data(plain_buf, plain_len, 0x11, (void**)&dev_info, &dev_info_len);
+ free(plain_buf);
+ if (!res) {
+ PAIRING_ERROR("[SRP] ERROR: Failed to locate device info in response");
+ ret = LOCKDOWN_E_PAIRING_FAILED;
+ break;
+ }
+ plist_t device_info = NULL;
+ opack_decode_to_plist(dev_info, dev_info_len, &device_info);
+ free(dev_info);
+
+ if (!device_info) {
+ PAIRING_ERROR("[SRP] ERROR: Failed to parse device info");
+ ret = LOCKDOWN_E_PAIRING_FAILED;
+ break;
+ }
+
+ if (pairing_callback) {
+ pairing_callback(LOCKDOWN_CU_PAIRING_DEVICE_INFO, cb_user_data, device_info, NULL);
+ }
+ plist_free(device_info);
+ } else {
+ PAIRING_ERROR("[SRP] ERROR: Invalid state");
+ ret = LOCKDOWN_E_PAIRING_FAILED;
+ break;
+ }
+ plist_free(dict);
+ dict = NULL;
+
+ } while (current_state != final_state);
+
+ plist_free(dict);
+
+ free(salt);
+ free(pubkey);
+
+ SRP_free(srp);
+ srp = NULL;
+
+ if (ret != LOCKDOWN_E_SUCCESS) {
+ if (thekey) {
+ cstr_free(thekey);
+ }
+ return ret;
+ }
+
+ free(client->cu_key);
+ client->cu_key = malloc(thekey->length);
+ memcpy(client->cu_key, thekey->data, thekey->length);
+ client->cu_key_len = thekey->length;
+ cstr_free(thekey);
+
+ return LOCKDOWN_E_SUCCESS;
+#else
+ debug_info("not supported");
+ return LOCKDOWN_E_UNKNOWN_ERROR;
+#endif
+}
+
+lockdownd_error_t lockdownd_cu_send_request_and_get_reply(lockdownd_client_t client, const char* request, plist_t request_payload, plist_t* reply)
+{
+#ifdef HAVE_WIRELESS_PAIRING
+ if (!client || !request)
+ return LOCKDOWN_E_INVALID_ARG;
+
+ if (!client->cu_key)
+ return LOCKDOWN_E_NO_RUNNING_SESSION;
+
+ lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
+
+ /* derive keys */
+ unsigned char cu_write_key[32];
+ unsigned int cu_write_key_len = sizeof(cu_write_key);
+ static const char WRITE_KEY_SALT_MDLD[] = "WriteKeySaltMDLD";
+ static const char WRITE_KEY_INFO_MDLD[] = "WriteKeyInfoMDLD";
+ hkdf_md(MD_ALGO_SHA512, (unsigned char*)WRITE_KEY_SALT_MDLD, sizeof(WRITE_KEY_SALT_MDLD)-1, (unsigned char*)WRITE_KEY_INFO_MDLD, sizeof(WRITE_KEY_INFO_MDLD)-1, client->cu_key, client->cu_key_len, cu_write_key, &cu_write_key_len);
+
+ unsigned char cu_read_key[32];
+ unsigned int cu_read_key_len = sizeof(cu_write_key);
+ static const char READ_KEY_SALT_MDLD[] = "ReadKeySaltMDLD";
+ static const char READ_KEY_INFO_MDLD[] = "ReadKeyInfoMDLD";
+ hkdf_md(MD_ALGO_SHA512, (unsigned char*)READ_KEY_SALT_MDLD, sizeof(READ_KEY_SALT_MDLD)-1, (unsigned char*)READ_KEY_INFO_MDLD, sizeof(READ_KEY_INFO_MDLD)-1, client->cu_key, client->cu_key_len, cu_read_key, &cu_read_key_len);
+
+ // Starting with iOS/tvOS 11.2 and WatchOS 4.2, this nonce is random and sent along with the request. Before, the request doesn't have a nonce and it uses hardcoded nonce "sendone01234".
+ unsigned char cu_nonce[12] = "sendone01234"; // guaranteed to be random by fair dice troll
+ if (client->device->version >= DEVICE_VERSION(11,2,0)) {
+#if defined(HAVE_OPENSSL)
+ RAND_bytes(cu_nonce, sizeof(cu_nonce));
+#elif defined(HAVE_GCRYPT)
+ gcry_create_nonce(cu_nonce, sizeof(cu_nonce));
+#endif
+ }
+
+ debug_plist(request_payload);
+
+ /* convert request payload to binary */
+ uint32_t bin_len = 0;
+ char* bin = NULL;
+ plist_to_bin(request_payload, &bin, &bin_len);
+
+ /* encrypt request */
+ size_t encrypted_len = bin_len + 16;
+ unsigned char* encrypted_buf = malloc(encrypted_len);
+ chacha20_poly1305_encrypt_96(cu_write_key, cu_nonce, NULL, 0, (unsigned char*)bin, bin_len, encrypted_buf, &encrypted_len);
+ free(bin);
+ bin = NULL;
+
+ plist_t dict = plist_new_dict();
+ plist_dict_set_item(dict,"Request", plist_new_string(request));
+ plist_dict_set_item(dict, "Payload", plist_new_data((char*)encrypted_buf, encrypted_len));
+ free(encrypted_buf);
+ plist_dict_set_item(dict, "Nonce", plist_new_data((char*)cu_nonce, sizeof(cu_nonce)));
+ plist_dict_set_item(dict, "Label", plist_new_string(client->label));
+ plist_dict_set_item(dict, "ProtocolVersion", plist_new_uint(2));
+
+ /* send to device */
+ ret = lockdownd_send(client, dict);
+ plist_free(dict);
+ dict = NULL;
+
+ if (ret != LOCKDOWN_E_SUCCESS)
+ return ret;
+
+ /* Now get device's answer */
+ ret = lockdownd_receive(client, &dict);
+ if (ret != LOCKDOWN_E_SUCCESS)
+ return ret;
+
+ ret = lockdown_check_result(dict, request);
+ if (ret != LOCKDOWN_E_SUCCESS) {
+ plist_free(dict);
+ return ret;
+ }
+
+ /* get payload */
+ plist_t blob = plist_dict_get_item(dict, "Payload");
+ if (!blob) {
+ plist_free(dict);
+ return LOCKDOWN_E_DICT_ERROR;
+ }
+
+ uint64_t dl = 0;
+ const char* dt = plist_get_data_ptr(blob, &dl);
+
+ /* see if we have a nonce */
+ blob = plist_dict_get_item(dict, "Nonce");
+ const unsigned char* rnonce = (unsigned char*)"receiveone01";
+ if (blob) {
+ uint64_t rl = 0;
+ rnonce = (const unsigned char*)plist_get_data_ptr(blob, &rl);
+ }
+
+ /* decrypt payload */
+ size_t decrypted_len = dl-16;
+ unsigned char* decrypted = malloc(decrypted_len);
+ chacha20_poly1305_decrypt_96(cu_read_key, (unsigned char*)rnonce, NULL, 0, (unsigned char*)dt, dl, decrypted, &decrypted_len);
+ plist_free(dict);
+ dict = NULL;
+
+ plist_from_memory((const char*)decrypted, decrypted_len, &dict, NULL);
+ if (!dict) {
+ ret = LOCKDOWN_E_PLIST_ERROR;
+ debug_info("Failed to parse PLIST from decrypted payload:");
+ debug_buffer((const char*)decrypted, decrypted_len);
+ free(decrypted);
+ return ret;
+ }
+ free(decrypted);
+
+ debug_plist(dict);
+
+ if (reply) {
+ *reply = dict;
+ } else {
+ plist_free(dict);
+ }
+
+ return LOCKDOWN_E_SUCCESS;
+#else
+ debug_info("not supported");
+ return LOCKDOWN_E_UNKNOWN_ERROR;
+#endif
+}
+
+lockdownd_error_t lockdownd_get_value_cu(lockdownd_client_t client, const char* domain, const char* key, plist_t* value)
+{
+#ifdef HAVE_WIRELESS_PAIRING
+ if (!client)
+ return LOCKDOWN_E_INVALID_ARG;
+
+ if (!client->cu_key)
+ return LOCKDOWN_E_NO_RUNNING_SESSION;
+
+ lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
+
+ plist_t request = plist_new_dict();
+ if (domain) {
+ plist_dict_set_item(request, "Domain", plist_new_string(domain));
+ }
+ if (key) {
+ plist_dict_set_item(request, "Key", plist_new_string(key));
+ }
+
+ plist_t reply = NULL;
+ ret = lockdownd_cu_send_request_and_get_reply(client, "GetValueCU", request, &reply);
+ plist_free(request);
+ if (ret != LOCKDOWN_E_SUCCESS) {
+ return ret;
+ }
+
+ plist_t value_node = plist_dict_get_item(reply, "Value");
+ if (value_node) {
+ debug_info("has a value");
+ *value = plist_copy(value_node);
+ }
+ plist_free(reply);
+
+ return ret;
+#else
+ debug_info("not supported");
+ return LOCKDOWN_E_UNKNOWN_ERROR;
+#endif
+}
+
+lockdownd_error_t lockdownd_pair_cu(lockdownd_client_t client)
+{
+#ifdef HAVE_WIRELESS_PAIRING
+ if (!client)
+ return LOCKDOWN_E_INVALID_ARG;
+
+ if (!client->cu_key)
+ return LOCKDOWN_E_NO_RUNNING_SESSION;
+
+ lockdownd_error_t ret;
+
+ plist_t wifi_mac = NULL;
+ ret = lockdownd_get_value_cu(client, NULL, "WiFiAddress", &wifi_mac);
+ if (ret != LOCKDOWN_E_SUCCESS) {
+ return ret;
+ }
+
+ plist_t pubkey = NULL;
+ ret = lockdownd_get_value_cu(client, NULL, "DevicePublicKey", &pubkey);
+ if (ret != LOCKDOWN_E_SUCCESS) {
+ plist_free(wifi_mac);
+ return ret;
+ }
+
+ key_data_t public_key = { NULL, 0 };
+ uint64_t data_len = 0;
+ plist_get_data_val(pubkey, (char**)&public_key.data, &data_len);
+ public_key.size = (unsigned int)data_len;
+ plist_free(pubkey);
+
+ plist_t pair_record_plist = plist_new_dict();
+ pair_record_generate_keys_and_certs(pair_record_plist, public_key);
+
+ char* host_id = NULL;
+ char* system_buid = NULL;
+
+ /* set SystemBUID */
+ userpref_read_system_buid(&system_buid);
+ if (system_buid) {
+ plist_dict_set_item(pair_record_plist, USERPREF_SYSTEM_BUID_KEY, plist_new_string(system_buid));
+ free(system_buid);
+ }
+
+ /* set HostID */
+ host_id = generate_uuid();
+ pair_record_set_host_id(pair_record_plist, host_id);
+ free(host_id);
+
+ plist_t request_pair_record = plist_copy(pair_record_plist);
+ /* remove stuff that is private */
+ plist_dict_remove_item(request_pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY);
+ plist_dict_remove_item(request_pair_record, USERPREF_HOST_PRIVATE_KEY_KEY);
+
+ plist_t request = plist_new_dict();
+ plist_dict_set_item(request, "PairRecord", request_pair_record);
+ plist_t pairing_opts = plist_new_dict();
+ plist_dict_set_item(pairing_opts, "ExtendedPairingErrors", plist_new_bool(1));
+ plist_dict_set_item(request, "PairingOptions", pairing_opts);
+
+ plist_t reply = NULL;
+ ret = lockdownd_cu_send_request_and_get_reply(client, "PairCU", request, &reply);
+ plist_free(request);
+ if (ret != LOCKDOWN_E_SUCCESS) {
+ plist_free(wifi_mac);
+ return ret;
+ }
+
+ char *s_udid = NULL;
+ plist_t p_udid = plist_dict_get_item(reply, "UDID");
+ if (p_udid) {
+ plist_get_string_val(p_udid, &s_udid);
+ }
+ plist_t ebag = plist_dict_get_item(reply, "EscrowBag");
+ if (ebag) {
+ plist_dict_set_item(pair_record_plist, USERPREF_ESCROW_BAG_KEY, plist_copy(ebag));
+ }
+ plist_dict_set_item(pair_record_plist, USERPREF_WIFI_MAC_ADDRESS_KEY, wifi_mac);
+ plist_free(reply);
+
+ if (userpref_save_pair_record(s_udid, 0, pair_record_plist) != 0) {
+ printf("Failed to save pair record for UDID %s\n", s_udid);
+ }
+ free(s_udid);
+ s_udid = NULL;
+ plist_free(pair_record_plist);
+
+ ret = LOCKDOWN_E_SUCCESS;
+
+ return ret;
+#else
+ debug_info("not supported");
+ return LOCKDOWN_E_UNKNOWN_ERROR;
+#endif
+}
diff --git a/src/lockdown.c b/src/lockdown.c
index 49f757c..256bff0 100644
--- a/src/lockdown.c
+++ b/src/lockdown.c
@@ -34,13 +34,13 @@
#include <ctype.h>
#include <unistd.h>
#include <plist/plist.h>
+#include <libimobiledevice-glue/utils.h>
#include "property_list_service.h"
#include "lockdown.h"
#include "idevice.h"
#include "common/debug.h"
#include "common/userpref.h"
-#include "common/utils.h"
#include "asprintf.h"
#ifdef WIN32
@@ -152,7 +152,7 @@ static lockdownd_error_t lockdownd_error(property_list_service_error_t err)
* LOCKDOWN_E_UNKNOWN_ERROR when the result is 'Failure',
* or a specific error code if derieved from the result.
*/
-static lockdownd_error_t lockdown_check_result(plist_t dict, const char *query_match)
+lockdownd_error_t lockdown_check_result(plist_t dict, const char *query_match)
{
lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
@@ -163,53 +163,40 @@ static lockdownd_error_t lockdown_check_result(plist_t dict, const char *query_m
if (plist_get_node_type(query_node) != PLIST_STRING) {
return ret;
- } else {
- char *query_value = NULL;
-
- plist_get_string_val(query_node, &query_value);
- if (!query_value) {
- return ret;
- }
+ }
- if (query_match && (strcmp(query_value, query_match) != 0)) {
- free(query_value);
- return ret;
- }
+ const char *query_value = plist_get_string_ptr(query_node, NULL);
+ if (!query_value) {
+ return ret;
+ }
- free(query_value);
+ if (query_match && (strcmp(query_value, query_match) != 0)) {
+ return ret;
}
- plist_t result_node = plist_dict_get_item(dict, "Result");
- if (!result_node) {
- /* iOS 5: the 'Result' key is not present anymore.
- But we need to check for the 'Error' key. */
- plist_t err_node = plist_dict_get_item(dict, "Error");
- if (err_node) {
- if (plist_get_node_type(err_node) == PLIST_STRING) {
- char *err_value = NULL;
-
- plist_get_string_val(err_node, &err_value);
- if (err_value) {
- debug_info("ERROR: %s", err_value);
- ret = lockdownd_strtoerr(err_value);
- free(err_value);
- } else {
- debug_info("ERROR: unknown error occurred");
- }
+ /* Check for 'Error' in reply */
+ plist_t err_node = plist_dict_get_item(dict, "Error");
+ if (err_node) {
+ if (plist_get_node_type(err_node) == PLIST_STRING) {
+ const char *err_value = plist_get_string_ptr(err_node, NULL);
+ if (err_value) {
+ debug_info("ERROR: %s", err_value);
+ ret = lockdownd_strtoerr(err_value);
+ } else {
+ debug_info("ERROR: unknown error occurred");
}
- return ret;
}
-
- ret = LOCKDOWN_E_SUCCESS;
-
return ret;
}
- plist_type result_type = plist_get_node_type(result_node);
- if (result_type == PLIST_STRING) {
- char *result_value = NULL;
-
- plist_get_string_val(result_node, &result_value);
+ plist_t result_node = plist_dict_get_item(dict, "Result");
+ if (!result_node) {
+ /* With iOS 5+ 'Result' is not present anymore.
+ If there is no 'Error', we can just assume success. */
+ return LOCKDOWN_E_SUCCESS;
+ }
+ if (plist_get_node_type(result_node) == PLIST_STRING) {
+ const char *result_value = plist_get_string_ptr(result_node, NULL);
if (result_value) {
if (!strcmp(result_value, "Success")) {
ret = LOCKDOWN_E_SUCCESS;
@@ -219,9 +206,6 @@ static lockdownd_error_t lockdown_check_result(plist_t dict, const char *query_m
debug_info("ERROR: unknown result value '%s'", result_value);
}
}
-
- if (result_value)
- free(result_value);
}
return ret;
@@ -242,7 +226,7 @@ static void plist_dict_add_label(plist_t plist, const char *label)
}
}
-LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client, const char *session_id)
+lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client, const char *session_id)
{
if (!client)
return LOCKDOWN_E_INVALID_ARG;
@@ -311,12 +295,13 @@ static lockdownd_error_t lockdownd_client_free_simple(lockdownd_client_t client)
free(client->session_id);
client->session_id = NULL;
}
- if (client->udid) {
- free(client->udid);
- }
if (client->label) {
free(client->label);
}
+ if (client->cu_key) {
+ free(client->cu_key);
+ client->cu_key = NULL;
+ }
free(client);
client = NULL;
@@ -324,7 +309,7 @@ static lockdownd_error_t lockdownd_client_free_simple(lockdownd_client_t client)
return ret;
}
-LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_free(lockdownd_client_t client)
+lockdownd_error_t lockdownd_client_free(lockdownd_client_t client)
{
if (!client)
return LOCKDOWN_E_INVALID_ARG;
@@ -340,7 +325,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_free(lockdownd_client_t
return ret;
}
-LIBIMOBILEDEVICE_API void lockdownd_client_set_label(lockdownd_client_t client, const char *label)
+void lockdownd_client_set_label(lockdownd_client_t client, const char *label)
{
if (client) {
if (client->label)
@@ -350,7 +335,7 @@ LIBIMOBILEDEVICE_API void lockdownd_client_set_label(lockdownd_client_t client,
}
}
-LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_receive(lockdownd_client_t client, plist_t *plist)
+lockdownd_error_t lockdownd_receive(lockdownd_client_t client, plist_t *plist)
{
if (!client || !plist || (plist && *plist))
return LOCKDOWN_E_INVALID_ARG;
@@ -358,7 +343,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_receive(lockdownd_client_t clie
return lockdownd_error(property_list_service_receive_plist(client->parent, plist));
}
-LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_send(lockdownd_client_t client, plist_t plist)
+lockdownd_error_t lockdownd_send(lockdownd_client_t client, plist_t plist)
{
if (!client || !plist)
return LOCKDOWN_E_INVALID_ARG;
@@ -366,7 +351,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_send(lockdownd_client_t client,
return lockdownd_error(property_list_service_send_xml_plist(client->parent, plist));
}
-LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_query_type(lockdownd_client_t client, char **type)
+lockdownd_error_t lockdownd_query_type(lockdownd_client_t client, char **type)
{
if (!client)
return LOCKDOWN_E_INVALID_ARG;
@@ -411,7 +396,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_query_type(lockdownd_client_t c
return ret;
}
-LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *domain, const char *key, plist_t *value)
+lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *domain, const char *key, plist_t *value)
{
if (!client)
return LOCKDOWN_E_INVALID_ARG;
@@ -465,7 +450,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_value(lockdownd_client_t cl
return ret;
}
-LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_set_value(lockdownd_client_t client, const char *domain, const char *key, plist_t value)
+lockdownd_error_t lockdownd_set_value(lockdownd_client_t client, const char *domain, const char *key, plist_t value)
{
if (!client || !value)
return LOCKDOWN_E_INVALID_ARG;
@@ -513,7 +498,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_set_value(lockdownd_client_t cl
return ret;
}
-LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_remove_value(lockdownd_client_t client, const char *domain, const char *key)
+lockdownd_error_t lockdownd_remove_value(lockdownd_client_t client, const char *domain, const char *key)
{
if (!client)
return LOCKDOWN_E_INVALID_ARG;
@@ -560,7 +545,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_remove_value(lockdownd_client_t
return ret;
}
-LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_device_udid(lockdownd_client_t client, char **udid)
+lockdownd_error_t lockdownd_get_device_udid(lockdownd_client_t client, char **udid)
{
lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
plist_t value = NULL;
@@ -606,7 +591,7 @@ static lockdownd_error_t lockdownd_get_device_public_key_as_key_data(lockdownd_c
return ret;
}
-LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_device_name(lockdownd_client_t client, char **device_name)
+lockdownd_error_t lockdownd_get_device_name(lockdownd_client_t client, char **device_name)
{
lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
plist_t value = NULL;
@@ -623,7 +608,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_device_name(lockdownd_clien
return ret;
}
-LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_new(idevice_t device, lockdownd_client_t *client, const char *label)
+lockdownd_error_t lockdownd_client_new(idevice_t device, lockdownd_client_t *client, const char *label)
{
if (!device || !client)
return LOCKDOWN_E_INVALID_ARG;
@@ -643,12 +628,13 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_new(idevice_t device, lo
client_loc->parent = plistclient;
client_loc->ssl_enabled = 0;
client_loc->session_id = NULL;
- client_loc->mux_id = device->mux_id;
+ client_loc->device = device;
+ client_loc->cu_key = NULL;
+ client_loc->cu_key_len = 0;
- if (idevice_get_udid(device, &client_loc->udid) != IDEVICE_E_SUCCESS) {
- debug_info("failed to get device udid.");
+ if (device->udid) {
+ debug_info("device udid: %s", device->udid);
}
- debug_info("device udid: %s", client_loc->udid);
client_loc->label = label ? strdup(label) : NULL;
@@ -657,7 +643,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_new(idevice_t device, lo
return LOCKDOWN_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_new_with_handshake(idevice_t device, lockdownd_client_t *client, const char *label)
+lockdownd_error_t lockdownd_client_new_with_handshake(idevice_t device, lockdownd_client_t *client, const char *label)
{
if (!client)
return LOCKDOWN_E_INVALID_ARG;
@@ -678,7 +664,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_new_with_handshake(idevi
ret = lockdownd_query_type(client_loc, &type);
if (LOCKDOWN_E_SUCCESS != ret) {
debug_info("QueryType failed in the lockdownd client.");
- } else if (strcmp("com.apple.mobile.lockdown", type)) {
+ } else if (strcmp("com.apple.mobile.lockdown", type) != 0) {
debug_info("Warning QueryType request returned \"%s\".", type);
}
free(type);
@@ -696,8 +682,37 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_new_with_handshake(idevi
}
plist_free(p_version);
}
+ if (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;
+ plist_get_string_val(p_device_class, &s_device_class);
+ if (s_device_class != NULL) {
+ if (!strcmp(s_device_class, "iPhone")) {
+ device->device_class = DEVICE_CLASS_IPHONE;
+ } else if (!strcmp(s_device_class, "iPad")) {
+ device->device_class = DEVICE_CLASS_IPAD;
+ } else if (!strcmp(s_device_class, "iPod")) {
+ device->device_class = DEVICE_CLASS_IPOD;
+ } else if (!strcmp(s_device_class, "Watch")) {
+ device->device_class = DEVICE_CLASS_WATCH;
+ } else if (!strcmp(s_device_class, "AppleTV")) {
+ device->device_class = DEVICE_CLASS_APPLETV;
+ } else {
+ device->device_class = DEVICE_CLASS_UNKNOWN;
+ }
+ free(s_device_class);
+ }
+ }
+ plist_free(p_device_class);
+ }
- userpref_read_pair_record(client_loc->udid, &pair_record);
+ 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);
+ lockdownd_client_free(client_loc);
+ return LOCKDOWN_E_RECEIVE_TIMEOUT;
+ }
if (pair_record) {
pair_record_get_host_id(pair_record, &host_id);
}
@@ -707,13 +722,15 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_new_with_handshake(idevi
if (LOCKDOWN_E_SUCCESS == ret && !pair_record) {
/* attempt pairing */
+ free(host_id);
+ host_id = NULL;
ret = lockdownd_pair(client_loc, NULL);
}
plist_free(pair_record);
pair_record = NULL;
- if (device->version < DEVICE_VERSION(7,0,0)) {
+ if (device->version < 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);
@@ -730,7 +747,20 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_new_with_handshake(idevi
if (LOCKDOWN_E_SUCCESS == ret) {
if (!host_id) {
- userpref_read_pair_record(client_loc->udid, &pair_record);
+ uerr = userpref_read_pair_record(client_loc->device->udid, &pair_record);
+ if (uerr == USERPREF_E_READ_ERROR) {
+ debug_info("ERROR: Failed to retrieve pair record for %s", client_loc->device->udid);
+ lockdownd_client_free(client_loc);
+ return LOCKDOWN_E_RECEIVE_TIMEOUT;
+ } else if (uerr == USERPREF_E_NOENT) {
+ debug_info("ERROR: No pair record for %s", client_loc->device->udid);
+ lockdownd_client_free(client_loc);
+ return LOCKDOWN_E_INVALID_CONF;
+ } else if (uerr != USERPREF_E_SUCCESS) {
+ debug_info("ERROR: Failed to retrieve or parse pair record for %s", client_loc->device->udid);
+ lockdownd_client_free(client_loc);
+ return LOCKDOWN_E_INVALID_CONF;
+ }
if (pair_record) {
pair_record_get_host_id(pair_record, &host_id);
plist_free(pair_record);
@@ -894,9 +924,16 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_
lockdownd_get_value(client, NULL, "WiFiAddress", &wifi_node);
} else {
/* use existing pair record */
- userpref_read_pair_record(client->udid, &pair_record_plist);
- if (!pair_record_plist) {
- return LOCKDOWN_E_INVALID_HOST_ID;
+ userpref_error_t uerr = userpref_read_pair_record(client->device->udid, &pair_record_plist);
+ if (uerr == USERPREF_E_READ_ERROR) {
+ debug_info("ERROR: Failed to retrieve pair record for %s", client->device->udid);
+ return LOCKDOWN_E_RECEIVE_TIMEOUT;
+ } else if (uerr == USERPREF_E_NOENT) {
+ debug_info("ERROR: No pair record for %s", client->device->udid);
+ return LOCKDOWN_E_INVALID_CONF;
+ } else if (uerr != USERPREF_E_SUCCESS) {
+ debug_info("ERROR: Failed to retrieve or parse pair record for %s", client->device->udid);
+ return LOCKDOWN_E_INVALID_CONF;
}
}
}
@@ -959,7 +996,7 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_
debug_info("internal pairing mode");
if (!strcmp("Unpair", verb)) {
/* remove public key from config */
- userpref_delete_pair_record(client->udid);
+ userpref_delete_pair_record(client->device->udid);
} else {
if (!strcmp("Pair", verb)) {
/* add returned escrow bag if available */
@@ -977,7 +1014,7 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_
wifi_node = NULL;
}
- userpref_save_pair_record(client->udid, client->mux_id, pair_record_plist);
+ userpref_save_pair_record(client->device->udid, client->device->mux_id, pair_record_plist);
}
}
} else {
@@ -1019,7 +1056,7 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_
return ret;
}
-LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record)
+lockdownd_error_t lockdownd_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record)
{
plist_t options = plist_new_dict();
@@ -1032,22 +1069,22 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_pair(lockdownd_client_t client,
return ret;
}
-LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_pair_with_options(lockdownd_client_t client, lockdownd_pair_record_t pair_record, plist_t options, plist_t *response)
+lockdownd_error_t lockdownd_pair_with_options(lockdownd_client_t client, lockdownd_pair_record_t pair_record, plist_t options, plist_t *response)
{
return lockdownd_do_pair(client, pair_record, "Pair", options, response);
}
-LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_validate_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record)
+lockdownd_error_t lockdownd_validate_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record)
{
return lockdownd_do_pair(client, pair_record, "ValidatePair", NULL, NULL);
}
-LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_unpair(lockdownd_client_t client, lockdownd_pair_record_t pair_record)
+lockdownd_error_t lockdownd_unpair(lockdownd_client_t client, lockdownd_pair_record_t pair_record)
{
return lockdownd_do_pair(client, pair_record, "Unpair", NULL, NULL);
}
-LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_enter_recovery(lockdownd_client_t client)
+lockdownd_error_t lockdownd_enter_recovery(lockdownd_client_t client)
{
if (!client)
return LOCKDOWN_E_INVALID_ARG;
@@ -1077,7 +1114,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_enter_recovery(lockdownd_client
return ret;
}
-LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client)
+lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client)
{
if (!client)
return LOCKDOWN_E_INVALID_ARG;
@@ -1111,7 +1148,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_goodbye(lockdownd_client_t clie
return ret;
}
-LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_start_session(lockdownd_client_t client, const char *host_id, char **session_id, int *ssl_enabled)
+lockdownd_error_t lockdownd_start_session(lockdownd_client_t client, const char *host_id, char **session_id, int *ssl_enabled)
{
lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;
plist_t dict = NULL;
@@ -1226,9 +1263,17 @@ static lockdownd_error_t lockdownd_build_start_service_request(lockdownd_client_
if (send_escrow_bag) {
/* get the pairing record */
plist_t pair_record = NULL;
- userpref_read_pair_record(client->udid, &pair_record);
- if (!pair_record) {
- debug_info("ERROR: failed to read pair record for device: %s", client->udid);
+ userpref_error_t uerr = userpref_read_pair_record(client->device->udid, &pair_record);
+ if (uerr == USERPREF_E_READ_ERROR) {
+ debug_info("ERROR: Failed to retrieve pair record for %s", client->device->udid);
+ plist_free(dict);
+ return LOCKDOWN_E_RECEIVE_TIMEOUT;
+ } else if (uerr == USERPREF_E_NOENT) {
+ debug_info("ERROR: No pair record for %s", client->device->udid);
+ plist_free(dict);
+ return LOCKDOWN_E_INVALID_CONF;
+ } else if (uerr != USERPREF_E_SUCCESS) {
+ debug_info("ERROR: Failed to retrieve or parse pair record for %s", client->device->udid);
plist_free(dict);
return LOCKDOWN_E_INVALID_CONF;
}
@@ -1347,17 +1392,17 @@ static lockdownd_error_t lockdownd_do_start_service(lockdownd_client_t client, c
return ret;
}
-LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char *identifier, lockdownd_service_descriptor_t *service)
+lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char *identifier, lockdownd_service_descriptor_t *service)
{
return lockdownd_do_start_service(client, identifier, 0, service);
}
-LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_start_service_with_escrow_bag(lockdownd_client_t client, const char *identifier, lockdownd_service_descriptor_t *service)
+lockdownd_error_t lockdownd_start_service_with_escrow_bag(lockdownd_client_t client, const char *identifier, lockdownd_service_descriptor_t *service)
{
return lockdownd_do_start_service(client, identifier, 1, service);
}
-LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_activate(lockdownd_client_t client, plist_t activation_record)
+lockdownd_error_t lockdownd_activate(lockdownd_client_t client, plist_t activation_record)
{
if (!client)
return LOCKDOWN_E_INVALID_ARG;
@@ -1396,7 +1441,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_activate(lockdownd_client_t cli
return ret;
}
-LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_deactivate(lockdownd_client_t client)
+lockdownd_error_t lockdownd_deactivate(lockdownd_client_t client)
{
if (!client)
return LOCKDOWN_E_INVALID_ARG;
@@ -1443,7 +1488,7 @@ static void str_remove_spaces(char *source)
*dest = 0;
}
-LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_sync_data_classes(lockdownd_client_t client, char ***classes, int *count)
+lockdownd_error_t lockdownd_get_sync_data_classes(lockdownd_client_t client, char ***classes, int *count)
{
if (!client)
return LOCKDOWN_E_INVALID_ARG;
@@ -1498,7 +1543,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_sync_data_classes(lockdownd
return LOCKDOWN_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_data_classes_free(char **classes)
+lockdownd_error_t lockdownd_data_classes_free(char **classes)
{
if (classes) {
int i = 0;
@@ -1510,7 +1555,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_data_classes_free(char **classe
return LOCKDOWN_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_service_descriptor_free(lockdownd_service_descriptor_t service)
+lockdownd_error_t lockdownd_service_descriptor_free(lockdownd_service_descriptor_t service)
{
if (service) {
free(service->identifier);
@@ -1520,7 +1565,7 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_service_descriptor_free(lockdow
return LOCKDOWN_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API const char* lockdownd_strerror(lockdownd_error_t err)
+const char* lockdownd_strerror(lockdownd_error_t err)
{
switch (err) {
case LOCKDOWN_E_SUCCESS:
diff --git a/src/lockdown.h b/src/lockdown.h
index bf595df..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"
@@ -32,9 +33,12 @@ struct lockdownd_client_private {
property_list_service_client_t parent;
int ssl_enabled;
char *session_id;
- char *udid;
char *label;
- uint32_t mux_id;
+ idevice_t device;
+ unsigned char* cu_key;
+ unsigned int cu_key_len;
};
+lockdownd_error_t lockdown_check_result(plist_t dict, const char *query_match);
+
#endif
diff --git a/src/misagent.c b/src/misagent.c
index d790a05..e3da997 100644
--- a/src/misagent.c
+++ b/src/misagent.c
@@ -85,12 +85,11 @@ static misagent_error_t misagent_check_result(plist_t response, int* status_code
*status_code = (int)(val & 0xFFFFFFFF);
if (*status_code == 0) {
return MISAGENT_E_SUCCESS;
- } else {
- return MISAGENT_E_REQUEST_FAILED;
}
+ return MISAGENT_E_REQUEST_FAILED;
}
-LIBIMOBILEDEVICE_API misagent_error_t misagent_client_new(idevice_t device, lockdownd_service_descriptor_t service, misagent_client_t *client)
+misagent_error_t misagent_client_new(idevice_t device, lockdownd_service_descriptor_t service, misagent_client_t *client)
{
property_list_service_client_t plistclient = NULL;
misagent_error_t err = misagent_error(property_list_service_client_new(device, service, &plistclient));
@@ -106,14 +105,14 @@ LIBIMOBILEDEVICE_API misagent_error_t misagent_client_new(idevice_t device, lock
return MISAGENT_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API misagent_error_t misagent_client_start_service(idevice_t device, misagent_client_t * client, const char* label)
+misagent_error_t misagent_client_start_service(idevice_t device, misagent_client_t * client, const char* label)
{
misagent_error_t err = MISAGENT_E_UNKNOWN_ERROR;
service_client_factory_start_service(device, MISAGENT_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(misagent_client_new), &err);
return err;
}
-LIBIMOBILEDEVICE_API misagent_error_t misagent_client_free(misagent_client_t client)
+misagent_error_t misagent_client_free(misagent_client_t client)
{
if (!client)
return MISAGENT_E_INVALID_ARG;
@@ -128,7 +127,7 @@ LIBIMOBILEDEVICE_API misagent_error_t misagent_client_free(misagent_client_t cli
return err;
}
-LIBIMOBILEDEVICE_API misagent_error_t misagent_install(misagent_client_t client, plist_t profile)
+misagent_error_t misagent_install(misagent_client_t client, plist_t profile)
{
if (!client || !client->parent || !profile || (plist_get_node_type(profile) != PLIST_DATA))
return MISAGENT_E_INVALID_ARG;
@@ -165,7 +164,7 @@ LIBIMOBILEDEVICE_API misagent_error_t misagent_install(misagent_client_t client,
return res;
}
-LIBIMOBILEDEVICE_API misagent_error_t misagent_copy(misagent_client_t client, plist_t* profiles)
+misagent_error_t misagent_copy(misagent_client_t client, plist_t* profiles)
{
if (!client || !client->parent || !profiles)
return MISAGENT_E_INVALID_ARG;
@@ -205,7 +204,7 @@ LIBIMOBILEDEVICE_API misagent_error_t misagent_copy(misagent_client_t client, pl
}
-LIBIMOBILEDEVICE_API misagent_error_t misagent_copy_all(misagent_client_t client, plist_t* profiles)
+misagent_error_t misagent_copy_all(misagent_client_t client, plist_t* profiles)
{
if (!client || !client->parent || !profiles)
return MISAGENT_E_INVALID_ARG;
@@ -245,7 +244,7 @@ LIBIMOBILEDEVICE_API misagent_error_t misagent_copy_all(misagent_client_t client
}
-LIBIMOBILEDEVICE_API misagent_error_t misagent_remove(misagent_client_t client, const char* profileID)
+misagent_error_t misagent_remove(misagent_client_t client, const char* profileID)
{
if (!client || !client->parent || !profileID)
return MISAGENT_E_INVALID_ARG;
@@ -282,7 +281,7 @@ LIBIMOBILEDEVICE_API misagent_error_t misagent_remove(misagent_client_t client,
return res;
}
-LIBIMOBILEDEVICE_API int misagent_get_status_code(misagent_client_t client)
+int misagent_get_status_code(misagent_client_t client)
{
if (!client) {
return -1;
diff --git a/src/misagent.h b/src/misagent.h
index 08ad063..e394087 100644
--- a/src/misagent.h
+++ b/src/misagent.h
@@ -22,6 +22,7 @@
#ifndef __MISAGENT_H
#define __MISAGENT_H
+#include "idevice.h"
#include "libimobiledevice/misagent.h"
#include "property_list_service.h"
diff --git a/src/mobile_image_mounter.c b/src/mobile_image_mounter.c
index 9ccfd85..5df8e86 100644
--- a/src/mobile_image_mounter.c
+++ b/src/mobile_image_mounter.c
@@ -78,7 +78,7 @@ static mobile_image_mounter_error_t mobile_image_mounter_error(property_list_ser
return MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR;
}
-LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_new(idevice_t device, lockdownd_service_descriptor_t service, mobile_image_mounter_client_t *client)
+mobile_image_mounter_error_t mobile_image_mounter_new(idevice_t device, lockdownd_service_descriptor_t service, mobile_image_mounter_client_t *client)
{
property_list_service_client_t plistclient = NULL;
mobile_image_mounter_error_t err = mobile_image_mounter_error(property_list_service_client_new(device, service, &plistclient));
@@ -95,14 +95,14 @@ LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_new(idevi
return MOBILE_IMAGE_MOUNTER_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_start_service(idevice_t device, mobile_image_mounter_client_t * client, const char* label)
+mobile_image_mounter_error_t mobile_image_mounter_start_service(idevice_t device, mobile_image_mounter_client_t * client, const char* label)
{
mobile_image_mounter_error_t err = MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR;
service_client_factory_start_service(device, MOBILE_IMAGE_MOUNTER_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(mobile_image_mounter_new), &err);
return err;
}
-LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_free(mobile_image_mounter_client_t client)
+mobile_image_mounter_error_t mobile_image_mounter_free(mobile_image_mounter_client_t client)
{
if (!client)
return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG;
@@ -115,7 +115,7 @@ LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_free(mobi
return MOBILE_IMAGE_MOUNTER_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_lookup_image(mobile_image_mounter_client_t client, const char *image_type, plist_t *result)
+mobile_image_mounter_error_t mobile_image_mounter_lookup_image(mobile_image_mounter_client_t client, const char *image_type, plist_t *result)
{
if (!client || !image_type || !result) {
return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG;
@@ -181,7 +181,7 @@ static mobile_image_mounter_error_t process_result(plist_t result, const char *e
return res;
}
-LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_upload_image(mobile_image_mounter_client_t client, const char *image_type, size_t image_size, const char *signature, uint16_t signature_size, mobile_image_mounter_upload_cb_t upload_cb, void* userdata)
+mobile_image_mounter_error_t mobile_image_mounter_upload_image(mobile_image_mounter_client_t client, const char *image_type, size_t image_size, const char *signature, uint16_t signature_size, mobile_image_mounter_upload_cb_t upload_cb, void* userdata)
{
if (!client || !image_type || (image_size == 0) || !upload_cb) {
return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG;
@@ -260,7 +260,7 @@ leave_unlock:
}
-LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_mount_image(mobile_image_mounter_client_t client, const char *image_path, const char *signature, uint16_t signature_size, const char *image_type, plist_t *result)
+mobile_image_mounter_error_t mobile_image_mounter_mount_image(mobile_image_mounter_client_t client, const char *image_path, const char *signature, uint16_t signature_size, const char *image_type, plist_t *result)
{
if (!client || !image_path || !image_type || !result) {
return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG;
@@ -292,7 +292,7 @@ leave_unlock:
return res;
}
-LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_hangup(mobile_image_mounter_client_t client)
+mobile_image_mounter_error_t mobile_image_mounter_hangup(mobile_image_mounter_client_t client)
{
if (!client) {
return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG;
diff --git a/src/mobile_image_mounter.h b/src/mobile_image_mounter.h
index e9754e4..9a8fcdd 100644
--- a/src/mobile_image_mounter.h
+++ b/src/mobile_image_mounter.h
@@ -22,9 +22,10 @@
#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 "common/thread.h"
+#include <libimobiledevice-glue/thread.h>
struct mobile_image_mounter_client_private {
property_list_service_client_t parent;
diff --git a/src/mobileactivation.c b/src/mobileactivation.c
index 2de4333..fce5f16 100644
--- a/src/mobileactivation.c
+++ b/src/mobileactivation.c
@@ -54,7 +54,7 @@ static mobileactivation_error_t mobileactivation_error(property_list_service_err
return MOBILEACTIVATION_E_UNKNOWN_ERROR;
}
-LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobileactivation_client_t *client)
+mobileactivation_error_t mobileactivation_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobileactivation_client_t *client)
{
if (!device || !service || service->port == 0 || !client || *client) {
return MOBILEACTIVATION_E_INVALID_ARG;
@@ -74,14 +74,14 @@ LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_client_new(idevic
return MOBILEACTIVATION_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_client_start_service(idevice_t device, mobileactivation_client_t * client, const char* label)
+mobileactivation_error_t mobileactivation_client_start_service(idevice_t device, mobileactivation_client_t * client, const char* label)
{
mobileactivation_error_t err = MOBILEACTIVATION_E_UNKNOWN_ERROR;
service_client_factory_start_service(device, MOBILEACTIVATION_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(mobileactivation_client_new), &err);
return err;
}
-LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_client_free(mobileactivation_client_t client)
+mobileactivation_error_t mobileactivation_client_free(mobileactivation_client_t client)
{
if (!client)
return MOBILEACTIVATION_E_INVALID_ARG;
@@ -109,8 +109,6 @@ static plist_t plist_data_from_plist(plist_t plist)
static mobileactivation_error_t mobileactivation_check_result(plist_t dict, const char *command)
{
- mobileactivation_error_t ret = MOBILEACTIVATION_E_UNKNOWN_ERROR;
-
if (!dict || plist_get_node_type(dict) != PLIST_DICT) {
return MOBILEACTIVATION_E_PLIST_ERROR;
}
@@ -118,14 +116,13 @@ static mobileactivation_error_t mobileactivation_check_result(plist_t dict, cons
plist_t err_node = plist_dict_get_item(dict, "Error");
if (!err_node) {
return MOBILEACTIVATION_E_SUCCESS;
- } else {
- char *errmsg = NULL;
- plist_get_string_val(err_node, &errmsg);
- debug_info("ERROR: %s: %s", command, errmsg);
- ret = MOBILEACTIVATION_E_REQUEST_FAILED;
- free(errmsg);
}
- return ret;
+
+ char *errmsg = NULL;
+ plist_get_string_val(err_node, &errmsg);
+ debug_info("ERROR: %s: %s", command, errmsg);
+ free(errmsg);
+ return MOBILEACTIVATION_E_REQUEST_FAILED;
}
static mobileactivation_error_t mobileactivation_send_command_plist(mobileactivation_client_t client, plist_t command, plist_t *result)
@@ -179,7 +176,7 @@ static mobileactivation_error_t mobileactivation_send_command(mobileactivation_c
return ret;
}
-LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_get_activation_state(mobileactivation_client_t client, plist_t *state)
+mobileactivation_error_t mobileactivation_get_activation_state(mobileactivation_client_t client, plist_t *state)
{
if (!client || !state)
return MOBILEACTIVATION_E_INVALID_ARG;
@@ -201,7 +198,7 @@ LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_get_activation_st
return ret;
}
-LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_create_activation_session_info(mobileactivation_client_t client, plist_t *blob)
+mobileactivation_error_t mobileactivation_create_activation_session_info(mobileactivation_client_t client, plist_t *blob)
{
if (!client || !blob)
return MOBILEACTIVATION_E_INVALID_ARG;
@@ -221,7 +218,7 @@ LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_create_activation
return ret;
}
-LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_create_activation_info(mobileactivation_client_t client, plist_t *info)
+mobileactivation_error_t mobileactivation_create_activation_info(mobileactivation_client_t client, plist_t *info)
{
if (!client || !info)
return MOBILEACTIVATION_E_INVALID_ARG;
@@ -243,7 +240,7 @@ LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_create_activation
return ret;
}
-LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_create_activation_info_with_session(mobileactivation_client_t client, plist_t handshake_response, plist_t *info)
+mobileactivation_error_t mobileactivation_create_activation_info_with_session(mobileactivation_client_t client, plist_t handshake_response, plist_t *info)
{
if (!client || !info)
return MOBILEACTIVATION_E_INVALID_ARG;
@@ -267,7 +264,7 @@ LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_create_activation
return ret;
}
-LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_activate(mobileactivation_client_t client, plist_t activation_record)
+mobileactivation_error_t mobileactivation_activate(mobileactivation_client_t client, plist_t activation_record)
{
if (!client || !activation_record)
return MOBILEACTIVATION_E_INVALID_ARG;
@@ -280,7 +277,7 @@ LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_activate(mobileac
return ret;
}
-LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_activate_with_session(mobileactivation_client_t client, plist_t activation_record, plist_t headers)
+mobileactivation_error_t mobileactivation_activate_with_session(mobileactivation_client_t client, plist_t activation_record, plist_t headers)
{
if (!client || !activation_record)
return MOBILEACTIVATION_E_INVALID_ARG;
@@ -303,7 +300,7 @@ LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_activate_with_ses
}
-LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_deactivate(mobileactivation_client_t client)
+mobileactivation_error_t mobileactivation_deactivate(mobileactivation_client_t client)
{
if (!client)
return MOBILEACTIVATION_E_INVALID_ARG;
diff --git a/src/mobileactivation.h b/src/mobileactivation.h
index 49b9ebc..a8dff5d 100644
--- a/src/mobileactivation.h
+++ b/src/mobileactivation.h
@@ -22,6 +22,7 @@
#ifndef __MOBILEACTIVATION_H
#define __MOBILEACTIVATION_H
+#include "idevice.h"
#include "libimobiledevice/mobileactivation.h"
#include "property_list_service.h"
diff --git a/src/mobilebackup.c b/src/mobilebackup.c
index cde96b5..36986a4 100644
--- a/src/mobilebackup.c
+++ b/src/mobilebackup.c
@@ -26,6 +26,7 @@
#include <plist/plist.h>
#include <string.h>
#include <stdlib.h>
+#include <stdio.h>
#include "mobilebackup.h"
#include "device_link_service.h"
@@ -34,7 +35,7 @@
#define MBACKUP_VERSION_INT1 100
#define MBACKUP_VERSION_INT2 0
-#define IS_FLAG_SET(x, y) ((x & y) == y)
+#define IS_FLAG_SET(x, y) (((x) & (y)) == (y))
/**
* Convert an device_link_service_error_t value to an mobilebackup_error_t value.
@@ -68,7 +69,7 @@ static mobilebackup_error_t mobilebackup_error(device_link_service_error_t err)
return MOBILEBACKUP_E_UNKNOWN_ERROR;
}
-LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobilebackup_client_t * client)
+mobilebackup_error_t mobilebackup_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobilebackup_client_t * client)
{
if (!device || !service || service->port == 0 || !client || *client)
return MOBILEBACKUP_E_INVALID_ARG;
@@ -95,14 +96,14 @@ LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_client_new(idevice_t devi
return ret;
}
-LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_client_start_service(idevice_t device, mobilebackup_client_t * client, const char* label)
+mobilebackup_error_t mobilebackup_client_start_service(idevice_t device, mobilebackup_client_t * client, const char* label)
{
mobilebackup_error_t err = MOBILEBACKUP_E_UNKNOWN_ERROR;
service_client_factory_start_service(device, MOBILEBACKUP_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(mobilebackup_client_new), &err);
return err;
}
-LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_client_free(mobilebackup_client_t client)
+mobilebackup_error_t mobilebackup_client_free(mobilebackup_client_t client)
{
if (!client)
return MOBILEBACKUP_E_INVALID_ARG;
@@ -115,7 +116,7 @@ LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_client_free(mobilebackup_
return err;
}
-LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_receive(mobilebackup_client_t client, plist_t * plist)
+mobilebackup_error_t mobilebackup_receive(mobilebackup_client_t client, plist_t * plist)
{
if (!client)
return MOBILEBACKUP_E_INVALID_ARG;
@@ -123,7 +124,7 @@ LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_receive(mobilebackup_clie
return ret;
}
-LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_send(mobilebackup_client_t client, plist_t plist)
+mobilebackup_error_t mobilebackup_send(mobilebackup_client_t client, plist_t plist)
{
if (!client || !plist)
return MOBILEBACKUP_E_INVALID_ARG;
@@ -240,7 +241,7 @@ leave:
return err;
}
-LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_request_backup(mobilebackup_client_t client, plist_t backup_manifest, const char *base_path, const char *proto_version)
+mobilebackup_error_t mobilebackup_request_backup(mobilebackup_client_t client, plist_t backup_manifest, const char *base_path, const char *proto_version)
{
if (!client || !client->parent || !base_path || !proto_version)
return MOBILEBACKUP_E_INVALID_ARG;
@@ -279,7 +280,15 @@ LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_request_backup(mobileback
char *str = NULL;
plist_get_string_val(node, &str);
if (str) {
- if (strcmp(str, proto_version) != 0) {
+ int maj = 0;
+ int min = 0;
+ sscanf(str, "%u.%u", &maj, &min);
+ uint32_t this_ver = ((maj & 0xFF) << 8) | (min & 0xFF);
+ maj = 0;
+ min = 0;
+ sscanf(proto_version, "%u.%u", &maj, &min);
+ uint32_t proto_ver = ((maj & 0xFF) << 8) | (min & 0xFF);
+ if (this_ver > proto_ver) {
err = MOBILEBACKUP_E_BAD_VERSION;
}
free(str);
@@ -300,12 +309,12 @@ leave:
return err;
}
-LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_send_backup_file_received(mobilebackup_client_t client)
+mobilebackup_error_t mobilebackup_send_backup_file_received(mobilebackup_client_t client)
{
return mobilebackup_send_message(client, "kBackupMessageBackupFileReceived", NULL);
}
-LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_request_restore(mobilebackup_client_t client, plist_t backup_manifest, mobilebackup_flags_t flags, const char *proto_version)
+mobilebackup_error_t mobilebackup_request_restore(mobilebackup_client_t client, plist_t backup_manifest, mobilebackup_flags_t flags, const char *proto_version)
{
if (!client || !client->parent || !backup_manifest || !proto_version)
return MOBILEBACKUP_E_INVALID_ARG;
@@ -346,7 +355,15 @@ LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_request_restore(mobilebac
char *str = NULL;
plist_get_string_val(node, &str);
if (str) {
- if (strcmp(str, proto_version) != 0) {
+ int maj = 0;
+ int min = 0;
+ sscanf(str, "%u.%u", &maj, &min);
+ uint32_t this_ver = ((maj & 0xFF) << 8) | (min & 0xFF);
+ maj = 0;
+ min = 0;
+ sscanf(proto_version, "%u.%u", &maj, &min);
+ uint32_t proto_ver = ((maj & 0xFF) << 8) | (min & 0xFF);
+ if (this_ver > proto_ver) {
err = MOBILEBACKUP_E_BAD_VERSION;
}
free(str);
@@ -359,17 +376,17 @@ leave:
return err;
}
-LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_receive_restore_file_received(mobilebackup_client_t client, plist_t *result)
+mobilebackup_error_t mobilebackup_receive_restore_file_received(mobilebackup_client_t client, plist_t *result)
{
return mobilebackup_receive_message(client, "BackupMessageRestoreFileReceived", result);
}
-LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_receive_restore_application_received(mobilebackup_client_t client, plist_t *result)
+mobilebackup_error_t mobilebackup_receive_restore_application_received(mobilebackup_client_t client, plist_t *result)
{
return mobilebackup_receive_message(client, "BackupMessageRestoreApplicationReceived", result);
}
-LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_send_restore_complete(mobilebackup_client_t client)
+mobilebackup_error_t mobilebackup_send_restore_complete(mobilebackup_client_t client)
{
mobilebackup_error_t err = mobilebackup_send_message(client, "BackupMessageRestoreComplete", NULL);
if (err != MOBILEBACKUP_E_SUCCESS) {
@@ -414,7 +431,7 @@ LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_send_restore_complete(mob
return err;
}
-LIBIMOBILEDEVICE_API mobilebackup_error_t mobilebackup_send_error(mobilebackup_client_t client, const char *reason)
+mobilebackup_error_t mobilebackup_send_error(mobilebackup_client_t client, const char *reason)
{
if (!client || !client->parent || !reason)
return MOBILEBACKUP_E_INVALID_ARG;
diff --git a/src/mobilebackup.h b/src/mobilebackup.h
index edda70f..04ec479 100644
--- a/src/mobilebackup.h
+++ b/src/mobilebackup.h
@@ -23,6 +23,7 @@
#ifndef __MOBILEBACKUP_H
#define __MOBILEBACKUP_H
+#include "idevice.h"
#include "libimobiledevice/mobilebackup.h"
#include "device_link_service.h"
diff --git a/src/mobilebackup2.c b/src/mobilebackup2.c
index 6c6556d..a8d673f 100644
--- a/src/mobilebackup2.c
+++ b/src/mobilebackup2.c
@@ -33,7 +33,7 @@
#define MBACKUP2_VERSION_INT1 400
#define MBACKUP2_VERSION_INT2 0
-#define IS_FLAG_SET(x, y) ((x & y) == y)
+#define IS_FLAG_SET(x, y) (((x) & (y)) == (y))
/**
* Convert an device_link_service_error_t value to an mobilebackup2_error_t value.
@@ -68,7 +68,7 @@ static mobilebackup2_error_t mobilebackup2_error(device_link_service_error_t err
return MOBILEBACKUP2_E_UNKNOWN_ERROR;
}
-LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_client_new(idevice_t device, lockdownd_service_descriptor_t service,
+mobilebackup2_error_t mobilebackup2_client_new(idevice_t device, lockdownd_service_descriptor_t service,
mobilebackup2_client_t * client)
{
if (!device || !service || service->port == 0 || !client || *client)
@@ -96,14 +96,14 @@ LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_client_new(idevice_t de
return ret;
}
-LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_client_start_service(idevice_t device, mobilebackup2_client_t * client, const char* label)
+mobilebackup2_error_t mobilebackup2_client_start_service(idevice_t device, mobilebackup2_client_t * client, const char* label)
{
mobilebackup2_error_t err = MOBILEBACKUP2_E_UNKNOWN_ERROR;
service_client_factory_start_service(device, MOBILEBACKUP2_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(mobilebackup2_client_new), &err);
return err;
}
-LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_client_free(mobilebackup2_client_t client)
+mobilebackup2_error_t mobilebackup2_client_free(mobilebackup2_client_t client)
{
if (!client)
return MOBILEBACKUP2_E_INVALID_ARG;
@@ -116,7 +116,7 @@ LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_client_free(mobilebacku
return err;
}
-LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_send_message(mobilebackup2_client_t client, const char *message, plist_t options)
+mobilebackup2_error_t mobilebackup2_send_message(mobilebackup2_client_t client, const char *message, plist_t options)
{
if (!client || !client->parent || (!message && !options))
return MOBILEBACKUP2_E_INVALID_ARG;
@@ -214,12 +214,12 @@ leave:
return err;
}
-LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_receive_message(mobilebackup2_client_t client, plist_t *msg_plist, char **dlmessage)
+mobilebackup2_error_t mobilebackup2_receive_message(mobilebackup2_client_t client, plist_t *msg_plist, char **dlmessage)
{
return mobilebackup2_error(device_link_service_receive_message(client->parent, msg_plist, dlmessage));
}
-LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_send_raw(mobilebackup2_client_t client, const char *data, uint32_t length, uint32_t *bytes)
+mobilebackup2_error_t mobilebackup2_send_raw(mobilebackup2_client_t client, const char *data, uint32_t length, uint32_t *bytes)
{
if (!client || !client->parent || !data || (length == 0) || !bytes)
return MOBILEBACKUP2_E_INVALID_ARG;
@@ -240,12 +240,11 @@ LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_send_raw(mobilebackup2_
if (sent > 0) {
*bytes = sent;
return MOBILEBACKUP2_E_SUCCESS;
- } else {
- return MOBILEBACKUP2_E_MUX_ERROR;
}
+ return MOBILEBACKUP2_E_MUX_ERROR;
}
-LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_receive_raw(mobilebackup2_client_t client, char *data, uint32_t length, uint32_t *bytes)
+mobilebackup2_error_t mobilebackup2_receive_raw(mobilebackup2_client_t client, char *data, uint32_t length, uint32_t *bytes)
{
if (!client || !client->parent || !data || (length == 0) || !bytes)
return MOBILEBACKUP2_E_INVALID_ARG;
@@ -265,14 +264,14 @@ LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_receive_raw(mobilebacku
if (received > 0) {
*bytes = received;
return MOBILEBACKUP2_E_SUCCESS;
- } else if (received == 0) {
+ }
+ if (received == 0) {
return MOBILEBACKUP2_E_SUCCESS;
- } else {
- return MOBILEBACKUP2_E_MUX_ERROR;
}
+ return MOBILEBACKUP2_E_MUX_ERROR;
}
-LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_version_exchange(mobilebackup2_client_t client, double local_versions[], char count, double *remote_version)
+mobilebackup2_error_t mobilebackup2_version_exchange(mobilebackup2_client_t client, double local_versions[], char count, double *remote_version)
{
int i;
@@ -330,7 +329,7 @@ leave:
return err;
}
-LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_send_request(mobilebackup2_client_t client, const char *request, const char *target_identifier, const char *source_identifier, plist_t options)
+mobilebackup2_error_t mobilebackup2_send_request(mobilebackup2_client_t client, const char *request, const char *target_identifier, const char *source_identifier, plist_t options)
{
if (!client || !client->parent || !request || !target_identifier)
return MOBILEBACKUP2_E_INVALID_ARG;
@@ -361,7 +360,7 @@ LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_send_request(mobileback
return err;
}
-LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_send_status_response(mobilebackup2_client_t client, int status_code, const char *status1, plist_t status2)
+mobilebackup2_error_t mobilebackup2_send_status_response(mobilebackup2_client_t client, int status_code, const char *status1, plist_t status2)
{
if (!client || !client->parent)
return MOBILEBACKUP2_E_INVALID_ARG;
diff --git a/src/mobilebackup2.h b/src/mobilebackup2.h
index 025b6bf..e232b97 100644
--- a/src/mobilebackup2.h
+++ b/src/mobilebackup2.h
@@ -22,6 +22,7 @@
#ifndef __MOBILEBACKUP2_H
#define __MOBILEBACKUP2_H
+#include "idevice.h"
#include "libimobiledevice/mobilebackup2.h"
#include "device_link_service.h"
diff --git a/src/mobilesync.c b/src/mobilesync.c
index 163a41e..9b81a49 100644
--- a/src/mobilesync.c
+++ b/src/mobilesync.c
@@ -34,7 +34,7 @@
#include "device_link_service.h"
#include "common/debug.h"
-#define MSYNC_VERSION_INT1 300
+#define MSYNC_VERSION_INT1 400
#define MSYNC_VERSION_INT2 100
#define EMPTY_PARAMETER_STRING "___EmptyParameterString___"
@@ -71,7 +71,7 @@ static mobilesync_error_t mobilesync_error(device_link_service_error_t err)
return MOBILESYNC_E_UNKNOWN_ERROR;
}
-LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_client_new(idevice_t device, lockdownd_service_descriptor_t service,
+mobilesync_error_t mobilesync_client_new(idevice_t device, lockdownd_service_descriptor_t service,
mobilesync_client_t * client)
{
if (!device || !service || service->port == 0 || !client || *client)
@@ -101,14 +101,14 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_client_new(idevice_t device,
return ret;
}
-LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_client_start_service(idevice_t device, mobilesync_client_t * client, const char* label)
+mobilesync_error_t mobilesync_client_start_service(idevice_t device, mobilesync_client_t * client, const char* label)
{
mobilesync_error_t err = MOBILESYNC_E_UNKNOWN_ERROR;
service_client_factory_start_service(device, MOBILESYNC_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(mobilesync_client_new), &err);
return err;
}
-LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_client_free(mobilesync_client_t client)
+mobilesync_error_t mobilesync_client_free(mobilesync_client_t client)
{
if (!client)
return MOBILESYNC_E_INVALID_ARG;
@@ -118,7 +118,7 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_client_free(mobilesync_client
return err;
}
-LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_receive(mobilesync_client_t client, plist_t * plist)
+mobilesync_error_t mobilesync_receive(mobilesync_client_t client, plist_t * plist)
{
if (!client)
return MOBILESYNC_E_INVALID_ARG;
@@ -126,14 +126,14 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_receive(mobilesync_client_t c
return ret;
}
-LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_send(mobilesync_client_t client, plist_t plist)
+mobilesync_error_t mobilesync_send(mobilesync_client_t client, plist_t plist)
{
if (!client || !plist)
return MOBILESYNC_E_INVALID_ARG;
return mobilesync_error(device_link_service_send(client->parent, plist));
}
-LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_start(mobilesync_client_t client, const char *data_class, mobilesync_anchors_t anchors, uint64_t computer_data_class_version, mobilesync_sync_type_t *sync_type, uint64_t *device_data_class_version, char** error_description)
+mobilesync_error_t mobilesync_start(mobilesync_client_t client, const char *data_class, mobilesync_anchors_t anchors, uint64_t computer_data_class_version, mobilesync_sync_type_t *sync_type, uint64_t *device_data_class_version, char** error_description)
{
if (!client || client->data_class || !data_class ||
!anchors || !anchors->computer_anchor) {
@@ -259,7 +259,7 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_start(mobilesync_client_t cli
return err;
}
-LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_finish(mobilesync_client_t client)
+mobilesync_error_t mobilesync_finish(mobilesync_client_t client)
{
if (!client || !client->data_class) {
return MOBILESYNC_E_INVALID_ARG;
@@ -344,17 +344,17 @@ static mobilesync_error_t mobilesync_get_records(mobilesync_client_t client, con
return err;
}
-LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_get_all_records_from_device(mobilesync_client_t client)
+mobilesync_error_t mobilesync_get_all_records_from_device(mobilesync_client_t client)
{
return mobilesync_get_records(client, "SDMessageGetAllRecordsFromDevice");
}
-LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_get_changes_from_device(mobilesync_client_t client)
+mobilesync_error_t mobilesync_get_changes_from_device(mobilesync_client_t client)
{
return mobilesync_get_records(client, "SDMessageGetChangesFromDevice");
}
-LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_receive_changes(mobilesync_client_t client, plist_t *entities, uint8_t *is_last_record, plist_t *actions)
+mobilesync_error_t mobilesync_receive_changes(mobilesync_client_t client, plist_t *entities, uint8_t *is_last_record, plist_t *actions)
{
if (!client || !client->data_class) {
return MOBILESYNC_E_INVALID_ARG;
@@ -421,7 +421,7 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_receive_changes(mobilesync_cl
return err;
}
-LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_clear_all_records_on_device(mobilesync_client_t client)
+mobilesync_error_t mobilesync_clear_all_records_on_device(mobilesync_client_t client)
{
if (!client || !client->data_class) {
return MOBILESYNC_E_INVALID_ARG;
@@ -473,7 +473,7 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_clear_all_records_on_device(m
goto out;
}
- if (strcmp(response_type, "SDMessageDeviceWillClearAllRecords")) {
+ if (strcmp(response_type, "SDMessageDeviceWillClearAllRecords") != 0) {
err = MOBILESYNC_E_PLIST_ERROR;
}
@@ -490,7 +490,7 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_clear_all_records_on_device(m
return err;
}
-LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_acknowledge_changes_from_device(mobilesync_client_t client)
+mobilesync_error_t mobilesync_acknowledge_changes_from_device(mobilesync_client_t client)
{
if (!client || !client->data_class) {
return MOBILESYNC_E_INVALID_ARG;
@@ -524,7 +524,7 @@ static plist_t create_process_changes_message(const char *data_class, plist_t en
return msg;
}
-LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_ready_to_send_changes_from_computer(mobilesync_client_t client)
+mobilesync_error_t mobilesync_ready_to_send_changes_from_computer(mobilesync_client_t client)
{
if (!client || !client->data_class) {
return MOBILESYNC_E_INVALID_ARG;
@@ -591,7 +591,7 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_ready_to_send_changes_from_co
return err;
}
-LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_send_changes(mobilesync_client_t client, plist_t entities, uint8_t is_last_record, plist_t actions)
+mobilesync_error_t mobilesync_send_changes(mobilesync_client_t client, plist_t entities, uint8_t is_last_record, plist_t actions)
{
if (!client || !client->data_class || !entities) {
return MOBILESYNC_E_INVALID_ARG;
@@ -619,7 +619,7 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_send_changes(mobilesync_clien
return err;
}
-LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_remap_identifiers(mobilesync_client_t client, plist_t *mapping)
+mobilesync_error_t mobilesync_remap_identifiers(mobilesync_client_t client, plist_t *mapping)
{
if (!client || !client->data_class) {
return MOBILESYNC_E_INVALID_ARG;
@@ -688,7 +688,7 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_remap_identifiers(mobilesync_
return err;
}
-LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_cancel(mobilesync_client_t client, const char* reason)
+mobilesync_error_t mobilesync_cancel(mobilesync_client_t client, const char* reason)
{
if (!client || !client->data_class || !reason) {
return MOBILESYNC_E_INVALID_ARG;
@@ -714,7 +714,7 @@ LIBIMOBILEDEVICE_API mobilesync_error_t mobilesync_cancel(mobilesync_client_t cl
return err;
}
-LIBIMOBILEDEVICE_API mobilesync_anchors_t mobilesync_anchors_new(const char *device_anchor, const char *computer_anchor)
+mobilesync_anchors_t mobilesync_anchors_new(const char *device_anchor, const char *computer_anchor)
{
mobilesync_anchors_t anchors = (mobilesync_anchors_t) malloc(sizeof(mobilesync_anchors));
if (device_anchor != NULL) {
@@ -731,7 +731,7 @@ LIBIMOBILEDEVICE_API mobilesync_anchors_t mobilesync_anchors_new(const char *dev
return anchors;
}
-LIBIMOBILEDEVICE_API void mobilesync_anchors_free(mobilesync_anchors_t anchors)
+void mobilesync_anchors_free(mobilesync_anchors_t anchors)
{
if (anchors->device_anchor != NULL) {
free(anchors->device_anchor);
@@ -745,12 +745,12 @@ LIBIMOBILEDEVICE_API void mobilesync_anchors_free(mobilesync_anchors_t anchors)
anchors = NULL;
}
-LIBIMOBILEDEVICE_API plist_t mobilesync_actions_new(void)
+plist_t mobilesync_actions_new(void)
{
return plist_new_dict();
}
-LIBIMOBILEDEVICE_API void mobilesync_actions_add(plist_t actions, ...)
+void mobilesync_actions_add(plist_t actions, ...)
{
if (!actions)
return;
@@ -782,7 +782,7 @@ LIBIMOBILEDEVICE_API void mobilesync_actions_add(plist_t actions, ...)
va_end(args);
}
-LIBIMOBILEDEVICE_API void mobilesync_actions_free(plist_t actions)
+void mobilesync_actions_free(plist_t actions)
{
if (actions) {
plist_free(actions);
diff --git a/src/mobilesync.h b/src/mobilesync.h
index f672252..3b5ece9 100644
--- a/src/mobilesync.h
+++ b/src/mobilesync.h
@@ -23,6 +23,7 @@
#ifndef __MOBILESYNC_H
#define __MOBILESYNC_H
+#include "idevice.h"
#include "libimobiledevice/mobilesync.h"
#include "device_link_service.h"
diff --git a/src/notification_proxy.c b/src/notification_proxy.c
index e17e2fe..60b2e03 100644
--- a/src/notification_proxy.c
+++ b/src/notification_proxy.c
@@ -89,7 +89,7 @@ static np_error_t np_error(property_list_service_error_t err)
return NP_E_UNKNOWN_ERROR;
}
-LIBIMOBILEDEVICE_API np_error_t np_client_new(idevice_t device, lockdownd_service_descriptor_t service, np_client_t *client)
+np_error_t np_client_new(idevice_t device, lockdownd_service_descriptor_t service, np_client_t *client)
{
property_list_service_client_t plistclient = NULL;
np_error_t err = np_error(property_list_service_client_new(device, service, &plistclient));
@@ -107,14 +107,14 @@ LIBIMOBILEDEVICE_API np_error_t np_client_new(idevice_t device, lockdownd_servic
return NP_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API np_error_t np_client_start_service(idevice_t device, np_client_t* client, const char* label)
+np_error_t np_client_start_service(idevice_t device, np_client_t* client, const char* label)
{
np_error_t err = NP_E_UNKNOWN_ERROR;
service_client_factory_start_service(device, NP_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(np_client_new), &err);
return err;
}
-LIBIMOBILEDEVICE_API np_error_t np_client_free(np_client_t client)
+np_error_t np_client_free(np_client_t client)
{
plist_t dict;
property_list_service_client_t parent;
@@ -168,7 +168,7 @@ LIBIMOBILEDEVICE_API np_error_t np_client_free(np_client_t client)
return NP_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API np_error_t np_post_notification(np_client_t client, const char *notification)
+np_error_t np_post_notification(np_client_t client, const char *notification)
{
if (!client || !notification) {
return NP_E_INVALID_ARG;
@@ -204,7 +204,7 @@ static np_error_t internal_np_observe_notification(np_client_t client, const cha
return res;
}
-LIBIMOBILEDEVICE_API np_error_t np_observe_notification( np_client_t client, const char *notification )
+np_error_t np_observe_notification( np_client_t client, const char *notification )
{
if (!client || !notification) {
return NP_E_INVALID_ARG;
@@ -215,7 +215,7 @@ LIBIMOBILEDEVICE_API np_error_t np_observe_notification( np_client_t client, con
return res;
}
-LIBIMOBILEDEVICE_API np_error_t np_observe_notifications(np_client_t client, const char **notification_spec)
+np_error_t np_observe_notifications(np_client_t client, const char **notification_spec)
{
int i = 0;
np_error_t res = NP_E_UNKNOWN_ERROR;
@@ -346,7 +346,7 @@ void* np_notifier( void* arg )
return NULL;
}
-LIBIMOBILEDEVICE_API np_error_t np_set_notify_callback( np_client_t client, np_notify_cb_t notify_cb, void *user_data )
+np_error_t np_set_notify_callback( np_client_t client, np_notify_cb_t notify_cb, void *user_data )
{
if (!client)
return NP_E_INVALID_ARG;
diff --git a/src/notification_proxy.h b/src/notification_proxy.h
index f641e25..595cb01 100644
--- a/src/notification_proxy.h
+++ b/src/notification_proxy.h
@@ -22,9 +22,10 @@
#ifndef __NOTIFICATION_PROXY_H
#define __NOTIFICATION_PROXY_H
+#include "idevice.h"
#include "libimobiledevice/notification_proxy.h"
#include "property_list_service.h"
-#include "common/thread.h"
+#include <libimobiledevice-glue/thread.h>
struct np_client_private {
property_list_service_client_t parent;
diff --git a/src/preboard.c b/src/preboard.c
index b975f0e..c3eff02 100644
--- a/src/preboard.c
+++ b/src/preboard.c
@@ -62,7 +62,7 @@ static preboard_error_t preboard_error(property_list_service_error_t err)
return PREBOARD_E_UNKNOWN_ERROR;
}
-LIBIMOBILEDEVICE_API preboard_error_t preboard_client_new(idevice_t device, lockdownd_service_descriptor_t service, preboard_client_t * client)
+preboard_error_t preboard_client_new(idevice_t device, lockdownd_service_descriptor_t service, preboard_client_t * client)
{
*client = NULL;
@@ -90,14 +90,14 @@ LIBIMOBILEDEVICE_API preboard_error_t preboard_client_new(idevice_t device, lock
return 0;
}
-LIBIMOBILEDEVICE_API preboard_error_t preboard_client_start_service(idevice_t device, preboard_client_t * client, const char* label)
+preboard_error_t preboard_client_start_service(idevice_t device, preboard_client_t * client, const char* label)
{
preboard_error_t err = PREBOARD_E_UNKNOWN_ERROR;
service_client_factory_start_service(device, PREBOARD_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(preboard_client_new), &err);
return err;
}
-LIBIMOBILEDEVICE_API preboard_error_t preboard_client_free(preboard_client_t client)
+preboard_error_t preboard_client_free(preboard_client_t client)
{
if (!client)
return PREBOARD_E_INVALID_ARG;
@@ -116,7 +116,7 @@ LIBIMOBILEDEVICE_API preboard_error_t preboard_client_free(preboard_client_t cli
return err;
}
-LIBIMOBILEDEVICE_API preboard_error_t preboard_send(preboard_client_t client, plist_t plist)
+preboard_error_t preboard_send(preboard_client_t client, plist_t plist)
{
preboard_error_t res = PREBOARD_E_UNKNOWN_ERROR;
res = preboard_error(property_list_service_send_binary_plist(client->parent, plist));
@@ -127,7 +127,7 @@ LIBIMOBILEDEVICE_API preboard_error_t preboard_send(preboard_client_t client, pl
return res;
}
-LIBIMOBILEDEVICE_API preboard_error_t preboard_receive_with_timeout(preboard_client_t client, plist_t * plist, uint32_t timeout_ms)
+preboard_error_t preboard_receive_with_timeout(preboard_client_t client, plist_t * plist, uint32_t timeout_ms)
{
preboard_error_t res = PREBOARD_E_UNKNOWN_ERROR;
plist_t outplist = NULL;
@@ -141,7 +141,7 @@ LIBIMOBILEDEVICE_API preboard_error_t preboard_receive_with_timeout(preboard_cli
return res;
}
-LIBIMOBILEDEVICE_API preboard_error_t preboard_receive(preboard_client_t client, plist_t * plist)
+preboard_error_t preboard_receive(preboard_client_t client, plist_t * plist)
{
return preboard_receive_with_timeout(client, plist, 5000);
}
@@ -162,7 +162,8 @@ static void* preboard_receive_status_loop_thread(void* arg)
preboard_error_t perr = preboard_receive_with_timeout(data->client, &pl, 1000);
if (perr == PREBOARD_E_TIMEOUT) {
continue;
- } else if (perr == PREBOARD_E_SUCCESS) {
+ }
+ if (perr == PREBOARD_E_SUCCESS) {
data->cbfunc(pl, data->user_data);
}
plist_free(pl);
@@ -208,7 +209,7 @@ static preboard_error_t preboard_receive_status_loop_with_callback(preboard_clie
return res;
}
-LIBIMOBILEDEVICE_API preboard_error_t preboard_create_stashbag(preboard_client_t client, plist_t manifest, preboard_status_cb_t status_cb, void *user_data)
+preboard_error_t preboard_create_stashbag(preboard_client_t client, plist_t manifest, preboard_status_cb_t status_cb, void *user_data)
{
if (!client) {
return PREBOARD_E_INVALID_ARG;
@@ -231,7 +232,7 @@ LIBIMOBILEDEVICE_API preboard_error_t preboard_create_stashbag(preboard_client_t
return preboard_receive_status_loop_with_callback(client, status_cb, user_data);
}
-LIBIMOBILEDEVICE_API preboard_error_t preboard_commit_stashbag(preboard_client_t client, plist_t manifest, preboard_status_cb_t status_cb, void *user_data)
+preboard_error_t preboard_commit_stashbag(preboard_client_t client, plist_t manifest, preboard_status_cb_t status_cb, void *user_data)
{
if (!client) {
return PREBOARD_E_INVALID_ARG;
diff --git a/src/preboard.h b/src/preboard.h
index c5143a9..f8164eb 100644
--- a/src/preboard.h
+++ b/src/preboard.h
@@ -22,9 +22,10 @@
#ifndef __PREBOARD_H
#define __PREBOARD_H
+#include "idevice.h"
#include "libimobiledevice/preboard.h"
#include "property_list_service.h"
-#include "common/thread.h"
+#include <libimobiledevice-glue/thread.h>
struct preboard_client_private {
property_list_service_client_t parent;
diff --git a/src/property_list_service.c b/src/property_list_service.c
index 7b5c738..2fca4e7 100644
--- a/src/property_list_service.c
+++ b/src/property_list_service.c
@@ -58,7 +58,7 @@ static property_list_service_error_t service_to_property_list_service_error(serv
return PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR;
}
-LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_client_new(idevice_t device, lockdownd_service_descriptor_t service, property_list_service_client_t *client)
+property_list_service_error_t property_list_service_client_new(idevice_t device, lockdownd_service_descriptor_t service, property_list_service_client_t *client)
{
if (!device || !service || service->port == 0 || !client || *client)
return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
@@ -78,7 +78,7 @@ LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_client_
return PROPERTY_LIST_SERVICE_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_client_free(property_list_service_client_t client)
+property_list_service_error_t property_list_service_client_free(property_list_service_client_t client)
{
if (!client)
return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
@@ -152,12 +152,12 @@ static property_list_service_error_t internal_plist_send(property_list_service_c
return res;
}
-LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_send_xml_plist(property_list_service_client_t client, plist_t plist)
+property_list_service_error_t property_list_service_send_xml_plist(property_list_service_client_t client, plist_t plist)
{
return internal_plist_send(client, plist, 0);
}
-LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_send_binary_plist(property_list_service_client_t client, plist_t plist)
+property_list_service_error_t property_list_service_send_binary_plist(property_list_service_client_t client, plist_t plist)
{
return internal_plist_send(client, plist, 1);
}
@@ -262,27 +262,34 @@ static property_list_service_error_t internal_plist_receive_timeout(property_lis
return res;
}
-LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_receive_plist_with_timeout(property_list_service_client_t client, plist_t *plist, unsigned int timeout)
+property_list_service_error_t property_list_service_receive_plist_with_timeout(property_list_service_client_t client, plist_t *plist, unsigned int timeout)
{
return internal_plist_receive_timeout(client, plist, timeout);
}
-LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_receive_plist(property_list_service_client_t client, plist_t *plist)
+property_list_service_error_t property_list_service_receive_plist(property_list_service_client_t client, plist_t *plist)
{
return internal_plist_receive_timeout(client, plist, 30000);
}
-LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_enable_ssl(property_list_service_client_t client)
+property_list_service_error_t property_list_service_enable_ssl(property_list_service_client_t client)
{
if (!client || !client->parent)
return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
return service_to_property_list_service_error(service_enable_ssl(client->parent));
}
-LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_disable_ssl(property_list_service_client_t client)
+property_list_service_error_t property_list_service_disable_ssl(property_list_service_client_t client)
{
if (!client || !client->parent)
return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
return service_to_property_list_service_error(service_disable_ssl(client->parent));
}
+property_list_service_error_t property_list_service_get_service_client(property_list_service_client_t client, service_client_t *service_client)
+{
+ if (!client || !client->parent || !service_client)
+ return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
+ *service_client = client->parent;
+ return PROPERTY_LIST_SERVICE_E_SUCCESS;
+}
diff --git a/src/property_list_service.h b/src/property_list_service.h
index 3c9e14d..0e9e948 100644
--- a/src/property_list_service.h
+++ b/src/property_list_service.h
@@ -22,6 +22,7 @@
#ifndef __PROPERTY_LIST_SERVICE_H
#define __PROPERTY_LIST_SERVICE_H
+#include "idevice.h"
#include "libimobiledevice/property_list_service.h"
#include "service.h"
diff --git a/src/restore.c b/src/restore.c
index 4e9d65a..d13a28a 100644
--- a/src/restore.c
+++ b/src/restore.c
@@ -111,7 +111,7 @@ static restored_error_t restored_error(property_list_service_error_t err)
return RESTORE_E_UNKNOWN_ERROR;
}
-LIBIMOBILEDEVICE_API restored_error_t restored_client_free(restored_client_t client)
+restored_error_t restored_client_free(restored_client_t client)
{
if (!client)
return RESTORE_E_INVALID_ARG;
@@ -139,7 +139,7 @@ LIBIMOBILEDEVICE_API restored_error_t restored_client_free(restored_client_t cli
return ret;
}
-LIBIMOBILEDEVICE_API void restored_client_set_label(restored_client_t client, const char *label)
+void restored_client_set_label(restored_client_t client, const char *label)
{
if (client) {
if (client->label)
@@ -149,7 +149,7 @@ LIBIMOBILEDEVICE_API void restored_client_set_label(restored_client_t client, co
}
}
-LIBIMOBILEDEVICE_API restored_error_t restored_receive(restored_client_t client, plist_t *plist)
+restored_error_t restored_receive(restored_client_t client, plist_t *plist)
{
if (!client || !plist || (plist && *plist))
return RESTORE_E_INVALID_ARG;
@@ -157,7 +157,7 @@ LIBIMOBILEDEVICE_API restored_error_t restored_receive(restored_client_t client,
return restored_error(property_list_service_receive_plist(client->parent, plist));
}
-LIBIMOBILEDEVICE_API restored_error_t restored_send(restored_client_t client, plist_t plist)
+restored_error_t restored_send(restored_client_t client, plist_t plist)
{
if (!client || !plist)
return RESTORE_E_INVALID_ARG;
@@ -165,7 +165,7 @@ LIBIMOBILEDEVICE_API restored_error_t restored_send(restored_client_t client, pl
return restored_error(property_list_service_send_xml_plist(client->parent, plist));
}
-LIBIMOBILEDEVICE_API restored_error_t restored_query_type(restored_client_t client, char **type, uint64_t *version)
+restored_error_t restored_query_type(restored_client_t client, char **type, uint64_t *version)
{
if (!client)
return RESTORE_E_INVALID_ARG;
@@ -224,7 +224,7 @@ LIBIMOBILEDEVICE_API restored_error_t restored_query_type(restored_client_t clie
return ret;
}
-LIBIMOBILEDEVICE_API restored_error_t restored_query_value(restored_client_t client, const char *key, plist_t *value)
+restored_error_t restored_query_value(restored_client_t client, const char *key, plist_t *value)
{
if (!client || !key)
return RESTORE_E_INVALID_ARG;
@@ -266,34 +266,32 @@ LIBIMOBILEDEVICE_API restored_error_t restored_query_value(restored_client_t cli
return ret;
}
-LIBIMOBILEDEVICE_API restored_error_t restored_get_value(restored_client_t client, const char *key, plist_t *value)
+restored_error_t restored_get_value(restored_client_t client, const char *key, plist_t *value)
{
+ plist_t item;
+
if (!client || !value || (value && *value))
return RESTORE_E_INVALID_ARG;
if (!client->info)
return RESTORE_E_NOT_ENOUGH_DATA;
- restored_error_t ret = RESTORE_E_SUCCESS;
- plist_t item = NULL;
-
if (!key) {
*value = plist_copy(client->info);
return RESTORE_E_SUCCESS;
- } else {
- item = plist_dict_get_item(client->info, key);
}
- if (item) {
- *value = plist_copy(item);
- } else {
- ret = RESTORE_E_PLIST_ERROR;
+ item = plist_dict_get_item(client->info, key);
+ if (!item) {
+ return RESTORE_E_PLIST_ERROR;
}
- return ret;
+ *value = plist_copy(item);
+
+ return RESTORE_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API restored_error_t restored_client_new(idevice_t device, restored_client_t *client, const char *label)
+restored_error_t restored_client_new(idevice_t device, restored_client_t *client, const char *label)
{
if (!client)
return RESTORE_E_INVALID_ARG;
@@ -337,7 +335,7 @@ LIBIMOBILEDEVICE_API restored_error_t restored_client_new(idevice_t device, rest
return ret;
}
-LIBIMOBILEDEVICE_API restored_error_t restored_goodbye(restored_client_t client)
+restored_error_t restored_goodbye(restored_client_t client)
{
if (!client)
return RESTORE_E_INVALID_ARG;
@@ -369,7 +367,7 @@ LIBIMOBILEDEVICE_API restored_error_t restored_goodbye(restored_client_t client)
return ret;
}
-LIBIMOBILEDEVICE_API restored_error_t restored_start_restore(restored_client_t client, plist_t options, uint64_t version)
+restored_error_t restored_start_restore(restored_client_t client, plist_t options, uint64_t version)
{
if (!client)
return RESTORE_E_INVALID_ARG;
@@ -393,7 +391,7 @@ LIBIMOBILEDEVICE_API restored_error_t restored_start_restore(restored_client_t c
return ret;
}
-LIBIMOBILEDEVICE_API restored_error_t restored_reboot(restored_client_t client)
+restored_error_t restored_reboot(restored_client_t client)
{
if (!client)
return RESTORE_E_INVALID_ARG;
diff --git a/src/restore.h b/src/restore.h
index 646d1d1..ec6fa04 100644
--- a/src/restore.h
+++ b/src/restore.h
@@ -24,6 +24,7 @@
#include <string.h>
+#include "idevice.h"
#include "libimobiledevice/restore.h"
#include "property_list_service.h"
diff --git a/src/reverse_proxy.c b/src/reverse_proxy.c
new file mode 100644
index 0000000..2fcfdd1
--- /dev/null
+++ b/src/reverse_proxy.c
@@ -0,0 +1,810 @@
+/*
+ * reverse_proxy.c
+ * com.apple.PurpleReverseProxy service implementation.
+ *
+ * Copyright (c) 2021 Nikias Bassen, All Rights Reserved.
+ * Copyright (c) 2014 BALATON Zoltan. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <string.h>
+#include <stdlib.h>
+#define _GNU_SOURCE 1
+#define __USE_GNU 1
+#include <stdio.h>
+#include <errno.h>
+
+#include <plist/plist.h>
+#include <libimobiledevice-glue/thread.h>
+#include <libimobiledevice-glue/socket.h>
+
+#include "reverse_proxy.h"
+#include "lockdown.h"
+#include "common/debug.h"
+#include "endianness.h"
+#include "asprintf.h"
+
+#ifndef ECONNRESET
+#define ECONNRESET 108
+#endif
+#ifndef ETIMEDOUT
+#define ETIMEDOUT 138
+#endif
+
+#define CTRL_PORT 1082
+#define CTRLCMD "BeginCtrl"
+#define HELLOCTRLCMD "HelloCtrl"
+#define HELLOCMD "HelloConn"
+
+#define RP_SYNC_MSG 0x1
+#define RP_PROXY_MSG 0x105
+#define RP_PLIST_MSG 0xbbaa
+
+/**
+ * Convert a service_error_t value to a reverse_proxy_error_t value.
+ * Used internally to get correct error codes.
+ *
+ * @param err A service_error_t error code
+ *
+ * @return A matching reverse_proxy_error_t error code,
+ * REVERSE_PROXY_E_UNKNOWN_ERROR otherwise.
+ */
+static reverse_proxy_error_t reverse_proxy_error(service_error_t err)
+{
+ switch (err) {
+ case SERVICE_E_SUCCESS:
+ return REVERSE_PROXY_E_SUCCESS;
+ case SERVICE_E_INVALID_ARG:
+ return REVERSE_PROXY_E_INVALID_ARG;
+ case SERVICE_E_MUX_ERROR:
+ return REVERSE_PROXY_E_MUX_ERROR;
+ case SERVICE_E_SSL_ERROR:
+ return REVERSE_PROXY_E_SSL_ERROR;
+ case SERVICE_E_NOT_ENOUGH_DATA:
+ return REVERSE_PROXY_E_NOT_ENOUGH_DATA;
+ case SERVICE_E_TIMEOUT:
+ return REVERSE_PROXY_E_TIMEOUT;
+ default:
+ break;
+ }
+ return REVERSE_PROXY_E_UNKNOWN_ERROR;
+}
+
+static void _reverse_proxy_log(reverse_proxy_client_t client, const char* format, ...)
+{
+ if (!client || !client->log_cb) {
+ return;
+ }
+ va_list args;
+ va_start(args, format);
+ char* buffer = NULL;
+ if(vasprintf(&buffer, format, args)<0){}
+ va_end(args);
+ client->log_cb(client, buffer, client->log_cb_user_data);
+ free(buffer);
+}
+
+static void _reverse_proxy_data(reverse_proxy_client_t client, int direction, char* buffer, uint32_t length)
+{
+ if (!client || !client->data_cb) {
+ return;
+ }
+ client->data_cb(client, direction, buffer, length, client->data_cb_user_data);
+}
+
+static void _reverse_proxy_status(reverse_proxy_client_t client, int status, const char* format, ...)
+{
+ if (!client || !client->status_cb) {
+ return;
+ }
+ va_list args;
+ va_start(args, format);
+ char* buffer = NULL;
+ if(vasprintf(&buffer, format, args)<0){}
+ va_end(args);
+ client->status_cb(client, status, buffer, client->status_cb_user_data);
+ free(buffer);
+}
+
+static int _reverse_proxy_handle_proxy_cmd(reverse_proxy_client_t client)
+{
+ reverse_proxy_error_t err = REVERSE_PROXY_E_SUCCESS;
+ char *buf = NULL;
+ size_t bufsize = 1048576;
+ uint32_t sent = 0, bytes = 0;
+ uint32_t sent_total = 0;
+ uint32_t recv_total = 0;
+ char *host = NULL;
+ uint16_t port = 0;
+
+ buf = malloc(bufsize);
+ if (!buf) {
+ _reverse_proxy_log(client, "ERROR: Failed to allocate buffer");
+ return -1;
+ }
+
+ err = reverse_proxy_receive(client, buf, bufsize, &bytes);
+ if (err != REVERSE_PROXY_E_SUCCESS) {
+ free(buf);
+ _reverse_proxy_log(client, "ERROR: Unable to read data for proxy command");
+ return -1;
+ }
+ _reverse_proxy_log(client, "Handling proxy command");
+
+ /* Just return success here unconditionally because we don't know
+ * anything else and we will eventually abort on failure anyway */
+ uint16_t ack = 5;
+ err = reverse_proxy_send(client, (char *)&ack, sizeof(ack), &sent);
+ if (err != REVERSE_PROXY_E_SUCCESS || sent != sizeof(ack)) {
+ free(buf);
+ _reverse_proxy_log(client, "ERROR: Unable to send ack. Sent %u of %u bytes.", sent, (uint32_t)sizeof(ack));
+ return -1;
+ }
+
+ if (bytes < 3) {
+ free(buf);
+ _reverse_proxy_log(client, "Proxy command data too short, retrying");
+ return 0;
+ }
+
+ /* ack command data too */
+ err = reverse_proxy_send(client, buf, bytes, &sent);
+ if (err != REVERSE_PROXY_E_SUCCESS || sent != bytes) {
+ free(buf);
+ _reverse_proxy_log(client, "ERROR: Unable to send data. Sent %u of %u bytes.", sent, bytes);
+ return -1;
+ }
+
+ /* Now try to handle actual messages */
+ /* Connect: 0 3 hostlen <host> <port> */
+ if (buf[0] == 0 && buf[1] == 3) {
+ uint16_t *p = (uint16_t *)&buf[bytes - 2];
+ port = be16toh(*p);
+ buf[bytes - 2] = '\0';
+ host = strdup(&buf[3]);
+ _reverse_proxy_log(client, "Connect request to %s:%u", host, port);
+ }
+
+ if (!host || !buf[2]) {
+ /* missing or zero length host name */
+ free(buf);
+ return 0;
+ }
+
+ /* else wait for messages and forward them */
+ int sockfd = socket_connect(host, port);
+ if (sockfd < 0) {
+ free(buf);
+ _reverse_proxy_log(client, "ERROR: Connection to %s:%u failed: %s", host, port, strerror(errno));
+ free(host);
+ return -1;
+ }
+
+ _reverse_proxy_status(client, RP_STATUS_CONNECTED, "Connected to %s:%u", host, port);
+
+ int res = 0, bytes_ret;
+ while (1) {
+ bytes = 0;
+ err = reverse_proxy_receive_with_timeout(client, buf, bufsize, &bytes, 100);
+ if (err == REVERSE_PROXY_E_TIMEOUT || (err == REVERSE_PROXY_E_SUCCESS && !bytes)) {
+ /* just a timeout condition */
+ }
+ else if (err != REVERSE_PROXY_E_SUCCESS) {
+ _reverse_proxy_log(client, "Connection closed");
+ res = -1;
+ break;
+ }
+ if (bytes) {
+ _reverse_proxy_log(client, "Proxying %u bytes of data", bytes);
+ _reverse_proxy_data(client, RP_DATA_DIRECTION_OUT, buf, bytes);
+ sent = 0;
+ while (sent < bytes) {
+ int s = socket_send(sockfd, buf + sent, bytes - sent);
+ if (s < 0) {
+ break;
+ }
+ sent += s;
+ }
+ sent_total += sent;
+ if (sent != bytes) {
+ _reverse_proxy_log(client, "ERROR: Sending proxy payload failed: %s. Sent %u of %u bytes.", strerror(errno), sent, bytes);
+ socket_close(sockfd);
+ res = -1;
+ break;
+ }
+ }
+ bytes_ret = socket_receive_timeout(sockfd, buf, bufsize, 0, 100);
+ if (bytes_ret == -ETIMEDOUT) {
+ bytes_ret = 0;
+ } else if (bytes_ret == -ECONNRESET) {
+ res = 1;
+ break;
+ } else if (bytes_ret < 0) {
+ _reverse_proxy_log(client, "ERROR: Failed to receive from host: %s", strerror(-bytes_ret));
+ break;
+ }
+
+ bytes = bytes_ret;
+ if (bytes) {
+ _reverse_proxy_log(client, "Received %u bytes reply data, sending to device\n", bytes);
+ _reverse_proxy_data(client, RP_DATA_DIRECTION_IN, buf, bytes);
+ recv_total += bytes;
+ sent = 0;
+ while (sent < bytes) {
+ uint32_t s;
+ err = reverse_proxy_send(client, buf + sent, bytes - sent, &s);
+ if (err != REVERSE_PROXY_E_SUCCESS) {
+ break;
+ }
+ sent += s;
+ }
+ if (err != REVERSE_PROXY_E_SUCCESS || bytes != sent) {
+ _reverse_proxy_log(client, "ERROR: Unable to send data (%d). Sent %u of %u bytes.", err, sent, bytes);
+ res = -1;
+ break;
+ }
+ }
+ }
+ socket_close(sockfd);
+ free(host);
+ free(buf);
+
+ _reverse_proxy_status(client, RP_STATUS_DISCONNECTED, "Disconnected (out: %u / in: %u)", sent_total, recv_total);
+
+ return res;
+}
+
+static int _reverse_proxy_handle_plist_cmd(reverse_proxy_client_t client)
+{
+ plist_t dict;
+ reverse_proxy_error_t err;
+
+ err = reverse_proxy_receive_plist(client, &dict);
+ if (err != REVERSE_PROXY_E_SUCCESS) {
+ _reverse_proxy_log(client, "ERROR: Unable to receive plist command, error", err);
+ return -1;
+ }
+ plist_t node = plist_dict_get_item(dict, "Command");
+ if (!node || (plist_get_node_type(node) != PLIST_STRING)) {
+ _reverse_proxy_log(client, "ERROR: No 'Command' in reply", err);
+ plist_free(dict);
+ return -1;
+ }
+ char *command = NULL;
+ plist_get_string_val(node, &command);
+ plist_free(dict);
+
+ if (!command) {
+ _reverse_proxy_log(client, "ERROR: Empty 'Command' string");
+ return -1;
+ }
+
+ if (!strcmp(command, "Ping")) {
+ _reverse_proxy_log(client, "Received Ping command, replying with Pong");
+ dict = plist_new_dict();
+ plist_dict_set_item(dict, "Pong", plist_new_bool(1));
+ err = reverse_proxy_send_plist(client, dict);
+ plist_free(dict);
+ if (err) {
+ _reverse_proxy_log(client, "ERROR: Unable to send Ping command reply");
+ free(command);
+ return -1;
+ }
+ } else {
+ _reverse_proxy_log(client, "WARNING: Received unhandled plist command '%s'", command);
+ free(command);
+ return -1;
+ }
+
+ free(command);
+ /* reverse proxy connection will be terminated remotely. Next receive will get nothing, error and terminate this worker thread. */
+ return 0;
+}
+
+static reverse_proxy_error_t reverse_proxy_client_new(idevice_t device, lockdownd_service_descriptor_t service, reverse_proxy_client_t * client)
+{
+ *client = NULL;
+
+ if (!device || !service || service->port == 0 || !client || *client) {
+ return REVERSE_PROXY_E_INVALID_ARG;
+ }
+
+ debug_info("Creating reverse_proxy_client, port = %d.", service->port);
+
+ service_client_t sclient = NULL;
+ reverse_proxy_error_t ret = reverse_proxy_error(service_client_new(device, service, &sclient));
+ if (ret != REVERSE_PROXY_E_SUCCESS) {
+ debug_info("Creating service client failed. Error: %i", ret);
+ return ret;
+ }
+
+ reverse_proxy_client_t client_loc = (reverse_proxy_client_t) calloc(1, sizeof(struct reverse_proxy_client_private));
+ client_loc->parent = sclient;
+ client_loc->th_ctrl = THREAD_T_NULL;
+ *client = client_loc;
+
+ return 0;
+}
+
+static void* _reverse_proxy_connection_thread(void *cdata)
+{
+ reverse_proxy_client_t client = (reverse_proxy_client_t)cdata;
+ uint32_t bytes = 0;
+ reverse_proxy_client_t conn_client = NULL;
+ reverse_proxy_error_t err = REVERSE_PROXY_E_UNKNOWN_ERROR;
+
+ if (client->conn_port == 0) {
+ service_client_factory_start_service(client->parent->connection->device, "com.apple.PurpleReverseProxy.Conn", (void**)&conn_client, client->label, SERVICE_CONSTRUCTOR(reverse_proxy_client_new), &err);
+ if (!conn_client) {
+ _reverse_proxy_log(client, "ERROR: Failed to start proxy connection service, error %d", err);
+ }
+ } else {
+ struct lockdownd_service_descriptor svc;
+ svc.port = client->conn_port;
+ svc.ssl_enabled = 0;
+ svc.identifier = NULL;
+ err = reverse_proxy_client_new(client->parent->connection->device, &svc, &conn_client);
+ if (!conn_client) {
+ _reverse_proxy_log(client, "ERROR: Failed to connect to proxy connection port %u, error %d", client->conn_port, err);
+ }
+ }
+ if (!conn_client) {
+ goto leave;
+ }
+ conn_client->type = RP_TYPE_CONN;
+ conn_client->protoversion = client->protoversion;
+ conn_client->log_cb = client->log_cb;
+ conn_client->log_cb_user_data = client->log_cb_user_data;
+ conn_client->status_cb = client->status_cb;
+ conn_client->status_cb_user_data = client->status_cb_user_data;
+
+ err = reverse_proxy_send(conn_client, HELLOCMD, sizeof(HELLOCMD), &bytes);
+ if (err != REVERSE_PROXY_E_SUCCESS || bytes != sizeof(HELLOCMD)) {
+ _reverse_proxy_log(conn_client, "ERROR: Unable to send " HELLOCMD " (sent %u/%u bytes)", bytes, sizeof(HELLOCMD));
+ goto leave;
+ }
+
+ if (conn_client->protoversion == 2) {
+ plist_t reply = NULL;
+ err = reverse_proxy_receive_plist(conn_client, &reply);
+ if (err != REVERSE_PROXY_E_SUCCESS) {
+ _reverse_proxy_log(conn_client, "ERROR: Did not receive " HELLOCMD " reply, error %d", err);
+ goto leave;
+ }
+ char* identifier = NULL;
+ char* cmd = NULL;
+ plist_t node = NULL;
+ node = plist_dict_get_item(reply, "Command");
+ if (node) {
+ plist_get_string_val(node, &cmd);
+ }
+ node = plist_dict_get_item(reply, "Identifier");
+ if (node) {
+ plist_get_string_val(node, &identifier);
+ }
+ plist_free(reply);
+
+ if (!cmd || (strcmp(cmd, HELLOCMD) != 0)) {
+ free(cmd);
+ free(identifier);
+ _reverse_proxy_log(conn_client, "ERROR: Unexpected reply to " HELLOCMD " received");
+ goto leave;
+ }
+ free(cmd);
+
+ if (identifier) {
+ _reverse_proxy_log(conn_client, "Got device identifier %s", identifier);
+ free(identifier);
+ }
+ } else {
+ char buf[16];
+ memset(buf, '\0', sizeof(buf));
+ bytes = 0;
+ err = reverse_proxy_receive(conn_client, buf, sizeof(HELLOCMD), &bytes);
+ if (err != REVERSE_PROXY_E_SUCCESS) {
+ _reverse_proxy_log(conn_client, "ERROR: Did not receive " HELLOCMD " reply, error %d", err);
+ goto leave;
+ }
+ if (memcmp(buf, HELLOCMD, sizeof(HELLOCMD)) != 0) {
+ _reverse_proxy_log(conn_client, "ERROR: Did not receive " HELLOCMD " as reply, but %.*s", (int)bytes, buf);
+ goto leave;
+ }
+ }
+
+ _reverse_proxy_status(conn_client, RP_STATUS_READY, "Ready");
+
+ int running = 1;
+ while (client->th_ctrl != THREAD_T_NULL && conn_client && running) {
+ uint16_t cmd = 0;
+ bytes = 0;
+ err = reverse_proxy_receive_with_timeout(conn_client, (char*)&cmd, sizeof(cmd), &bytes, 1000);
+ if (err == REVERSE_PROXY_E_TIMEOUT || (err == REVERSE_PROXY_E_SUCCESS && bytes != sizeof(cmd))) {
+ continue;
+ } else if (err != REVERSE_PROXY_E_SUCCESS) {
+ _reverse_proxy_log(conn_client, "Connection closed");
+ break;
+ }
+ cmd = le16toh(cmd);
+ switch (cmd) {
+ case 0xBBAA:
+ /* plist command */
+ if (_reverse_proxy_handle_plist_cmd(conn_client) < 0) {
+ running = 0;
+ }
+ break;
+ case 0x105:
+ /* proxy command */
+ if (_reverse_proxy_handle_proxy_cmd(conn_client) < 0) {
+ running = 0;
+ }
+ break;
+ default:
+ /* unknown */
+ debug_info("ERROR: Unknown request 0x%x", cmd);
+ _reverse_proxy_log(conn_client, "ERROR: Unknown request 0x%x", cmd);
+ running = 0;
+ break;
+ }
+ }
+
+leave:
+ _reverse_proxy_status(conn_client, RP_STATUS_TERMINATE, "Terminated");
+ if (conn_client) {
+ reverse_proxy_client_free(conn_client);
+ }
+
+ return NULL;
+}
+
+static void* _reverse_proxy_control_thread(void *cdata)
+{
+ reverse_proxy_client_t client = (reverse_proxy_client_t)cdata;
+ THREAD_T th_conn = THREAD_T_NULL;
+ int running = 1;
+ _reverse_proxy_status(client, RP_STATUS_READY, "Ready");
+ while (client && client->parent && running) {
+ uint32_t cmd = 0;
+ uint32_t bytes = 0;
+ reverse_proxy_error_t err = reverse_proxy_receive_with_timeout(client, (char*)&cmd, sizeof(cmd), &bytes, 1000);
+ if (err == REVERSE_PROXY_E_TIMEOUT || (err == REVERSE_PROXY_E_SUCCESS && bytes != sizeof(cmd))) {
+ continue;
+ } else if (err != REVERSE_PROXY_E_SUCCESS) {
+ _reverse_proxy_log(client, "Connection closed");
+ break;
+ }
+ cmd = le32toh(cmd);
+ switch (cmd) {
+ case 1:
+ /* connection request */
+ debug_info("ReverseProxy<%p> got connect request", client);
+ _reverse_proxy_status(client, RP_STATUS_CONNECT_REQ, "Connect Request");
+ if (thread_new(&th_conn, _reverse_proxy_connection_thread, client) != 0) {
+ debug_info("ERROR: Failed to start connection thread");
+ th_conn = THREAD_T_NULL;
+ running = 0;
+ }
+ break;
+ case 2:
+ /* shutdown request */
+ debug_info("ReverseProxy<%p> got shutdown request", client);
+ _reverse_proxy_status(client, RP_STATUS_SHUTDOWN_REQ, "Shutdown Request");
+ running = 0;
+ break;
+ default:
+ /* unknown */
+ debug_info("ERROR: Unknown request 0x%x", cmd);
+ _reverse_proxy_log(client, "ERROR: Unknown request 0x%x", cmd);
+ running = 0;
+ break;
+ }
+ }
+ _reverse_proxy_log(client, "Terminating");
+
+ client->th_ctrl = THREAD_T_NULL;
+ if (th_conn) {
+ debug_info("joining connection thread");
+ thread_join(th_conn);
+ thread_free(th_conn);
+ }
+
+ _reverse_proxy_status(client, RP_STATUS_TERMINATE, "Terminated");
+
+ return NULL;
+}
+
+reverse_proxy_error_t reverse_proxy_client_start_proxy(reverse_proxy_client_t client, int control_protocol_version)
+{
+ char buf[16] = {0, };
+ uint32_t bytes = 0;
+ reverse_proxy_error_t err = REVERSE_PROXY_E_UNKNOWN_ERROR;
+
+ if (!client) {
+ return REVERSE_PROXY_E_INVALID_ARG;
+ }
+ if (control_protocol_version < 1 || control_protocol_version > 2) {
+ debug_info("invalid protocol version %d, must be 1 or 2", control_protocol_version);
+ return REVERSE_PROXY_E_INVALID_ARG;
+ }
+
+ if (control_protocol_version == 2) {
+ err = reverse_proxy_send(client, CTRLCMD, sizeof(CTRLCMD), &bytes);
+ if (err != REVERSE_PROXY_E_SUCCESS) {
+ _reverse_proxy_log(client, "ERROR: Failed to send " CTRLCMD " to device, error %d", err);
+ return err;
+ }
+ plist_t dict = plist_new_dict();
+ plist_dict_set_item(dict, "Command", plist_new_string(CTRLCMD));
+ plist_dict_set_item(dict, "CtrlProtoVersion", plist_new_uint(client->protoversion));
+ err = reverse_proxy_send_plist(client, dict);
+ plist_free(dict);
+ if (err != REVERSE_PROXY_E_SUCCESS) {
+ _reverse_proxy_log(client, "ERROR: Could not send " CTRLCMD " plist command, error %d", err);
+ return err;
+ }
+ dict = NULL;
+ err = reverse_proxy_receive_plist(client, &dict);
+ if (err != REVERSE_PROXY_E_SUCCESS) {
+ _reverse_proxy_log(client, "ERROR: Could not receive " CTRLCMD " plist reply, error %d", err);
+ return err;
+ }
+ plist_t node = plist_dict_get_item(dict, "ConnPort");
+ if (node && plist_get_node_type(node) == PLIST_UINT) {
+ uint64_t u64val = 0;
+ plist_get_uint_val(node, &u64val);
+ client->conn_port = (uint16_t)u64val;
+ } else {
+ _reverse_proxy_log(client, "ERROR: Could not get ConnPort value");
+ return REVERSE_PROXY_E_UNKNOWN_ERROR;
+ }
+ client->protoversion = 2;
+ } else {
+ err = reverse_proxy_send(client, HELLOCTRLCMD, sizeof(HELLOCTRLCMD), &bytes);
+ if (err != REVERSE_PROXY_E_SUCCESS) {
+ _reverse_proxy_log(client, "ERROR: Failed to send " HELLOCTRLCMD " to device, error %d", err);
+ return err;
+ }
+
+ bytes = 0;
+ err = reverse_proxy_receive(client, buf, sizeof(HELLOCTRLCMD)-1, &bytes);
+ if (err != REVERSE_PROXY_E_SUCCESS) {
+ _reverse_proxy_log(client, "ERROR: Could not receive " HELLOCTRLCMD " reply, error %d", err);
+ return err;
+ }
+
+ uint16_t cport = 0;
+ bytes = 0;
+ err = reverse_proxy_receive(client, (char*)&cport, 2, &bytes);
+ if (err != REVERSE_PROXY_E_SUCCESS) {
+ _reverse_proxy_log(client, "ERROR: Failed to receive connection port, error %d", err);
+ return err;
+ }
+ client->conn_port = le16toh(cport);
+ client->protoversion = 1;
+ }
+
+ if (thread_new(&(client->th_ctrl), _reverse_proxy_control_thread, client) != 0) {
+ _reverse_proxy_log(client, "ERROR: Failed to start control thread");
+ client->th_ctrl = THREAD_T_NULL; /* undefined after failure */
+ err = REVERSE_PROXY_E_UNKNOWN_ERROR;
+ }
+
+ return err;
+}
+
+reverse_proxy_error_t reverse_proxy_client_create_with_service(idevice_t device, reverse_proxy_client_t* client, const char* label)
+{
+ reverse_proxy_error_t err = REVERSE_PROXY_E_UNKNOWN_ERROR;
+ service_client_factory_start_service(device, "com.apple.PurpleReverseProxy.Ctrl", (void**)client, label, SERVICE_CONSTRUCTOR(reverse_proxy_client_new), &err);
+ if (!*client) {
+ return err;
+ }
+ (*client)->label = strdup(label);
+ (*client)->type = RP_TYPE_CTRL;
+
+ return REVERSE_PROXY_E_SUCCESS;
+}
+
+reverse_proxy_error_t reverse_proxy_client_create_with_port(idevice_t device, reverse_proxy_client_t* client, uint16_t device_port)
+{
+ reverse_proxy_client_t client_loc = NULL;
+ reverse_proxy_error_t err;
+
+ struct lockdownd_service_descriptor svc;
+ svc.port = device_port;
+ svc.ssl_enabled = 0;
+ svc.identifier = NULL;
+
+ err = reverse_proxy_client_new(device, &svc, &client_loc);
+ if (err != REVERSE_PROXY_E_SUCCESS) {
+ return err;
+ }
+
+ client_loc->type = RP_TYPE_CTRL;
+ *client = client_loc;
+
+ return REVERSE_PROXY_E_SUCCESS;
+}
+
+reverse_proxy_error_t reverse_proxy_client_free(reverse_proxy_client_t client)
+{
+ if (!client)
+ return REVERSE_PROXY_E_INVALID_ARG;
+ service_client_t parent = client->parent;
+ client->parent = NULL;
+ if (client->th_ctrl) {
+ debug_info("joining control thread");
+ thread_join(client->th_ctrl);
+ thread_free(client->th_ctrl);
+ client->th_ctrl = THREAD_T_NULL;
+ }
+ reverse_proxy_error_t err = reverse_proxy_error(service_client_free(parent));
+ free(client->label);
+ free(client);
+
+ return err;
+}
+
+reverse_proxy_client_type_t reverse_proxy_get_type(reverse_proxy_client_t client)
+{
+ if (!client)
+ return 0;
+ return client->type;
+}
+
+void reverse_proxy_client_set_status_callback(reverse_proxy_client_t client, reverse_proxy_status_cb_t status_callback, void* user_data)
+{
+ if (!client) {
+ return;
+ }
+ client->status_cb = status_callback;
+ client->status_cb_user_data = user_data;
+}
+
+void reverse_proxy_client_set_log_callback(reverse_proxy_client_t client, reverse_proxy_log_cb_t log_callback, void* user_data)
+{
+ if (!client) {
+ return;
+ }
+ client->log_cb = log_callback;
+ client->log_cb_user_data = user_data;
+}
+
+void reverse_proxy_client_set_data_callback(reverse_proxy_client_t client, reverse_proxy_data_cb_t data_callback, void* user_data)
+{
+ if (!client) {
+ return;
+ }
+ client->data_cb = data_callback;
+ client->data_cb_user_data = user_data;
+}
+
+reverse_proxy_error_t reverse_proxy_send(reverse_proxy_client_t client, const char* data, uint32_t len, uint32_t* sent)
+{
+ reverse_proxy_error_t err = reverse_proxy_error(service_send(client->parent, data, len, sent));
+ return err;
+}
+
+reverse_proxy_error_t reverse_proxy_receive_with_timeout(reverse_proxy_client_t client, char* buffer, uint32_t len, uint32_t* received, unsigned int timeout)
+{
+ if (!client)
+ return REVERSE_PROXY_E_INVALID_ARG;
+ return reverse_proxy_error(service_receive_with_timeout(client->parent, buffer, len, received, timeout));
+}
+
+reverse_proxy_error_t reverse_proxy_receive(reverse_proxy_client_t client, char* buffer, uint32_t len, uint32_t* received)
+{
+ return reverse_proxy_receive_with_timeout(client, buffer, len, received, 20000);
+}
+
+reverse_proxy_error_t reverse_proxy_send_plist(reverse_proxy_client_t client, plist_t plist)
+{
+ reverse_proxy_error_t err;
+ uint32_t len = 0;
+ char* buf = NULL;
+ uint32_t bytes = 0;
+
+ plist_to_bin(plist, &buf, &len);
+
+ if (!buf) {
+ return REVERSE_PROXY_E_INVALID_ARG;
+ }
+
+ debug_info("Sending %u bytes", len);
+
+ uint32_t slen = htole32(len);
+ err = reverse_proxy_send(client, (char*)&slen, sizeof(slen), &bytes);
+ if (err != REVERSE_PROXY_E_SUCCESS) {
+ free(buf);
+ debug_info("ERROR: Unable to send data length, error %d. Sent %u/%u bytes.", err, bytes, (uint32_t)sizeof(slen));
+ return err;
+ }
+ uint32_t done = 0;
+ do {
+ bytes = 0;
+ err = reverse_proxy_send(client, buf+done, len-done, &bytes);
+ if (err != REVERSE_PROXY_E_SUCCESS) {
+ break;
+ }
+ done += bytes;
+ } while (done < len);
+ free(buf);
+ if (err != REVERSE_PROXY_E_SUCCESS || done != len) {
+ debug_info("ERROR: Unable to send data, error %d. Sent %u/%u bytes.", err, done, len);
+ return err;
+ }
+
+ debug_info("Sent %u bytes", len);
+
+ return REVERSE_PROXY_E_SUCCESS;
+}
+
+reverse_proxy_error_t reverse_proxy_receive_plist(reverse_proxy_client_t client, plist_t* plist)
+{
+ return reverse_proxy_receive_plist_with_timeout(client, plist, 20000);
+}
+
+reverse_proxy_error_t reverse_proxy_receive_plist_with_timeout(reverse_proxy_client_t client, plist_t * plist, uint32_t timeout_ms)
+{
+ uint32_t len;
+ uint32_t bytes;
+ reverse_proxy_error_t err;
+
+ err = reverse_proxy_receive_with_timeout(client, (char*)&len, sizeof(len), &bytes, timeout_ms);
+ if (err != REVERSE_PROXY_E_SUCCESS) {
+ if (err != REVERSE_PROXY_E_TIMEOUT) {
+ debug_info("ERROR: Unable to receive packet length, error %d\n", err);
+ }
+ return err;
+ }
+
+ len = le32toh(len);
+ char* buf = calloc(1, len);
+ if (!buf) {
+ debug_info("ERROR: Out of memory");
+ return REVERSE_PROXY_E_UNKNOWN_ERROR;
+ }
+
+ uint32_t done = 0;
+ do {
+ bytes = 0;
+ err = reverse_proxy_receive_with_timeout(client, buf+done, len-done, &bytes, timeout_ms);
+ if (err != REVERSE_PROXY_E_SUCCESS) {
+ break;
+ }
+ done += bytes;
+ } while (done < len);
+
+ if (err != REVERSE_PROXY_E_SUCCESS || done != len) {
+ free(buf);
+ debug_info("ERROR: Unable to receive data, error %d. Received %u/%u bytes.", err, done, len);
+ return err;
+ }
+
+ debug_info("Received %u bytes", len);
+
+ plist_from_bin(buf, len, plist);
+ free(buf);
+
+ if (!(*plist)) {
+ debug_info("ERROR: Failed to convert buffer to plist");
+ return REVERSE_PROXY_E_PLIST_ERROR;
+ }
+
+ return REVERSE_PROXY_E_SUCCESS;
+}
diff --git a/src/reverse_proxy.h b/src/reverse_proxy.h
new file mode 100644
index 0000000..7f441bd
--- /dev/null
+++ b/src/reverse_proxy.h
@@ -0,0 +1,51 @@
+/*
+ * reverse_proxy.h
+ * com.apple.PurpleReverseProxy service header file.
+ *
+ * Copyright (c) 2021 Nikias Bassen, All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __REVERSE_PROXY_H
+#define __REVERSE_PROXY_H
+
+#include "idevice.h"
+#include "libimobiledevice/reverse_proxy.h"
+#include "service.h"
+
+struct reverse_proxy_client_private {
+ service_client_t parent;
+ char* label;
+ int type;
+ int protoversion;
+ THREAD_T th_ctrl;
+ uint16_t conn_port;
+ reverse_proxy_log_cb_t log_cb;
+ void* log_cb_user_data;
+ reverse_proxy_data_cb_t data_cb;
+ void* data_cb_user_data;
+ reverse_proxy_status_cb_t status_cb;
+ void* status_cb_user_data;
+};
+
+reverse_proxy_error_t reverse_proxy_send(reverse_proxy_client_t client, const char* data, uint32_t len, uint32_t* sent);
+reverse_proxy_error_t reverse_proxy_receive(reverse_proxy_client_t client, char* buffer, uint32_t len, uint32_t* received);
+reverse_proxy_error_t reverse_proxy_receive_with_timeout(reverse_proxy_client_t client, char* buffer, uint32_t len, uint32_t* received, unsigned int timeout);
+reverse_proxy_error_t reverse_proxy_send_plist(reverse_proxy_client_t client, plist_t plist);
+reverse_proxy_error_t reverse_proxy_receive_plist(reverse_proxy_client_t client, plist_t* plist);
+reverse_proxy_error_t reverse_proxy_receive_plist_with_timeout(reverse_proxy_client_t client, plist_t * plist, uint32_t timeout_ms);
+
+#endif
diff --git a/src/sbservices.c b/src/sbservices.c
index ccb7c4b..365e130 100644
--- a/src/sbservices.c
+++ b/src/sbservices.c
@@ -79,7 +79,7 @@ static sbservices_error_t sbservices_error(property_list_service_error_t err)
return SBSERVICES_E_UNKNOWN_ERROR;
}
-LIBIMOBILEDEVICE_API sbservices_error_t sbservices_client_new(idevice_t device, lockdownd_service_descriptor_t service, sbservices_client_t *client)
+sbservices_error_t sbservices_client_new(idevice_t device, lockdownd_service_descriptor_t service, sbservices_client_t *client)
{
property_list_service_client_t plistclient = NULL;
sbservices_error_t err = sbservices_error(property_list_service_client_new(device, service, &plistclient));
@@ -95,14 +95,14 @@ LIBIMOBILEDEVICE_API sbservices_error_t sbservices_client_new(idevice_t device,
return SBSERVICES_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API sbservices_error_t sbservices_client_start_service(idevice_t device, sbservices_client_t * client, const char* label)
+sbservices_error_t sbservices_client_start_service(idevice_t device, sbservices_client_t * client, const char* label)
{
sbservices_error_t err = SBSERVICES_E_UNKNOWN_ERROR;
service_client_factory_start_service(device, SBSERVICES_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(sbservices_client_new), &err);
return err;
}
-LIBIMOBILEDEVICE_API sbservices_error_t sbservices_client_free(sbservices_client_t client)
+sbservices_error_t sbservices_client_free(sbservices_client_t client)
{
if (!client)
return SBSERVICES_E_INVALID_ARG;
@@ -115,7 +115,7 @@ LIBIMOBILEDEVICE_API sbservices_error_t sbservices_client_free(sbservices_client
return err;
}
-LIBIMOBILEDEVICE_API sbservices_error_t sbservices_get_icon_state(sbservices_client_t client, plist_t *state, const char *format_version)
+sbservices_error_t sbservices_get_icon_state(sbservices_client_t client, plist_t *state, const char *format_version)
{
if (!client || !client->parent || !state)
return SBSERVICES_E_INVALID_ARG;
@@ -155,7 +155,7 @@ leave_unlock:
return res;
}
-LIBIMOBILEDEVICE_API sbservices_error_t sbservices_set_icon_state(sbservices_client_t client, plist_t newstate)
+sbservices_error_t sbservices_set_icon_state(sbservices_client_t client, plist_t newstate)
{
if (!client || !client->parent || !newstate)
return SBSERVICES_E_INVALID_ARG;
@@ -172,7 +172,10 @@ LIBIMOBILEDEVICE_API sbservices_error_t sbservices_set_icon_state(sbservices_cli
if (res != SBSERVICES_E_SUCCESS) {
debug_info("could not send plist, error %d", res);
}
- /* NO RESPONSE */
+
+ uint32_t bytes = 0;
+ service_receive_with_timeout(client->parent->parent, malloc(4), 4, &bytes, 2000);
+ debug_info("setIconState response: %u", bytes);
if (dict) {
plist_free(dict);
@@ -181,7 +184,7 @@ LIBIMOBILEDEVICE_API sbservices_error_t sbservices_set_icon_state(sbservices_cli
return res;
}
-LIBIMOBILEDEVICE_API sbservices_error_t sbservices_get_icon_pngdata(sbservices_client_t client, const char *bundleId, char **pngdata, uint64_t *pngsize)
+sbservices_error_t sbservices_get_icon_pngdata(sbservices_client_t client, const char *bundleId, char **pngdata, uint64_t *pngsize)
{
if (!client || !client->parent || !bundleId || !pngdata)
return SBSERVICES_E_INVALID_ARG;
@@ -218,7 +221,7 @@ leave_unlock:
return res;
}
-LIBIMOBILEDEVICE_API sbservices_error_t sbservices_get_interface_orientation(sbservices_client_t client, sbservices_interface_orientation_t* interface_orientation)
+sbservices_error_t sbservices_get_interface_orientation(sbservices_client_t client, sbservices_interface_orientation_t* interface_orientation)
{
if (!client || !client->parent || !interface_orientation)
return SBSERVICES_E_INVALID_ARG;
@@ -256,7 +259,7 @@ leave_unlock:
return res;
}
-LIBIMOBILEDEVICE_API sbservices_error_t sbservices_get_home_screen_wallpaper_pngdata(sbservices_client_t client, char **pngdata, uint64_t *pngsize)
+sbservices_error_t sbservices_get_home_screen_wallpaper_pngdata(sbservices_client_t client, char **pngdata, uint64_t *pngsize)
{
if (!client || !client->parent || !pngdata)
return SBSERVICES_E_INVALID_ARG;
diff --git a/src/sbservices.h b/src/sbservices.h
index 6c047ce..b67281e 100644
--- a/src/sbservices.h
+++ b/src/sbservices.h
@@ -22,9 +22,10 @@
#ifndef __SBSERVICES_H
#define __SBSERVICES_H
+#include "idevice.h"
#include "libimobiledevice/sbservices.h"
#include "property_list_service.h"
-#include "common/thread.h"
+#include <libimobiledevice-glue/thread.h>
struct sbservices_client_private {
property_list_service_client_t parent;
diff --git a/src/screenshotr.c b/src/screenshotr.c
index 11d6506..c3cc9ba 100644
--- a/src/screenshotr.c
+++ b/src/screenshotr.c
@@ -65,7 +65,7 @@ static screenshotr_error_t screenshotr_error(device_link_service_error_t err)
return SCREENSHOTR_E_UNKNOWN_ERROR;
}
-LIBIMOBILEDEVICE_API screenshotr_error_t screenshotr_client_new(idevice_t device, lockdownd_service_descriptor_t service,
+screenshotr_error_t screenshotr_client_new(idevice_t device, lockdownd_service_descriptor_t service,
screenshotr_client_t * client)
{
if (!device || !service || service->port == 0 || !client || *client)
@@ -93,14 +93,14 @@ LIBIMOBILEDEVICE_API screenshotr_error_t screenshotr_client_new(idevice_t device
return ret;
}
-LIBIMOBILEDEVICE_API screenshotr_error_t screenshotr_client_start_service(idevice_t device, screenshotr_client_t * client, const char* label)
+screenshotr_error_t screenshotr_client_start_service(idevice_t device, screenshotr_client_t * client, const char* label)
{
screenshotr_error_t err = SCREENSHOTR_E_UNKNOWN_ERROR;
service_client_factory_start_service(device, SCREENSHOTR_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(screenshotr_client_new), &err);
return err;
}
-LIBIMOBILEDEVICE_API screenshotr_error_t screenshotr_client_free(screenshotr_client_t client)
+screenshotr_error_t screenshotr_client_free(screenshotr_client_t client)
{
if (!client)
return SCREENSHOTR_E_INVALID_ARG;
@@ -110,7 +110,7 @@ LIBIMOBILEDEVICE_API screenshotr_error_t screenshotr_client_free(screenshotr_cli
return err;
}
-LIBIMOBILEDEVICE_API screenshotr_error_t screenshotr_take_screenshot(screenshotr_client_t client, char **imgdata, uint64_t *imgsize)
+screenshotr_error_t screenshotr_take_screenshot(screenshotr_client_t client, char **imgdata, uint64_t *imgsize)
{
if (!client || !client->parent || !imgdata)
return SCREENSHOTR_E_INVALID_ARG;
@@ -142,7 +142,7 @@ LIBIMOBILEDEVICE_API screenshotr_error_t screenshotr_take_screenshot(screenshotr
plist_t node = plist_dict_get_item(dict, "MessageType");
char *strval = NULL;
plist_get_string_val(node, &strval);
- if (!strval || strcmp(strval, "ScreenShotReply")) {
+ if (!strval || strcmp(strval, "ScreenShotReply") != 0) {
debug_info("invalid screenshot data received!");
res = SCREENSHOTR_E_PLIST_ERROR;
goto leave;
diff --git a/src/screenshotr.h b/src/screenshotr.h
index 47d4e42..1319ec0 100644
--- a/src/screenshotr.h
+++ b/src/screenshotr.h
@@ -22,6 +22,7 @@
#ifndef __SCREENSHOTR_H
#define __SCREENSHOTR_H
+#include "idevice.h"
#include "libimobiledevice/screenshotr.h"
#include "device_link_service.h"
diff --git a/src/service.c b/src/service.c
index 88132d2..9474021 100644
--- a/src/service.c
+++ b/src/service.c
@@ -56,7 +56,7 @@ static service_error_t idevice_to_service_error(idevice_error_t err)
return SERVICE_E_UNKNOWN_ERROR;
}
-LIBIMOBILEDEVICE_API service_error_t service_client_new(idevice_t device, lockdownd_service_descriptor_t service, service_client_t *client)
+service_error_t service_client_new(idevice_t device, lockdownd_service_descriptor_t service, service_client_t *client)
{
if (!device || !service || service->port == 0 || !client || *client)
return SERVICE_E_INVALID_ARG;
@@ -80,7 +80,7 @@ LIBIMOBILEDEVICE_API service_error_t service_client_new(idevice_t device, lockdo
return SERVICE_E_SUCCESS;
}
-LIBIMOBILEDEVICE_API service_error_t service_client_factory_start_service(idevice_t device, const char* service_name, void **client, const char* label, int32_t (*constructor_func)(idevice_t, lockdownd_service_descriptor_t, void**), int32_t *error_code)
+service_error_t service_client_factory_start_service(idevice_t device, const char* service_name, void **client, const char* label, int32_t (*constructor_func)(idevice_t, lockdownd_service_descriptor_t, void**), int32_t *error_code)
{
*client = NULL;
@@ -91,11 +91,11 @@ LIBIMOBILEDEVICE_API service_error_t service_client_factory_start_service(idevic
}
lockdownd_service_descriptor_t service = NULL;
- lockdownd_start_service(lckd, service_name, &service);
+ lockdownd_error_t lerr = lockdownd_start_service(lckd, service_name, &service);
lockdownd_client_free(lckd);
- if (!service || service->port == 0) {
- debug_info("Could not start service %s!", service_name);
+ if (lerr != LOCKDOWN_E_SUCCESS) {
+ debug_info("Could not start service %s: %s", service_name, lockdownd_strerror(lerr));
return SERVICE_E_START_SERVICE_ERROR;
}
@@ -119,7 +119,7 @@ LIBIMOBILEDEVICE_API service_error_t service_client_factory_start_service(idevic
return (ec == SERVICE_E_SUCCESS) ? SERVICE_E_SUCCESS : SERVICE_E_START_SERVICE_ERROR;
}
-LIBIMOBILEDEVICE_API service_error_t service_client_free(service_client_t client)
+service_error_t service_client_free(service_client_t client)
{
if (!client)
return SERVICE_E_INVALID_ARG;
@@ -132,7 +132,7 @@ LIBIMOBILEDEVICE_API service_error_t service_client_free(service_client_t client
return err;
}
-LIBIMOBILEDEVICE_API service_error_t service_send(service_client_t client, const char* data, uint32_t size, uint32_t *sent)
+service_error_t service_send(service_client_t client, const char* data, uint32_t size, uint32_t *sent)
{
service_error_t res = SERVICE_E_UNKNOWN_ERROR;
uint32_t bytes = 0;
@@ -153,7 +153,7 @@ LIBIMOBILEDEVICE_API service_error_t service_send(service_client_t client, const
return res;
}
-LIBIMOBILEDEVICE_API service_error_t service_receive_with_timeout(service_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout)
+service_error_t service_receive_with_timeout(service_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout)
{
service_error_t res = SERVICE_E_UNKNOWN_ERROR;
uint32_t bytes = 0;
@@ -174,27 +174,34 @@ LIBIMOBILEDEVICE_API service_error_t service_receive_with_timeout(service_client
return res;
}
-LIBIMOBILEDEVICE_API service_error_t service_receive(service_client_t client, char* data, uint32_t size, uint32_t *received)
+service_error_t service_receive(service_client_t client, char* data, uint32_t size, uint32_t *received)
{
return service_receive_with_timeout(client, data, size, received, 30000);
}
-LIBIMOBILEDEVICE_API service_error_t service_enable_ssl(service_client_t client)
+service_error_t service_enable_ssl(service_client_t client)
{
if (!client || !client->connection)
return SERVICE_E_INVALID_ARG;
return idevice_to_service_error(idevice_connection_enable_ssl(client->connection));
}
-LIBIMOBILEDEVICE_API service_error_t service_disable_ssl(service_client_t client)
+service_error_t service_disable_ssl(service_client_t client)
{
return service_disable_bypass_ssl(client, 0);
}
-LIBIMOBILEDEVICE_API service_error_t service_disable_bypass_ssl(service_client_t client, uint8_t sslBypass)
+service_error_t service_disable_bypass_ssl(service_client_t client, uint8_t sslBypass)
{
if (!client || !client->connection)
return SERVICE_E_INVALID_ARG;
return idevice_to_service_error(idevice_connection_disable_bypass_ssl(client->connection, sslBypass));
}
+service_error_t service_get_connection(service_client_t client, idevice_connection_t *connection)
+{
+ if (!client || !client->connection || !connection)
+ return SERVICE_E_INVALID_ARG;
+ *connection = client->connection;
+ return SERVICE_E_SUCCESS;
+}
diff --git a/src/service.h b/src/service.h
index 3fc3077..071fe3f 100644
--- a/src/service.h
+++ b/src/service.h
@@ -21,9 +21,9 @@
#ifndef SERVICE_H
#define SERVICE_H
+#include "idevice.h"
#include "libimobiledevice/service.h"
#include "libimobiledevice/lockdown.h"
-#include "idevice.h"
struct service_client_private {
idevice_connection_t connection;
diff --git a/src/syslog_relay.c b/src/syslog_relay.c
index c137297..9f4296e 100644
--- a/src/syslog_relay.c
+++ b/src/syslog_relay.c
@@ -67,7 +67,7 @@ static syslog_relay_error_t syslog_relay_error(service_error_t err)
return SYSLOG_RELAY_E_UNKNOWN_ERROR;
}
-LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, syslog_relay_client_t * client)
+syslog_relay_error_t syslog_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, syslog_relay_client_t * client)
{
*client = NULL;
@@ -95,14 +95,14 @@ LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_client_new(idevice_t devi
return 0;
}
-LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_client_start_service(idevice_t device, syslog_relay_client_t * client, const char* label)
+syslog_relay_error_t syslog_relay_client_start_service(idevice_t device, syslog_relay_client_t * client, const char* label)
{
syslog_relay_error_t err = SYSLOG_RELAY_E_UNKNOWN_ERROR;
service_client_factory_start_service(device, SYSLOG_RELAY_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(syslog_relay_client_new), &err);
return err;
}
-LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_client_free(syslog_relay_client_t client)
+syslog_relay_error_t syslog_relay_client_free(syslog_relay_client_t client)
{
if (!client)
return SYSLOG_RELAY_E_INVALID_ARG;
@@ -113,12 +113,12 @@ LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_client_free(syslog_relay_
return err;
}
-LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_receive(syslog_relay_client_t client, char* data, uint32_t size, uint32_t *received)
+syslog_relay_error_t syslog_relay_receive(syslog_relay_client_t client, char* data, uint32_t size, uint32_t *received)
{
return syslog_relay_receive_with_timeout(client, data, size, received, 1000);
}
-LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_receive_with_timeout(syslog_relay_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout)
+syslog_relay_error_t syslog_relay_receive_with_timeout(syslog_relay_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout)
{
syslog_relay_error_t res = SYSLOG_RELAY_E_UNKNOWN_ERROR;
int bytes = 0;
@@ -154,16 +154,15 @@ void *syslog_relay_worker(void *arg)
ret = syslog_relay_receive_with_timeout(srwt->client, &c, 1, &bytes, 100);
if (ret == SYSLOG_RELAY_E_TIMEOUT || ret == SYSLOG_RELAY_E_NOT_ENOUGH_DATA || ((bytes == 0) && (ret == SYSLOG_RELAY_E_SUCCESS))) {
continue;
- } else if (ret < 0) {
+ }
+ if (ret < 0) {
debug_info("Connection to syslog relay interrupted");
break;
}
if (srwt->is_raw) {
srwt->cbfunc(c, srwt->user_data);
- } else {
- if (c != 0) {
- srwt->cbfunc(c, srwt->user_data);
- }
+ } else if (c != 0) {
+ srwt->cbfunc(c, srwt->user_data);
}
}
@@ -176,7 +175,7 @@ void *syslog_relay_worker(void *arg)
return NULL;
}
-LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_start_capture(syslog_relay_client_t client, syslog_relay_receive_cb_t callback, void* user_data)
+syslog_relay_error_t syslog_relay_start_capture(syslog_relay_client_t client, syslog_relay_receive_cb_t callback, void* user_data)
{
if (!client || !callback)
return SYSLOG_RELAY_E_INVALID_ARG;
@@ -204,7 +203,7 @@ LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_start_capture(syslog_rela
return res;
}
-LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_start_capture_raw(syslog_relay_client_t client, syslog_relay_receive_cb_t callback, void* user_data)
+syslog_relay_error_t syslog_relay_start_capture_raw(syslog_relay_client_t client, syslog_relay_receive_cb_t callback, void* user_data)
{
if (!client || !callback)
return SYSLOG_RELAY_E_INVALID_ARG;
@@ -232,7 +231,7 @@ LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_start_capture_raw(syslog_
return res;
}
-LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_stop_capture(syslog_relay_client_t client)
+syslog_relay_error_t syslog_relay_stop_capture(syslog_relay_client_t client)
{
if (client->worker) {
/* notify thread to finish */
diff --git a/src/syslog_relay.h b/src/syslog_relay.h
index 3e48fa4..d5263e2 100644
--- a/src/syslog_relay.h
+++ b/src/syslog_relay.h
@@ -22,9 +22,10 @@
#ifndef _SYSLOG_RELAY_H
#define _SYSLOG_RELAY_H
+#include "idevice.h"
#include "libimobiledevice/syslog_relay.h"
#include "service.h"
-#include "common/thread.h"
+#include <libimobiledevice-glue/thread.h>
struct syslog_relay_client_private {
service_client_t parent;
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 8ed8ad9..4cac1fc 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -4,21 +4,15 @@ AM_CPPFLAGS = \
AM_CFLAGS = \
$(GLOBAL_CFLAGS) \
- $(libgnutls_CFLAGS) \
- $(libtasn1_CFLAGS) \
- $(libgcrypt_CFLAGS) \
- $(openssl_CFLAGS) \
+ $(ssl_lib_CFLAGS) \
$(libplist_CFLAGS) \
$(LFS_CFLAGS)
AM_LDFLAGS = \
- $(libgnutls_LIBS) \
- $(libtasn1_LIBS) \
- $(libgcrypt_LIBS) \
- $(openssl_LIBS) \
$(libplist_LIBS)
bin_PROGRAMS = \
+ idevicebtlogger\
idevice_id \
ideviceinfo \
idevicename \
@@ -34,13 +28,20 @@ bin_PROGRAMS = \
idevicedebugserverproxy \
idevicediagnostics \
idevicedebug \
+ idevicedevmodectl \
idevicenotificationproxy \
idevicecrashreport \
- idevicesetlocation
+ idevicesetlocation \
+ afcclient
+
+idevicebtlogger_SOURCES = idevicebtlogger.c
+iidevicebtlogger_CFLAGS = $(AM_CFLAGS)
+idevicebtlogger_LDFLAGS = $(top_builddir)/common/libinternalcommon.la $(AM_LDFLAGS)
+idevicebtlogger_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la
ideviceinfo_SOURCES = ideviceinfo.c
-ideviceinfo_CFLAGS = $(AM_CFLAGS)
-ideviceinfo_LDFLAGS = $(top_builddir)/common/libinternalcommon.la $(AM_LDFLAGS)
+ideviceinfo_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS)
+ideviceinfo_LDFLAGS = $(AM_LDFLAGS) $(limd_glue_LIBS)
ideviceinfo_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la
idevicename_SOURCES = idevicename.c
@@ -49,13 +50,13 @@ idevicename_LDFLAGS = $(AM_LDFLAGS)
idevicename_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la
idevicepair_SOURCES = idevicepair.c
-idevicepair_CFLAGS = -I$(top_srcdir) $(AM_CFLAGS)
-idevicepair_LDFLAGS = $(top_builddir)/common/libinternalcommon.la $(AM_LDFLAGS) $(libusbmuxd_LIBS)
-idevicepair_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la
+idevicepair_CFLAGS = $(AM_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)
idevicesyslog_SOURCES = idevicesyslog.c
-idevicesyslog_CFLAGS = $(AM_CFLAGS)
-idevicesyslog_LDFLAGS = $(AM_LDFLAGS)
+idevicesyslog_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS)
+idevicesyslog_LDFLAGS = $(AM_LDFLAGS) $(limd_glue_LIBS)
idevicesyslog_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la
idevice_id_SOURCES = idevice_id.c
@@ -64,18 +65,18 @@ idevice_id_LDFLAGS = $(AM_LDFLAGS)
idevice_id_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la
idevicebackup_SOURCES = idevicebackup.c
-idevicebackup_CFLAGS = $(AM_CFLAGS)
-idevicebackup_LDFLAGS = $(top_builddir)/common/libinternalcommon.la $(AM_LDFLAGS)
+idevicebackup_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS)
+idevicebackup_LDFLAGS = $(AM_LDFLAGS) $(ssl_lib_LIBS) $(limd_glue_LIBS)
idevicebackup_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la
idevicebackup2_SOURCES = idevicebackup2.c
-idevicebackup2_CFLAGS = $(AM_CFLAGS)
-idevicebackup2_LDFLAGS = $(top_builddir)/common/libinternalcommon.la $(AM_LDFLAGS)
+idevicebackup2_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS)
+idevicebackup2_LDFLAGS = $(AM_LDFLAGS) $(limd_glue_LIBS)
idevicebackup2_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la
ideviceimagemounter_SOURCES = ideviceimagemounter.c
-ideviceimagemounter_CFLAGS = $(AM_CFLAGS)
-ideviceimagemounter_LDFLAGS = $(top_builddir)/common/libinternalcommon.la $(AM_LDFLAGS)
+ideviceimagemounter_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS)
+ideviceimagemounter_LDFLAGS = $(AM_LDFLAGS) $(limd_glue_LIBS)
ideviceimagemounter_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la
idevicescreenshot_SOURCES = idevicescreenshot.c
@@ -94,13 +95,13 @@ idevicedate_LDFLAGS = $(AM_LDFLAGS)
idevicedate_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la
ideviceprovision_SOURCES = ideviceprovision.c
-ideviceprovision_CFLAGS = $(AM_CFLAGS)
-ideviceprovision_LDFLAGS = $(top_builddir)/common/libinternalcommon.la $(AM_LDFLAGS)
+ideviceprovision_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS)
+ideviceprovision_LDFLAGS = $(AM_LDFLAGS) $(limd_glue_LIBS)
ideviceprovision_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la
idevicedebugserverproxy_SOURCES = idevicedebugserverproxy.c
-idevicedebugserverproxy_CFLAGS = -I$(top_srcdir) $(AM_CFLAGS)
-idevicedebugserverproxy_LDFLAGS = $(top_builddir)/common/libinternalcommon.la $(AM_LDFLAGS)
+idevicedebugserverproxy_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS)
+idevicedebugserverproxy_LDFLAGS = $(AM_LDFLAGS) $(limd_glue_LIBS)
idevicedebugserverproxy_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la
idevicediagnostics_SOURCES = idevicediagnostics.c
@@ -109,9 +110,14 @@ idevicediagnostics_LDFLAGS = $(AM_LDFLAGS)
idevicediagnostics_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la
idevicedebug_SOURCES = idevicedebug.c
-idevicedebug_CFLAGS = $(AM_CFLAGS)
-idevicedebug_LDFLAGS = $(top_builddir)/common/libinternalcommon.la $(AM_LDFLAGS)
-idevicedebug_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la
+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)
@@ -119,11 +125,20 @@ idevicenotificationproxy_LDFLAGS = $(AM_LDFLAGS)
idevicenotificationproxy_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la
idevicecrashreport_SOURCES = idevicecrashreport.c
-idevicecrashreport_CFLAGS = -I$(top_srcdir) $(AM_CFLAGS)
-idevicecrashreport_LDFLAGS = $(top_builddir)/common/libinternalcommon.la $(AM_LDFLAGS)
+idevicecrashreport_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS)
+idevicecrashreport_LDFLAGS = $(AM_LDFLAGS) $(limd_glue_LIBS)
idevicecrashreport_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la
idevicesetlocation_SOURCES = idevicesetlocation.c
idevicesetlocation_CFLAGS = $(AM_CFLAGS)
-idevicesetlocation_LDFLAGS = $(top_builddir)/common/libinternalcommon.la $(AM_LDFLAGS)
+idevicesetlocation_LDFLAGS = $(AM_LDFLAGS)
idevicesetlocation_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la
+
+afcclient_SOURCES = afcclient.c
+afcclient_CFLAGS = $(AM_CFLAGS)
+afcclient_LDFLAGS = $(AM_LDFLAGS)
+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..9bcd77b
--- /dev/null
+++ b/tools/afcclient.c
@@ -0,0 +1,1346 @@
+/*
+ * 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>
+
+#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>
+
+#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 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 PATH [LOCALPATH] - transfer file at PATH from device to LOCALPATH\n");
+ printf("put 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)
+{
+ char **info = NULL;
+ afc_error_t err = afc_get_device_info(afc, &info);
+ if (err == AFC_E_SUCCESS && info) {
+ int i;
+ for (i = 0; info[i]; i += 2) {
+ printf("%s: %s\n", info[i], info[i+1]);
+ }
+ } else {
+ printf("Error: Failed to get device info: %s (%d)\n", afc_strerror(err), err);
+ }
+ afc_dictionary_free(info);
+}
+
+static int get_file_info_stat(afc_client_t afc, const char* path, struct afc_file_stat *stbuf)
+{
+ char **info = NULL;
+ afc_error_t ret = afc_get_file_info(afc, path, &info);
+ memset(stbuf, 0, sizeof(struct afc_file_stat));
+ if (ret != AFC_E_SUCCESS) {
+ return -1;
+ } else if (!info) {
+ return -1;
+ } else {
+ // get file attributes from info list
+ int i;
+ for (i = 0; info[i]; i += 2) {
+ if (!strcmp(info[i], "st_size")) {
+ stbuf->st_size = atoll(info[i+1]);
+ } else if (!strcmp(info[i], "st_blocks")) {
+ stbuf->st_blocks = atoi(info[i+1]);
+ } else if (!strcmp(info[i], "st_ifmt")) {
+ if (!strcmp(info[i+1], "S_IFREG")) {
+ stbuf->st_mode = S_IFREG;
+ } else if (!strcmp(info[i+1], "S_IFDIR")) {
+ stbuf->st_mode = S_IFDIR;
+ } else if (!strcmp(info[i+1], "S_IFLNK")) {
+ stbuf->st_mode = S_IFLNK;
+ } else if (!strcmp(info[i+1], "S_IFBLK")) {
+ stbuf->st_mode = S_IFBLK;
+ } else if (!strcmp(info[i+1], "S_IFCHR")) {
+ stbuf->st_mode = S_IFCHR;
+ } else if (!strcmp(info[i+1], "S_IFIFO")) {
+ stbuf->st_mode = S_IFIFO;
+ } else if (!strcmp(info[i+1], "S_IFSOCK")) {
+ stbuf->st_mode = S_IFSOCK;
+ }
+ } else if (!strcmp(info[i], "st_nlink")) {
+ stbuf->st_nlink = atoi(info[i+1]);
+ } else if (!strcmp(info[i], "st_mtime")) {
+ stbuf->st_mtime = (time_t)(atoll(info[i+1]) / 1000000000);
+ } else if (!strcmp(info[i], "st_birthtime")) { /* available on iOS 7+ */
+ stbuf->st_birthtime = (time_t)(atoll(info[i+1]) / 1000000000);
+ }
+ }
+ afc_dictionary_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;
+ }
+
+ char **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(afc, abspath, &info);
+ if (err == AFC_E_SUCCESS && info) {
+ int i;
+ for (i = 0; info[i]; i += 2) {
+ printf("%s: %s\n", info[i], info[i+1]);
+ }
+ } else {
+ printf("Error: Failed to get file info for %s: %s (%d)\n", argv[0], afc_strerror(err), err);
+ }
+ afc_dictionary_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 void handle_get(afc_client_t afc, int argc, char** argv)
+{
+ if (argc < 1 || argc > 2) {
+ printf("Error: Invalid number of arguments\n");
+ return;
+ }
+ char *srcpath = NULL;
+ char* dstpath = NULL;
+ if (argc == 1) {
+ srcpath = get_absolute_path(argv[0]);
+ dstpath = strdup(path_get_basename(argv[0]));
+ } else {
+ srcpath = get_absolute_path(argv[0]);
+ dstpath = strdup(argv[1]);
+ }
+
+ char **info = NULL;
+ uint64_t file_size = 0;
+ afc_get_file_info(afc, srcpath, &info);
+ if (info) {
+ char **p = info;
+ while (p && *p) {
+ if (!strcmp(*p, "st_size")) {
+ p++;
+ file_size = (uint64_t)strtoull(*p, NULL, 10);
+ break;
+ }
+ p++;
+ }
+ }
+ uint64_t fh = 0;
+ afc_error_t err = afc_file_open(afc, srcpath, AFC_FOPEN_RDONLY, &fh);
+ if (err != AFC_E_SUCCESS) {
+ free(srcpath);
+ free(dstpath);
+ printf("Error: Failed to open file '%s': %s (%d)\n", argv[0], afc_strerror(err), err);
+ return;
+ }
+ FILE *f = fopen(dstpath, "wb");
+ if (!f && errno == EISDIR) {
+ const char* basen = path_get_basename(argv[0]);
+ size_t len = strlen(dstpath) + 1 + strlen(basen) + 1;
+ char* newdst = (char*)malloc(len);
+ snprintf(newdst, len, "%s/%s", dstpath, basen);
+ f = fopen(newdst, "wb");
+ free(newdst);
+ }
+ if (f) {
+ 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);
+ }
+ 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");
+ 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", argv[0], afc_strerror(err), err);
+ }
+ free(buf);
+ fclose(f);
+ } else {
+ printf("Error: Failed to open local file '%s': %s\n", dstpath, strerror(errno));
+ }
+ afc_file_close(afc, fh);
+ free(srcpath);
+}
+
+static void handle_put(afc_client_t afc, int argc, char** argv)
+{
+ if (argc < 1 || argc > 2) {
+ printf("Error: Invalid number of arguments\n");
+ return;
+ }
+
+ char *dstpath = NULL;
+ if (argc == 1) {
+ dstpath = get_absolute_path(path_get_basename(argv[0]));
+ } else {
+ dstpath = get_absolute_path(argv[1]);
+ }
+
+ uint64_t fh = 0;
+ FILE *f = fopen(argv[0], "rb");
+ if (f) {
+ afc_error_t err = afc_file_open(afc, dstpath, AFC_FOPEN_RW, &fh);
+ if (err == AFC_E_OBJECT_IS_DIR) {
+ const char* basen = path_get_basename(argv[0]);
+ size_t len = strlen(dstpath) + 1 + strlen(basen) + 1;
+ char* newdst = (char*)malloc(len);
+ snprintf(newdst, len, "%s/%s", dstpath, basen);
+ free(dstpath);
+ dstpath = get_absolute_path(newdst);
+ free(newdst);
+ err = afc_file_open(afc, dstpath, AFC_FOPEN_RW, &fh);
+ }
+ if (err != AFC_E_SUCCESS) {
+ printf("Error: Failed to open file '%s' on device: %s (%d)\n", argv[1], afc_strerror(err), err);
+ } else {
+ 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;
+ 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");
+ }
+ 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");
+ 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;
+ }
+ }
+ }
+ printf("\n");
+ free(buf);
+ afc_file_close(afc, fh);
+ }
+ fclose(f);
+ } else {
+ printf("Error: Failed to open local file '%s': %s\n", argv[0], strerror(errno));
+ }
+ 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;
+ char **info = NULL;
+ afc_error_t err = afc_get_file_info(afc, path, &info);
+ if (err == AFC_E_SUCCESS && info) {
+ int i;
+ for (i = 0; info[i]; i += 2) {
+ if (!strcmp(info[i], "st_ifmt")) {
+ if (!strcmp(info[i+1], "S_IFDIR")) {
+ is_dir = 1;
+ }
+ break;
+ }
+ }
+ afc_dictionary_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/idevice_id.c b/tools/idevice_id.c
index 98fd22d..540a6f2 100644
--- a/tools/idevice_id.c
+++ b/tools/idevice_id.c
@@ -38,24 +38,23 @@
static void print_usage(int argc, char **argv, int is_error)
{
- char *name = NULL;
- name = strrchr(argv[0], '/');
+ char *name = strrchr(argv[0], '/');
fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS] [UDID]\n", (name ? name + 1: argv[0]));
fprintf(is_error ? stderr : stdout,
+ "\n"
+ "List attached devices or print device name of given device.\n"
"\n" \
- "List attached devices or print device name of given device.\n" \
+ " If UDID is given, the name of the connected device with that UDID"
+ " will be retrieved.\n"
"\n" \
- " If UDID is given, the name of the connected device with that UDID" \
- " will be retrieved.\n" \
- "\n" \
- "OPTIONS:\n" \
- " -l, --list list UDIDs of all devices attached via USB\n" \
- " -n, --network list UDIDs of all devices available via network\n" \
- " -d, --debug enable communication debugging\n" \
- " -h, --help prints usage information\n" \
- " -v, --version prints version information\n" \
- "\n" \
- "Homepage: <" PACKAGE_URL ">\n" \
+ "OPTIONS:\n"
+ " -l, --list list UDIDs of all devices attached via USB\n"
+ " -n, --network list UDIDs of all devices available via network\n"
+ " -d, --debug enable communication debugging\n"
+ " -h, --help prints usage information\n"
+ " -v, --version prints version information\n"
+ "\n"
+ "Homepage: <" PACKAGE_URL ">\n"
"Bug Reports: <" PACKAGE_BUGREPORT ">\n"
);
}
diff --git a/tools/idevicebackup.c b/tools/idevicebackup.c
index dfd7b8b..5694c12 100644
--- a/tools/idevicebackup.c
+++ b/tools/idevicebackup.c
@@ -31,10 +31,24 @@
#include <errno.h>
#include <stdlib.h>
#include <signal.h>
-#ifdef HAVE_OPENSSL
+#include <getopt.h>
+#if defined(HAVE_OPENSSL)
#include <openssl/sha.h>
-#else
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/evp.h>
+#endif
+#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>
@@ -45,7 +59,8 @@
#include <libimobiledevice/mobilebackup.h>
#include <libimobiledevice/notification_proxy.h>
#include <libimobiledevice/afc.h>
-#include "common/utils.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"
@@ -78,10 +93,12 @@ enum device_link_file_status_t {
static void sha1_of_data(const char *input, uint32_t size, unsigned char *hash_out)
{
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL)
SHA1((const unsigned char*)input, size, hash_out);
-#else
+#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
}
@@ -96,12 +113,34 @@ 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)
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_DigestUpdate(context, data, len);
+#else
+ SHA1_Update(context, data, len);
+#endif
+#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)
{
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL)
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_MD_CTX* sha1 = EVP_MD_CTX_new();
+ EVP_DigestInit(sha1, EVP_sha1());
+ void* psha1 = sha1;
+#else
SHA_CTX sha1;
SHA1_Init(&sha1);
-#else
+ void* psha1 = &sha1;
+#endif
+#elif defined(HAVE_GNUTLS)
gcry_md_hd_t hd = NULL;
gcry_md_open(&hd, GCRY_MD_SHA1, 0);
if (!hd) {
@@ -109,102 +148,68 @@ static void compute_datahash(const char *path, const char *destpath, uint8_t gre
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
FILE *f = fopen(path, "rb");
if (f) {
unsigned char buf[16384];
size_t len;
while ((len = fread(buf, 1, 16384, f)) > 0) {
-#ifdef HAVE_OPENSSL
- SHA1_Update(&sha1, buf, len);
-#else
- gcry_md_write(hd, buf, len);
-#endif
+ _sha1_update(psha1, (const char*)buf, len);
}
fclose(f);
-#ifdef HAVE_OPENSSL
- SHA1_Update(&sha1, destpath, strlen(destpath));
- SHA1_Update(&sha1, ";", 1);
-#else
- gcry_md_write(hd, destpath, strlen(destpath));
- gcry_md_write(hd, ";", 1);
-#endif
+ _sha1_update(psha1, destpath, strlen(destpath));
+ _sha1_update(psha1, ";", 1);
+
if (greylist == 1) {
-#ifdef HAVE_OPENSSL
- SHA1_Update(&sha1, "true", 4);
-#else
- gcry_md_write(hd, "true", 4);
-#endif
+ _sha1_update(psha1, "true", 4);
} else {
-#ifdef HAVE_OPENSSL
- SHA1_Update(&sha1, "false", 5);
-#else
- gcry_md_write(hd, "false", 5);
-#endif
+ _sha1_update(psha1, "false", 5);
}
-#ifdef HAVE_OPENSSL
- SHA1_Update(&sha1, ";", 1);
-#else
- gcry_md_write(hd, ";", 1);
-#endif
+ _sha1_update(psha1, ";", 1);
+
if (domain) {
-#ifdef HAVE_OPENSSL
- SHA1_Update(&sha1, domain, strlen(domain));
-#else
- gcry_md_write(hd, domain, strlen(domain));
-#endif
+ _sha1_update(psha1, domain, strlen(domain));
} else {
-#ifdef HAVE_OPENSSL
- SHA1_Update(&sha1, "(null)", 6);
-#else
- gcry_md_write(hd, "(null)", 6);
-#endif
+ _sha1_update(psha1, "(null)", 6);
}
-#ifdef HAVE_OPENSSL
- SHA1_Update(&sha1, ";", 1);
-#else
- gcry_md_write(hd, ";", 1);
-#endif
+ _sha1_update(psha1, ";", 1);
+
if (appid) {
-#ifdef HAVE_OPENSSL
- SHA1_Update(&sha1, appid, strlen(appid));
-#else
- gcry_md_write(hd, appid, strlen(appid));
-#endif
+ _sha1_update(psha1, appid, strlen(appid));
} else {
-#ifdef HAVE_OPENSSL
- SHA1_Update(&sha1, "(null)", 6);
-#else
- gcry_md_write(hd, "(null)", 6);
-#endif
+ _sha1_update(psha1, "(null)", 6);
}
-#ifdef HAVE_OPENSSL
- SHA1_Update(&sha1, ";", 1);
-#else
- gcry_md_write(hd, ";", 1);
-#endif
+ _sha1_update(psha1, ";", 1);
+
if (version) {
-#ifdef HAVE_OPENSSL
- SHA1_Update(&sha1, version, strlen(version));
-#else
- gcry_md_write(hd, version, strlen(version));
-#endif
+ _sha1_update(psha1, version, strlen(version));
} else {
-#ifdef HAVE_OPENSSL
- SHA1_Update(&sha1, "(null)", 6);
-#else
- gcry_md_write(hd, "(null)", 6);
-#endif
+ _sha1_update(psha1, "(null)", 6);
}
-#ifdef HAVE_OPENSSL
- SHA1_Final(hash_out, &sha1);
+#if defined(HAVE_OPENSSL)
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_DigestFinal(sha1, hash_out, NULL);
+ EVP_MD_CTX_destroy(sha1);
#else
+ SHA1_Final(hash_out, &sha1);
+#endif
+#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
}
-#ifndef HAVE_OPENSSL
+#if defined(HAVE_GNUTLS)
gcry_md_close(hd);
+#elif defined(HAVE_MBEDTLS)
+ mbedtls_sha1_free(&sha1);
#endif
}
@@ -331,7 +336,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;
@@ -345,7 +350,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");
@@ -468,7 +473,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");
@@ -548,7 +553,7 @@ static int mobilebackup_check_file_integrity(const char *backup_directory, const
for ( i = 0; i < 20; i++, p += 2 ) {
snprintf (p, 3, "%02x", (unsigned char)fnhash[i] );
}
- if (strcmp(fnamehash, hash)) {
+ if (strcmp(fnamehash, hash) != 0) {
printf("\r\n");
printf("WARNING: filename hash does not match for entry '%s'\n", hash);
}
@@ -559,7 +564,7 @@ static int mobilebackup_check_file_integrity(const char *backup_directory, const
plist_get_string_val(node, &auth_version);
}
- if (strcmp(auth_version, "1.0")) {
+ if (strcmp(auth_version, "1.0") != 0) {
printf("\r\n");
printf("WARNING: Unknown AuthVersion '%s', DataHash cannot be verified!\n", auth_version);
}
@@ -613,15 +618,15 @@ static void do_post_notification(const char *notification)
}
}
- lockdownd_start_service(client, NP_SERVICE_NAME, &service);
- if (service && service->port) {
+ lockdownd_error_t ldret = lockdownd_start_service(client, NP_SERVICE_NAME, &service);
+ if (ldret == LOCKDOWN_E_SUCCESS) {
np_client_new(device, service, &np);
if (np) {
np_post_notification(np, notification);
np_client_free(np);
}
} else {
- printf("Could not start %s\n", NP_SERVICE_NAME);
+ printf("Could not start %s: %s\n", NP_SERVICE_NAME, lockdownd_strerror(ldret));
}
if (service) {
@@ -662,27 +667,28 @@ static void clean_exit(int sig)
quit_flag++;
}
-static void print_usage(int argc, char **argv)
+static void print_usage(int argc, char **argv, int is_error)
{
- char *name = NULL;
- name = strrchr(argv[0], '/');
- printf("Usage: %s [OPTIONS] CMD [DIRECTORY]\n", (name ? name + 1: argv[0]));
- printf("\n");
- printf("Create or restore backup from the current or specified directory.\n");
- printf("\n");
- printf("CMD:\n");
- printf(" backup\tSaves a device backup into DIRECTORY\n");
- printf(" restore\tRestores a device backup from DIRECTORY.\n");
- printf("\n");
- printf("OPTIONS:\n");
- printf(" -u, --udid UDID\ttarget specific device by UDID\n");
- printf(" -n, --network\t\tconnect to network device\n");
- printf(" -d, --debug\t\tenable communication debugging\n");
- printf(" -h, --help\t\tprints usage information\n");
- printf(" -v, --version\t\tprints version information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\n");
- printf("Bug Reports: <" PACKAGE_BUGREPORT ">\n");
+ char *name = strrchr(argv[0], '/');
+ fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS] CMD DIRECTORY\n", (name ? name + 1: argv[0]));
+ fprintf(is_error ? stderr : stdout,
+ "\n"
+ "Create or restore backup in/from the specified directory.\n"
+ "\n"
+ "CMD:\n"
+ " backup Saves a device backup into DIRECTORY\n"
+ " restore Restores a device backup from DIRECTORY.\n"
+ "\n"
+ "OPTIONS:\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 prints usage information\n"
+ " -v, --version prints version information\n"
+ "\n"
+ "Homepage: <" PACKAGE_URL ">\n"
+ "Bug Reports: <" PACKAGE_BUGREPORT ">\n"
+ );
}
int main(int argc, char *argv[])
@@ -706,7 +712,15 @@ int main(int argc, char *argv[])
uint64_t length = 0;
uint64_t backup_total_size = 0;
enum device_link_file_status_t file_status = DEVICE_LINK_FILE_STATUS_NONE;
- uint64_t c = 0;
+ 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}
+ };
/* we need to exit cleanly on running backups and restores or we cause havok */
signal(SIGINT, clean_exit);
@@ -717,59 +731,58 @@ int main(int argc, char *argv[])
#endif
/* parse cmdline args */
- for (i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) {
+ while ((c = getopt_long(argc, argv, "dhu:nv", longopts, NULL)) != -1) {
+ switch (c) {
+ case 'd':
idevice_set_debug_level(1);
- continue;
- }
- else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--udid")) {
- i++;
- if (!argv[i] || !*argv[i]) {
- print_usage(argc, argv);
- return 0;
+ break;
+ case 'u':
+ if (!*optarg) {
+ fprintf(stderr, "ERROR: UDID must not be empty!\n");
+ print_usage(argc, argv, 1);
+ return 2;
}
- udid = strdup(argv[i]);
- continue;
- }
- else if (!strcmp(argv[i], "-n") || !strcmp(argv[i], "--network")) {
+ udid = strdup(optarg);
+ break;
+ case 'n':
use_network = 1;
- continue;
- }
- else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
- print_usage(argc, argv);
+ break;
+ case 'h':
+ print_usage(argc, argv, 0);
return 0;
- }
- else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
+ case 'v':
printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION);
return 0;
- }
- else if (!strcmp(argv[i], "backup")) {
- cmd = CMD_BACKUP;
- }
- else if (!strcmp(argv[i], "restore")) {
- cmd = CMD_RESTORE;
- }
- else if (backup_directory == NULL) {
- backup_directory = argv[i];
- }
- else {
- print_usage(argc, argv);
- return 0;
+ default:
+ print_usage(argc, argv, 1);
+ return 2;
}
}
+ argc -= optind;
+ argv += optind;
- /* verify options */
- if (cmd == -1) {
- printf("No command specified.\n");
- print_usage(argc, argv);
- return -1;
+ if (argc < 1) {
+ fprintf(stderr, "ERROR: Missing command.\n");
+ print_usage(argc+optind, argv-optind, 1);
+ return 2;
}
- if (backup_directory == NULL) {
- printf("No target backup directory specified.\n");
- print_usage(argc, argv);
- return -1;
+ if (!strcmp(argv[0], "backup")) {
+ cmd = CMD_BACKUP;
+ } else if (!strcmp(argv[0], "restore")) {
+ cmd = CMD_RESTORE;
+ } else {
+ fprintf(stderr, "ERROR: Invalid command '%s'.\n", argv[0]);
+ print_usage(argc+optind, argv-optind, 1);
+ return 2;
+ }
+
+ if (argc < 2) {
+ fprintf(stderr, "No target backup directory specified.\n");
+ print_usage(argc+optind, argv-optind, 1);
+ return 2;
}
+ backup_directory = argv[1];
/* verify if passed backup directory exists */
if (stat(backup_directory, &st) != 0) {
@@ -799,9 +812,14 @@ int main(int argc, char *argv[])
return -1;
}
+ if (!udid) {
+ idevice_get_udid(device, &udid);
+ }
+
if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &client, TOOL_NAME))) {
printf("ERROR: Could not connect to lockdownd, error code %d\n", ldret);
idevice_free(device);
+ free(udid);
return -1;
}
@@ -821,6 +839,7 @@ int main(int argc, char *argv[])
printf("ERROR: This tool is only compatible with iOS 3 or below. For newer iOS versions please use the idevicebackup2 tool.\n");
lockdownd_client_free(client);
idevice_free(device);
+ free(udid);
return -1;
}
}
@@ -841,7 +860,7 @@ int main(int argc, char *argv[])
};
np_observe_notifications(np, noties);
} else {
- printf("ERROR: Could not start service %s.\n", NP_SERVICE_NAME);
+ printf("ERROR: Could not start service %s: %s\n", NP_SERVICE_NAME, lockdownd_strerror(ldret));
}
afc_client_t afc = NULL;
@@ -849,9 +868,11 @@ int main(int argc, char *argv[])
/* start AFC, we need this for the lock file */
service->port = 0;
service->ssl_enabled = 0;
- ldret = lockdownd_start_service(client, "com.apple.afc", &service);
+ ldret = lockdownd_start_service(client, AFC_SERVICE_NAME, &service);
if ((ldret == LOCKDOWN_E_SUCCESS) && service->port) {
afc_client_new(device, service, &afc);
+ } else {
+ printf("ERROR: Could not start service %s: %s\n", AFC_SERVICE_NAME, lockdownd_strerror(ldret));
}
}
@@ -864,7 +885,7 @@ int main(int argc, char *argv[])
ldret = lockdownd_start_service(client, MOBILEBACKUP_SERVICE_NAME, &service);
if ((ldret == LOCKDOWN_E_SUCCESS) && service && service->port) {
printf("Started \"%s\" service on port %d.\n", MOBILEBACKUP_SERVICE_NAME, service->port);
- mobilebackup_client_new(device, service, &mobilebackup);
+ printf("%d\n", mobilebackup_client_new(device, service, &mobilebackup));
if (service) {
lockdownd_service_descriptor_free(service);
@@ -880,7 +901,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");
@@ -891,7 +912,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;
@@ -924,15 +945,16 @@ int main(int argc, char *argv[])
if (aerr == AFC_E_SUCCESS) {
do_post_notification(NP_SYNC_DID_START);
break;
- } else if (aerr == AFC_E_OP_WOULD_BLOCK) {
+ }
+ if (aerr == AFC_E_OP_WOULD_BLOCK) {
usleep(LOCK_WAIT);
continue;
- } else {
- fprintf(stderr, "ERROR: could not lock file! error code: %d\n", aerr);
- afc_file_close(afc, lockfile);
- lockfile = 0;
- cmd = CMD_LEAVE;
}
+
+ fprintf(stderr, "ERROR: could not lock file! error code: %d\n", aerr);
+ afc_file_close(afc, lockfile);
+ lockfile = 0;
+ cmd = CMD_LEAVE;
}
if (i == LOCK_ATTEMPTS) {
fprintf(stderr, "ERROR: timeout while locking for sync\n");
@@ -956,7 +978,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;
@@ -974,7 +996,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);
@@ -1006,7 +1028,7 @@ int main(int argc, char *argv[])
} else if (err == MOBILEBACKUP_E_REPLY_NOT_OK) {
printf("ERROR: Could not start backup process: device refused to start the backup process.\n");
} else {
- printf("ERROR: Could not start backup process: unspecified error occurred\n");
+ printf("ERROR: Could not start backup process: unspecified error occurred (%d)\n", err);
}
break;
}
@@ -1028,6 +1050,7 @@ int main(int argc, char *argv[])
char *format_size = NULL;
int is_manifest = 0;
uint8_t b = 0;
+ uint64_t u64val = 0;
/* process series of DLSendFile messages */
do {
@@ -1059,8 +1082,8 @@ int main(int argc, char *argv[])
/* check DLFileStatusKey (codes: 1 = Hunk, 2 = Last Hunk) */
node = plist_dict_get_item(node_tmp, "DLFileStatusKey");
- plist_get_uint_val(node, &c);
- file_status = c;
+ plist_get_uint_val(node, &u64val);
+ file_status = u64val;
/* get source filename */
node = plist_dict_get_item(node_tmp, "BackupManifestKey");
@@ -1112,7 +1135,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);
}
@@ -1154,9 +1177,8 @@ int main(int argc, char *argv[])
if ((!is_manifest)) {
if (hunk_index == 0 && file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) {
print_progress(100);
- } else {
- if (file_size > 0)
- print_progress((double)((file_size_current*100)/file_size));
+ } else if (file_size > 0) {
+ print_progress((double)(file_size_current*100)/file_size);
}
}
@@ -1225,7 +1247,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;
@@ -1256,7 +1278,7 @@ 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;
@@ -1383,7 +1405,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");
@@ -1603,7 +1625,7 @@ files_out:
if (manifest_path)
free(manifest_path);
} else {
- printf("ERROR: Could not start service %s.\n", MOBILEBACKUP_SERVICE_NAME);
+ printf("ERROR: Could not start service %s: %s\n", MOBILEBACKUP_SERVICE_NAME, lockdownd_strerror(ldret));
lockdownd_client_free(client);
client = NULL;
}
@@ -1624,9 +1646,7 @@ files_out:
idevice_free(device);
- if (udid) {
- free(udid);
- }
+ free(udid);
return 0;
}
diff --git a/tools/idevicebackup2.c b/tools/idevicebackup2.c
index 068420d..c73b269 100644
--- a/tools/idevicebackup2.c
+++ b/tools/idevicebackup2.c
@@ -2,7 +2,7 @@
* idevicebackup2.c
* Command line interface to use the device's backup and restore service
*
- * Copyright (c) 2010-2019 Nikias Bassen, All Rights Reserved.
+ * Copyright (c) 2010-2022 Nikias Bassen, All Rights Reserved.
* Copyright (c) 2009-2010 Martin Szulecki, All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
@@ -36,6 +36,7 @@
#include <libgen.h>
#include <ctype.h>
#include <time.h>
+#include <getopt.h>
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
@@ -45,7 +46,8 @@
#include <libimobiledevice/installation_proxy.h>
#include <libimobiledevice/sbservices.h>
#include <libimobiledevice/diagnostics_relay.h>
-#include "common/utils.h"
+#include <libimobiledevice-glue/utils.h>
+#include <plist/plist.h>
#include <endianness.h>
@@ -183,9 +185,8 @@ static int mkdir_with_parents(const char *dir, int mode)
if (!dir) return -1;
if (__mkdir(dir, mode) == 0) {
return 0;
- } else {
- if (errno == EEXIST) return 0;
}
+ if (errno == EEXIST) return 0;
int res;
char *parent = strdup(dir);
char *parentdir = dirname(parent);
@@ -606,7 +607,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");
@@ -638,15 +639,15 @@ static void do_post_notification(idevice_t device, const char *notification)
return;
}
- lockdownd_start_service(lockdown, NP_SERVICE_NAME, &service);
- if (service && service->port) {
+ lockdownd_error_t ldret = lockdownd_start_service(lockdown, NP_SERVICE_NAME, &service);
+ if (ldret == LOCKDOWN_E_SUCCESS) {
np_client_new(device, service, &np);
if (np) {
np_post_notification(np, notification);
np_client_free(np);
}
} else {
- printf("Could not start %s\n", NP_SERVICE_NAME);
+ printf("ERROR: Could not start service %s: %s\n", NP_SERVICE_NAME, lockdownd_strerror(ldret));
}
if (service) {
@@ -972,10 +973,12 @@ static int mb2_receive_filename(mobilebackup2_client_t mobilebackup2, char** fil
if ((nlen == 0) && (rlen == 4)) {
// a zero length means no more files to receive
return 0;
- } else if(rlen == 0) {
+ }
+ if (rlen == 0) {
// device needs more time, waiting...
continue;
- } else if (nlen > 4096) {
+ }
+ if (nlen > 4096) {
// filename length is too large
printf("ERROR: %s: too large filename length (%d)!\n", __func__, nlen);
return 0;
@@ -1367,7 +1370,8 @@ static void get_hidden_input(char *buf, int maxlen)
while ((c = my_getch())) {
if ((c == '\r') || (c == '\n')) {
break;
- } else if (isprint(c)) {
+ }
+ if (isprint(c)) {
if (pwlen < maxlen-1)
buf[pwlen++] = c;
fputc('*', stderr);
@@ -1415,54 +1419,57 @@ static void clean_exit(int sig)
quit_flag++;
}
-static void print_usage(int argc, char **argv)
+static void print_usage(int argc, char **argv, int is_error)
{
- char *name = NULL;
- name = strrchr(argv[0], '/');
- printf("Usage: %s [OPTIONS] CMD [CMDOPTIONS] DIRECTORY\n", (name ? name + 1: argv[0]));
- printf("\n");
- printf("Create or restore backup from the current or specified directory.\n");
- printf("\n");
- printf("CMD:\n");
- printf(" backup\tcreate backup for the device\n");
- printf(" --full\t\tforce full backup from device.\n");
- printf(" restore\trestore last backup to the device\n");
- printf(" --system\t\trestore system files, too.\n");
- printf(" --no-reboot\t\tdo NOT reboot the device when done (default: yes).\n");
- printf(" --copy\t\tcreate a copy of backup folder before restoring.\n");
- printf(" --settings\t\trestore device settings from the backup.\n");
- printf(" --remove\t\tremove items which are not being restored\n");
- printf(" --skip-apps\t\tdo not trigger re-installation of apps after restore\n");
- printf(" --password PWD\tsupply the password of the source backup\n");
- printf(" info\t\tshow details about last completed backup of device\n");
- printf(" list\t\tlist files of last completed backup in CSV format\n");
- printf(" unback\tunpack a completed backup in DIRECTORY/_unback_/\n");
- printf(" encryption on|off [PWD]\tenable or disable backup encryption\n");
- printf(" NOTE: password will be requested in interactive mode if omitted\n");
- printf(" changepw [OLD NEW] change backup password on target device\n");
- printf(" NOTE: passwords will be requested in interactive mode if omitted\n");
- printf(" cloud on|off\tenable or disable cloud use (requires iCloud account)\n");
- printf("\n");
- printf("OPTIONS:\n");
- printf(" -u, --udid UDID\ttarget specific device by UDID\n");
- printf(" -s, --source UDID\tuse backup data from device specified by UDID\n");
- printf(" -n, --network\t\tconnect to network device\n");
- printf(" -i, --interactive\trequest passwords interactively\n");
- printf(" -d, --debug\t\tenable communication debugging\n");
- printf(" -h, --help\t\tprints usage information\n");
- printf(" -v, --version\t\tprints version information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\n");
- printf("Bug Reports: <" PACKAGE_BUGREPORT ">\n");
+ char *name = strrchr(argv[0], '/');
+ fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS] CMD [CMDOPTIONS] DIRECTORY\n", (name ? name + 1: argv[0]));
+ fprintf(is_error ? stderr : stdout,
+ "\n"
+ "Create or restore backup in/from the specified directory.\n"
+ "\n"
+ "CMD:\n"
+ " backup create backup for the device\n"
+ " --full force full backup from device.\n"
+ " restore restore last backup to the device\n"
+ " --system restore system files, too.\n"
+ " --no-reboot do NOT reboot the device when done (default: yes).\n"
+ " --copy create a copy of backup folder before restoring.\n"
+ " --settings restore device settings from the backup.\n"
+ " --remove remove items which are not being restored\n"
+ " --skip-apps do not trigger re-installation of apps after restore\n"
+ " --password PWD supply the password for the encrypted source backup\n"
+ " info show details about last completed backup of device\n"
+ " list list files of last completed backup in CSV format\n"
+ " unback unpack a completed backup in DIRECTORY/_unback_/\n"
+ " encryption on|off [PWD] enable or disable backup encryption\n"
+ " changepw [OLD NEW] change backup password on target device\n"
+ " cloud on|off enable or disable cloud use (requires iCloud account)\n"
+ "\n"
+ "NOTE: Passwords will be requested in interactive mode (-i) if omitted, or can\n"
+ "be passed via environment variable BACKUP_PASSWORD/BACKUP_PASSWORD_NEW.\n"
+ "See man page for further details.\n"
+ "\n"
+ "OPTIONS:\n"
+ " -u, --udid UDID target specific device by UDID\n"
+ " -s, --source UDID use backup data from device specified by UDID\n"
+ " -n, --network connect to network device\n"
+ " -i, --interactive request passwords interactively\n"
+ " -d, --debug enable communication debugging\n"
+ " -h, --help prints usage information\n"
+ " -v, --version prints version information\n"
+ "\n"
+ "Homepage: <" PACKAGE_URL ">\n"
+ "Bug Reports: <" PACKAGE_BUGREPORT ">\n"
+ );
}
-#define DEVICE_VERSION(maj, min, patch) (((maj & 0xFF) << 16) | ((min & 0xFF) << 8) | (patch & 0xFF))
+#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;
lockdownd_error_t ldret = LOCKDOWN_E_UNKNOWN_ERROR;
- int i;
+ int i = 0;
char* udid = NULL;
char* source_udid = NULL;
int use_network = 0;
@@ -1479,7 +1486,46 @@ int main(int argc, char *argv[])
plist_t node_tmp = NULL;
plist_t info_plist = NULL;
plist_t opts = NULL;
+
+ idevice_t device = NULL;
+ afc_client_t afc = NULL;
+ np_client_t np = NULL;
+ lockdownd_client_t lockdown = NULL;
+ mobilebackup2_client_t mobilebackup2 = NULL;
mobilebackup2_error_t err;
+ uint64_t lockfile = 0;
+
+#define OPT_SYSTEM 1
+#define OPT_REBOOT 2
+#define OPT_NO_REBOOT 3
+#define OPT_COPY 4
+#define OPT_SETTINGS 5
+#define OPT_REMOVE 6
+#define OPT_SKIP_APPS 7
+#define OPT_PASSWORD 8
+#define OPT_FULL 9
+
+ int c = 0;
+ const struct option longopts[] = {
+ { "debug", no_argument, NULL, 'd' },
+ { "help", no_argument, NULL, 'h' },
+ { "udid", required_argument, NULL, 'u' },
+ { "source", required_argument, NULL, 's' },
+ { "interactive", no_argument, NULL, 'i' },
+ { "network", no_argument, NULL, 'n' },
+ { "version", no_argument, NULL, 'v' },
+ // command options:
+ { "system", no_argument, NULL, OPT_SYSTEM },
+ { "reboot", no_argument, NULL, OPT_REBOOT },
+ { "no-reboot", no_argument, NULL, OPT_NO_REBOOT },
+ { "copy", no_argument, NULL, OPT_COPY },
+ { "settings", no_argument, NULL, OPT_SETTINGS },
+ { "remove", no_argument, NULL, OPT_REMOVE },
+ { "skip-apps", no_argument, NULL, OPT_SKIP_APPS },
+ { "password", required_argument, NULL, OPT_PASSWORD },
+ { "full", no_argument, NULL, OPT_FULL },
+ { NULL, 0, NULL, 0}
+ };
/* we need to exit cleanly on running backups and restores or we cause havok */
signal(SIGINT, clean_exit);
@@ -1490,206 +1536,196 @@ int main(int argc, char *argv[])
#endif
/* parse cmdline args */
- for (i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) {
+ while ((c = getopt_long(argc, argv, "dhu:s:inv", longopts, NULL)) != -1) {
+ switch (c) {
+ case 'd':
idevice_set_debug_level(1);
- continue;
- }
- else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--udid")) {
- i++;
- if (!argv[i] || !*argv[i]) {
- print_usage(argc, argv);
- return -1;
+ break;
+ case 'u':
+ if (!*optarg) {
+ fprintf(stderr, "ERROR: UDID argument must not be empty!\n");
+ print_usage(argc, argv, 1);
+ return 2;
}
- udid = strdup(argv[i]);
- continue;
- }
- else if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--source")) {
- i++;
- if (!argv[i] || !*argv[i]) {
- print_usage(argc, argv);
- return -1;
+ udid = strdup(optarg);
+ break;
+ case 's':
+ if (!*optarg) {
+ fprintf(stderr, "ERROR: SOURCE argument must not be empty!\n");
+ print_usage(argc, argv, 1);
+ return 2;
}
- source_udid = strdup(argv[i]);
- continue;
- }
- else if (!strcmp(argv[i], "-n") || !strcmp(argv[i], "--network")) {
- use_network = 1;
- continue;
- }
- else if (!strcmp(argv[i], "-i") || !strcmp(argv[i], "--interactive")) {
+ source_udid = strdup(optarg);
+ break;
+ case 'i':
interactive_mode = 1;
- continue;
- }
- else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
- print_usage(argc, argv);
+ break;
+ case 'n':
+ use_network = 1;
+ break;
+ case 'h':
+ print_usage(argc, argv, 0);
return 0;
- }
- else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
+ case 'v':
printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION);
return 0;
- }
- else if (!strcmp(argv[i], "backup")) {
- cmd = CMD_BACKUP;
- }
- else if (!strcmp(argv[i], "restore")) {
- cmd = CMD_RESTORE;
- }
- else if (!strcmp(argv[i], "--system")) {
+ case OPT_SYSTEM:
cmd_flags |= CMD_FLAG_RESTORE_SYSTEM_FILES;
- }
- else if (!strcmp(argv[i], "--reboot")) {
+ break;
+ case OPT_REBOOT:
cmd_flags &= ~CMD_FLAG_RESTORE_NO_REBOOT;
- }
- else if (!strcmp(argv[i], "--no-reboot")) {
+ break;
+ case OPT_NO_REBOOT:
cmd_flags |= CMD_FLAG_RESTORE_NO_REBOOT;
- }
- else if (!strcmp(argv[i], "--copy")) {
+ break;
+ case OPT_COPY:
cmd_flags |= CMD_FLAG_RESTORE_COPY_BACKUP;
- }
- else if (!strcmp(argv[i], "--settings")) {
+ break;
+ case OPT_SETTINGS:
cmd_flags |= CMD_FLAG_RESTORE_SETTINGS;
- }
- else if (!strcmp(argv[i], "--remove")) {
+ break;
+ case OPT_REMOVE:
cmd_flags |= CMD_FLAG_RESTORE_REMOVE_ITEMS;
- }
- else if (!strcmp(argv[i], "--skip-apps")) {
+ break;
+ case OPT_SKIP_APPS:
cmd_flags |= CMD_FLAG_RESTORE_SKIP_APPS;
- }
- else if (!strcmp(argv[i], "--password")) {
- i++;
- if (!argv[i]) {
- print_usage(argc, argv);
- return -1;
- }
- if (backup_password)
- free(backup_password);
- backup_password = strdup(argv[i]);
- continue;
- }
- else if (!strcmp(argv[i], "cloud")) {
- cmd = CMD_CLOUD;
- i++;
- if (!argv[i]) {
- printf("No argument given for cloud command; requires either 'on' or 'off'.\n");
- print_usage(argc, argv);
- return -1;
- }
- if (!strcmp(argv[i], "on")) {
- cmd_flags |= CMD_FLAG_CLOUD_ENABLE;
- } else if (!strcmp(argv[i], "off")) {
- cmd_flags |= CMD_FLAG_CLOUD_DISABLE;
- } else {
- printf("Invalid argument '%s' for cloud command; must be either 'on' or 'off'.\n", argv[i]);
- }
- continue;
- }
- else if (!strcmp(argv[i], "--full")) {
+ break;
+ case OPT_PASSWORD:
+ free(backup_password);
+ backup_password = strdup(optarg);
+ break;
+ case OPT_FULL:
cmd_flags |= CMD_FLAG_FORCE_FULL_BACKUP;
+ break;
+ default:
+ print_usage(argc, argv, 1);
+ return 2;
}
- else if (!strcmp(argv[i], "info")) {
- cmd = CMD_INFO;
- verbose = 0;
- }
- else if (!strcmp(argv[i], "list")) {
- cmd = CMD_LIST;
- verbose = 0;
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (!argv[0]) {
+ fprintf(stderr, "ERROR: No command specified.\n");
+ print_usage(argc+optind, argv-optind, 1);
+ return 2;
+ }
+
+ if (!strcmp(argv[0], "backup")) {
+ cmd = CMD_BACKUP;
+ }
+ else if (!strcmp(argv[0], "restore")) {
+ cmd = CMD_RESTORE;
+ }
+ else if (!strcmp(argv[0], "cloud")) {
+ cmd = CMD_CLOUD;
+ i = 1;
+ if (!argv[i]) {
+ fprintf(stderr, "ERROR: No argument given for cloud command; requires either 'on' or 'off'.\n");
+ print_usage(argc+optind, argv-optind, 1);
+ return 2;
}
- else if (!strcmp(argv[i], "unback")) {
- cmd = CMD_UNBACK;
+ if (!strcmp(argv[i], "on")) {
+ cmd_flags |= CMD_FLAG_CLOUD_ENABLE;
+ } else if (!strcmp(argv[i], "off")) {
+ cmd_flags |= CMD_FLAG_CLOUD_DISABLE;
+ } else {
+ fprintf(stderr, "ERROR: Invalid argument '%s' for cloud command; must be either 'on' or 'off'.\n", argv[i]);
+ print_usage(argc+optind, argv-optind, 1);
+ return 2;
+ }
+ }
+ else if (!strcmp(argv[0], "info")) {
+ cmd = CMD_INFO;
+ verbose = 0;
+ }
+ else if (!strcmp(argv[0], "list")) {
+ cmd = CMD_LIST;
+ verbose = 0;
+ }
+ else if (!strcmp(argv[0], "unback")) {
+ cmd = CMD_UNBACK;
+ }
+ else if (!strcmp(argv[0], "encryption")) {
+ cmd = CMD_CHANGEPW;
+ i = 1;
+ if (!argv[i]) {
+ fprintf(stderr, "ERROR: No argument given for encryption command; requires either 'on' or 'off'.\n");
+ print_usage(argc+optind, argv-optind, 1);
+ return 2;
+ }
+ if (!strcmp(argv[i], "on")) {
+ cmd_flags |= CMD_FLAG_ENCRYPTION_ENABLE;
+ } else if (!strcmp(argv[i], "off")) {
+ cmd_flags |= CMD_FLAG_ENCRYPTION_DISABLE;
+ } else {
+ fprintf(stderr, "ERROR: Invalid argument '%s' for encryption command; must be either 'on' or 'off'.\n", argv[i]);
+ print_usage(argc+optind, argv-optind, 1);
+ return 2;
}
- else if (!strcmp(argv[i], "encryption")) {
- cmd = CMD_CHANGEPW;
- i++;
- if (!argv[i]) {
- printf("No argument given for encryption command; requires either 'on' or 'off'.\n");
- print_usage(argc, argv);
- return -1;
- }
- if (!strcmp(argv[i], "on")) {
- cmd_flags |= CMD_FLAG_ENCRYPTION_ENABLE;
- } else if (!strcmp(argv[i], "off")) {
- cmd_flags |= CMD_FLAG_ENCRYPTION_DISABLE;
- } else {
- printf("Invalid argument '%s' for encryption command; must be either 'on' or 'off'.\n", argv[i]);
- }
- // check if a password was given on the command line
- if (newpw) {
- free(newpw);
- newpw = NULL;
- }
- if (backup_password) {
- free(backup_password);
- backup_password = NULL;
- }
- i++;
- if (argv[i]) {
- if (cmd_flags & CMD_FLAG_ENCRYPTION_ENABLE) {
- newpw = strdup(argv[i]);
- } else if (cmd_flags & CMD_FLAG_ENCRYPTION_DISABLE) {
- backup_password = strdup(argv[i]);
- }
+ // check if a password was given on the command line
+ free(newpw);
+ newpw = NULL;
+ free(backup_password);
+ backup_password = NULL;
+ i++;
+ if (argv[i]) {
+ if (cmd_flags & CMD_FLAG_ENCRYPTION_ENABLE) {
+ newpw = strdup(argv[i]);
+ } else if (cmd_flags & CMD_FLAG_ENCRYPTION_DISABLE) {
+ backup_password = strdup(argv[i]);
}
- continue;
}
- else if (!strcmp(argv[i], "changepw")) {
- cmd = CMD_CHANGEPW;
- cmd_flags |= CMD_FLAG_ENCRYPTION_CHANGEPW;
- // check if passwords were given on command line
- if (newpw) {
- free(newpw);
- newpw = NULL;
- }
- if (backup_password) {
- free(backup_password);
- backup_password = NULL;
- }
+ }
+ else if (!strcmp(argv[0], "changepw")) {
+ cmd = CMD_CHANGEPW;
+ cmd_flags |= CMD_FLAG_ENCRYPTION_CHANGEPW;
+ // check if passwords were given on command line
+ free(newpw);
+ newpw = NULL;
+ free(backup_password);
+ backup_password = NULL;
+ i = 1;
+ if (argv[i]) {
+ backup_password = strdup(argv[i]);
i++;
- if (argv[i]) {
- backup_password = strdup(argv[i]);
- i++;
- if (!argv[i]) {
- printf("Old and new passwords have to be passed as arguments for the changepw command\n");
- print_usage(argc, argv);
- return -1;
- }
- newpw = strdup(argv[i]);
+ if (!argv[i]) {
+ fprintf(stderr, "ERROR: Old and new passwords have to be passed as arguments for the changepw command\n");
+ print_usage(argc+optind, argv-optind, 1);
+ return 2;
}
- continue;
- }
- else if (backup_directory == NULL) {
- backup_directory = argv[i];
- }
- else {
- print_usage(argc, argv);
- return -1;
+ newpw = strdup(argv[i]);
}
}
+ i++;
+ if (argv[i]) {
+ backup_directory = argv[i];
+ }
+
/* verify options */
if (cmd == -1) {
- printf("No command specified.\n");
- print_usage(argc, argv);
- return -1;
+ fprintf(stderr, "ERROR: Unsupported command '%s'.\n", argv[0]);
+ print_usage(argc+optind, argv-optind, 1);
+ return 2;
}
if (cmd == CMD_CHANGEPW || cmd == CMD_CLOUD) {
backup_directory = (char*)".this_folder_is_not_present_on_purpose";
} else {
if (backup_directory == NULL) {
- printf("No target backup directory specified.\n");
- print_usage(argc, argv);
- return -1;
+ fprintf(stderr, "ERROR: No target backup directory specified.\n");
+ print_usage(argc+optind, argv-optind, 1);
+ return 2;
}
/* verify if passed backup directory exists */
if (stat(backup_directory, &st) != 0) {
- printf("ERROR: Backup directory \"%s\" does not exist!\n", backup_directory);
+ fprintf(stderr, "ERROR: Backup directory \"%s\" does not exist!\n", backup_directory);
return -1;
}
}
- idevice_t device = NULL;
ret = idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX);
if (ret != IDEVICE_E_SUCCESS) {
if (udid) {
@@ -1711,6 +1747,20 @@ int main(int argc, char *argv[])
uint8_t is_encrypted = 0;
char *info_path = NULL;
if (cmd == CMD_CHANGEPW) {
+ if (!interactive_mode) {
+ if (!newpw) {
+ newpw = getenv("BACKUP_PASSWORD_NEW");
+ if (newpw) {
+ newpw = strdup(newpw);
+ }
+ }
+ if (!backup_password) {
+ backup_password = getenv("BACKUP_PASSWORD");
+ if (backup_password) {
+ backup_password = strdup(backup_password);
+ }
+ }
+ }
if (!interactive_mode && !backup_password && !newpw) {
idevice_free(device);
printf("ERROR: Can't get password input in non-interactive mode. Either pass password(s) on the command line, or enable interactive mode with -i or --interactive.\n");
@@ -1731,7 +1781,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);
@@ -1752,6 +1802,12 @@ int main(int argc, char *argv[])
if (cmd != CMD_CLOUD && is_encrypted) {
PRINT_VERBOSE(1, "This is an encrypted backup.\n");
if (backup_password == NULL) {
+ backup_password = getenv("BACKUP_PASSWORD");
+ if (backup_password) {
+ backup_password = strdup(backup_password);
+ }
+ }
+ if (backup_password == NULL) {
if (interactive_mode) {
backup_password = ask_for_password("Enter backup password", 0);
}
@@ -1770,7 +1826,6 @@ int main(int argc, char *argv[])
}
}
- lockdownd_client_t lockdown = NULL;
if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME))) {
printf("ERROR: Could not connect to lockdownd, error code %d\n", ldret);
idevice_free(device);
@@ -1808,7 +1863,6 @@ int main(int argc, char *argv[])
}
/* start notification_proxy */
- np_client_t np = NULL;
ldret = lockdownd_start_service(lockdown, NP_SERVICE_NAME, &service);
if ((ldret == LOCKDOWN_E_SUCCESS) && service && service->port) {
np_client_new(device, service, &np);
@@ -1822,17 +1876,24 @@ int main(int argc, char *argv[])
};
np_observe_notifications(np, noties);
} else {
- printf("ERROR: Could not start service %s.\n", NP_SERVICE_NAME);
+ printf("ERROR: Could not start service %s: %s\n", NP_SERVICE_NAME, lockdownd_strerror(ldret));
+ cmd = CMD_LEAVE;
+ goto checkpoint;
+ }
+ if (service) {
+ lockdownd_service_descriptor_free(service);
+ service = NULL;
}
- afc_client_t afc = NULL;
if (cmd == CMD_BACKUP || cmd == CMD_RESTORE) {
/* start AFC, we need this for the lock file */
- service->port = 0;
- service->ssl_enabled = 0;
ldret = lockdownd_start_service(lockdown, AFC_SERVICE_NAME, &service);
if ((ldret == LOCKDOWN_E_SUCCESS) && service->port) {
afc_client_new(device, service, &afc);
+ } else {
+ printf("ERROR: Could not start service %s: %s\n", AFC_SERVICE_NAME, lockdownd_strerror(ldret));
+ cmd = CMD_LEAVE;
+ goto checkpoint;
}
}
@@ -1842,7 +1903,6 @@ int main(int argc, char *argv[])
}
/* start mobilebackup service and retrieve port */
- mobilebackup2_client_t mobilebackup2 = NULL;
ldret = lockdownd_start_service_with_escrow_bag(lockdown, MOBILEBACKUP2_SERVICE_NAME, &service);
lockdownd_client_free(lockdown);
lockdown = NULL;
@@ -1877,7 +1937,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");
@@ -1892,7 +1952,6 @@ int main(int argc, char *argv[])
}
}
- uint64_t lockfile = 0;
if (cmd == CMD_BACKUP || cmd == CMD_RESTORE) {
do_post_notification(device, NP_SYNC_WILL_START);
afc_file_open(afc, "/com.apple.itunes.lock_sync", AFC_FOPEN_RW, &lockfile);
@@ -1905,15 +1964,16 @@ int main(int argc, char *argv[])
if (aerr == AFC_E_SUCCESS) {
do_post_notification(device, NP_SYNC_DID_START);
break;
- } else if (aerr == AFC_E_OP_WOULD_BLOCK) {
+ }
+ if (aerr == AFC_E_OP_WOULD_BLOCK) {
usleep(LOCK_WAIT);
continue;
- } else {
- fprintf(stderr, "ERROR: could not lock file! error code: %d\n", aerr);
- afc_file_close(afc, lockfile);
- lockfile = 0;
- cmd = CMD_LEAVE;
}
+
+ fprintf(stderr, "ERROR: could not lock file! error code: %d\n", aerr);
+ afc_file_close(afc, lockfile);
+ lockfile = 0;
+ cmd = CMD_LEAVE;
}
if (i == LOCK_ATTEMPTS) {
fprintf(stderr, "ERROR: timeout while locking for sync\n");
@@ -1971,7 +2031,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);
@@ -2032,9 +2092,8 @@ checkpoint:
PRINT_VERBOSE(1, "Don't copy backup: %s\n", ((cmd_flags & CMD_FLAG_RESTORE_COPY_BACKUP) == 0 ? "Yes":"No"));
plist_dict_set_item(opts, "RestorePreserveSettings", plist_new_bool((cmd_flags & CMD_FLAG_RESTORE_SETTINGS) == 0));
PRINT_VERBOSE(1, "Preserve settings of device: %s\n", ((cmd_flags & CMD_FLAG_RESTORE_SETTINGS) == 0 ? "Yes":"No"));
- if (cmd_flags & CMD_FLAG_RESTORE_REMOVE_ITEMS)
- plist_dict_set_item(opts, "RemoveItemsNotRestored", plist_new_bool(1));
- PRINT_VERBOSE(1, "Remove items that are not restored: %s\n", ((cmd_flags & CMD_FLAG_RESTORE_REMOVE_ITEMS) ? "Yes":"No"));
+ plist_dict_set_item(opts, "RemoveItemsNotRestored", plist_new_bool(cmd_flags & CMD_FLAG_RESTORE_REMOVE_ITEMS));
+ PRINT_VERBOSE(1, "Remove items that are not restored: %s\n", ((cmd_flags & CMD_FLAG_RESTORE_REMOVE_ITEMS) ? "Yes":"No"));
if (backup_password != NULL) {
plist_dict_set_item(opts, "Password", plist_new_string(backup_password));
}
@@ -2048,9 +2107,8 @@ checkpoint:
if (write_restore_applications(info_plist, afc) < 0) {
cmd = CMD_LEAVE;
break;
- } else {
- PRINT_VERBOSE(1, "Wrote RestoreApplications.plist\n");
}
+ PRINT_VERBOSE(1, "Wrote RestoreApplications.plist\n");
}
/* Start restore */
@@ -2105,6 +2163,12 @@ checkpoint:
if (cmd_flags & CMD_FLAG_ENCRYPTION_ENABLE) {
if (!willEncrypt) {
if (!newpw) {
+ newpw = getenv("BACKUP_PASSWORD");
+ if (newpw) {
+ newpw = strdup(newpw);
+ }
+ }
+ if (!newpw) {
newpw = ask_for_password("Enter new backup password", 1);
}
if (!newpw) {
@@ -2121,6 +2185,12 @@ checkpoint:
} else if (cmd_flags & CMD_FLAG_ENCRYPTION_DISABLE) {
if (willEncrypt) {
if (!backup_password) {
+ backup_password = getenv("BACKUP_PASSWORD");
+ if (backup_password) {
+ backup_password = strdup(backup_password);
+ }
+ }
+ if (!backup_password) {
backup_password = ask_for_password("Enter current backup password", 0);
}
} else {
@@ -2444,7 +2514,7 @@ checkpoint:
/* print status */
if ((overall_progress > 0) && !progress_finished) {
- if (overall_progress >= 100.0f) {
+ if (overall_progress >= 100.0F) {
progress_finished = 1;
}
print_progress_real(overall_progress, 0);
@@ -2568,7 +2638,7 @@ files_out:
do_post_notification(device, NP_SYNC_DID_FINISH);
}
} else {
- printf("ERROR: Could not start service %s.\n", MOBILEBACKUP2_SERVICE_NAME);
+ printf("ERROR: Could not start service %s: %s\n", MOBILEBACKUP2_SERVICE_NAME, lockdownd_strerror(ldret));
lockdownd_client_free(lockdown);
lockdown = NULL;
}
diff --git a/tools/idevicebtlogger.c b/tools/idevicebtlogger.c
new file mode 100644
index 0000000..8de6b22
--- /dev/null
+++ b/tools/idevicebtlogger.c
@@ -0,0 +1,458 @@
+/*
+ * idevicebt_packet_logger.c
+ * Capture Bluetooth HCI traffic to native PKLG or PCAP
+ *
+ * Copyright (c) 2021 Geoffrey Kruse, All Rights Reserved.
+ * Copyright (c) 2022 Matthias Ringwald, 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 "idevicebtlogger"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <assert.h>
+#include <fcntl.h>
+
+#ifdef WIN32
+#include <windows.h>
+#define sleep(x) Sleep(x*1000)
+#else
+#include <arpa/inet.h>
+#endif
+
+
+#include <libimobiledevice/libimobiledevice.h>
+#include <libimobiledevice/bt_packet_logger.h>
+
+typedef enum {
+ HCI_COMMAND = 0x00,
+ HCI_EVENT = 0x01,
+ SENT_ACL_DATA = 0x02,
+ RECV_ACL_DATA = 0x03,
+ SENT_SCO_DATA = 0x08,
+ RECV_SCO_DATA = 0x09,
+} PacketLoggerPacketType;
+
+static int quit_flag = 0;
+static int exit_on_disconnect = 0;
+
+static char* udid = NULL;
+static idevice_t device = NULL;
+static bt_packet_logger_client_t bt_packet_logger = NULL;
+static int use_network = 0;
+static char* out_filename = NULL;
+static char* log_format_string = NULL;
+static FILE * packetlogger_file = NULL;
+
+static enum {
+ LOG_FORMAT_PACKETLOGGER,
+ LOG_FORMAT_PCAP
+} log_format = LOG_FORMAT_PACKETLOGGER;
+
+const uint8_t pcap_file_header[] = {
+ // Magic Number
+ 0xA1, 0xB2, 0xC3, 0xD4,
+ // Major / Minor Version
+ 0x00, 0x02, 0x00, 0x04,
+ // Reserved1
+ 0x00, 0x00, 0x00, 0x00,
+ // Reserved2
+ 0x00, 0x00, 0x00, 0x00,
+ // Snaplen == max packet size - use 2kB (larger than any ACL)
+ 0x00, 0x00, 0x08, 0x00,
+ // LinkType: DLT_BLUETOOTH_HCI_H4_WITH_PHDR
+ 0x00, 0x00, 0x00, 201,
+};
+
+static uint32_t big_endian_read_32(const uint8_t * buffer, int position)
+{
+ return ((uint32_t) buffer[position+3]) | (((uint32_t)buffer[position+2]) << 8) | (((uint32_t)buffer[position+1]) << 16) | (((uint32_t) buffer[position]) << 24);
+}
+
+static void big_endian_store_32(uint8_t * buffer, uint16_t position, uint32_t value)
+{
+ uint16_t pos = position;
+ buffer[pos++] = (uint8_t)(value >> 24);
+ buffer[pos++] = (uint8_t)(value >> 16);
+ buffer[pos++] = (uint8_t)(value >> 8);
+ buffer[pos++] = (uint8_t)(value);
+}
+
+/**
+ * Callback from the packet logger service to handle packets and log to PacketLogger format
+ */
+static void bt_packet_logger_callback_packetlogger(uint8_t * data, uint16_t len, void *user_data)
+{
+ (void) fwrite(data, 1, len, packetlogger_file);
+}
+
+/**
+ * Callback from the packet logger service to handle packets and log to pcap
+ */
+static void bt_packet_logger_callback_pcap(uint8_t * data, uint16_t len, void *user_data)
+{
+ // check len
+ if (len < 13) {
+ return;
+ }
+
+ // parse packet header (ignore len field)
+ uint32_t ts_secs = big_endian_read_32(data, 4);
+ uint32_t ts_us = big_endian_read_32(data, 8);
+ uint8_t packet_type = data[12];
+ data += 13;
+ len -= 13;
+
+ // map PacketLogger packet type onto PCAP direction flag and hci_h4_type
+ uint8_t direction_in = 0;
+ uint8_t hci_h4_type = 0xff;
+ switch(packet_type) {
+ case HCI_COMMAND:
+ hci_h4_type = 0x01;
+ direction_in = 0;
+ break;
+ case SENT_ACL_DATA:
+ hci_h4_type = 0x02;
+ direction_in = 0;
+ break;
+ case RECV_ACL_DATA:
+ hci_h4_type = 0x02;
+ direction_in = 1;
+ break;
+ case SENT_SCO_DATA:
+ hci_h4_type = 0x03;
+ direction_in = 0;
+ break;
+ case RECV_SCO_DATA:
+ hci_h4_type = 0x03;
+ direction_in = 1;
+ break;
+ case HCI_EVENT:
+ hci_h4_type = 0x04;
+ direction_in = 1;
+ break;
+ default:
+ // unknown packet logger type, drop packet
+ return;
+ }
+
+ // setup pcap record header, 4 byte direction flag, 1 byte HCI H4 packet type, data
+ uint8_t pcap_record_header[21];
+ big_endian_store_32(pcap_record_header, 0, ts_secs); // Timestamp seconds
+ big_endian_store_32(pcap_record_header, 4, ts_us); // Timestamp microseconds
+ big_endian_store_32(pcap_record_header, 8, 4 + 1 + len); // Captured Packet Length
+ big_endian_store_32(pcap_record_header, 12, 4 + 1 + len); // Original Packet Length
+ big_endian_store_32(pcap_record_header, 16, direction_in); // Direction: Incoming = 1
+ pcap_record_header[20] = hci_h4_type;
+
+ // write header
+ (void) fwrite(pcap_record_header, 1, sizeof(pcap_record_header), packetlogger_file);
+
+ // write packet
+ (void) fwrite(data, 1, len, packetlogger_file);
+
+ // flush
+ (void) fflush(packetlogger_file);
+}
+
+/**
+ * Disable HCI log capture
+ */
+static void stop_logging(void)
+{
+ fflush(NULL);
+
+ if (bt_packet_logger) {
+ bt_packet_logger_client_free(bt_packet_logger);
+ bt_packet_logger = NULL;
+ }
+
+ if (device) {
+ idevice_free(device);
+ device = NULL;
+ }
+}
+
+/**
+ * Enable HCI log capture
+ */
+static int start_logging(void)
+{
+ 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;
+ lockdownd_error_t lerr = lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME);
+ if (lerr != LOCKDOWN_E_SUCCESS) {
+ fprintf(stderr, "ERROR: Could not connect to lockdownd: %d\n", lerr);
+ idevice_free(device);
+ device = NULL;
+ return -1;
+ }
+
+ /* start bt_packet_logger service */
+ bt_packet_logger_client_start_service(device, &bt_packet_logger, TOOL_NAME);
+
+ /* start capturing bt_packet_logger */
+ void (*callback)(uint8_t * data, uint16_t len, void *user_data);
+ switch (log_format){
+ case LOG_FORMAT_PCAP:
+ callback = bt_packet_logger_callback_pcap;
+ break;
+ case LOG_FORMAT_PACKETLOGGER:
+ callback = bt_packet_logger_callback_packetlogger;
+ break;
+ default:
+ assert(0);
+ return 0;
+ }
+ bt_packet_logger_error_t serr = bt_packet_logger_start_capture(bt_packet_logger, callback, NULL);
+ if (serr != BT_PACKET_LOGGER_E_SUCCESS) {
+ fprintf(stderr, "ERROR: Unable to start capturing bt_packet_logger.\n");
+ bt_packet_logger_client_free(bt_packet_logger);
+ bt_packet_logger = NULL;
+ idevice_free(device);
+ device = NULL;
+ return -1;
+ }
+
+ fprintf(stderr, "[connected:%s]\n", udid);
+ fflush(stderr);
+
+ return 0;
+}
+
+/**
+ * Callback for device events
+ */
+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 (!bt_packet_logger) {
+ if (!udid) {
+ udid = strdup(event->udid);
+ }
+ if (strcmp(udid, event->udid) == 0) {
+ if (start_logging() != 0) {
+ fprintf(stderr, "Could not start logger for udid %s\n", udid);
+ }
+ }
+ }
+ } else if (event->event == IDEVICE_DEVICE_REMOVE) {
+ if (bt_packet_logger && (strcmp(udid, event->udid) == 0)) {
+ stop_logging();
+ fprintf(stderr, "[disconnected:%s]\n", udid);
+ if (exit_on_disconnect) {
+ quit_flag++;
+ }
+ }
+ }
+}
+
+/**
+ * signal handler function for cleaning up properly
+ */
+static void clean_exit(int sig)
+{
+ fprintf(stderr, "\nExiting...\n");
+ quit_flag++;
+}
+
+/**
+ * print usage information
+ */
+static void print_usage(int argc, char **argv, int is_error)
+{
+ char *name = NULL;
+ name = strrchr(argv[0], '/');
+ fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS] <FILE>\n", (name ? name + 1: argv[0]));
+ fprintf(is_error ? stderr : stdout,
+ "\n" \
+ "Capture HCI packets from a connected device.\n" \
+ "\n" \
+ "OPTIONS:\n" \
+ " -u, --udid UDID target specific device by UDID\n" \
+ " -n, --network connect to network device\n" \
+ " -f, --format FORMAT logging format: packetlogger (default) or pcap\n" \
+ " -x, --exit exit when device disconnects\n" \
+ " -h, --help prints usage information\n" \
+ " -d, --debug enable communication debugging\n" \
+ " -v, --version prints version information\n" \
+ "\n" \
+ "Homepage: <" PACKAGE_URL ">\n"
+ "Bug Reports: <" PACKAGE_BUGREPORT ">\n"
+ );
+}
+
+/**
+ * Program entry
+ */
+int main(int argc, char *argv[])
+{
+ int c = 0;
+ const struct option longopts[] = {
+ { "debug", no_argument, NULL, 'd' },
+ { "help", no_argument, NULL, 'h' },
+ { "udid", required_argument, NULL, 'u' },
+ { "format", required_argument, NULL, 'f' },
+ { "network", no_argument, NULL, 'n' },
+ { "exit", no_argument, NULL, 'x' },
+ { "version", no_argument, NULL, 'v' },
+ { NULL, 0, NULL, 0}
+ };
+
+ signal(SIGINT, clean_exit);
+ signal(SIGTERM, clean_exit);
+#ifndef WIN32
+ signal(SIGQUIT, clean_exit);
+ signal(SIGPIPE, SIG_IGN);
+#endif
+
+ while ((c = getopt_long(argc, argv, "dhu:f:nxv", 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;
+ }
+ free(udid);
+ udid = strdup(optarg);
+ break;
+ case 'f':
+ if (!*optarg) {
+ fprintf(stderr, "ERROR: FORMAT must not be empty!\n");
+ print_usage(argc, argv, 1);
+ return 2;
+ }
+ free(log_format_string);
+ log_format_string = strdup(optarg);
+ break;
+ case 'n':
+ use_network = 1;
+ break;
+ case 'x':
+ exit_on_disconnect = 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;
+ }
+ }
+
+ if (optind < argc) {
+ out_filename = argv[optind];
+ // printf("Output File: %s\n", out_filename);
+ }
+ else {
+ print_usage(argc, argv, 1);
+ return 2;
+ }
+
+ if (log_format_string != NULL){
+ if (strcmp("packetlogger", log_format_string) == 0){
+ log_format = LOG_FORMAT_PACKETLOGGER;
+ } else if (strcmp("pcap", log_format_string) == 0){
+ log_format = LOG_FORMAT_PCAP;
+ } else {
+ printf("Unknown logging format: '%s'\n", log_format_string);
+ print_usage(argc, argv, 1);
+ return 2;
+ }
+ }
+
+ int num = 0;
+ idevice_info_t *devices = NULL;
+ idevice_get_device_list_extended(&devices, &num);
+ idevice_device_list_extended_free(devices);
+ if (num == 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;
+ } else {
+ fprintf(stderr, "Waiting for device with UDID %s to become available...\n", udid);
+ }
+ }
+
+ // support streaming to stdout
+ if (strcmp(out_filename, "-") == 0){
+ packetlogger_file = stdout;
+ } else {
+ packetlogger_file = fopen(out_filename, "wb");
+ }
+
+
+ if (packetlogger_file == NULL){
+ fprintf(stderr, "Failed to open file %s, errno = %d\n", out_filename, errno);
+ return -2;
+ }
+
+ switch (log_format){
+ case LOG_FORMAT_PCAP:
+ // printf("Output Format: PCAP\n");
+ // write PCAP file header
+ (void) fwrite(&pcap_file_header, 1, sizeof(pcap_file_header), packetlogger_file);
+ break;
+ case LOG_FORMAT_PACKETLOGGER:
+ printf("Output Format: PacketLogger\n");
+ break;
+ default:
+ assert(0);
+ return -2;
+ }
+ idevice_subscription_context_t context = NULL;
+ idevice_events_subscribe(&context, device_event_cb, NULL);
+
+ while (!quit_flag) {
+ sleep(1);
+ }
+
+ idevice_events_unsubscribe(context);
+ stop_logging();
+
+ fclose(packetlogger_file);
+
+ free(udid);
+
+ return 0;
+}
diff --git a/tools/idevicecrashreport.c b/tools/idevicecrashreport.c
index 2945111..09bd537 100644
--- a/tools/idevicecrashreport.c
+++ b/tools/idevicecrashreport.c
@@ -30,10 +30,11 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <getopt.h>
#ifndef WIN32
#include <signal.h>
#endif
-#include "common/utils.h"
+#include <libimobiledevice-glue/utils.h>
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
@@ -47,6 +48,9 @@
#define S_IFSOCK S_IFREG
#endif
+#define CRASH_REPORT_MOVER_SERVICE "com.apple.crashreportmover"
+#define CRASH_REPORT_COPY_MOBILE_SERVICE "com.apple.crashreportcopymobile"
+
const char* target_directory = NULL;
static int extract_raw_crash_reports = 0;
static int keep_crash_reports = 0;
@@ -77,7 +81,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);
@@ -100,7 +104,7 @@ static int extract_raw_crash_report(const char* filename)
return res;
}
-static int afc_client_copy_and_remove_crash_reports(afc_client_t afc, const char* device_directory, const char* host_directory)
+static int afc_client_copy_and_remove_crash_reports(afc_client_t afc, const char* device_directory, const char* host_directory, const char* filename_filter)
{
afc_error_t afc_error;
int k;
@@ -148,10 +152,18 @@ 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
+ /* replace every ':' with '-' since ':' is an illegal character for file names in windows */
+ char* current_pos = strchr(list[k], ':');
+ while (current_pos) {
+ *current_pos = '-';
+ current_pos = strchr(current_pos, ':');
+ }
+#endif
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 {
@@ -231,12 +243,16 @@ static int afc_client_copy_and_remove_crash_reports(afc_client_t afc, const char
#else
mkdir(target_filename, 0755);
#endif
- res = afc_client_copy_and_remove_crash_reports(afc, source_filename, target_filename);
+ res = afc_client_copy_and_remove_crash_reports(afc, source_filename, target_filename, filename_filter);
/* remove directory from device */
if (!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;
+ }
+
/* copy file to host */
afc_error = afc_file_open(afc, source_filename, AFC_FOPEN_RDONLY, &handle);
if(afc_error != AFC_E_SUCCESS) {
@@ -298,26 +314,27 @@ static int afc_client_copy_and_remove_crash_reports(afc_client_t afc, const char
return res;
}
-static void print_usage(int argc, char **argv)
+static void print_usage(int argc, char **argv, int is_error)
{
- char *name = NULL;
-
- name = strrchr(argv[0], '/');
- printf("Usage: %s [OPTIONS] DIRECTORY\n", (name ? name + 1: argv[0]));
- printf("\n");
- printf("Move crash reports from device to a local DIRECTORY.\n");
- printf("\n");
- printf("OPTIONS:\n");
- printf(" -u, --udid UDID\ttarget specific device by UDID\n");
- printf(" -n, --network\t\tconnect to network device\n");
- printf(" -e, --extract\t\textract raw crash report into separate '.crash' file\n");
- printf(" -k, --keep\t\tcopy but do not remove crash reports from device\n");
- printf(" -d, --debug\t\tenable communication debugging\n");
- printf(" -h, --help\t\tprints usage information\n");
- printf(" -v, --version\t\tprints version information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\n");
- printf("Bug Reports: <" PACKAGE_BUGREPORT ">\n");
+ char *name = strrchr(argv[0], '/');
+ fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS] DIRECTORY\n", (name ? name + 1: argv[0]));
+ fprintf(is_error ? stderr : stdout,
+ "\n"
+ "Move crash reports from device to a local DIRECTORY.\n"
+ "\n"
+ "OPTIONS:\n"
+ " -u, --udid UDID target specific device by UDID\n"
+ " -n, --network connect to network device\n"
+ " -e, --extract extract raw crash report into separate '.crash' file\n"
+ " -k, --keep copy but do not remove crash reports from device\n"
+ " -d, --debug enable communication debugging\n"
+ " -f, --filter NAME filter crash reports by NAME (case sensitive)\n"
+ " -h, --help prints usage information\n"
+ " -v, --version prints version information\n"
+ "\n"
+ "Homepage: <" PACKAGE_URL ">\n"
+ "Bug Reports: <" PACKAGE_BUGREPORT ">\n"
+ );
}
int main(int argc, char* argv[])
@@ -330,69 +347,84 @@ int main(int argc, char* argv[])
lockdownd_error_t lockdownd_error = LOCKDOWN_E_SUCCESS;
afc_error_t afc_error = AFC_E_SUCCESS;
- int i;
const char* udid = NULL;
int use_network = 0;
+ const char* filename_filter = 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' },
+ { "filter", required_argument, NULL, 'f' },
+ { "extract", no_argument, NULL, 'e' },
+ { "keep", no_argument, NULL, 'k' },
+ { NULL, 0, NULL, 0}
+ };
#ifndef WIN32
signal(SIGPIPE, SIG_IGN);
#endif
+
/* parse cmdline args */
- for (i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) {
+ while ((c = getopt_long(argc, argv, "dhu:nvf:ek", longopts, NULL)) != -1) {
+ switch (c) {
+ case 'd':
idevice_set_debug_level(1);
- continue;
- }
- else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--udid")) {
- i++;
- if (!argv[i] || !*argv[i]) {
- print_usage(argc, argv);
- return 0;
+ break;
+ case 'u':
+ if (!*optarg) {
+ fprintf(stderr, "ERROR: UDID argument must not be empty!\n");
+ print_usage(argc, argv, 1);
+ return 2;
}
- udid = argv[i];
- continue;
- }
- else if (!strcmp(argv[i], "-n") || !strcmp(argv[i], "--network")) {
+ udid = optarg;
+ break;
+ case 'n':
use_network = 1;
- continue;
- }
- else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
- print_usage(argc, argv);
+ break;
+ case 'h':
+ print_usage(argc, argv, 0);
return 0;
- }
- else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
+ case 'v':
printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION);
return 0;
- }
- else if (!strcmp(argv[i], "-e") || !strcmp(argv[i], "--extract")) {
+ case 'f':
+ if (!*optarg) {
+ fprintf(stderr, "ERROR: filter argument must not be empty!\n");
+ print_usage(argc, argv, 1);
+ return 2;
+ }
+ filename_filter = optarg;
+ break;
+ case 'e':
extract_raw_crash_reports = 1;
- continue;
- }
- else if (!strcmp(argv[i], "-k") || !strcmp(argv[i], "--keep")) {
+ break;
+ case 'k':
keep_crash_reports = 1;
- continue;
- }
- else if (target_directory == NULL) {
- target_directory = argv[i];
- continue;
- }
- else {
- print_usage(argc, argv);
- return 0;
+ break;
+ default:
+ print_usage(argc, argv, 1);
+ return 2;
}
}
+ argc -= optind;
+ argv += optind;
/* ensure a target directory was supplied */
- if (!target_directory) {
- print_usage(argc, argv);
- return 0;
+ if (!argv[0]) {
+ fprintf(stderr, "ERROR: missing target directory.\n");
+ print_usage(argc+optind, argv-optind, 1);
+ return 2;
}
+ target_directory = argv[0];
/* check if target directory exists */
if (!file_exists(target_directory)) {
fprintf(stderr, "ERROR: Directory '%s' does not exist.\n", target_directory);
- print_usage(argc, argv);
- return 0;
+ return 1;
}
device_error = idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX);
@@ -414,8 +446,9 @@ int main(int argc, char* argv[])
/* start crash log mover service */
lockdownd_service_descriptor_t service = NULL;
- lockdownd_error = lockdownd_start_service(lockdownd, "com.apple.crashreportmover", &service);
+ lockdownd_error = lockdownd_start_service(lockdownd, CRASH_REPORT_MOVER_SERVICE, &service);
if (lockdownd_error != LOCKDOWN_E_SUCCESS) {
+ fprintf(stderr, "ERROR: Could not start service %s: %s\n", CRASH_REPORT_MOVER_SERVICE, lockdownd_strerror(lockdownd_error));
lockdownd_client_free(lockdownd);
idevice_free(device);
return -1;
@@ -442,10 +475,10 @@ int main(int argc, char* argv[])
if (service_error == SERVICE_E_SUCCESS || service_error == SERVICE_E_TIMEOUT) {
attempts++;
continue;
- } else {
- fprintf(stderr, "ERROR: Crash logs could not be moved. Connection interrupted (%d).\n", service_error);
- break;
}
+
+ fprintf(stderr, "ERROR: Crash logs could not be moved. Connection interrupted (%d).\n", service_error);
+ break;
}
service_client_free(svcmove);
free(ping);
@@ -457,8 +490,9 @@ int main(int argc, char* argv[])
return -1;
}
- lockdownd_error = lockdownd_start_service(lockdownd, "com.apple.crashreportcopymobile", &service);
+ lockdownd_error = lockdownd_start_service(lockdownd, CRASH_REPORT_COPY_MOBILE_SERVICE, &service);
if (lockdownd_error != LOCKDOWN_E_SUCCESS) {
+ fprintf(stderr, "ERROR: Could not start service %s: %s\n", CRASH_REPORT_COPY_MOBILE_SERVICE, lockdownd_strerror(lockdownd_error));
lockdownd_client_free(lockdownd);
idevice_free(device);
return -1;
@@ -479,7 +513,7 @@ int main(int argc, char* argv[])
}
/* recursively copy crash reports from the device to a local directory */
- if (afc_client_copy_and_remove_crash_reports(afc, ".", target_directory) < 0) {
+ if (afc_client_copy_and_remove_crash_reports(afc, ".", target_directory, filename_filter) < 0) {
fprintf(stderr, "ERROR: Failed to get crash reports from device.\n");
afc_client_free(afc);
idevice_free(device);
diff --git a/tools/idevicedate.c b/tools/idevicedate.c
index a9d78c1..d05f63e 100644
--- a/tools/idevicedate.c
+++ b/tools/idevicedate.c
@@ -28,6 +28,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <getopt.h>
#include <time.h>
#if HAVE_LANGINFO_CODESET
#include <langinfo.h>
@@ -42,32 +43,36 @@
#ifdef _DATE_FMT
#define DATE_FMT_LANGINFO nl_langinfo (_DATE_FMT)
#else
+#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"
#endif
+#endif
-static void print_usage(int argc, char **argv)
+static void print_usage(int argc, char **argv, int is_error)
{
- char *name = NULL;
-
- name = strrchr(argv[0], '/');
- printf("Usage: %s [OPTIONS]\n", (name ? name + 1: argv[0]));
- printf("\n");
- printf("Display the current date or set it on a device.\n");
- printf("\n");
- printf("NOTE: Setting the time on iOS 6 and later is only supported\n");
- printf(" in the setup wizard screens before device activation.\n");
- printf("\n");
- printf("OPTIONS:\n");
- printf(" -u, --udid UDID\ttarget specific device by UDID\n");
- printf(" -n, --network\t\tconnect to network device\n");
- printf(" -s, --set TIMESTAMP\tset UTC time described by TIMESTAMP\n");
- printf(" -c, --sync\t\tset time of device to current system time\n");
- printf(" -d, --debug\t\tenable communication debugging\n");
- printf(" -h, --help\t\tprints usage information\n");
- printf(" -v, --version\t\tprints version information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\n");
- printf("Bug Reports: <" PACKAGE_BUGREPORT ">\n");
+ 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"
+ "Display the current date or set it on a device.\n"
+ "\n"
+ "NOTE: Setting the time on iOS 6 and later is only supported\n"
+ " in the setup wizard screens before device activation.\n"
+ "\n"
+ "OPTIONS:\n"
+ " -u, --udid UDID target specific device by UDID\n"
+ " -n, --network connect to network device\n"
+ " -s, --set TIMESTAMP set UTC time described by TIMESTAMP\n"
+ " -c, --sync set time of device to current system time\n"
+ " -d, --debug enable communication debugging\n"
+ " -h, --help prints usage information\n"
+ " -v, --version prints version information\n"
+ "\n"
+ "Homepage: <" PACKAGE_URL ">\n"
+ "Bug Reports: <" PACKAGE_BUGREPORT ">\n"
+ );
}
int main(int argc, char *argv[])
@@ -76,7 +81,6 @@ int main(int argc, char *argv[])
lockdownd_error_t ldret = LOCKDOWN_E_UNKNOWN_ERROR;
idevice_t device = NULL;
idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR;
- int i;
const char* udid = NULL;
int use_network = 0;
time_t setdate = 0;
@@ -88,65 +92,72 @@ int main(int argc, char *argv[])
char buffer[80];
int result = 0;
+ 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' },
+ { "set", required_argument, NULL, 's' },
+ { "sync", no_argument, NULL, 'c' },
+ { NULL, 0, NULL, 0}
+ };
+
#ifndef WIN32
signal(SIGPIPE, SIG_IGN);
#endif
/* parse cmdline args */
- for (i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) {
+ while ((c = getopt_long(argc, argv, "dhu:nvs:c", longopts, NULL)) != -1) {
+ switch (c) {
+ case 'd':
idevice_set_debug_level(1);
- continue;
- }
- else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--udid")) {
- i++;
- if (!argv[i] || !*argv[i]) {
- print_usage(argc, argv);
- return 0;
+ break;
+ case 'u':
+ if (!*optarg) {
+ fprintf(stderr, "ERROR: UDID argument must not be empty!\n");
+ print_usage(argc, argv, 1);
+ return 2;
}
- udid = argv[i];
- continue;
- }
- else if (!strcmp(argv[i], "-n") || !strcmp(argv[i], "--network")) {
+ udid = optarg;
+ break;
+ case 'n':
use_network = 1;
- continue;
- }
- else if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--set")) {
- i++;
- if (!argv[i] || (strlen(argv[i]) <= 1)) {
- print_usage(argc, argv);
- return 0;
+ break;
+ case 'h':
+ print_usage(argc, argv, 0);
+ return 0;
+ case 'v':
+ printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION);
+ return 0;
+ case 's':
+ if (!*optarg) {
+ fprintf(stderr, "ERROR: set argument must not be empty!\n");
+ print_usage(argc, argv, 1);
+ return 2;
}
- setdate = atoi(argv[i]);
+ setdate = atoi(optarg);
if (setdate == 0) {
- printf("ERROR: Invalid timestamp value.\n");
- print_usage(argc, argv);
+ fprintf(stderr, "ERROR: Invalid timestamp value.\n");
+ print_usage(argc, argv, 1);
return 0;
}
- continue;
- }
- else if (!strcmp(argv[i], "-c") || !strcmp(argv[i], "--sync")) {
- i++;
+ break;
+ case 'c':
/* get current time */
setdate = time(NULL);
/* convert it to local time which sets timezone/daylight variables */
tmp = localtime(&setdate);
/* recalculate to make it UTC */
setdate = mktime(tmp);
- continue;
- }
- else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
- print_usage(argc, argv);
- return 0;
- }
- else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
- printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION);
- return 0;
- }
- else {
- print_usage(argc, argv);
- return 0;
+ break;
+ default:
+ print_usage(argc, argv, 1);
+ return 2;
}
}
+ argc -= optind;
+ argv += optind;
ret = idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX);
if (ret != IDEVICE_E_SUCCESS) {
diff --git a/tools/idevicedebug.c b/tools/idevicedebug.c
index 74ce069..36c594e 100644
--- a/tools/idevicedebug.c
+++ b/tools/idevicedebug.c
@@ -32,6 +32,7 @@
#include <time.h>
#include <unistd.h>
#include <libgen.h>
+#include <getopt.h>
#ifdef WIN32
#include <windows.h>
@@ -50,7 +51,8 @@ static int debug_level = 0;
enum cmd_mode {
CMD_NONE = 0,
- CMD_RUN
+ CMD_RUN,
+ CMD_KILL
};
static int quit_flag = 0;
@@ -61,7 +63,12 @@ static void on_signal(int sig)
quit_flag++;
}
-static instproxy_error_t instproxy_client_get_object_by_key_from_info_directionary_for_bundle_identifier(instproxy_client_t client, const char* appid, const char* key, plist_t* node)
+static int cancel_receive()
+{
+ return quit_flag;
+}
+
+static instproxy_error_t instproxy_client_get_object_by_key_from_info_dictionary_for_bundle_identifier(instproxy_client_t client, const char* appid, const char* key, plist_t* node)
{
if (!client || !appid || !key)
return INSTPROXY_E_INVALID_ARG;
@@ -108,103 +115,90 @@ static instproxy_error_t instproxy_client_get_object_by_key_from_info_directiona
return INSTPROXY_E_SUCCESS;
}
-static debugserver_error_t debugserver_client_handle_response(debugserver_client_t client, char** response, int send_reply)
+static debugserver_error_t debugserver_client_handle_response(debugserver_client_t client, char** response, int* exit_status)
{
debugserver_error_t dres = DEBUGSERVER_E_SUCCESS;
- debugserver_command_t command = NULL;
char* o = NULL;
char* r = *response;
+ /* Documentation of response codes can be found here:
+ https://github.com/llvm/llvm-project/blob/4fe839ef3a51e0ea2e72ea2f8e209790489407a2/lldb/docs/lldb-gdb-remote.txt#L1269
+ */
+
if (r[0] == 'O') {
/* stdout/stderr */
debugserver_decode_string(r + 1, strlen(r) - 1, &o);
printf("%s", o);
fflush(stdout);
- if (o != NULL) {
- free(o);
- o = NULL;
- }
-
- free(*response);
- *response = NULL;
-
- if (!send_reply)
- return dres;
-
- /* send reply */
- debugserver_command_new("OK", 0, NULL, &command);
- dres = debugserver_client_send_command(client, command, response, NULL);
- log_debug("result: %d", dres);
- debugserver_command_free(command);
- command = NULL;
} else if (r[0] == 'T') {
/* thread stopped information */
log_debug("Thread stopped. Details:\n%s", r + 1);
-
- free(*response);
- *response = NULL;
-
- if (!send_reply)
- return dres;
-
+ if (exit_status != NULL) {
+ /* "Thread stopped" seems to happen when assert() fails.
+ Use bash convention where signals cause an exit
+ status of 128 + signal
+ */
+ *exit_status = 128 + SIGABRT;
+ }
+ /* Break out of the loop. */
dres = DEBUGSERVER_E_UNKNOWN_ERROR;
- } else if (r[0] == 'E' || r[0] == 'W') {
- printf("%s: %s\n", (r[0] == 'E' ? "ERROR": "WARNING") , r + 1);
-
- free(*response);
- *response = NULL;
-
- if (!send_reply)
- return dres;
-
- /* send reply */
- debugserver_command_new("OK", 0, NULL, &command);
- dres = debugserver_client_send_command(client, command, response, NULL);
- log_debug("result: %d", dres);
- debugserver_command_free(command);
- command = NULL;
+ } else if (r[0] == 'E') {
+ printf("ERROR: %s\n", r + 1);
+ } else if (r[0] == 'W' || r[0] == 'X') {
+ /* process exited */
+ debugserver_decode_string(r + 1, strlen(r) - 1, &o);
+ if (o != NULL) {
+ printf("Exit %s: %u\n", (r[0] == 'W' ? "status" : "due to signal"), o[0]);
+ if (exit_status != NULL) {
+ /* Use bash convention where signals cause an
+ exit status of 128 + signal
+ */
+ *exit_status = o[0] + (r[0] == 'W' ? 0 : 128);
+ }
+ } else {
+ log_debug("Unable to decode exit status from %s", r);
+ dres = DEBUGSERVER_E_UNKNOWN_ERROR;
+ }
} else if (r && strlen(r) == 0) {
- if (!send_reply)
- return dres;
-
- free(*response);
- *response = NULL;
-
- /* no command */
- debugserver_command_new("OK", 0, NULL, &command);
- dres = debugserver_client_send_command(client, command, response, NULL);
- log_debug("result: %d", dres);
- debugserver_command_free(command);
- command = NULL;
+ log_debug("empty response");
} else {
log_debug("ERROR: unhandled response '%s'", r);
}
+ if (o != NULL) {
+ free(o);
+ o = NULL;
+ }
+
+ free(*response);
+ *response = NULL;
return dres;
}
-static void print_usage(int argc, char **argv)
+static void print_usage(int argc, char **argv, int is_error)
{
- char *name = NULL;
- name = strrchr(argv[0], '/');
- printf("Usage: %s [OPTIONS] COMMAND\n", (name ? name + 1: argv[0]));
- printf("\n");
- printf("Interact with the debugserver service of a device.\n");
- printf("\n");
- printf("Where COMMAND is one of:\n");
- printf(" run BUNDLEID [ARGS...]\trun app with BUNDLEID and optional ARGS on device.\n");
- printf("\n");
- printf("The following OPTIONS are accepted:\n");
- printf(" -u, --udid UDID\ttarget specific device by UDID\n");
- printf(" -n, --network\t\tconnect to network device\n");
- printf(" --detach\t\tdetach from app after launch, keeping it running\n");
- printf(" -e, --env NAME=VALUE\tset environment variable NAME to VALUE\n");
- printf(" -d, --debug\t\tenable communication debugging\n");
- printf(" -h, --help\t\tprints usage information\n");
- printf(" -v, --version\t\tprints version information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\n");
- printf("Bug Reports: <" PACKAGE_BUGREPORT ">\n");
+ 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"
+ "Interact with the debugserver service of a device.\n"
+ "\n"
+ "Where COMMAND is one of:\n"
+ " run BUNDLEID [ARGS...] run app with BUNDLEID and optional ARGS on device.\n"
+ " kill BUNDLEID kill app with BUNDLEID\n"
+ "\n"
+ "The following OPTIONS are accepted:\n"
+ " -u, --udid UDID target specific device by UDID\n"
+ " -n, --network connect to network device\n"
+ " --detach detach from app after launch, keeping it running\n"
+ " -e, --env NAME=VALUE set environment variable NAME to VALUE\n"
+ " -d, --debug enable communication debugging\n"
+ " -h, --help prints usage information\n"
+ " -v, --version prints version information\n"
+ "\n"
+ "Homepage: <" PACKAGE_URL ">\n"
+ "Bug Reports: <" PACKAGE_BUGREPORT ">\n"
+ );
}
int main(int argc, char *argv[])
@@ -230,6 +224,18 @@ int main(int argc, char *argv[])
debugserver_command_t command = NULL;
debugserver_error_t dres = DEBUGSERVER_E_UNKNOWN_ERROR;
+ 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' },
+ { "detach", no_argument, NULL, 1 },
+ { "env", required_argument, NULL, 'e' },
+ { "version", no_argument, NULL, 'v' },
+ { NULL, 0, NULL, 0 }
+ };
+
/* map signals */
signal(SIGINT, on_signal);
signal(SIGTERM, on_signal);
@@ -238,32 +244,33 @@ int main(int argc, char *argv[])
signal(SIGPIPE, SIG_IGN);
#endif
- /* parse command line arguments */
- for (i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) {
+ while ((c = getopt_long(argc, argv, "dhu:ne:v", longopts, NULL)) != -1) {
+ switch (c) {
+ case 'd':
debug_level++;
- idevice_set_debug_level(debug_level);
- continue;
- } else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--udid")) {
- i++;
- if (!argv[i] || !*argv[i]) {
- print_usage(argc, argv);
- res = 0;
- goto cleanup;
+ if (debug_level > 1) {
+ idevice_set_debug_level(debug_level-1);
}
- udid = argv[i];
- continue;
- } else if (!strcmp(argv[i], "-n") || !strcmp(argv[i], "--network")) {
+ break;
+ case 'u':
+ if (!*optarg) {
+ fprintf(stderr, "ERROR: UDID must not be empty!\n");
+ print_usage(argc, argv, 1);
+ return 2;
+ }
+ udid = optarg;
+ break;
+ case 'n':
use_network = 1;
- continue;
- } else if (!strcmp(argv[i], "--detach")) {
+ break;
+ case 1:
detach_after_start = 1;
- continue;
- } else if (!strcmp(argv[i], "-e") || !strcmp(argv[i], "--env")) {
- i++;
- if (!argv[i] || (strlen(argv[i]) <= 1) || strchr(argv[i], '=') == NULL) {
- print_usage(argc, argv);
- res = 0;
+ break;
+ case 'e':
+ if (!*optarg || strchr(optarg, '=') == NULL) {
+ fprintf(stderr, "ERROR: environment variables need to be specified as -e KEY=VALUE\n");
+ print_usage(argc, argv, 1);
+ res = 2;
goto cleanup;
}
/* add environment variable */
@@ -271,50 +278,75 @@ int main(int argc, char *argv[])
newlist = malloc((environment_count + 1) * sizeof(char*));
else
newlist = realloc(environment, (environment_count + 1) * sizeof(char*));
- newlist[environment_count++] = strdup(argv[i]);
+ newlist[environment_count++] = strdup(optarg);
environment = newlist;
- continue;
- } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
- print_usage(argc, argv);
+ break;
+ case 'h':
+ print_usage(argc, argv, 0);
res = 0;
goto cleanup;
- } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
+ break;
+ case 'v':
printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION);
res = 0;
goto cleanup;
- } else if (!strcmp(argv[i], "run")) {
- cmd = CMD_RUN;
-
- i++;
- if (!argv[i]) {
- /* make sure at least the bundle identifier was provided */
- printf("Please supply the bundle identifier of the app to run.\n");
- print_usage(argc, argv);
- res = 0;
- goto cleanup;
- }
- /* read bundle identifier */
- bundle_identifier = argv[i];
break;
- } else {
- print_usage(argc, argv);
- res = 0;
+ default:
+ print_usage(argc, argv, 1);
+ res = 2;
goto cleanup;
+ break;
}
}
+ argc -= optind;
+ argv += optind;
- if (environment) {
- newlist = realloc(environment, (environment_count + 1) * sizeof(char*));
- newlist[environment_count] = NULL;
- environment = newlist;
+ if (argc < 1) {
+ fprintf(stderr, "ERROR: Missing command.\n");
+ print_usage(argc+optind, argv-optind, 1);
+ return 2;
+ }
+
+ if (!strcmp(argv[0], "run")) {
+ cmd = CMD_RUN;
+ if (argc < 2) {
+ /* make sure at least the bundle identifier was provided */
+ fprintf(stderr, "ERROR: Please supply the bundle identifier of the app to run.\n");
+ print_usage(argc+optind, argv-optind, 1);
+ res = 2;
+ goto cleanup;
+ }
+ /* read bundle identifier */
+ bundle_identifier = argv[1];
+ i = 1;
+ } else if (!strcmp(argv[0], "kill")) {
+ cmd = CMD_KILL;
+ if (argc < 2) {
+ /* make sure at least the bundle identifier was provided */
+ fprintf(stderr, "ERROR: Please supply the bundle identifier of the app to run.\n");
+ print_usage(argc+optind, argv-optind, 1);
+ res = 2;
+ goto cleanup;
+ }
+ /* read bundle identifier */
+ bundle_identifier = argv[1];
+ i = 1;
}
/* verify options */
if (cmd == CMD_NONE) {
- print_usage(argc, argv);
+ fprintf(stderr, "ERROR: Unsupported command specified.\n");
+ print_usage(argc+optind, argv-optind, 1);
+ res = 2;
goto cleanup;
}
+ if (environment) {
+ newlist = realloc(environment, (environment_count + 1) * sizeof(char*));
+ newlist[environment_count] = NULL;
+ environment = newlist;
+ }
+
/* connect to the device */
ret = idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX);
if (ret != IDEVICE_E_SUCCESS) {
@@ -326,198 +358,243 @@ int main(int argc, char *argv[])
goto cleanup;
}
- switch (cmd) {
- case CMD_RUN:
- default:
- /* get the path to the app and it's working directory */
- if (instproxy_client_start_service(device, &instproxy_client, TOOL_NAME) != INSTPROXY_E_SUCCESS) {
- fprintf(stderr, "Could not start installation proxy service.\n");
- goto cleanup;
- }
- plist_t container = NULL;
- instproxy_client_get_object_by_key_from_info_directionary_for_bundle_identifier(instproxy_client, bundle_identifier, "Container", &container);
- instproxy_client_get_path_for_bundle_identifier(instproxy_client, bundle_identifier, &path);
- instproxy_client_free(instproxy_client);
- instproxy_client = NULL;
-
- if (container && (plist_get_node_type(container) == PLIST_STRING)) {
- plist_get_string_val(container, &working_directory);
- log_debug("working_directory: %s\n", working_directory);
- plist_free(container);
- } else {
- plist_free(container);
- fprintf(stderr, "Could not determine container path for bundle identifier %s.\n", bundle_identifier);
- goto cleanup;
- }
+ /* get the path to the app and it's working directory */
+ if (instproxy_client_start_service(device, &instproxy_client, TOOL_NAME) != INSTPROXY_E_SUCCESS) {
+ fprintf(stderr, "Could not start installation proxy service.\n");
+ goto cleanup;
+ }
- /* start and connect to debugserver */
- if (debugserver_client_start_service(device, &debugserver_client, TOOL_NAME) != DEBUGSERVER_E_SUCCESS) {
- fprintf(stderr,
- "Could not start com.apple.debugserver!\n"
- "Please make sure to mount the developer disk image first:\n"
- " 1) Get the iOS version from `ideviceinfo -k ProductVersion`.\n"
- " 2) Find the matching iPhoneOS DeveloperDiskImage.dmg files.\n"
- " 3) Run `ideviceimagemounter` with the above path.\n");
- goto cleanup;
- }
+ instproxy_client_get_path_for_bundle_identifier(instproxy_client, bundle_identifier, &path);
+ if (!path) {
+ fprintf(stderr, "Invalid bundle identifier: %s\n", bundle_identifier);
+ goto cleanup;
+ }
- /* enable logging for the session in debug mode */
- if (debug_level) {
- log_debug("Setting logging bitmask...");
- debugserver_command_new("QSetLogging:bitmask=LOG_ALL|LOG_RNB_REMOTE|LOG_RNB_PACKETS", 0, NULL, &command);
- dres = debugserver_client_send_command(debugserver_client, command, &response, NULL);
- debugserver_command_free(command);
- command = NULL;
- if (response) {
- if (strncmp(response, "OK", 2)) {
- debugserver_client_handle_response(debugserver_client, &response, 0);
- goto cleanup;
- }
- free(response);
- response = NULL;
- }
- }
+ plist_t container = NULL;
+ instproxy_client_get_object_by_key_from_info_dictionary_for_bundle_identifier(instproxy_client, bundle_identifier, "Container", &container);
+ instproxy_client_free(instproxy_client);
+ instproxy_client = NULL;
- /* set maximum packet size */
- log_debug("Setting maximum packet size...");
- char* packet_size[2] = {strdup("1024"), NULL};
- debugserver_command_new("QSetMaxPacketSize:", 1, packet_size, &command);
- free(packet_size[0]);
- dres = debugserver_client_send_command(debugserver_client, command, &response, NULL);
- debugserver_command_free(command);
- command = NULL;
- if (response) {
- if (strncmp(response, "OK", 2)) {
- debugserver_client_handle_response(debugserver_client, &response, 0);
- goto cleanup;
- }
- free(response);
- response = NULL;
- }
+ if (container && (plist_get_node_type(container) == PLIST_STRING)) {
+ plist_get_string_val(container, &working_directory);
+ log_debug("working_directory: %s\n", working_directory);
+ plist_free(container);
+ } else {
+ plist_free(container);
+ fprintf(stderr, "Could not determine container path for bundle identifier %s.\n", bundle_identifier);
+ goto cleanup;
+ }
- /* set working directory */
- log_debug("Setting working directory...");
- char* working_dir[2] = {working_directory, NULL};
- debugserver_command_new("QSetWorkingDir:", 1, working_dir, &command);
- dres = debugserver_client_send_command(debugserver_client, command, &response, NULL);
- debugserver_command_free(command);
- command = NULL;
- if (response) {
- if (strncmp(response, "OK", 2)) {
- debugserver_client_handle_response(debugserver_client, &response, 0);
- goto cleanup;
- }
- free(response);
- response = NULL;
- }
+ /* start and connect to debugserver */
+ if (debugserver_client_start_service(device, &debugserver_client, TOOL_NAME) != DEBUGSERVER_E_SUCCESS) {
+ fprintf(stderr,
+ "Could not start com.apple.debugserver!\n"
+ "Please make sure to mount the developer disk image first:\n"
+ " 1) Get the iOS version from `ideviceinfo -k ProductVersion`.\n"
+ " 2) Find the matching iPhoneOS DeveloperDiskImage.dmg files.\n"
+ " 3) Run `ideviceimagemounter` with the above path.\n");
+ goto cleanup;
+ }
- /* set environment */
- if (environment) {
- log_debug("Setting environment...");
- for (environment_index = 0; environment_index < environment_count; environment_index++) {
- log_debug("setting environment variable: %s", environment[environment_index]);
- debugserver_client_set_environment_hex_encoded(debugserver_client, environment[environment_index], NULL);
- }
- }
+ /* set receive params */
+ if (debugserver_client_set_receive_params(debugserver_client, cancel_receive, 250) != DEBUGSERVER_E_SUCCESS) {
+ fprintf(stderr, "Error in debugserver_client_set_receive_params\n");
+ goto cleanup;
+ }
- /* set arguments and run app */
- log_debug("Setting argv...");
- i++; /* i is the offset of the bundle identifier, thus skip it */
- int app_argc = (argc - i + 2);
- char **app_argv = (char**)malloc(sizeof(char*) * app_argc);
- app_argv[0] = path;
- log_debug("app_argv[%d] = %s", 0, app_argv[0]);
- app_argc = 1;
- while (i < argc && argv && argv[i]) {
- log_debug("app_argv[%d] = %s", app_argc, argv[i]);
- app_argv[app_argc++] = argv[i];
- i++;
+ /* enable logging for the session in debug mode */
+ if (debug_level) {
+ log_debug("Setting logging bitmask...");
+ debugserver_command_new("QSetLogging:bitmask=LOG_ALL|LOG_RNB_REMOTE|LOG_RNB_PACKETS;", 0, NULL, &command);
+ dres = debugserver_client_send_command(debugserver_client, command, &response, NULL);
+ debugserver_command_free(command);
+ command = NULL;
+ if (response) {
+ if (strncmp(response, "OK", 2) != 0) {
+ debugserver_client_handle_response(debugserver_client, &response, NULL);
+ goto cleanup;
}
- app_argv[app_argc] = NULL;
- debugserver_client_set_argv(debugserver_client, app_argc, app_argv, NULL);
- free(app_argv);
+ free(response);
+ response = NULL;
+ }
+ }
- /* check if launch succeeded */
- log_debug("Checking if launch succeeded...");
- debugserver_command_new("qLaunchSuccess", 0, NULL, &command);
+ /* set maximum packet size */
+ log_debug("Setting maximum packet size...");
+ char* packet_size[2] = { (char*)"1024", NULL};
+ debugserver_command_new("QSetMaxPacketSize:", 1, packet_size, &command);
+ dres = debugserver_client_send_command(debugserver_client, command, &response, NULL);
+ debugserver_command_free(command);
+ command = NULL;
+ if (response) {
+ if (strncmp(response, "OK", 2) != 0) {
+ debugserver_client_handle_response(debugserver_client, &response, NULL);
+ goto cleanup;
+ }
+ free(response);
+ response = NULL;
+ }
+
+ /* set working directory */
+ log_debug("Setting working directory...");
+ char* working_dir[2] = {working_directory, NULL};
+ debugserver_command_new("QSetWorkingDir:", 1, working_dir, &command);
+ dres = debugserver_client_send_command(debugserver_client, command, &response, NULL);
+ debugserver_command_free(command);
+ command = NULL;
+ if (response) {
+ if (strncmp(response, "OK", 2) != 0) {
+ debugserver_client_handle_response(debugserver_client, &response, NULL);
+ goto cleanup;
+ }
+ free(response);
+ response = NULL;
+ }
+
+ /* set environment */
+ if (environment) {
+ log_debug("Setting environment...");
+ for (environment_index = 0; environment_index < environment_count; environment_index++) {
+ log_debug("setting environment variable: %s", environment[environment_index]);
+ debugserver_client_set_environment_hex_encoded(debugserver_client, environment[environment_index], NULL);
+ }
+ }
+
+ /* set arguments and run app */
+ log_debug("Setting argv...");
+ i++; /* i is the offset of the bundle identifier, thus skip it */
+ int app_argc = (argc - i + 2);
+ char **app_argv = (char**)malloc(sizeof(char*) * app_argc);
+ app_argv[0] = path;
+ log_debug("app_argv[%d] = %s", 0, app_argv[0]);
+ app_argc = 1;
+ while (i < argc && argv && argv[i]) {
+ log_debug("app_argv[%d] = %s", app_argc, argv[i]);
+ app_argv[app_argc++] = argv[i];
+ i++;
+ }
+ app_argv[app_argc] = NULL;
+ debugserver_client_set_argv(debugserver_client, app_argc, app_argv, NULL);
+ free(app_argv);
+
+ /* check if launch succeeded */
+ log_debug("Checking if launch succeeded...");
+ debugserver_command_new("qLaunchSuccess", 0, NULL, &command);
+ dres = debugserver_client_send_command(debugserver_client, command, &response, NULL);
+ debugserver_command_free(command);
+ command = NULL;
+ if (response) {
+ if (strncmp(response, "OK", 2) != 0) {
+ debugserver_client_handle_response(debugserver_client, &response, NULL);
+ goto cleanup;
+ }
+ free(response);
+ response = NULL;
+ }
+
+ if (cmd == CMD_KILL) {
+ debugserver_command_new("k", 0, NULL, &command);
+ dres = debugserver_client_send_command(debugserver_client, command, &response, NULL);
+ debugserver_command_free(command);
+ command = NULL;
+ goto cleanup;
+ } else
+ if (cmd == CMD_RUN) {
+ if (detach_after_start) {
+ log_debug("Detaching from app");
+ debugserver_command_new("D", 0, NULL, &command);
dres = debugserver_client_send_command(debugserver_client, command, &response, NULL);
debugserver_command_free(command);
command = NULL;
- if (response) {
- if (strncmp(response, "OK", 2)) {
- debugserver_client_handle_response(debugserver_client, &response, 0);
- goto cleanup;
- }
- free(response);
- response = NULL;
+
+ res = (dres == DEBUGSERVER_E_SUCCESS) ? 0: -1;
+ goto cleanup;
+ }
+
+ /* set thread */
+ log_debug("Setting thread...");
+ debugserver_command_new("Hc0", 0, NULL, &command);
+ dres = debugserver_client_send_command(debugserver_client, command, &response, NULL);
+ debugserver_command_free(command);
+ command = NULL;
+ if (response) {
+ if (strncmp(response, "OK", 2) != 0) {
+ debugserver_client_handle_response(debugserver_client, &response, NULL);
+ goto cleanup;
}
+ free(response);
+ response = NULL;
+ }
- if (detach_after_start) {
- log_debug("Detaching from app");
- debugserver_command_new("D", 0, NULL, &command);
- dres = debugserver_client_send_command(debugserver_client, command, &response, NULL);
- debugserver_command_free(command);
- command = NULL;
+ /* continue running process */
+ log_debug("Continue running process...");
+ debugserver_command_new("c", 0, NULL, &command);
+ dres = debugserver_client_send_command(debugserver_client, command, &response, NULL);
+ debugserver_command_free(command);
+ command = NULL;
+ log_debug("Continue response: %s", response);
- res = (dres == DEBUGSERVER_E_SUCCESS) ? 0: -1;
+ /* main loop which is parsing/handling packets during the run */
+ log_debug("Entering run loop...");
+ while (!quit_flag) {
+ if (dres != DEBUGSERVER_E_SUCCESS) {
+ log_debug("failed to receive response; error %d", dres);
break;
}
- /* set thread */
- log_debug("Setting thread...");
- debugserver_command_new("Hc0", 0, NULL, &command);
- dres = debugserver_client_send_command(debugserver_client, command, &response, NULL);
- debugserver_command_free(command);
- command = NULL;
if (response) {
- if (strncmp(response, "OK", 2)) {
- debugserver_client_handle_response(debugserver_client, &response, 0);
- goto cleanup;
+ log_debug("response: %s", response);
+ if (strncmp(response, "OK", 2) != 0) {
+ dres = debugserver_client_handle_response(debugserver_client, &response, &res);
+ if (dres != DEBUGSERVER_E_SUCCESS) {
+ log_debug("failed to process response; error %d; %s", dres, response);
+ break;
+ }
}
- free(response);
- response = NULL;
+ }
+ if (res >= 0) {
+ goto cleanup;
}
- /* continue running process */
- log_debug("Continue running process...");
- debugserver_command_new("c", 0, NULL, &command);
- dres = debugserver_client_send_command(debugserver_client, command, &response, NULL);
- debugserver_command_free(command);
- command = NULL;
-
- /* main loop which is parsing/handling packets during the run */
- log_debug("Entering run loop...");
- while (!quit_flag) {
- if (dres != DEBUGSERVER_E_SUCCESS) {
- log_debug("failed to receive response");
- break;
- }
+ dres = debugserver_client_receive_response(debugserver_client, &response, NULL);
+ }
- if (response) {
- log_debug("response: %s", response);
- dres = debugserver_client_handle_response(debugserver_client, &response, 1);
- }
+ /* ignore quit_flag after this point */
+ if (debugserver_client_set_receive_params(debugserver_client, NULL, 5000) != DEBUGSERVER_E_SUCCESS) {
+ fprintf(stderr, "Error in debugserver_client_set_receive_params\n");
+ goto cleanup;
+ }
- sleep(1);
+ /* interrupt execution */
+ debugserver_command_new("\x03", 0, NULL, &command);
+ dres = debugserver_client_send_command(debugserver_client, command, &response, NULL);
+ debugserver_command_free(command);
+ command = NULL;
+ if (response) {
+ if (strncmp(response, "OK", 2) != 0) {
+ debugserver_client_handle_response(debugserver_client, &response, NULL);
}
+ free(response);
+ response = NULL;
+ }
- /* kill process after we finished */
- log_debug("Killing process...");
- debugserver_command_new("k", 0, NULL, &command);
- dres = debugserver_client_send_command(debugserver_client, command, &response, NULL);
- debugserver_command_free(command);
- command = NULL;
- if (response) {
- if (strncmp(response, "OK", 2)) {
- debugserver_client_handle_response(debugserver_client, &response, 0);
- goto cleanup;
- }
- free(response);
- response = NULL;
+ /* kill process after we finished */
+ log_debug("Killing process...");
+ debugserver_command_new("k", 0, NULL, &command);
+ dres = debugserver_client_send_command(debugserver_client, command, &response, NULL);
+ debugserver_command_free(command);
+ command = NULL;
+ if (response) {
+ if (strncmp(response, "OK", 2) != 0) {
+ debugserver_client_handle_response(debugserver_client, &response, NULL);
}
+ free(response);
+ response = NULL;
+ }
+ if (res < 0) {
res = (dres == DEBUGSERVER_E_SUCCESS) ? 0: -1;
- break;
+ }
}
cleanup:
diff --git a/tools/idevicedebugserverproxy.c b/tools/idevicedebugserverproxy.c
index 5b42473..9fe7051 100644
--- a/tools/idevicedebugserverproxy.c
+++ b/tools/idevicedebugserverproxy.c
@@ -2,6 +2,7 @@
* idevicedebugserverproxy.c
* Proxy a debugserver connection from device for remote debugging
*
+ * Copyright (c) 2021 Nikias Bassen, All Rights Reserved.
* Copyright (c) 2012 Martin Szulecki All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
@@ -28,31 +29,43 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <getopt.h>
#include <errno.h>
#include <signal.h>
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#else
+#include <sys/select.h>
+#endif
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/debugserver.h>
-#include "common/socket.h"
-#include "common/thread.h"
+#include <libimobiledevice-glue/socket.h>
+#include <libimobiledevice-glue/thread.h>
+
+#ifndef ETIMEDOUT
+#define ETIMEDOUT 138
+#endif
#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;
idevice_t device;
debugserver_client_t debugserver_client;
- volatile int stop_ctod;
- volatile int stop_dtoc;
} socket_info_t;
struct thread_info {
THREAD_T th;
+ int client_fd;
struct thread_info *next;
};
@@ -65,173 +78,114 @@ static void clean_exit(int sig)
quit_flag++;
}
-static void print_usage(int argc, char **argv)
+static void print_usage(int argc, char **argv, int is_error)
{
- char *name = NULL;
-
- name = strrchr(argv[0], '/');
- printf("Usage: %s [OPTIONS] <PORT>\n", (name ? name + 1: argv[0]));
- printf("\n");
- printf("Proxy debugserver connection from device to a local socket at PORT.\n");
- printf("\n");
- printf("OPTIONS:\n");
- printf(" -u, --udid UDID\ttarget specific device by UDID\n");
- printf(" -n, --network\t\tconnect to network device\n");
- printf(" -d, --debug\t\tenable communication debugging\n");
- printf(" -h, --help\t\tprints usage information\n");
- printf(" -v, --version\t\tprints version information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\n");
- printf("Bug Reports: <" PACKAGE_BUGREPORT ">\n");
+ char *name = strrchr(argv[0], '/');
+ fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS] [PORT]\n", (name ? name + 1: argv[0]));
+ fprintf(is_error ? stderr : stdout,
+ "\n"
+ "Proxy debugserver connection from device to a local socket at PORT.\n"
+ "If PORT is omitted, the next available port will be used and printed\n"
+ "to stdout.\n"
+ "\n"
+ "OPTIONS:\n"
+ " -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"
+ "Homepage: <" PACKAGE_URL ">\n"
+ "Bug Reports: <" PACKAGE_BUGREPORT ">\n"
+ );
}
-static void *thread_device_to_client(void *data)
-{
- socket_info_t* socket_info = (socket_info_t*)data;
- debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR;
-
- int recv_len;
- int sent;
- char buffer[131072];
-
- debug("%s: started thread...\n", __func__);
-
- debug("%s: client_fd = %d\n", __func__, socket_info->client_fd);
-
- while (!quit_flag && !socket_info->stop_dtoc && socket_info->client_fd > 0) {
- debug("%s: receiving data from device...\n", __func__);
-
- res = debugserver_client_receive_with_timeout(socket_info->debugserver_client, buffer, sizeof(buffer), (uint32_t*)&recv_len, 5000);
+static int intercept_packet(char *packet, ssize_t *packet_len) {
+ static const char kReqLaunchServer[] = "$qLaunchGDBServer;#4b";
- if (recv_len <= 0) {
- if (recv_len == 0 && res == DEBUGSERVER_E_SUCCESS) {
- // try again
- continue;
- } else {
- fprintf(stderr, "recv failed: %s\n", strerror(errno));
- break;
- }
- } else {
- /* send to device */
- debug("%s: sending data to client...\n", __func__);
- sent = socket_send(socket_info->client_fd, buffer, recv_len);
- if (sent < recv_len) {
- if (sent <= 0) {
- fprintf(stderr, "send failed: %s\n", strerror(errno));
- break;
- } else {
- fprintf(stderr, "only sent %d from %d bytes\n", sent, recv_len);
- }
- } else {
- // sending succeeded, receive from device
- debug("%s: pushed %d bytes to client\n", __func__, sent);
- }
- }
+ 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;
}
-
- debug("%s: shutting down...\n", __func__);
-
- socket_shutdown(socket_info->client_fd, SHUT_RDWR);
- socket_close(socket_info->client_fd);
-
- socket_info->client_fd = -1;
- socket_info->stop_ctod = 1;
-
- return NULL;
+ 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 *thread_client_to_device(void *data)
+static void* connection_handler(void* data)
{
+ debugserver_error_t derr = DEBUGSERVER_E_SUCCESS;
socket_info_t* socket_info = (socket_info_t*)data;
- debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR;
+ const int bufsize = 65536;
+ char* buf;
- int recv_len;
- int sent;
- char buffer[131072];
- THREAD_T dtoc;
+ int client_fd = socket_info->client_fd;
- debug("%s: started thread...\n", __func__);
+ debug("%s: client_fd = %d\n", __func__, client_fd);
- debug("%s: client_fd = %d\n", __func__, socket_info->client_fd);
+ derr = debugserver_client_start_service(socket_info->device, &socket_info->debugserver_client, TOOL_NAME);
+ if (derr != DEBUGSERVER_E_SUCCESS) {
+ fprintf(stderr, "Could not start debugserver on device!\nPlease make sure to mount a developer disk image first.\n");
+ return NULL;
+ }
- /* spawn server to client thread */
- socket_info->stop_dtoc = 0;
- if (thread_new(&dtoc, thread_device_to_client, data) != 0) {
- fprintf(stderr, "Failed to start device to client thread...\n");
+ buf = malloc(bufsize);
+ if (!buf) {
+ fprintf(stderr, "Failed to allocate buffer\n");
+ return NULL;
}
- while (!quit_flag && !socket_info->stop_ctod && socket_info->client_fd > 0) {
- debug("%s: receiving data from client...\n", __func__);
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(client_fd, &fds);
- /* attempt to read incoming data from client */
- recv_len = socket_receive_timeout(socket_info->client_fd, buffer, sizeof(buffer), 0, 5000);
+ int dtimeout = 1;
- /* any data received? */
- if (recv_len <= 0) {
- if (recv_len == 0) {
- /* try again */
- continue;
- } else {
- fprintf(stderr, "Receive failed: %s\n", strerror(errno));
+ while (!quit_flag) {
+ ssize_t n = socket_receive_timeout(client_fd, buf, bufsize, 0, 1);
+ if (n != -ETIMEDOUT) {
+ if (n < 0) {
+ fprintf(stderr, "Failed to read from client fd: %s\n", strerror(-n));
+ break;
+ } else if (n == 0) {
+ fprintf(stderr, "connection closed\n");
break;
}
- } else {
- /* forward data to device */
- debug("%s: sending data to device...\n", __func__);
- res = debugserver_client_send(socket_info->debugserver_client, buffer, recv_len, (uint32_t*)&sent);
-
- if (sent < recv_len || res != DEBUGSERVER_E_SUCCESS) {
- if (sent <= 0) {
- fprintf(stderr, "send failed: %s\n", strerror(errno));
- break;
- } else {
- fprintf(stderr, "only sent %d from %d bytes\n", sent, recv_len);
- }
+ 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);
+ }
+ do {
+ uint32_t r = 0;
+ derr = debugserver_client_receive_with_timeout(socket_info->debugserver_client, buf, bufsize, &r, dtimeout);
+ if (r > 0) {
+ socket_send(client_fd, buf, r);
+ dtimeout = 1;
+ } else if (derr == DEBUGSERVER_E_TIMEOUT) {
+ dtimeout = 5;
+ break;
} else {
- // sending succeeded, receive from device
- debug("%s: sent %d bytes to device\n", __func__, sent);
+ fprintf(stderr, "debugserver connection closed\n");
+ break;
}
+ } while (derr == DEBUGSERVER_E_SUCCESS);
+ if (derr != DEBUGSERVER_E_TIMEOUT && derr != DEBUGSERVER_E_SUCCESS) {
+ break;
}
}
-
- debug("%s: shutting down...\n", __func__);
-
- socket_shutdown(socket_info->client_fd, SHUT_RDWR);
- socket_close(socket_info->client_fd);
-
- socket_info->client_fd = -1;
- socket_info->stop_dtoc = 1;
-
- /* join other thread to allow it to stop */
- thread_join(dtoc);
- thread_free(dtoc);
-
- return NULL;
-}
-
-static void* connection_handler(void* data)
-{
- debugserver_error_t derr = DEBUGSERVER_E_SUCCESS;
- socket_info_t* socket_info = (socket_info_t*)data;
- THREAD_T ctod;
-
- debug("%s: client_fd = %d\n", __func__, socket_info->client_fd);
-
- derr = debugserver_client_start_service(socket_info->device, &socket_info->debugserver_client, TOOL_NAME);
- if (derr != DEBUGSERVER_E_SUCCESS) {
- fprintf(stderr, "Could not start debugserver on device!\nPlease make sure to mount a developer disk image first.\n");
- return NULL;
- }
-
- /* spawn client to device thread */
- socket_info->stop_ctod = 0;
- if (thread_new(&ctod, thread_client_to_device, data) != 0) {
- fprintf(stderr, "Failed to start client to device thread...\n");
- }
-
- /* join the fun */
- thread_join(ctod);
- thread_free(ctod);
+ free(buf);
debug("%s: shutting down...\n", __func__);
@@ -252,10 +206,18 @@ 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 i;
+ 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' },
+ { "lldb", no_argument, NULL, 'l' },
+ { "version", no_argument, NULL, 'v' },
+ { NULL, 0, NULL, 0}
+ };
#ifndef WIN32
struct sigaction sa;
@@ -280,49 +242,43 @@ int main(int argc, char *argv[])
#endif
/* parse cmdline arguments */
- for (i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) {
+ while ((c = getopt_long(argc, argv, "dhu:nv", longopts, NULL)) != -1) {
+ switch (c) {
+ case 'd':
debug_mode = 1;
idevice_set_debug_level(1);
socket_set_verbose(3);
- continue;
- }
- else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--udid")) {
- i++;
- if (!argv[i] || !*argv[i]) {
- print_usage(argc, argv);
- return 0;
+ break;
+ case 'u':
+ if (!*optarg) {
+ fprintf(stderr, "ERROR: UDID argument must not be empty!\n");
+ print_usage(argc, argv, 1);
+ return 2;
}
- udid = argv[i];
- continue;
- }
- else if (!strcmp(argv[i], "-n") || !strcmp(argv[i], "--network")) {
+ udid = optarg;
+ break;
+ case 'n':
use_network = 1;
- continue;
- }
- else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
- print_usage(argc, argv);
- return EXIT_SUCCESS;
- }
- else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
+ break;
+ case 'l':
+ support_lldb = 1;
+ break;
+ case 'h':
+ print_usage(argc, argv, 0);
+ return 0;
+ case 'v':
printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION);
- return EXIT_SUCCESS;
- }
- else if (atoi(argv[i]) > 0) {
- local_port = atoi(argv[i]);
- continue;
- }
- else {
- print_usage(argc, argv);
- return EXIT_SUCCESS;
+ return 0;
+ default:
+ print_usage(argc, argv, 1);
+ return 2;
}
}
+ argc -= optind;
+ argv += optind;
- /* a PORT is mandatory */
- if (!local_port) {
- fprintf(stderr, "Please specify a PORT.\n");
- print_usage(argc, argv);
- goto leave_cleanup;
+ if (argv[0] && (atoi(argv[0]) > 0)) {
+ local_port = atoi(argv[0]);
}
/* start services and connect to device */
@@ -345,6 +301,17 @@ int main(int argc, char *argv[])
goto leave_cleanup;
}
+ if (local_port == 0) {
+ /* The user asked for any available port. Report the actual port. */
+ uint16_t port;
+ if (0 > socket_get_socket_port(server_fd, &port)) {
+ fprintf(stderr, "Could not determine socket port\n");
+ result = EXIT_FAILURE;
+ goto leave_cleanup;
+ }
+ printf("Listening on port %d\n", port);
+ }
+
while (!quit_flag) {
debug("%s: Waiting for connection on local port %d\n", __func__, local_port);
@@ -361,6 +328,7 @@ int main(int argc, char *argv[])
fprintf(stderr, "Out of memory\n");
exit(EXIT_FAILURE);
}
+ el->client_fd = client_fd;
el->next = NULL;
if (thread_list) {
@@ -390,6 +358,8 @@ int main(int argc, char *argv[])
/* join and clean up threads */
while (thread_list) {
thread_info_t *el = thread_list;
+ socket_shutdown(el->client_fd, SHUT_RDWR);
+ socket_close(el->client_fd);
thread_join(el->th);
thread_free(el->th);
thread_list = el->next;
diff --git a/tools/idevicedevmodectl.c b/tools/idevicedevmodectl.c
new file mode 100644
index 0000000..bd1de6a
--- /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 0e3e66e..e699bc4 100644
--- a/tools/idevicediagnostics.c
+++ b/tools/idevicediagnostics.c
@@ -28,6 +28,7 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <getopt.h>
#include <errno.h>
#include <time.h>
#ifndef WIN32
@@ -59,7 +60,34 @@ static void print_xml(plist_t node)
}
}
-void print_usage(int argc, char **argv);
+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"
+ "Use diagnostics interface of a device running iOS 4 or later.\n"
+ "\n"
+ "Where COMMAND is one of:\n"
+ " diagnostics [TYPE] print diagnostics information from device by TYPE (All, WiFi, GasGauge, NAND)\n"
+ " mobilegestalt KEY [...] print mobilegestalt keys passed as arguments separated by a space.\n"
+ " ioreg [PLANE] print IORegistry of device, optionally by PLANE (IODeviceTree, IOPower, IOService) (iOS 5+ only)\n"
+ " ioregentry [KEY] print IORegistry entry of device (AppleARMPMUCharger, ASPStorage, ...) (iOS 5+ only)\n"
+ " shutdown shutdown device\n"
+ " restart restart device\n"
+ " sleep put device into sleep mode (disconnects from host)\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 prints usage information\n"
+ " -v, --version prints version information\n"
+ "\n"
+ "Homepage: <" PACKAGE_URL ">\n"
+ "Bug Reports: <" PACKAGE_BUGREPORT ">\n"
+ );
+}
int main(int argc, char **argv)
{
@@ -69,130 +97,119 @@ int main(int argc, char **argv)
lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
lockdownd_service_descriptor_t service = NULL;
int result = EXIT_FAILURE;
- int i;
const char *udid = NULL;
int use_network = 0;
int cmd = CMD_NONE;
char* cmd_arg = NULL;
plist_t node = NULL;
plist_t keys = 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 */
- for (i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) {
+ while ((c = getopt_long(argc, argv, "dhu:nv", longopts, NULL)) != -1) {
+ switch (c) {
+ case 'd':
idevice_set_debug_level(1);
- continue;
- }
- else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--udid")) {
- i++;
- if (!argv[i] || !*argv[i]) {
- print_usage(argc, argv);
- result = EXIT_SUCCESS;
- goto cleanup;
+ break;
+ case 'u':
+ if (!*optarg) {
+ fprintf(stderr, "ERROR: UDID argument must not be empty!\n");
+ print_usage(argc, argv, 1);
+ return 2;
}
- udid = argv[i];
- continue;
- }
- else if (!strcmp(argv[i], "-n") || !strcmp(argv[i], "--network")) {
+ udid = optarg;
+ break;
+ case 'n':
use_network = 1;
- continue;
- }
- else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
- print_usage(argc, argv);
- result = EXIT_SUCCESS;
- goto cleanup;
- }
- else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
+ break;
+ case 'h':
+ print_usage(argc, argv, 0);
+ return 0;
+ case 'v':
printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION);
- result = EXIT_SUCCESS;
- goto cleanup;
- }
- else if (!strcmp(argv[i], "sleep")) {
- cmd = CMD_SLEEP;
+ return 0;
+ default:
+ print_usage(argc, argv, 1);
+ return 2;
}
- else if (!strcmp(argv[i], "restart")) {
- cmd = CMD_RESTART;
- }
- else if (!strcmp(argv[i], "shutdown")) {
- cmd = CMD_SHUTDOWN;
- }
- else if (!strcmp(argv[i], "diagnostics")) {
- cmd = CMD_DIAGNOSTICS;
- /* read type */
- i++;
- if (!argv[i] || ((strcmp(argv[i], "All") != 0) && (strcmp(argv[i], "WiFi") != 0) && (strcmp(argv[i], "GasGauge") != 0) && (strcmp(argv[i], "NAND") != 0) && (strcmp(argv[i], "HDMI") != 0))) {
- if (argv[i] == NULL) {
- cmd_arg = strdup("All");
- continue;
- }
+ }
+ argc -= optind;
+ argv += optind;
- if (!strncmp(argv[i], "-", 1)) {
- cmd_arg = strdup("All");
- i--;
- continue;
- }
+ if (!argv[0]) {
+ fprintf(stderr, "ERROR: No command specified\n");
+ print_usage(argc+optind, argv-optind, 1);
+ return 2;
+ }
- printf("ERROR: Unknown TYPE %s\n", argv[i]);
- print_usage(argc, argv);
+ if (!strcmp(argv[0], "sleep")) {
+ cmd = CMD_SLEEP;
+ }
+ else if (!strcmp(argv[0], "restart")) {
+ cmd = CMD_RESTART;
+ }
+ else if (!strcmp(argv[0], "shutdown")) {
+ cmd = CMD_SHUTDOWN;
+ }
+ else if (!strcmp(argv[0], "diagnostics")) {
+ cmd = CMD_DIAGNOSTICS;
+ /* read type */
+ if (!argv[1] || ((strcmp(argv[1], "All") != 0) && (strcmp(argv[1], "WiFi") != 0) && (strcmp(argv[1], "GasGauge") != 0) && (strcmp(argv[1], "NAND") != 0) && (strcmp(argv[1], "HDMI") != 0))) {
+ if (argv[1] == NULL) {
+ cmd_arg = strdup("All");
+ } else {
+ fprintf(stderr, "ERROR: Unknown TYPE %s\n", argv[1]);
+ print_usage(argc+optind, argv-optind, 1);
goto cleanup;
}
-
- cmd_arg = strdup(argv[i]);
- continue;
}
- else if (!strcmp(argv[i], "mobilegestalt")) {
- cmd = CMD_MOBILEGESTALT;
- /* read keys */
- i++;
-
- if (!argv[i] || argv[i] == NULL || (!strncmp(argv[i], "-", 1))) {
- printf("ERROR: Please supply the key to query.\n");
- print_usage(argc, argv);
- goto cleanup;
- }
-
- keys = plist_new_array();
- while(1) {
- if (argv[i] && (strlen(argv[i]) >= 2) && (strncmp(argv[i], "-", 1) != 0)) {
- plist_array_append_item(keys, plist_new_string(argv[i]));
- i++;
- } else {
- i--;
- break;
- }
- }
- continue;
+ cmd_arg = strdup(argv[1]);
+ }
+ else if (!strcmp(argv[0], "mobilegestalt")) {
+ cmd = CMD_MOBILEGESTALT;
+ /* read keys */
+ if (!argv[1] || !*argv[1]) {
+ fprintf(stderr, "ERROR: Please supply the key to query.\n");
+ print_usage(argc, argv, 1);
+ goto cleanup;
}
- else if (!strcmp(argv[i], "ioreg")) {
- cmd = CMD_IOREGISTRY;
- /* read plane */
+ int i = 1;
+ keys = plist_new_array();
+ while (argv[i] && *argv[i]) {
+ plist_array_append_item(keys, plist_new_string(argv[i]));
i++;
- if (argv[i]) {
- cmd_arg = strdup(argv[i]);
- }
- continue;
}
- else if (!strcmp(argv[i], "ioregentry")) {
- cmd = CMD_IOREGISTRY_ENTRY;
- /* read key */
- i++;
- if (argv[i]) {
- cmd_arg = strdup(argv[i]);
- }
- continue;
+ }
+ else if (!strcmp(argv[0], "ioreg")) {
+ cmd = CMD_IOREGISTRY;
+ /* read plane */
+ if (argv[1]) {
+ cmd_arg = strdup(argv[1]);
}
- else {
- print_usage(argc, argv);
- return EXIT_SUCCESS;
+ }
+ else if (!strcmp(argv[0], "ioregentry")) {
+ cmd = CMD_IOREGISTRY_ENTRY;
+ /* read key */
+ if (argv[1]) {
+ cmd_arg = strdup(argv[1]);
}
}
/* verify options */
if (cmd == CMD_NONE) {
- print_usage(argc, argv);
+ fprintf(stderr, "ERROR: Unsupported command '%s'\n", argv[0]);
+ print_usage(argc+optind, argv-optind, 1);
goto cleanup;
}
@@ -213,13 +230,18 @@ int main(int argc, char **argv)
/* attempt to use newer diagnostics service available on iOS 5 and later */
ret = lockdownd_start_service(lockdown_client, "com.apple.mobile.diagnostics_relay", &service);
- if (ret != LOCKDOWN_E_SUCCESS) {
+ if (ret == LOCKDOWN_E_INVALID_SERVICE) {
/* attempt to use older diagnostics service */
ret = lockdownd_start_service(lockdown_client, "com.apple.iosdiagnostics.relay", &service);
}
-
lockdownd_client_free(lockdown_client);
+ if (ret != LOCKDOWN_E_SUCCESS) {
+ idevice_free(device);
+ printf("ERROR: Could not start diagnostics relay service: %s\n", lockdownd_strerror(ret));
+ goto cleanup;
+ }
+
result = EXIT_FAILURE;
if ((ret == LOCKDOWN_E_SUCCESS) && service && (service->port > 0)) {
@@ -320,31 +342,3 @@ cleanup:
}
return result;
}
-
-void print_usage(int argc, char **argv)
-{
- char *name = NULL;
- name = strrchr(argv[0], '/');
- printf("Usage: %s [OPTIONS] COMMAND\n", (name ? name + 1: argv[0]));
- printf("\n");
- printf("Use diagnostics interface of a device running iOS 4 or later.\n");
- printf("\n");
- printf("Where COMMAND is one of:\n");
- printf(" diagnostics [TYPE]\t\tprint diagnostics information from device by TYPE (All, WiFi, GasGauge, NAND)\n");
- printf(" mobilegestalt KEY [...]\tprint mobilegestalt keys passed as arguments separated by a space.\n");
- printf(" ioreg [PLANE]\t\t\tprint IORegistry of device, optionally by PLANE (IODeviceTree, IOPower, IOService) (iOS 5+ only)\n");
- printf(" ioregentry [KEY]\t\tprint IORegistry entry of device (AppleARMPMUCharger, ASPStorage, ...) (iOS 5+ only)\n");
- printf(" shutdown\t\t\tshutdown device\n");
- printf(" restart\t\t\trestart device\n");
- printf(" sleep\t\t\t\tput device into sleep mode (disconnects from host)\n");
- printf("\n");
- printf("The following OPTIONS are accepted:\n");
- printf(" -u, --udid UDID\ttarget specific device by UDID\n");
- printf(" -n, --network\t\tconnect to network device\n");
- printf(" -d, --debug\t\tenable communication debugging\n");
- printf(" -h, --help\t\tprints usage information\n");
- printf(" -v, --version\t\tprints version information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\n");
- printf("Bug Reports: <" PACKAGE_BUGREPORT ">\n");
-}
diff --git a/tools/ideviceenterrecovery.c b/tools/ideviceenterrecovery.c
index 822c10a..29cc5c9 100644
--- a/tools/ideviceenterrecovery.c
+++ b/tools/ideviceenterrecovery.c
@@ -27,8 +27,9 @@
#include <stdio.h>
#include <string.h>
-#include <errno.h>
#include <stdlib.h>
+#include <getopt.h>
+#include <errno.h>
#ifndef WIN32
#include <signal.h>
#endif
@@ -36,22 +37,22 @@
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
-static void print_usage(int argc, char **argv)
+static void print_usage(int argc, char **argv, int is_error)
{
- char *name = NULL;
-
- name = strrchr(argv[0], '/');
- printf("Usage: %s [OPTIONS] UDID\n", (name ? name + 1: argv[0]));
- printf("\n");
- printf("Makes a device with the supplied UDID enter recovery mode immediately.\n");
- printf("\n");
- printf("OPTIONS:\n");
- printf(" -d, --debug\t\tenable communication debugging\n");
- printf(" -h, --help\t\tprints usage information\n");
- printf(" -v, --version\t\tprints version information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\n");
- printf("Bug Reports: <" PACKAGE_BUGREPORT ">\n");
+ char *name = strrchr(argv[0], '/');
+ fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS] UDID\n", (name ? name + 1: argv[0]));
+ fprintf(is_error ? stderr : stdout,
+ "\n"
+ "Makes a device with the supplied UDID enter recovery mode immediately.\n"
+ "\n"
+ "OPTIONS:\n"
+ " -d, --debug enable communication debugging\n"
+ " -h, --help prints usage information\n"
+ " -v, --version prints version information\n"
+ "\n"
+ "Homepage: <" PACKAGE_URL ">\n"
+ "Bug Reports: <" PACKAGE_BUGREPORT ">\n"
+ );
}
int main(int argc, char *argv[])
@@ -60,57 +61,79 @@ int main(int argc, char *argv[])
lockdownd_error_t ldret = LOCKDOWN_E_UNKNOWN_ERROR;
idevice_t device = NULL;
idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR;
- int i;
const char* udid = NULL;
+ int c = 0;
+ const struct option longopts[] = {
+ { "debug", no_argument, NULL, 'd' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'v' },
+ { NULL, 0, NULL, 0}
+ };
#ifndef WIN32
signal(SIGPIPE, SIG_IGN);
#endif
/* parse cmdline args */
- for (i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) {
+ while ((c = getopt_long(argc, argv, "dhv", longopts, NULL)) != -1) {
+ switch (c) {
+ case 'd':
idevice_set_debug_level(1);
- continue;
- }
- else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
- print_usage(argc, argv);
+ break;
+ case 'h':
+ print_usage(argc, argv, 0);
return 0;
- }
- else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
+ case 'v':
printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION);
return 0;
+ default:
+ print_usage(argc, argv, 1);
+ return 2;
}
}
+ argc -= optind;
+ argv += optind;
- i--;
- if (argc < 2 || !argv[i] || !*argv[i]) {
- print_usage(argc, argv);
- return 0;
+ if (!argv[0]) {
+ fprintf(stderr, "ERROR: No UDID specified\n");
+ print_usage(argc+optind, argv-optind, 1);
+ return 2;
}
- udid = argv[i];
+ udid = argv[0];
ret = idevice_new(&device, udid);
if (ret != IDEVICE_E_SUCCESS) {
printf("No device found with udid %s.\n", udid);
- return -1;
+ return 1;
}
if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new(device, &client, TOOL_NAME))) {
- printf("ERROR: Could not connect to lockdownd, error code %d\n", ldret);
+ printf("ERROR: Could not connect to lockdownd: %s (%d)\n", lockdownd_strerror(ldret), ldret);
idevice_free(device);
- return -1;
+ return 1;
}
- /* run query and output information */
+ int res = 0;
printf("Telling device with udid %s to enter recovery mode.\n", udid);
- if(lockdownd_enter_recovery(client) != LOCKDOWN_E_SUCCESS)
- {
+ ldret = lockdownd_enter_recovery(client);
+ if (ldret == LOCKDOWN_E_SESSION_INACTIVE) {
+ lockdownd_client_free(client);
+ client = NULL;
+ if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &client, TOOL_NAME))) {
+ printf("ERROR: Could not connect to lockdownd: %s (%d)\n", lockdownd_strerror(ldret), ldret);
+ idevice_free(device);
+ return 1;
+ }
+ ldret = lockdownd_enter_recovery(client);
+ }
+ if (ldret != LOCKDOWN_E_SUCCESS) {
printf("Failed to enter recovery mode.\n");
+ res = 1;
+ } else {
+ printf("Device is successfully switching to recovery mode.\n");
}
- printf("Device is successfully switching to recovery mode.\n");
lockdownd_client_free(client);
idevice_free(device);
- return 0;
+ return res;
}
diff --git a/tools/ideviceimagemounter.c b/tools/ideviceimagemounter.c
index 325a9e2..f551b6c 100644
--- a/tools/ideviceimagemounter.c
+++ b/tools/ideviceimagemounter.c
@@ -46,7 +46,7 @@
#include <libimobiledevice/notification_proxy.h>
#include <libimobiledevice/mobile_image_mounter.h>
#include <asprintf.h>
-#include "common/utils.h"
+#include <plist/plist.h>
static int list_mode = 0;
static int use_network = 0;
@@ -62,27 +62,27 @@ typedef enum {
DISK_IMAGE_UPLOAD_TYPE_UPLOAD_IMAGE
} disk_image_upload_type_t;
-static void print_usage(int argc, char **argv)
+static void print_usage(int argc, char **argv, int is_error)
{
- char *name = NULL;
-
- name = strrchr(argv[0], '/');
- printf("Usage: %s [OPTIONS] IMAGE_FILE IMAGE_SIGNATURE_FILE\n", (name ? name + 1: argv[0]));
- printf("\n");
- printf("Mounts the specified disk image on the device.\n");
- printf("\n");
- printf("OPTIONS:\n");
- printf(" -u, --udid UDID\ttarget specific device by UDID\n");
- printf(" -n, --network\t\tconnect to network device\n");
- printf(" -l, --list\t\tList mount information\n");
- printf(" -t, --imagetype\tImage type to use, default is 'Developer'\n");
- printf(" -x, --xml\t\tUse XML output\n");
- printf(" -d, --debug\t\tenable communication debugging\n");
- printf(" -h, --help\t\tprints usage information\n");
- printf(" -v, --version\t\tprints version information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\n");
- printf("Bug Reports: <" PACKAGE_BUGREPORT ">\n");
+ 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,
+ "\n"
+ "Mounts the specified disk image on the device.\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"
+ " -h, --help prints usage information\n"
+ " -v, --version prints version information\n"
+ "\n"
+ "Homepage: <" PACKAGE_URL ">\n"
+ "Bug Reports: <" PACKAGE_BUGREPORT ">\n"
+ );
}
static void parse_opts(int argc, char **argv)
@@ -108,12 +108,12 @@ static void parse_opts(int argc, char **argv)
switch (c) {
case 'h':
- print_usage(argc, argv);
+ print_usage(argc, argv, 0);
exit(0);
case 'u':
if (!*optarg) {
fprintf(stderr, "ERROR: UDID must not be empty!\n");
- print_usage(argc, argv);
+ print_usage(argc, argv, 1);
exit(2);
}
udid = optarg;
@@ -137,21 +137,12 @@ static void parse_opts(int argc, char **argv)
printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION);
exit(0);
default:
- print_usage(argc, argv);
+ print_usage(argc, argv, 1);
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);
-}
-
static ssize_t mim_upload_cb(void* buf, size_t size, void* userdata)
{
return fread(buf, 1, size, (FILE*)userdata);
@@ -224,6 +215,20 @@ int main(int argc, char **argv)
}
}
+ if (product_version_major == 16) {
+ 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;
+ }
+ }
+
lockdownd_start_service(lckd, "com.apple.mobile.mobile_image_mounter", &service);
if (!service || service->port == 0) {
@@ -283,11 +288,7 @@ int main(int argc, char **argv)
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);
}
@@ -415,20 +416,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,19 +433,11 @@ 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);
- }
+ plist_write_to_stream(result, stdout, (xml_mode) ? PLIST_FORMAT_XML : PLIST_FORMAT_LIMD, 0);
}
}
} else {
diff --git a/tools/ideviceinfo.c b/tools/ideviceinfo.c
index 97ae03a..fd45763 100644
--- a/tools/ideviceinfo.c
+++ b/tools/ideviceinfo.c
@@ -37,7 +37,7 @@
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
-#include "common/utils.h"
+#include <plist/plist.h>
#define FORMAT_KEY_VALUE 1
#define FORMAT_XML 2
@@ -74,6 +74,8 @@ static const char *domains[] = {
"com.apple.iTunes",
"com.apple.mobile.iTunes.store",
"com.apple.mobile.iTunes",
+ "com.apple.fmip",
+ "com.apple.Accessibility",
NULL
};
@@ -91,23 +93,22 @@ static int is_domain_known(const char *domain)
static void print_usage(int argc, char **argv, int is_error)
{
int i = 0;
- char *name = NULL;
- name = strrchr(argv[0], '/');
+ 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" \
- "Show information about a connected device.\n" \
- "\n" \
- "OPTIONS:\n" \
- " -u, --udid UDID target specific device by UDID\n" \
- " -n, --network connect to network device\n" \
- " -s, --simple use a simple connection to avoid auto-pairing with the device\n" \
- " -q, --domain NAME set domain of query to NAME. Default: None\n" \
- " -k, --key NAME only query key specified by NAME. Default: All keys.\n" \
- " -x, --xml output information as xml plist instead of key/value pairs\n" \
- " -h, --help prints usage information\n" \
- " -d, --debug enable communication debugging\n" \
- " -v, --version prints version information\n" \
+ "\n"
+ "Show information about a connected device.\n"
+ "\n"
+ "OPTIONS:\n"
+ " -u, --udid UDID target specific device by UDID\n"
+ " -n, --network connect to network device\n"
+ " -s, --simple use simple connection to avoid auto-pairing with device\n"
+ " -q, --domain NAME set domain of query to NAME. Default: None\n" \
+ " -k, --key NAME only query key specified by NAME. Default: All keys.\n" \
+ " -x, --xml output information in XML property list format\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, "Known domains are:\n\n");
@@ -211,9 +212,9 @@ int main(int argc, char *argv[])
ret = idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX);
if (ret != IDEVICE_E_SUCCESS) {
if (udid) {
- printf("ERROR: Device %s not found!\n", udid);
+ fprintf(stderr, "ERROR: Device %s not found!\n", udid);
} else {
- printf("ERROR: No device found!\n");
+ fprintf(stderr, "ERROR: No device found!\n");
}
return -1;
}
@@ -240,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 97bf2d4..69b76f6 100644
--- a/tools/idevicename.c
+++ b/tools/idevicename.c
@@ -37,21 +37,24 @@
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
-static void print_usage(void)
+static void print_usage(int argc, char** argv, int is_error)
{
- printf("Usage: idevicename [OPTIONS] [NAME]\n");
- printf("\n");
- printf("Display the device name or set it to NAME if specified.\n");
- printf("\n");
- printf("OPTIONS:\n");
- printf(" -u, --udid UDID\ttarget specific device by UDID\n");
- printf(" -n, --network\t\tconnect to network device\n");
- printf(" -d, --debug\t\tenable communication debugging\n");
- printf(" -h, --help\t\tprint usage information\n");
- printf(" -v, --version\t\tprint version information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\n");
- printf("Bug Reports: <" PACKAGE_BUGREPORT ">\n");
+ char *name = strrchr(argv[0], '/');
+ fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS] [NAME]\n", (name ? name + 1: argv[0]));
+ fprintf(is_error ? stderr : stdout,
+ "\n"
+ "Display the device name or set it to NAME if specified.\n"
+ "\n"
+ "OPTIONS:\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"
+ );
}
int main(int argc, char** argv)
@@ -78,7 +81,7 @@ int main(int argc, char** argv)
case 'u':
if (!*optarg) {
fprintf(stderr, "ERROR: UDID must not be empty!\n");
- print_usage();
+ print_usage(argc, argv, 1);
exit(2);
}
udid = optarg;
@@ -87,7 +90,7 @@ int main(int argc, char** argv)
use_network = 1;
break;
case 'h':
- print_usage();
+ print_usage(argc, argv, 0);
return 0;
case 'd':
idevice_set_debug_level(1);
@@ -96,7 +99,7 @@ int main(int argc, char** argv)
printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION);
return 0;
default:
- print_usage();
+ print_usage(argc, argv, 1);
return 2;
}
}
@@ -105,8 +108,8 @@ int main(int argc, char** argv)
argv += optind;
if (argc > 1) {
- print_usage();
- return -1;
+ print_usage(argc, argv, 1);
+ return 2;
}
idevice_t device = NULL;
diff --git a/tools/idevicenotificationproxy.c b/tools/idevicenotificationproxy.c
index cfc9260..d1e25c1 100644
--- a/tools/idevicenotificationproxy.c
+++ b/tools/idevicenotificationproxy.c
@@ -27,9 +27,10 @@
#include <stdio.h>
#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
#include <errno.h>
#include <signal.h>
-#include <stdlib.h>
#ifdef WIN32
#include <windows.h>
@@ -59,28 +60,29 @@ static void clean_exit(int sig)
quit_flag++;
}
-static void print_usage(int argc, char **argv)
+static void print_usage(int argc, char **argv, int is_error)
{
- char *name = NULL;
-
- name = strrchr(argv[0], '/');
- printf("Usage: %s [OPTIONS] COMMAND\n", (name ? name + 1: argv[0]));
- printf("\n");
- printf("Post or observe notifications on a device.\n");
- printf("\n");
- printf("Where COMMAND is one of:\n");
- printf(" post ID [...]\t\tpost notification IDs to device and exit\n");
- printf(" observe ID [...]\tobserve notification IDs in the foreground until CTRL+C or signal is received\n");
- printf("\n");
- printf("The following OPTIONS are accepted:\n");
- printf(" -u, --udid UDID\ttarget specific device by UDID\n");
- printf(" -n, --network\t\tconnect to network device\n");
- printf(" -d, --debug\t\tenable communication debugging\n");
- printf(" -h, --help\t\tprints usage information\n");
- printf(" -v, --version\t\tprints version information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\n");
- printf("Bug Reports: <" PACKAGE_BUGREPORT ">\n");
+ 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"
+ "Post or observe notifications on a device.\n"
+ "\n"
+ "Where COMMAND is one of:\n"
+ " post ID [...] post notification IDs to device and exit\n"
+ " observe ID [...] observe notification IDs in foreground until CTRL+C\n"
+ " or signal is received\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 prints usage information\n"
+ " -v, --version prints version information\n"
+ "\n"
+ "Homepage: <" PACKAGE_URL ">\n"
+ "Bug Reports: <" PACKAGE_BUGREPORT ">\n"
+ );
}
static void notify_cb(const char *notification, void *user_data)
@@ -97,7 +99,7 @@ int main(int argc, char *argv[])
np_client_t gnp = NULL;
int result = -1;
- int i;
+ int i = 0;
const char* udid = NULL;
int use_network = 0;
int cmd = CMD_NONE;
@@ -107,6 +109,16 @@ int main(int argc, char *argv[])
char **nspec = NULL;
char **nspectmp = 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}
+ };
+
signal(SIGINT, clean_exit);
signal(SIGTERM, clean_exit);
#ifndef WIN32
@@ -115,80 +127,82 @@ int main(int argc, char *argv[])
#endif
/* parse cmdline args */
- for (i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) {
+ while ((c = getopt_long(argc, argv, "dhu:nv", longopts, NULL)) != -1) {
+ switch (c) {
+ case 'd':
idevice_set_debug_level(1);
- continue;
- }
- else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--udid")) {
- i++;
- if (!argv[i] || !*argv[i]) {
- print_usage(argc, argv);
- result = 0;
- goto cleanup;
+ break;
+ case 'u':
+ if (!*optarg) {
+ fprintf(stderr, "ERROR: UDID argument must not be empty!\n");
+ print_usage(argc, argv, 1);
+ return 2;
}
- udid = argv[i];
- continue;
- }
- else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
- print_usage(argc, argv);
- result = 0;
- goto cleanup;
- }
- else if (!strcmp(argv[i], "-n") || !strcmp(argv[i], "--network")) {
+ udid = optarg;
+ break;
+ case 'n':
use_network = 1;
- continue;
- }
- else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
+ break;
+ case 'h':
+ print_usage(argc, argv, 0);
+ return 0;
+ case 'v':
printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION);
- result = 0;
- goto cleanup;
+ return 0;
+ default:
+ print_usage(argc, argv, 1);
+ return 2;
}
- else if (!strcmp(argv[i], "post") || !strcmp(argv[i], "observe")) {
- cmd = CMD_POST;
- if (!strcmp(argv[i], "observe")) {
- cmd = CMD_OBSERVE;
- }
-
- i++;
+ }
+ argc -= optind;
+ argv += optind;
- if (!argv[i] || argv[i] == NULL || (!strncmp(argv[i], "-", 1))) {
- printf("Please supply a valid notification identifier.\n");
- print_usage(argc, argv);
- goto cleanup;
- }
+ if (!argv[i]) {
+ fprintf(stderr, "ERROR: Missing command\n");
+ print_usage(argc+optind, argv-optind, 1);
+ return 2;
+ }
- count = 0;
- nspec = malloc(sizeof(char*) * (count+1));
-
- while(1) {
- if (argv[i] && (strlen(argv[i]) >= 2) && (strncmp(argv[i], "-", 1) != 0)) {
- nspectmp = realloc(nspec, sizeof(char*) * (count+1));
- nspectmp[count] = strdup(argv[i]);
- nspec = nspectmp;
- count = count+1;
- i++;
- } else {
- i--;
- break;
- }
- }
+ if (!strcmp(argv[i], "post")) {
+ cmd = CMD_POST;
+ } else if (!strcmp(argv[i], "observe")) {
+ cmd = CMD_OBSERVE;
+ }
- nspectmp = realloc(nspec, sizeof(char*) * (count+1));
- nspectmp[count] = NULL;
- nspec = nspectmp;
- continue;
+ if (cmd == CMD_POST || cmd == CMD_OBSERVE) {
+ i++;
+ if (!argv[i]) {
+ fprintf(stderr, "ERROR: Please supply a valid notification identifier.\n");
+ print_usage(argc+optind, argv-optind, 1);
+ return 2;
}
- else {
- print_usage(argc, argv);
- return 0;
+
+ count = 0;
+ nspec = malloc(sizeof(char*) * (count+1));
+
+ while(1) {
+ if (argv[i] && (strlen(argv[i]) >= 2) && (strncmp(argv[i], "-", 1) != 0)) {
+ nspectmp = realloc(nspec, sizeof(char*) * (count+1));
+ nspectmp[count] = strdup(argv[i]);
+ nspec = nspectmp;
+ count = count+1;
+ i++;
+ } else {
+ i--;
+ break;
+ }
}
+
+ nspectmp = realloc(nspec, sizeof(char*) * (count+1));
+ nspectmp[count] = NULL;
+ nspec = nspectmp;
}
/* verify options */
if (cmd == CMD_NONE) {
- print_usage(argc, argv);
- goto cleanup;
+ fprintf(stderr, "ERROR: Unsupported command '%s'\n", argv[0]);
+ print_usage(argc+optind, argv-optind, 1);
+ return 2;
}
if (IDEVICE_E_SUCCESS != idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX)) {
@@ -250,7 +264,7 @@ int main(int argc, char *argv[])
}
}
} else {
- printf("Could not start notification_proxy service on device.\n");
+ printf("ERROR: Could not start service %s: %s\n", NP_SERVICE_NAME, lockdownd_strerror(ret));
}
if (service) {
diff --git a/tools/idevicepair.c b/tools/idevicepair.c
index 0dcd45f..94d3f04 100644
--- a/tools/idevicepair.c
+++ b/tools/idevicepair.c
@@ -2,7 +2,7 @@
* idevicepair.c
* Manage pairings with devices and this host
*
- * Copyright (c) 2010-2019 Nikias Bassen, All Rights Reserved.
+ * Copyright (c) 2010-2021 Nikias Bassen, All Rights Reserved.
* Copyright (c) 2014 Martin Szulecki, All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
@@ -30,16 +30,87 @@
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
-#ifndef WIN32
+#include <ctype.h>
+#include <unistd.h>
+#ifdef WIN32
+#include <windows.h>
+#include <conio.h>
+#else
+#include <termios.h>
#include <signal.h>
#endif
+
#include "common/userpref.h"
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
+#include <plist/plist.h>
static char *udid = NULL;
+#ifdef HAVE_WIRELESS_PAIRING
+
+#ifdef WIN32
+#define BS_CC '\b'
+#define my_getch getch
+#else
+#define BS_CC 0x7f
+static int my_getch(void)
+{
+ struct termios oldt, newt;
+ int ch;
+ tcgetattr(STDIN_FILENO, &oldt);
+ newt = oldt;
+ newt.c_lflag &= ~(ICANON | ECHO);
+ tcsetattr(STDIN_FILENO, TCSANOW, &newt);
+ ch = getchar();
+ tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
+ return ch;
+}
+#endif
+
+static int get_hidden_input(char *buf, int maxlen)
+{
+ int pwlen = 0;
+ int c;
+
+ while ((c = my_getch())) {
+ if ((c == '\r') || (c == '\n')) {
+ break;
+ } else if (isprint(c)) {
+ if (pwlen < maxlen-1)
+ buf[pwlen++] = c;
+ fputc('*', stderr);
+ } else if (c == BS_CC) {
+ if (pwlen > 0) {
+ fputs("\b \b", stderr);
+ pwlen--;
+ }
+ }
+ }
+ buf[pwlen] = 0;
+ return pwlen;
+}
+
+static void pairing_cb(lockdownd_cu_pairing_cb_type_t cb_type, void *user_data, void* data_ptr, unsigned int* data_size)
+{
+ if (cb_type == LOCKDOWN_CU_PAIRING_PIN_REQUESTED) {
+ printf("Enter PIN: ");
+ fflush(stdout);
+
+ *data_size = get_hidden_input((char*)data_ptr, *data_size);
+
+ printf("\n");
+ } else if (cb_type == LOCKDOWN_CU_PAIRING_DEVICE_INFO) {
+ printf("Device info:\n");
+ 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)");
+ }
+}
+
+#endif /* HAVE_WIRELESS_PAIRING */
+
static void print_error_message(lockdownd_error_t err)
{
switch (err) {
@@ -56,37 +127,66 @@ static void print_error_message(lockdownd_error_t err)
case LOCKDOWN_E_USER_DENIED_PAIRING:
printf("ERROR: Device %s said that the user denied the trust dialog.\n", udid);
break;
+ case LOCKDOWN_E_PAIRING_FAILED:
+ printf("ERROR: Pairing with device %s failed.\n", udid);
+ break;
+ case LOCKDOWN_E_GET_PROHIBITED:
+ case LOCKDOWN_E_PAIRING_PROHIBITED_OVER_THIS_CONNECTION:
+ printf("ERROR: Pairing is not possible over this connection.\n");
+#ifdef HAVE_WIRELESS_PAIRING
+ printf("To perform a wireless pairing use the -w command line switch. See usage or man page for details.\n");
+#endif
+ break;
default:
printf("ERROR: Device %s returned unhandled error code %d\n", udid, err);
break;
}
}
-static void print_usage(int argc, char **argv)
+static void print_usage(int argc, char **argv, int is_error)
{
- char *name = NULL;
-
- name = strrchr(argv[0], '/');
- printf("Usage: %s [OPTIONS] COMMAND\n", (name ? name + 1: argv[0]));
- printf("\n");
- printf("Manage host pairings with devices and usbmuxd.\n");
- printf("\n");
- printf("Where COMMAND is one of:\n");
- printf(" systembuid print the system buid of the usbmuxd host\n");
- printf(" hostid print the host id for target device\n");
- printf(" pair pair device with this host\n");
- printf(" validate validate if device is paired with this host\n");
- printf(" unpair unpair device with this host\n");
- printf(" list list devices paired with this host\n");
- printf("\n");
- printf("The following OPTIONS are accepted:\n");
- printf(" -u, --udid UDID target specific device by UDID\n");
- printf(" -d, --debug enable communication debugging\n");
- printf(" -h, --help prints usage information\n");
- printf(" -v, --version prints version information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\n");
- printf("Bug Reports: <" PACKAGE_BUGREPORT ">\n");
+ 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"
+ "Manage host pairings with devices and usbmuxd.\n"
+ "\n"
+ "Where COMMAND is one of:\n"
+ " systembuid print the system buid of the usbmuxd host\n"
+ " hostid print the host id for target device\n"
+ " pair pair device with this host\n"
+ " validate validate if device is paired with this host\n"
+ " unpair unpair device with this host\n"
+ " list list devices paired with this host\n"
+ "\n"
+ "The following OPTIONS are accepted:\n"
+ " -u, --udid UDID target specific device by UDID\n"
+ );
+#ifdef HAVE_WIRELESS_PAIRING
+ fprintf(is_error ? stderr : stdout,
+ " -w, --wireless perform wireless pairing (see NOTE)\n"
+ " -n, --network connect to network device (see NOTE)\n"
+ );
+#endif
+ fprintf(is_error ? stderr : stdout,
+ " -d, --debug enable communication debugging\n"
+ " -h, --help prints usage information\n"
+ " -v, --version prints version information\n"
+ );
+#ifdef HAVE_WIRELESS_PAIRING
+ fprintf(is_error ? stderr : stdout,
+ "\n"
+ "NOTE: Pairing over network (wireless pairing) is only supported by Apple TV\n"
+ "devices. To perform a wireless pairing, you need to use the -w command line\n"
+ "switch. Make sure to put the device into pairing mode first by opening\n"
+ "Settings > Remotes and Devices > Remote App and Devices.\n"
+ );
+#endif
+ fprintf(is_error ? stderr : stdout,
+ "\n"
+ "Homepage: <" PACKAGE_URL ">\n"
+ "Bug Reports: <" PACKAGE_BUGREPORT ">\n"
+ );
}
int main(int argc, char **argv)
@@ -95,10 +195,20 @@ int main(int argc, char **argv)
static struct option longopts[] = {
{ "help", no_argument, NULL, 'h' },
{ "udid", required_argument, NULL, 'u' },
+#ifdef HAVE_WIRELESS_PAIRING
+ { "wireless", no_argument, NULL, 'w' },
+ { "network", no_argument, NULL, 'n' },
+ { "hostinfo", required_argument, NULL, 1 },
+#endif
{ "debug", no_argument, NULL, 'd' },
{ "version", no_argument, NULL, 'v' },
{ NULL, 0, NULL, 0}
};
+#ifdef HAVE_WIRELESS_PAIRING
+#define SHORT_OPTIONS "hu:wndv"
+#else
+#define SHORT_OPTIONS "hu:dv"
+#endif
lockdownd_client_t client = NULL;
idevice_t device = NULL;
idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR;
@@ -106,27 +216,69 @@ int main(int argc, char **argv)
int result;
char *type = NULL;
+ int use_network = 0;
+ int wireless_pairing = 0;
+#ifdef HAVE_WIRELESS_PAIRING
+ plist_t host_info_plist = NULL;
+#endif
char *cmd;
typedef enum {
OP_NONE = 0, OP_PAIR, OP_VALIDATE, OP_UNPAIR, OP_LIST, OP_HOSTID, OP_SYSTEMBUID
} op_t;
op_t op = OP_NONE;
- while ((c = getopt_long(argc, argv, "hu:dv", longopts, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, SHORT_OPTIONS, longopts, NULL)) != -1) {
switch (c) {
case 'h':
- print_usage(argc, argv);
+ print_usage(argc, argv, 0);
exit(EXIT_SUCCESS);
case 'u':
if (!*optarg) {
fprintf(stderr, "ERROR: UDID must not be empty!\n");
- print_usage(argc, argv);
+ print_usage(argc, argv, 1);
result = EXIT_FAILURE;
goto leave;
}
free(udid);
udid = strdup(optarg);
break;
+#ifdef HAVE_WIRELESS_PAIRING
+ case 'w':
+ wireless_pairing = 1;
+ break;
+ case 'n':
+ use_network = 1;
+ break;
+ case 1:
+ if (!*optarg) {
+ fprintf(stderr, "ERROR: --hostinfo argument must not be empty!\n");
+ result = EXIT_FAILURE;
+ goto leave;
+ }
+ if (*optarg == '@') {
+ 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;
+ goto leave;
+ }
+ }
+#ifdef HAVE_PLIST_JSON
+ else if (*optarg == '{') {
+ if (plist_from_json(optarg, strlen(optarg), &host_info_plist) != PLIST_ERR_SUCCESS) {
+ fprintf(stderr, "ERROR: --hostinfo argument not valid. Make sure it is a JSON dictionary.\n");
+ result = EXIT_FAILURE;
+ goto leave;
+ }
+ }
+#endif
+ else {
+ fprintf(stderr, "ERROR: --hostinfo argument not valid. To specify a path prefix with '@'\n");
+ result = EXIT_FAILURE;
+ goto leave;
+ }
+ break;
+#endif
case 'd':
idevice_set_debug_level(1);
break;
@@ -135,7 +287,7 @@ int main(int argc, char **argv)
result = EXIT_SUCCESS;
goto leave;
default:
- print_usage(argc, argv);
+ print_usage(argc, argv, 1);
result = EXIT_FAILURE;
goto leave;
}
@@ -146,8 +298,15 @@ int main(int argc, char **argv)
#endif
if ((argc - optind) < 1) {
- printf("ERROR: You need to specify a COMMAND!\n");
- print_usage(argc, argv);
+ fprintf(stderr, "ERROR: You need to specify a COMMAND!\n");
+ print_usage(argc, argv, 1);
+ result = EXIT_FAILURE;
+ goto leave;
+ }
+
+ if (wireless_pairing && use_network) {
+ fprintf(stderr, "ERROR: You cannot use -w and -n together.\n");
+ print_usage(argc, argv, 1);
result = EXIT_FAILURE;
goto leave;
}
@@ -167,9 +326,20 @@ int main(int argc, char **argv)
} else if (!strcmp(cmd, "systembuid")) {
op = OP_SYSTEMBUID;
} else {
- printf("ERROR: Invalid command '%s' specified\n", cmd);
- print_usage(argc, argv);
- exit(EXIT_FAILURE);
+ fprintf(stderr, "ERROR: Invalid command '%s' specified\n", cmd);
+ print_usage(argc, argv, 1);
+ result = EXIT_FAILURE;
+ goto leave;
+ }
+
+ if (wireless_pairing) {
+ if (op == OP_VALIDATE || op == OP_UNPAIR) {
+ fprintf(stderr, "ERROR: Command '%s' is not supported with -w\n", cmd);
+ print_usage(argc, argv, 1);
+ result = EXIT_FAILURE;
+ goto leave;
+ }
+ use_network = 1;
}
if (op == OP_SYSTEMBUID) {
@@ -198,7 +368,7 @@ int main(int argc, char **argv)
goto leave;
}
- ret = idevice_new(&device, udid);
+ 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);
@@ -248,7 +418,7 @@ int main(int argc, char **argv)
result = EXIT_FAILURE;
goto leave;
} else {
- if (strcmp("com.apple.mobile.lockdown", type)) {
+ if (strcmp("com.apple.mobile.lockdown", type) != 0) {
printf("WARNING: QueryType request returned '%s'\n", type);
}
free(type);
@@ -257,7 +427,17 @@ int main(int argc, char **argv)
switch(op) {
default:
case OP_PAIR:
- lerr = lockdownd_pair(client, NULL);
+#ifdef HAVE_WIRELESS_PAIRING
+ if (wireless_pairing) {
+ lerr = lockdownd_cu_pairing_create(client, pairing_cb, NULL, host_info_plist, NULL);
+ if (lerr == LOCKDOWN_E_SUCCESS) {
+ lerr = lockdownd_pair_cu(client);
+ }
+ } else
+#endif
+ {
+ lerr = lockdownd_pair(client, NULL);
+ }
if (lerr == LOCKDOWN_E_SUCCESS) {
printf("SUCCESS: Paired with device %s\n", udid);
} else {
diff --git a/tools/ideviceprovision.c b/tools/ideviceprovision.c
index c93a682..4080a28 100644
--- a/tools/ideviceprovision.c
+++ b/tools/ideviceprovision.c
@@ -29,6 +29,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <getopt.h>
#include <sys/stat.h>
#include <errno.h>
#ifndef WIN32
@@ -44,42 +45,42 @@
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
#include <libimobiledevice/misagent.h>
-#include "common/utils.h"
+#include <plist/plist.h>
-static void print_usage(int argc, char **argv)
+static void print_usage(int argc, char **argv, int is_error)
{
- char *name = NULL;
-
- name = strrchr(argv[0], '/');
- printf("Usage: %s [OPTIONS] COMMAND\n", (name ? name + 1: argv[0]));
- printf("\n");
- printf("Manage provisioning profiles on a device.\n");
- printf("\n");
- printf("Where COMMAND is one of:\n");
- printf(" install FILE\tInstalls the provisioning profile specified by FILE.\n");
- printf(" \tA valid .mobileprovision file is expected.\n");
- printf(" list\t\tGet a list of all provisioning profiles on the device.\n");
- printf(" copy PATH\tRetrieves all provisioning profiles from the device and\n");
- printf(" \tstores them into the existing directory specified by PATH.\n");
- printf(" \tThe files will be stored as UUID.mobileprovision\n");
- printf(" copy UUID PATH Retrieves the provisioning profile identified by UUID\n");
- printf(" \tfrom the device and stores it into the existing directory\n");
- printf(" \tspecified by PATH. The file will be stored as UUID.mobileprovision.\n");
- printf(" remove UUID\tRemoves the provisioning profile identified by UUID.\n");
- printf(" remove-all\tRemoves all installed provisioning profiles.\n");
- printf(" dump FILE\tPrints detailed information about the provisioning profile\n");
- printf(" \tspecified by FILE.\n");
- printf("\n");
- printf("The following OPTIONS are accepted:\n");
- printf(" -u, --udid UDID target specific device by UDID\n");
- printf(" -n, --network connect to network device\n");
- printf(" -x, --xml print XML output when using the 'dump' command\n");
- printf(" -d, --debug enable communication debugging\n");
- printf(" -h, --help prints usage information\n");
- printf(" -v, --version prints version information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\n");
- printf("Bug Reports: <" PACKAGE_BUGREPORT ">\n");
+ 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"
+ "Manage provisioning profiles on a device.\n"
+ "\n"
+ "Where COMMAND is one of:\n"
+ " install FILE Installs the provisioning profile specified by FILE.\n"
+ " A valid .mobileprovision file is expected.\n"
+ " list Get a list of all provisioning profiles on the device.\n"
+ " copy PATH Retrieves all provisioning profiles from the device and\n"
+ " stores them into the existing directory specified by PATH.\n"
+ " The files will be stored as UUID.mobileprovision\n"
+ " copy UUID PATH Retrieves the provisioning profile identified by UUID\n"
+ " from the device and stores it into the existing directory\n"
+ " specified by PATH. The file will be stored as UUID.mobileprovision.\n"
+ " remove UUID Removes the provisioning profile identified by UUID.\n"
+ " remove-all Removes all installed provisioning profiles.\n"
+ " dump FILE Prints detailed information about the provisioning profile\n"
+ " specified by FILE.\n"
+ "\n"
+ "The following OPTIONS are accepted:\n"
+ " -u, --udid UDID target specific device by UDID\n"
+ " -n, --network connect to network device\n"
+ " -x, --xml print XML output when using the 'dump' command\n"
+ " -d, --debug enable communication debugging\n"
+ " -h, --help prints usage information\n"
+ " -v, --version prints version information\n"
+ "\n"
+ "Homepage: <" PACKAGE_URL ">\n"
+ "Bug Reports: <" PACKAGE_BUGREPORT ">\n"
+ );
}
enum {
@@ -106,7 +107,7 @@ static void asn1_next_item(unsigned char** p)
}
}
-static size_t asn1_item_get_size(unsigned char* p)
+static size_t asn1_item_get_size(const unsigned char* p)
{
size_t res = 0;
char bsize = *(p+1);
@@ -302,102 +303,115 @@ int main(int argc, char *argv[])
const char* param = NULL;
const char* param2 = NULL;
int use_network = 0;
+ 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' },
+ { "xml", no_argument, NULL, 'x' },
+ { NULL, 0, NULL, 0}
+ };
#ifndef WIN32
signal(SIGPIPE, SIG_IGN);
#endif
/* parse cmdline args */
- for (i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) {
+ while ((c = getopt_long(argc, argv, "dhu:nvx", longopts, NULL)) != -1) {
+ switch (c) {
+ case 'd':
idevice_set_debug_level(1);
- continue;
- }
- else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--udid")) {
- i++;
- if (!argv[i] || !*argv[i]) {
- print_usage(argc, argv);
- return 0;
+ break;
+ case 'u':
+ if (!*optarg) {
+ fprintf(stderr, "ERROR: UDID argument must not be empty!\n");
+ print_usage(argc, argv, 1);
+ return 2;
}
- udid = argv[i];
- continue;
- }
- else if (!strcmp(argv[i], "-n") || !strcmp(argv[i], "--network")) {
+ udid = optarg;
+ break;
+ case 'n':
use_network = 1;
- continue;
- }
- else if (!strcmp(argv[i], "install")) {
- i++;
- if (!argv[i] || (strlen(argv[i]) < 1)) {
- print_usage(argc, argv);
- return 0;
- }
- param = argv[i];
- op = OP_INSTALL;
- continue;
- }
- else if (!strcmp(argv[i], "list")) {
- op = OP_LIST;
- }
- else if (!strcmp(argv[i], "copy")) {
- i++;
- if (!argv[i] || (strlen(argv[i]) < 1)) {
- print_usage(argc, argv);
- return 0;
- }
- param = argv[i];
- op = OP_COPY;
- i++;
- if (argv[i] && (strlen(argv[i]) > 0)) {
- param2 = argv[i];
- }
- continue;
- }
- else if (!strcmp(argv[i], "remove")) {
- i++;
- if (!argv[i] || (strlen(argv[i]) < 1)) {
- print_usage(argc, argv);
- return 0;
- }
- param = argv[i];
- op = OP_REMOVE;
- continue;
- }
- else if (!strcmp(argv[i], "remove-all")) {
- i++;
- op = OP_REMOVE;
- continue;
+ break;
+ case 'h':
+ print_usage(argc, argv, 0);
+ return 0;
+ case 'v':
+ printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION);
+ return 0;
+ case 'x':
+ output_xml = 1;
+ break;
+ default:
+ print_usage(argc, argv, 1);
+ return 2;
}
- else if (!strcmp(argv[i], "dump")) {
- i++;
- if (!argv[i] || (strlen(argv[i]) < 1)) {
- print_usage(argc, argv);
- return 0;
- }
- param = argv[i];
- op = OP_DUMP;
- continue;
+ }
+ 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], "install")) {
+ op = OP_INSTALL;
+ i++;
+ if (!argv[i] || !*argv[i]) {
+ fprintf(stderr, "Missing argument for 'install' command.\n");
+ print_usage(argc+optind, argv-optind, 1);
+ return 2;
}
- else if (!strcmp(argv[i], "-x") || !strcmp(argv[i], "--xml")) {
- output_xml = 1;
- continue;
+ param = argv[i];
+ }
+ else if (!strcmp(argv[i], "list")) {
+ op = OP_LIST;
+ }
+ else if (!strcmp(argv[i], "copy")) {
+ op = OP_COPY;
+ i++;
+ if (!argv[i] || !*argv[i]) {
+ fprintf(stderr, "Missing argument for 'copy' command.\n");
+ print_usage(argc+optind, argv-optind, 1);
+ return 2;
}
- else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
- print_usage(argc, argv);
- return 0;
+ param = argv[i];
+ i++;
+ if (argv[i] && (strlen(argv[i]) > 0)) {
+ param2 = argv[i];
}
- else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
- printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION);
- return 0;
+ }
+ else if (!strcmp(argv[i], "remove")) {
+ op = OP_REMOVE;
+ i++;
+ if (!argv[i] || !*argv[i]) {
+ fprintf(stderr, "Missing argument for 'remove' command.\n");
+ print_usage(argc+optind, argv-optind, 1);
+ return 2;
}
- else {
- print_usage(argc, argv);
- return 0;
+ param = argv[i];
+ }
+ else if (!strcmp(argv[i], "remove-all")) {
+ op = OP_REMOVE;
+ }
+ else if (!strcmp(argv[i], "dump")) {
+ op = OP_DUMP;
+ i++;
+ if (!argv[i] || !*argv[i]) {
+ fprintf(stderr, "Missing argument for 'remove' command.\n");
+ print_usage(argc+optind, argv-optind, 1);
+ return 2;
}
+ param = argv[i];
}
-
if ((op == -1) || (op >= NUM_OPS)) {
- print_usage(argc, argv);
- return 0;
+ fprintf(stderr, "ERROR: Unsupported command '%s'\n", argv[i]);
+ print_usage(argc+optind, argv-optind, 1);
+ return 2;
}
if (op == OP_DUMP) {
@@ -422,7 +436,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;
@@ -434,7 +448,9 @@ int main(int argc, char *argv[])
plist_free(pl);
return res;
- } else if (op == OP_COPY) {
+ }
+
+ if (op == OP_COPY) {
struct stat st;
const char *checkdir = (param2) ? param2 : param;
if ((stat(checkdir, &st) < 0) || !S_ISDIR(st.st_mode)) {
@@ -481,8 +497,9 @@ int main(int argc, char *argv[])
}
int product_version = ((product_version_major & 0xFF) << 16) | ((product_version_minor & 0xFF) << 8) | (product_version_patch & 0xFF);
- if (LOCKDOWN_E_SUCCESS != lockdownd_start_service(client, "com.apple.misagent", &service)) {
- fprintf(stderr, "Could not start service \"com.apple.misagent\"\n");
+ lockdownd_error_t lerr = lockdownd_start_service(client, MISAGENT_SERVICE_NAME, &service);
+ if (lerr != LOCKDOWN_E_SUCCESS) {
+ fprintf(stderr, "Could not start service %s: %s\n", MISAGENT_SERVICE_NAME, lockdownd_strerror(lerr));
lockdownd_client_free(client);
idevice_free(device);
return -1;
@@ -492,7 +509,7 @@ int main(int argc, char *argv[])
misagent_client_t mis = NULL;
if (misagent_client_new(device, service, &mis) != MISAGENT_E_SUCCESS) {
- fprintf(stderr, "Could not connect to \"com.apple.misagent\" on device\n");
+ fprintf(stderr, "Could not connect to %s on device\n", MISAGENT_SERVICE_NAME);
if (service)
lockdownd_service_descriptor_free(service);
lockdownd_client_free(client);
diff --git a/tools/idevicescreenshot.c b/tools/idevicescreenshot.c
index 62bb4a3..0e694c7 100644
--- a/tools/idevicescreenshot.c
+++ b/tools/idevicescreenshot.c
@@ -28,6 +28,7 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <getopt.h>
#include <errno.h>
#include <time.h>
#include <unistd.h>
@@ -39,8 +40,86 @@
#include <libimobiledevice/lockdown.h>
#include <libimobiledevice/screenshotr.h>
-void get_image_filename(char *imgdata, char **filename);
-void print_usage(int argc, char **argv);
+static void get_image_filename(char *imgdata, char **filename)
+{
+ // If the provided filename already has an extension, use it as is.
+ if (*filename) {
+ char *last_dot = strrchr(*filename, '.');
+ if (last_dot && !strchr(last_dot, '/')) {
+ return;
+ }
+ }
+
+ // Find the appropriate file extension for the filename.
+ const char *fileext = NULL;
+ if (memcmp(imgdata, "\x89PNG", 4) == 0) {
+ fileext = ".png";
+ } else if (memcmp(imgdata, "MM\x00*", 4) == 0) {
+ fileext = ".tiff";
+ } else {
+ printf("WARNING: screenshot data has unexpected image format.\n");
+ fileext = ".dat";
+ }
+
+ // If a filename without an extension is provided, append the extension.
+ // Otherwise, generate a filename based on the current time.
+ char *basename = NULL;
+ if (*filename) {
+ basename = (char*)malloc(strlen(*filename) + 1);
+ strcpy(basename, *filename);
+ free(*filename);
+ *filename = NULL;
+ } else {
+ time_t now = time(NULL);
+ basename = (char*)malloc(32);
+ strftime(basename, 31, "screenshot-%Y-%m-%d-%H-%M-%S", gmtime(&now));
+ }
+
+ // Ensure the filename is unique on disk.
+ char *unique_filename = (char*)malloc(strlen(basename) + strlen(fileext) + 7);
+ sprintf(unique_filename, "%s%s", basename, fileext);
+ int i;
+ for (i = 2; i < (1 << 16); i++) {
+ if (access(unique_filename, F_OK) == -1) {
+ *filename = unique_filename;
+ break;
+ }
+ sprintf(unique_filename, "%s-%d%s", basename, i, fileext);
+ }
+ if (!*filename) {
+ free(unique_filename);
+ }
+ free(basename);
+}
+
+static void print_usage(int argc, char **argv, int is_error)
+{
+ char *name = strrchr(argv[0], '/');
+ fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS] [FILE]\n", (name ? name + 1: argv[0]));
+ fprintf(is_error ? stderr : stdout,
+ "\n"
+ "Gets a screenshot from a connected device.\n"
+ "\n"
+ "The image is in PNG format for iOS 9+ and otherwise in TIFF format.\n"
+ "The screenshot is saved as an image with the given FILE name.\n"
+ "If FILE has no extension, FILE will be a prefix of the saved filename.\n"
+ "If FILE is not specified, \"screenshot-DATE\", will be used as a prefix\n"
+ "of the filename, e.g.:\n"
+ " ./screenshot-2013-12-31-23-59-59.tiff\n"
+ "\n"
+ "NOTE: A mounted developer disk image is required on the device, otherwise\n"
+ "the screenshotr service is not available.\n"
+ "\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 prints usage information\n"
+ " -v, --version prints version information\n"
+ "\n"
+ "Homepage: <" PACKAGE_URL ">\n"
+ "Bug Reports: <" PACKAGE_BUGREPORT ">\n"
+ );
+}
int main(int argc, char **argv)
{
@@ -50,50 +129,58 @@ int main(int argc, char **argv)
screenshotr_client_t shotr = NULL;
lockdownd_service_descriptor_t service = NULL;
int result = -1;
- int i;
const char *udid = NULL;
int use_network = 0;
char *filename = 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 */
- for (i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) {
+
+ /* parse cmdline arguments */
+ while ((c = getopt_long(argc, argv, "dhu:nv", longopts, NULL)) != -1) {
+ switch (c) {
+ case 'd':
idevice_set_debug_level(1);
- continue;
- }
- else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--udid")) {
- i++;
- if (!argv[i] || !*argv[i]) {
- print_usage(argc, argv);
- return 0;
+ break;
+ case 'u':
+ if (!*optarg) {
+ fprintf(stderr, "ERROR: UDID argument must not be empty!\n");
+ print_usage(argc, argv, 1);
+ return 2;
}
- udid = argv[i];
- continue;
- }
- else if (!strcmp(argv[i], "-n") || !strcmp(argv[i], "--network")) {
+ udid = optarg;
+ break;
+ case 'n':
use_network = 1;
- continue;
- }
- else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
- print_usage(argc, argv);
+ break;
+ case 'h':
+ print_usage(argc, argv, 0);
return 0;
- }
- else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
+ case 'v':
printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION);
return 0;
- }
- else if (argv[i][0] != '-' && !filename) {
- filename = strdup(argv[i]);
- continue;
- }
- else {
- print_usage(argc, argv);
- return 0;
+ default:
+ print_usage(argc, argv, 1);
+ return 2;
}
}
+ argc -= optind;
+ argv += optind;
+
+ if (argv[0]) {
+ filename = strdup(argv[0]);
+ }
if (IDEVICE_E_SUCCESS != idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX)) {
if (udid) {
@@ -110,9 +197,9 @@ int main(int argc, char **argv)
return -1;
}
- lockdownd_start_service(lckd, "com.apple.mobile.screenshotr", &service);
+ lockdownd_error_t lerr = lockdownd_start_service(lckd, SCREENSHOTR_SERVICE_NAME, &service);
lockdownd_client_free(lckd);
- if (service && service->port > 0) {
+ if (lerr == LOCKDOWN_E_SUCCESS) {
if (screenshotr_client_new(device, service, &shotr) != SCREENSHOTR_E_SUCCESS) {
printf("Could not connect to screenshotr!\n");
} else {
@@ -142,7 +229,7 @@ int main(int argc, char **argv)
screenshotr_client_free(shotr);
}
} else {
- printf("Could not start screenshotr service! Remember that you have to mount the Developer disk image on your device if you want to use the screenshotr service.\n");
+ printf("Could not start screenshotr service: %s\nRemember that you have to mount the Developer disk image on your device if you want to use the screenshotr service.\n", lockdownd_strerror(lerr));
}
if (service)
@@ -153,84 +240,3 @@ int main(int argc, char **argv)
return result;
}
-
-void get_image_filename(char *imgdata, char **filename)
-{
- // If the provided filename already has an extension, use it as is.
- if (*filename) {
- char *last_dot = strrchr(*filename, '.');
- if (last_dot && !strchr(last_dot, '/')) {
- return;
- }
- }
-
- // Find the appropriate file extension for the filename.
- const char *fileext = NULL;
- if (memcmp(imgdata, "\x89PNG", 4) == 0) {
- fileext = ".png";
- } else if (memcmp(imgdata, "MM\x00*", 4) == 0) {
- fileext = ".tiff";
- } else {
- printf("WARNING: screenshot data has unexpected image format.\n");
- fileext = ".dat";
- }
-
- // If a filename without an extension is provided, append the extension.
- // Otherwise, generate a filename based on the current time.
- char *basename = NULL;
- if (*filename) {
- basename = (char*)malloc(strlen(*filename) + 1);
- strcpy(basename, *filename);
- free(*filename);
- *filename = NULL;
- } else {
- time_t now = time(NULL);
- basename = (char*)malloc(32);
- strftime(basename, 31, "screenshot-%Y-%m-%d-%H-%M-%S", gmtime(&now));
- }
-
- // Ensure the filename is unique on disk.
- char *unique_filename = (char*)malloc(strlen(basename) + strlen(fileext) + 7);
- sprintf(unique_filename, "%s%s", basename, fileext);
- int i;
- for (i = 2; i < (1 << 16); i++) {
- if (access(unique_filename, F_OK) == -1) {
- *filename = unique_filename;
- break;
- }
- sprintf(unique_filename, "%s-%d%s", basename, i, fileext);
- }
- if (!*filename) {
- free(unique_filename);
- }
- free(basename);
-}
-
-void print_usage(int argc, char **argv)
-{
- char *name = NULL;
-
- name = strrchr(argv[0], '/');
- printf("Usage: %s [OPTIONS] [FILE]\n", (name ? name + 1: argv[0]));
- printf("\n");
- printf("Gets a screenshot from a connected device.\n");
- printf("\n");
- printf("The image is in PNG format for iOS 9+ and otherwise in TIFF format.\n");
- printf("The screenshot is saved as an image with the given FILE name.\n");
- printf("If FILE has no extension, FILE will be a prefix of the saved filename.\n");
- printf("If FILE is not specified, \"screenshot-DATE\", will be used as a prefix\n");
- printf("of the filename, e.g.:\n");
- printf(" ./screenshot-2013-12-31-23-59-59.tiff\n");
- printf("\n");
- printf("NOTE: A mounted developer disk image is required on the device, otherwise\n");
- printf("the screenshotr service is not available.\n");
- printf("\n");
- printf(" -u, --udid UDID\ttarget specific device by UDID\n");
- printf(" -n, --network\t\tconnect to network device\n");
- printf(" -d, --debug\t\tenable communication debugging\n");
- printf(" -h, --help\t\tprints usage information\n");
- printf(" -v, --version\t\tprints version information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\n");
- printf("Bug Reports: <" PACKAGE_BUGREPORT ">\n");
-}
diff --git a/tools/idevicesetlocation.c b/tools/idevicesetlocation.c
index 412b47c..69fbaf5 100644
--- a/tools/idevicesetlocation.c
+++ b/tools/idevicesetlocation.c
@@ -51,15 +51,16 @@ static void print_usage(int argc, char **argv, int is_error)
fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS] -- <LAT> <LONG>\n", bname);
fprintf(is_error ? stderr : stdout, " %s [OPTIONS] reset\n", bname);
- fprintf(is_error ? stderr : stdout, "\n" \
- "OPTIONS:\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 prints usage information\n" \
- " -v, --version prints version information\n" \
- "\n" \
- "Homepage: <" PACKAGE_URL ">\n" \
+ fprintf(is_error ? stderr : stdout,
+ "\n"
+ "OPTIONS:\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 prints usage information\n"
+ " -v, --version prints version information\n"
+ "\n"
+ "Homepage: <" PACKAGE_URL ">\n"
"Bug Reports: <" PACKAGE_BUGREPORT ">\n"
);
}
@@ -141,10 +142,11 @@ int main(int argc, char **argv)
lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME);
lockdownd_service_descriptor_t svc = NULL;
- if (lockdownd_start_service(lockdown, DT_SIMULATELOCATION_SERVICE, &svc) != LOCKDOWN_E_SUCCESS) {
+ lockdownd_error_t lerr = lockdownd_start_service(lockdown, DT_SIMULATELOCATION_SERVICE, &svc);
+ if (lerr != LOCKDOWN_E_SUCCESS) {
lockdownd_client_free(lockdown);
idevice_free(device);
- printf("ERROR: Could not start the simulatelocation service. Make sure a developer disk image is mounted!\n");
+ printf("ERROR: Could not start the simulatelocation service: %s\nMake sure a developer disk image is mounted!\n", lockdownd_strerror(lerr));
return -1;
}
lockdownd_client_free(lockdown);
diff --git a/tools/idevicesyslog.c b/tools/idevicesyslog.c
index d9b627f..a0e641d 100644
--- a/tools/idevicesyslog.c
+++ b/tools/idevicesyslog.c
@@ -41,10 +41,10 @@
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/syslog_relay.h>
+#include <libimobiledevice-glue/termcolors.h>
static int quit_flag = 0;
static int exit_on_disconnect = 0;
-static int use_colors = 0;
static int show_device_name = 0;
static char* udid = NULL;
@@ -75,58 +75,6 @@ static char *line = NULL;
static int line_buffer_size = 0;
static int lp = 0;
-#ifdef WIN32
-static WORD COLOR_RESET = 0;
-static HANDLE h_stdout = INVALID_HANDLE_VALUE;
-
-#define COLOR_NORMAL COLOR_RESET
-#define COLOR_DARK FOREGROUND_INTENSITY
-#define COLOR_RED FOREGROUND_RED |FOREGROUND_INTENSITY
-#define COLOR_DARK_RED FOREGROUND_RED
-#define COLOR_GREEN FOREGROUND_GREEN | FOREGROUND_INTENSITY
-#define COLOR_DARK_GREEN FOREGROUND_GREEN
-#define COLOR_YELLOW FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY
-#define COLOR_DARK_YELLOW FOREGROUND_GREEN | FOREGROUND_RED
-#define COLOR_BLUE FOREGROUND_BLUE | FOREGROUND_INTENSITY
-#define COLOR_DARK_BLUE FOREGROUND_BLUE
-#define COLOR_MAGENTA FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY
-#define COLOR_DARK_MAGENTA FOREGROUND_BLUE | FOREGROUND_RED
-#define COLOR_CYAN FOREGROUND_BLUE | FOREGROUND_GREEN
-#define COLOR_BRIGHT_CYAN FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY
-#define COLOR_DARK_CYAN FOREGROUND_BLUE | FOREGROUND_GREEN
-#define COLOR_WHITE FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY
-#define COLOR_DARK_WHITE FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
-
-static void TEXT_COLOR(WORD attr)
-{
- if (use_colors) {
- SetConsoleTextAttribute(h_stdout, attr);
- }
-}
-#else
-
-#define COLOR_RESET "\e[m"
-#define COLOR_NORMAL "\e[0m"
-#define COLOR_DARK "\e[2m"
-#define COLOR_RED "\e[0;31m"
-#define COLOR_DARK_RED "\e[2;31m"
-#define COLOR_GREEN "\e[0;32m"
-#define COLOR_DARK_GREEN "\e[2;32m"
-#define COLOR_YELLOW "\e[0;33m"
-#define COLOR_DARK_YELLOW "\e[2;33m"
-#define COLOR_BLUE "\e[0;34m"
-#define COLOR_DARK_BLUE "\e[2;34m"
-#define COLOR_MAGENTA "\e[0;35m"
-#define COLOR_DARK_MAGENTA "\e[2;35m"
-#define COLOR_CYAN "\e[0;36m"
-#define COLOR_BRIGHT_CYAN "\e[1;36m"
-#define COLOR_DARK_CYAN "\e[2;36m"
-#define COLOR_WHITE "\e[1;37m"
-#define COLOR_DARK_WHITE "\e[0;37m"
-
-#define TEXT_COLOR(x) if (use_colors) { fwrite(x, 1, sizeof(x)-1, stdout); }
-#endif
-
static void add_filter(const char* filterstr)
{
int filter_len = strlen(filterstr);
@@ -171,7 +119,7 @@ static void add_filter(const char* filterstr)
}
}
-static int find_char(char c, char** p, char* end)
+static int find_char(char c, char** p, const char* end)
{
while ((**p != c) && (*p < end)) {
(*p)++;
@@ -201,9 +149,11 @@ static void syslog_callback(char c, void *user_data)
do {
if (lp < 16) {
shall_print = 1;
- TEXT_COLOR(COLOR_WHITE);
+ cprintf(FG_WHITE);
break;
- } else if (line[3] == ' ' && line[6] == ' ' && line[15] == ' ') {
+ }
+
+ if (line[3] == ' ' && line[6] == ' ' && line[15] == ' ') {
char* end = &line[lp];
char* p = &line[16];
@@ -242,10 +192,9 @@ static void syslog_callback(char c, void *user_data)
if (!found) {
shall_print = 0;
break;
- } else {
- triggered = 1;
- shall_print = 1;
}
+ triggered = 1;
+ shall_print = 1;
} else if (num_trigger_filters == 0 && num_untrigger_filters > 0 && !triggered) {
shall_print = 0;
quit_flag++;
@@ -265,9 +214,8 @@ static void syslog_callback(char c, void *user_data)
if (!found) {
shall_print = 0;
break;
- } else {
- shall_print = 1;
}
+ shall_print = 1;
}
/* process name */
@@ -331,46 +279,42 @@ static void syslog_callback(char c, void *user_data)
/* log level */
char* level_start = p;
char* level_end = p;
-#ifdef WIN32
- WORD level_color = COLOR_NORMAL;
-#else
const char* level_color = NULL;
-#endif
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 */
- TEXT_COLOR(COLOR_DARK_WHITE);
+ cprintf(FG_LIGHT_GRAY);
fwrite(line, 1, 16, stdout);
if (show_device_name) {
/* write device name */
- TEXT_COLOR(COLOR_DARK_YELLOW);
+ cprintf(FG_DARK_YELLOW);
fwrite(device_name_start, 1, device_name_end-device_name_start+1, stdout);
- TEXT_COLOR(COLOR_RESET);
+ cprintf(COLOR_RESET);
}
/* write process name */
- TEXT_COLOR(COLOR_BRIGHT_CYAN);
+ cprintf(FG_BRIGHT_CYAN);
fwrite(process_name_start, 1, process_name_end-process_name_start, stdout);
- TEXT_COLOR(COLOR_CYAN);
+ cprintf(FG_CYAN);
fwrite(process_name_end, 1, proc_name_end-process_name_end+1, stdout);
/* write log level */
- TEXT_COLOR(level_color);
+ cprintf(level_color);
if (level_end > level_start) {
fwrite(level_start, 1, level_end-level_start, stdout);
p = level_end;
@@ -379,17 +323,17 @@ static void syslog_callback(char c, void *user_data)
lp -= p - linep;
linep = p;
- TEXT_COLOR(COLOR_WHITE);
+ cprintf(FG_WHITE);
} else {
shall_print = 1;
- TEXT_COLOR(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) {
fwrite(linep, 1, lp, stdout);
- TEXT_COLOR(COLOR_RESET);
+ cprintf(COLOR_RESET);
fflush(stdout);
if (trigger_off) {
triggered = 0;
@@ -486,7 +430,8 @@ 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) {
+ }
+ if (!use_network && event->conn_type != CONNECTION_USBMUXD) {
return;
}
if (event->event == IDEVICE_DEVICE_ADD) {
@@ -522,37 +467,39 @@ static void clean_exit(int sig)
static void print_usage(int argc, char **argv, int is_error)
{
- char *name = NULL;
- name = strrchr(argv[0], '/');
+ 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" \
- "Relay syslog of a connected device.\n" \
- "\n" \
- "OPTIONS:\n" \
- " -u, --udid UDID target specific device by UDID\n" \
- " -n, --network connect to network device\n" \
- " -x, --exit exit when device disconnects\n" \
- " -h, --help prints usage information\n" \
- " -d, --debug enable communication debugging\n" \
- " -v, --version prints version information\n" \
- " --no-colors disable colored output\n" \
- "\n" \
- "FILTER OPTIONS:\n" \
- " -m, --match STRING only print messages that 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" \
- " -e, --exclude PROCESS print all messages except matching process(es)\n" \
- " PROCESS is a process name or multiple process names\n" \
- " separated by \"|\".\n" \
- " -q, --quiet set a filter to exclude common noisy processes\n" \
- " --quiet-list prints the list of processes for --quiet and exits\n" \
- " -k, --kernel only print kernel messages\n" \
- " -K, --no-kernel suppress kernel messages\n" \
- "\n" \
- "For filter examples consult idevicesyslog(1) man page.\n" \
- "\n" \
+ "\n"
+ "Relay syslog of a connected device.\n"
+ "\n"
+ "OPTIONS:\n"
+ " -u, --udid UDID target specific device by UDID\n"
+ " -n, --network connect to network device\n"
+ " -x, --exit exit when device disconnects\n"
+ " -h, --help prints usage information\n"
+ " -d, --debug enable communication debugging\n"
+ " -v, --version prints version information\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"
+ "\n"
+ "FILTER OPTIONS:\n"
+ " -m, --match STRING only print messages that 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"
+ " -e, --exclude PROCESS print all messages except matching process(es)\n"
+ " PROCESS is a process name or multiple process names\n"
+ " separated by \"|\".\n"
+ " -q, --quiet set a filter to exclude common noisy processes\n"
+ " --quiet-list prints the list of processes for --quiet and exits\n"
+ " -k, --kernel only print kernel messages\n"
+ " -K, --no-kernel suppress kernel messages\n"
+ "\n"
+ "For filter examples consult idevicesyslog(1) man page.\n"
+ "\n"
"Homepage: <" PACKAGE_URL ">\n"
"Bug Reports: <" PACKAGE_BUGREPORT ">\n"
);
@@ -560,18 +507,11 @@ static void print_usage(int argc, char **argv, int is_error)
int main(int argc, char *argv[])
{
-#ifdef WIN32
- CONSOLE_SCREEN_BUFFER_INFO csbi;
- h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
- if (GetConsoleScreenBufferInfo(h_stdout, &csbi)) {
- COLOR_RESET = csbi.wAttributes;
- }
-#endif
- int no_colors = 0;
int include_filter = 0;
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' },
@@ -589,6 +529,8 @@ 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 },
+ { "output", required_argument, NULL, 'o' },
{ "version", no_argument, NULL, 'v' },
{ NULL, 0, NULL, 0}
};
@@ -600,7 +542,7 @@ int main(int argc, char *argv[])
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:e:p:qkKo:v", longopts, NULL)) != -1) {
switch (c) {
case 'd':
idevice_set_debug_level(1);
@@ -700,7 +642,23 @@ int main(int argc, char *argv[])
return 0;
}
case 2:
- no_colors = 1;
+ term_colors_set_enabled(0);
+ break;
+ case 3:
+ force_colors = 1;
+ 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);
@@ -711,6 +669,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);
@@ -721,7 +683,8 @@ int main(int argc, char *argv[])
fprintf(stderr, "ERROR: -p and -e/-q cannot be used together.\n");
print_usage(argc, argv, 1);
return 2;
- } else if (include_filter > 0 && exclude_kernel > 0) {
+ }
+ if (include_filter > 0 && exclude_kernel > 0) {
fprintf(stderr, "ERROR: -p and -K cannot be used together.\n");
print_usage(argc, argv, 1);
return 2;
@@ -756,10 +719,6 @@ int main(int argc, char *argv[])
argc -= optind;
argv += optind;
- if (!no_colors && isatty(1)) {
- use_colors = 1;
- }
-
int num = 0;
idevice_info_t *devices = NULL;
idevice_get_device_list_extended(&devices, &num);
@@ -768,20 +727,21 @@ int main(int argc, char *argv[])
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;
- } else {
- fprintf(stderr, "Waiting for device with UDID %s to become available...\n", udid);
}
+
+ fprintf(stderr, "Waiting for device with UDID %s to become available...\n", udid);
}
line_buffer_size = 1024;
line = malloc(line_buffer_size);
- idevice_event_subscribe(device_event_cb, NULL);
+ idevice_subscription_context_t context = NULL;
+ idevice_events_subscribe(&context, device_event_cb, NULL);
while (!quit_flag) {
sleep(1);
}
- idevice_event_unsubscribe();
+ idevice_events_unsubscribe(context);
stop_logging();
if (num_proc_filters > 0) {