summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitattributes1
-rw-r--r--.github/workflows/build.yml239
-rw-r--r--.gitignore19
-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.am11
-rw-r--r--NEWS78
-rw-r--r--README.md203
-rwxr-xr-xautogen.sh28
-rw-r--r--common/Makefile.am25
-rw-r--r--common/debug.c15
-rw-r--r--common/socket.c501
-rw-r--r--common/socket.h65
-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.c483
-rw-r--r--common/utils.h60
-rw-r--r--configure.ac271
-rw-r--r--cython/Makefile.am96
-rw-r--r--cython/afc.pxi28
-rw-r--r--cython/debugserver.pxi15
-rw-r--r--cython/diagnostics_relay.pxi10
-rw-r--r--cython/imobiledevice.pxd11
-rw-r--r--cython/imobiledevice.pyx9
-rw-r--r--cython/installation_proxy.pxi2
-rw-r--r--cython/lockdown.pxi26
-rw-r--r--cython/mobilebackup.pxi8
-rw-r--r--cython/mobilebackup2.pxi41
-rw-r--r--cython/mobilesync.pxi14
-rw-r--r--cython/notification_proxy.pxi2
-rw-r--r--cython/restore.pxi16
-rw-r--r--cython/screenshotr.pxi6
-rw-r--r--docs/Makefile.am22
-rw-r--r--docs/afcclient.176
-rw-r--r--docs/doxygen/custom.css1722
-rw-r--r--docs/doxygen/favicon.icobin0 -> 1150 bytes
-rw-r--r--docs/doxygen/folder-open.pngbin0 -> 625 bytes
-rw-r--r--docs/doxygen/folder.pngbin0 -> 498 bytes
-rw-r--r--docs/doxygen/footer.html9
-rw-r--r--docs/doxygen/header.html64
-rw-r--r--docs/doxygen/layout.xml226
-rw-r--r--docs/doxygen/logo-vector-clean.svg1
-rw-r--r--docs/doxygen/text-x-generic.pngbin0 -> 333 bytes
-rw-r--r--docs/idevice_id.157
-rw-r--r--docs/idevicebackup.119
-rw-r--r--docs/idevicebackup2.153
-rw-r--r--docs/idevicebtlogger.160
-rw-r--r--docs/idevicecrashreport.117
-rw-r--r--docs/idevicedate.116
-rw-r--r--docs/idevicedebug.120
-rw-r--r--docs/idevicedebugserverproxy.120
-rw-r--r--docs/idevicedevmodectl.158
-rw-r--r--docs/idevicediagnostics.114
-rw-r--r--docs/ideviceenterrecovery.17
-rw-r--r--docs/ideviceimagemounter.116
-rw-r--r--docs/ideviceinfo.119
-rw-r--r--docs/idevicename.116
-rw-r--r--docs/idevicenotificationproxy.110
-rw-r--r--docs/idevicepair.135
-rw-r--r--docs/ideviceprovision.110
-rw-r--r--docs/idevicescreenshot.116
-rw-r--r--docs/idevicesetlocation.138
-rw-r--r--docs/idevicesyslog.1117
-rw-r--r--doxygen.cfg.in562
-rwxr-xr-xgit-version-gen20
-rw-r--r--include/Makefile.am55
-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.h212
-rw-r--r--include/libimobiledevice/debugserver.h62
-rw-r--r--include/libimobiledevice/diagnostics_relay.h93
-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.h69
-rw-r--r--include/libimobiledevice/libimobiledevice.h215
-rw-r--r--include/libimobiledevice/lockdown.h180
-rw-r--r--include/libimobiledevice/misagent.h19
-rw-r--r--include/libimobiledevice/mobile_image_mounter.h18
-rw-r--r--include/libimobiledevice/mobileactivation.h25
-rw-r--r--include/libimobiledevice/mobilebackup.h48
-rw-r--r--include/libimobiledevice/mobilebackup2.h37
-rw-r--r--include/libimobiledevice/mobilesync.h67
-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.h35
-rw-r--r--include/libimobiledevice/reverse_proxy.h213
-rw-r--r--include/libimobiledevice/sbservices.h23
-rw-r--r--include/libimobiledevice/screenshotr.h29
-rw-r--r--include/libimobiledevice/service.h47
-rw-r--r--include/libimobiledevice/syslog_relay.h42
-rw-r--r--include/libimobiledevice/webinspector.h17
-rw-r--r--m4/ac_pkg_cython.m46
-rw-r--r--m4/as-compiler-flag.m44
-rw-r--r--m4/ax_pthread.m4255
-rw-r--r--src/Makefile.am94
-rw-r--r--src/afc.c485
-rw-r--r--src/afc.h5
-rw-r--r--src/bt_packet_logger.c231
-rw-r--r--src/bt_packet_logger.h37
-rw-r--r--src/companion_proxy.c380
-rw-r--r--src/companion_proxy.h35
-rw-r--r--src/debugserver.c289
-rw-r--r--src/debugserver.h3
-rw-r--r--src/device_link_service.c103
-rw-r--r--src/device_link_service.h23
-rw-r--r--src/diagnostics_relay.c47
-rw-r--r--src/diagnostics_relay.h1
-rw-r--r--src/file_relay.c16
-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.c17
-rw-r--r--src/house_arrest.h1
-rw-r--r--src/idevice.c990
-rw-r--r--src/idevice.h55
-rw-r--r--src/installation_proxy.c80
-rw-r--r--src/installation_proxy.h3
-rw-r--r--src/libimobiledevice-1.0.pc.in6
-rw-r--r--src/lockdown-cu.c1193
-rw-r--r--src/lockdown.c385
-rw-r--r--src/lockdown.h8
-rw-r--r--src/misagent.c22
-rw-r--r--src/misagent.h1
-rw-r--r--src/mobile_image_mounter.c94
-rw-r--r--src/mobile_image_mounter.h3
-rw-r--r--src/mobileactivation.c41
-rw-r--r--src/mobileactivation.h1
-rw-r--r--src/mobilebackup.c55
-rw-r--r--src/mobilebackup.h2
-rw-r--r--src/mobilebackup2.c42
-rw-r--r--src/mobilebackup2.h3
-rw-r--r--src/mobilesync.c54
-rw-r--r--src/mobilesync.h1
-rw-r--r--src/notification_proxy.c17
-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.c36
-rw-r--r--src/property_list_service.h1
-rw-r--r--src/restore.c95
-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.c24
-rw-r--r--src/sbservices.h3
-rw-r--r--src/screenshotr.c21
-rw-r--r--src/screenshotr.h1
-rw-r--r--src/service.c38
-rw-r--r--src/service.h2
-rw-r--r--src/syslog_relay.c54
-rw-r--r--src/syslog_relay.h3
-rw-r--r--src/webinspector.c12
-rw-r--r--src/webinspector.h1
-rw-r--r--tools/Makefile.am139
-rw-r--r--tools/afcclient.c1346
-rw-r--r--tools/idevice_id.c124
-rw-r--r--tools/idevicebackup.c383
-rw-r--r--tools/idevicebackup2.c661
-rw-r--r--tools/idevicebtlogger.c458
-rw-r--r--tools/idevicecrashreport.c181
-rw-r--r--tools/idevicedate.c158
-rw-r--r--tools/idevicedebug.c663
-rw-r--r--tools/idevicedebugserverproxy.c339
-rw-r--r--tools/idevicedevmodectl.c462
-rw-r--r--tools/idevicediagnostics.c273
-rw-r--r--tools/ideviceenterrecovery.c106
-rw-r--r--tools/ideviceimagemounter.c168
-rw-r--r--tools/ideviceinfo.c188
-rw-r--r--tools/idevicename.c86
-rw-r--r--tools/idevicenotificationproxy.c183
-rw-r--r--tools/idevicepair.c390
-rw-r--r--tools/ideviceprovision.c264
-rw-r--r--tools/idevicescreenshot.c221
-rw-r--r--tools/idevicesetlocation.c192
-rw-r--r--tools/idevicesyslog.c646
218 files changed, 26136 insertions, 5462 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/.gitignore b/.gitignore
index ae08cdb..30b57ec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,23 +36,8 @@ src/.libs
docs/html
libimobiledevice-1.0.pc
tools/.libs/*
-tools/idevice_id
-tools/ideviceinfo
-tools/idevicesyslog
-tools/idevicebackup
-tools/ideviceimagemounter
-tools/idevicescreenshot
-tools/idevicebackup2
-tools/idevicedate
-tools/idevicedebugserverproxy
-tools/idevicediagnostics
-tools/ideviceenterrecovery
-tools/idevicename
-tools/idevicepair
-tools/ideviceprovision
-tools/idevicecrashreport
-tools/idevicedebug
-tools/idevicenotificationproxy
+tools/idevice*
+!tools/idevice*.[ch]
cython/.libs/*
cython/*.c
doxygen.cfg
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 c7d69cc..352b28f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,8 +1,15 @@
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
+EXTRA_DIST = \
+ docs \
+ README.md \
+ git-version-gen
+
+dist-hook:
+ @if ! git diff --quiet; then echo "Uncommitted changes present; not releasing"; exit 1; fi
+ echo $(VERSION) > $(distdir)/.tarball-version
docs/html: $(top_builddir)/doxygen.cfg $(top_srcdir)/src/*.c $(top_srcdir)/src/*.h $(top_srcdir)/include/libimobiledevice/*.h
rm -rf docs/html
diff --git a/NEWS b/NEWS
index c6618e9..72823dc 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,81 @@
+Version 1.3.0
+~~~~~~~~~~~~~
+
+* Development release "Let's get the party started."
+* Changes:
+ - Fix Python 3 support
+ - Add more lockdown error codes
+ - Add new lockdownd_pair_with_options() function
+ - Fix GnuTLS support with iOS 10
+ - Make sure sockets only listen locally due to security reasons
+ - Plug various memory leaks
+ - Fix SSL version negotiation for newer versions of OpenSSL
+ - Optimize lockdown pair record handling
+ - Return proper error code when a lockdown pair record is missing
+ - Fix building with MingGW
+ - Store application information in Info.plist using idevicebackup2
+ - Fix application backup handling to allow the device to restore applications
+ that were installed using idevicebackup2
+ - Make idevicebackup2 reboot after restore the default to allow the device to
+ migrate data correctly and thus improve the restored device data state
+ - Improve console frontend information output in idevicebackup2
+ - Extend ideviceprovision tool to allow retrieving and removing all
+ provisioning profiles
+ - Fix parsing large provisioning profile using ideviceprovision
+ - Fix receiving large property lists in property list service
+ - Propagate lower level errors to callers instead of returning
+ IDEVICE_E_UNKNOWN_ERROR
+ - API: Add IDEVICE_DEVICE_PAIRED event type
+ - Detect screenshot format to support png, tiff and dat formats using
+ idevicescreenshot tool
+ - API: Add mobileactivation service implementation
+ - Wait for passcode entry if required using idevicesyslog
+ - Add HDMI option to diagnostics command for idevicediagnostics
+ - Fix IORegistry command for iOS 11+ devices in idevicediagnostics
+ - Remove 40-digit character limit for UDID in tools to support newer devices
+ - Fix broken validate command in idevicepair with iOS 11+
+ - Fix OpenSSL version checks for configure target when using LibreSSL
+ - Migrate latest improved common code from libusbmuxd
+ - Convert README file to markdown format
+ - Fix idevicecrashreport tool to work with iOS 13+
+ - Fix various errors in SSL communication logic
+ - API: Add preboard service implementation
+ - Output hint to user to enter passcode when changing password using
+ idevicebackup2
+ - Cython: Fix and improve debugserver and diagnostics service bindings
+ - API: Add WiFi device support via new idevice_new_with_options() function
+ - API: Add idevice_get_device_list_extended() to also list network devices
+ - API: Add lockdown_strerror() helper to get error representation as string
+ - Add network device support to idevicesyslog and ideviceinfo tools
+ - Make debug output consistently output to stderr
+ - Add new idevicesetlocation tool (requires mounted developer image)
+ - Add option to exit if device disconnects in idevicesyslog
+ - API: Add syslog_relay_start_capture_raw() for raw syslog capture
+ - Add color output and process filter support to idevicesyslog
+ - API: Add companion_proxy service implementation
+ - Bump dependency to libusbmuxd 2.0.2
+ - Bump dependency to libplist 2.2.0
+ - Improve error handling and reporting in library and tools
+ - Fix various memory leaks in library and tools
+ - Add "--network" and "--version" options to all tools
+ - Fix socket_connect_addr() not connecting to network devices using IPv6
+ in some cases.
+ - Improve IPv6 "scope id" detection to fix connecting to network devices with
+ link-local adresses.
+ - Update man pages
+ - Fix various inconsistent declarations in public headers
+ - Allow OpenSSL >= 1.1.0 to use older/disallowed TLS versions fixing issues
+ where pairing records were getting removed repeatingly
+ - Fixed memory leaks
+ - Cython: Rewrite version detection logic in configure.ac
+ - Rename "--enable-debug-code" configure option to "--enable-debug"
+ - Improve README.md with project description, installation, contributing and
+ usage sections
+ - Rename library and all related files by adding an API version resulting
+ in "libimobiledevice-1.0"
+ - Bump soname version
+* API is UNSTABLE
+
Version 1.2.0
~~~~~~~~~~~~~
diff --git a/README.md b/README.md
index 3f9493c..89db882 100644
--- a/README.md
+++ b/README.md
@@ -1,35 +1,90 @@
# libimobiledevice
-## About
+*A library to communicate with services on iOS devices using native protocols.*
-A library to communicate with services of Apple iOS devices using native
-protocols.
+![](https://github.com/libimobiledevice/libimobiledevice/actions/workflows/build.yml/badge.svg)
-## Requirements
+## Features
-Development Packages of:
-* OpenSSL or GnuTLS
-* libplist
-* libusbmuxd
+libimobiledevice is a cross-platform software library that talks the protocols
+to interact with iOS devices.
-Software:
-* usbmuxd (OSS or Apple's version)
-* make
-* autoheader
-* automake
-* autoconf
-* libtool
-* pkg-config
-* gcc or clang
+Unlike other projects, it does not depend on using any existing proprietary
+libraries and does not require jailbreaking.
-Optional:
-* cython (Python bindings)
-* doxygen (Documentation)
+Some key features are:
-## Installation
+- **Interface**: Implements many high-level interfaces for device services
+- **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, GnuTLS, or MbedTLS to handle SSL communication
+- **Network**: Supports network connections with "WiFi sync" enabled devices
+- **Python:** Provides Cython based bindings for Python
-To compile run:
-```bash
+The implemented interfaces of many device service protocols allow applications
+to:
+
+* Access filesystem of a device
+* Access documents of file sharing apps
+* Retrieve information about a device and modify various settings
+* Backup and restore the device in a native way compatible with iTunes
+* Manage app icons arrangement on the device
+* Install, remove, list and basically manage apps
+* Activate a device using official servers
+* Manage contacts, calendars, notes and bookmarks
+* Retrieve and remove crashreports
+* Retrieve various diagnostics information
+* Establish a debug connection for app debugging
+* Mount filesystem images
+* Forward device notifications
+* Manage device provisioning
+* Take screenshots from the device screen (requires mounted developer image)
+* Simulate changed geolocation of the device (requires mounted developer image)
+* Relay the syslog of the device
+* Expose a connection for WebKit remote debugging
+
+... and much more.
+
+The library is in development since August 2007 with the goal to bring support
+for these devices to the Linux Desktop.
+
+## Installation / Getting started
+
+### Debian / Ubuntu Linux
+
+First install all required dependencies and build tools:
+```shell
+sudo apt-get install \
+ build-essential \
+ pkg-config \
+ checkinstall \
+ git \
+ autoconf \
+ automake \
+ libtool-bin \
+ libplist-dev \
+ libusbmuxd-dev \
+ libimobiledevice-glue-dev \
+ libssl-dev \
+ usbmuxd
+```
+
+If you want to optionally build the documentation or Python bindings use:
+```shell
+sudo apt-get install \
+ doxygen \
+ cython
+```
+
+Then clone the actual project repository:
+```shell
+git clone https://github.com/libimobiledevice/libimobiledevice.git
+cd libimobiledevice
+```
+
+Now you can build and install it:
+```shell
./autogen.sh
make
sudo make install
@@ -38,31 +93,105 @@ sudo make install
If you require a custom prefix or other option being passed to `./configure`
you can pass them directly to `./autogen.sh` like this:
```bash
-./autogen.sh --prefix=/opt/local --enable-debug-code
+./autogen.sh --prefix=/opt/local --enable-debug
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
```
-## Who/What/Where?
+## Usage
-* Home: https://www.libimobiledevice.org/
-* Code: `git clone https://git.libimobiledevice.org/libimobiledevice.git`
-* Code (Mirror): `git clone https://github.com/libimobiledevice/libimobiledevice.git`
-* Tickets: https://github.com/libimobiledevice/libimobiledevice/issues
+Documentation about using the library in your application is not available yet.
+The "hacker way" for now is to look at the implementation of the included
+utilities.
+
+### Utilities
+
+The library bundles the following command-line utilities in the tools directory:
+
+| Utility | Description |
+| -------------------------- | ------------------------------------------------------------------ |
+| `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 |
+| `idevicedebugserverproxy` | Proxy a debugserver connection from a device for remote debugging |
+| `idevicediagnostics` | Interact with the diagnostics interface of a device |
+| `ideviceenterrecovery` | Make a device enter recovery mode |
+| `ideviceimagemounter` | Mount disk images on the device |
+| `ideviceinfo` | Show information about a connected device |
+| `idevicename` | Display or set the device name |
+| `idevicenotificationproxy` | Post or observe notifications on a device |
+| `idevicepair` | Manage host pairings with devices and usbmuxd |
+| `ideviceprovision` | Manage provisioning profiles on a device |
+| `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:
+```shell
+ideviceinfo --help
+man ideviceinfo
+```
+
+## Contributing
+
+We welcome contributions from anyone and are grateful for every pull request!
+
+If you'd like to contribute, please fork the `master` branch, change, commit and
+send a pull request for review. Once approved it can be merged into the main
+code base.
+
+If you plan to contribute larger changes or a major refactoring, please create a
+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 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
+
+We are still working on the guidelines so bear with us!
+
+## Links
+
+* Homepage: https://libimobiledevice.org/
+* Repository: https://git.libimobiledevice.org/libimobiledevice.git
+* Repository (Mirror): https://github.com/libimobiledevice/libimobiledevice.git
+* Issue Tracker: https://github.com/libimobiledevice/libimobiledevice/issues
* Mailing List: https://lists.libimobiledevice.org/mailman/listinfo/libimobiledevice-devel
-* IRC: irc://irc.freenode.net#libimobiledevice
* Twitter: https://twitter.com/libimobiledev
+## License
+
+This library and utilities are licensed under the [GNU Lesser General Public License v2.1](https://www.gnu.org/licenses/lgpl-2.1.en.html),
+also included in the repository in the `COPYING` file.
+
## Credits
-Apple, iPhone, iPod, and iPod Touch are trademarks of Apple Inc.
-libimobiledevice is an independent software library and has not been
-authorized, sponsored, or otherwise approved by Apple Inc.
+Apple, iPhone, iPad, iPod, iPod Touch, Apple TV, Apple Watch, Mac, iOS,
+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: 2019-06-21
+README Updated on: 2023-12-30
diff --git a/autogen.sh b/autogen.sh
index f45d20f..5a0ec43 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -4,21 +4,23 @@ olddir=`pwd`
srcdir=`dirname $0`
test -z "$srcdir" && srcdir=.
-cd "$srcdir"
+(
+ cd "$srcdir"
-gprefix=`which glibtoolize 2>&1 >/dev/null`
-if [ $? -eq 0 ]; then
- glibtoolize --force
-else
- libtoolize --force
-fi
-aclocal -I m4
-autoheader
-automake --add-missing
-autoconf
+ gprefix=`which glibtoolize 2>&1 >/dev/null`
+ if [ $? -eq 0 ]; then
+ glibtoolize --force
+ else
+ libtoolize --force
+ fi
+ aclocal -I m4
+ autoheader
+ automake --add-missing
+ autoconf
-cd "$olddir"
+ cd "$olddir"
+)
if [ -z "$NOCONFIGURE" ]; then
- $srcdir/configure "$@"
+ $srcdir/configure "$@"
fi
diff --git a/common/Makefile.am b/common/Makefile.am
index 054e2a1..bd09bad 100644
--- a/common/Makefile.am
+++ b/common/Makefile.am
@@ -1,17 +1,26 @@
-AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)
-AM_CFLAGS = $(GLOBAL_CFLAGS) $(libusbmuxd_CFLAGS) $(libplist_CFLAGS) $(libgnutls_CFLAGS) $(libtasn1_CFLAGS) $(openssl_CFLAGS) $(LFS_CFLAGS)
-AM_LDFLAGS = $(libusbmuxd_LIBS) $(libplist_LIBS) ${libpthread_LIBS}
+AM_CFLAGS = \
+ $(GLOBAL_CFLAGS) \
+ $(ssl_lib_CFLAGS) \
+ $(LFS_CFLAGS) \
+ $(libusbmuxd_CFLAGS) \
+ $(libplist_CFLAGS)
+
+AM_LDFLAGS = \
+ $(ssl_lib_LIBS) \
+ ${libpthread_LIBS} \
+ $(libusbmuxd_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
+ debug.c debug.h \
+ userpref.c userpref.h
if WIN32
libinternalcommon_la_LIBADD += -lole32 -lws2_32
diff --git a/common/debug.c b/common/debug.c
index acca456..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,19 +60,16 @@ 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 */
/* print header */
- printf ("%s: ", header);
+ fprintf(stderr, "%s: ", header);
/* print actual debug content */
- printf ("%s\n", buffer);
-
- /* flush this output, as we need to debug */
- fflush (stdout);
+ fprintf(stderr, "%s\n", buffer);
free (header);
}
@@ -89,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 0ee8105..0000000
--- a/common/socket.c
+++ /dev/null
@@ -1,501 +0,0 @@
-/*
- * socket.c
- *
- * Copyright (C) 2012-2018 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>
-static int wsa_init = 0;
-#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>
-#endif
-#include "socket.h"
-
-#define RECV_TIMEOUT 20000
-#define CONNECT_TIMEOUT 5000
-
-#ifndef ECONNRESET
-#define ECONNRESET 108
-#endif
-
-static int verbose = 0;
-
-void socket_set_verbose(int level)
-{
- verbose = level;
-}
-
-#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, 10) < 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;
-
- if (connect(sfd, (struct sockaddr*)&name, sizeof(name)) < 0) {
- socket_close(sfd);
- if (verbose >= 2)
- fprintf(stderr, "%s: connect: %s\n", __func__,
- strerror(errno));
- return -1;
- }
-
- return sfd;
-}
-#endif
-
-int socket_create(uint16_t port)
-{
- int sfd = -1;
- int yes = 1;
-#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
- struct sockaddr_in saddr;
-
- if (0 > (sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) {
- perror("socket()");
- return -1;
- }
-
- if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) {
- perror("setsockopt()");
- socket_close(sfd);
- 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
-
- memset((void *) &saddr, 0, sizeof(saddr));
- saddr.sin_family = AF_INET;
- saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- saddr.sin_port = htons(port);
-
- if (0 > bind(sfd, (struct sockaddr *) &saddr, sizeof(saddr))) {
- perror("bind()");
- socket_close(sfd);
- return -1;
- }
-
- if (listen(sfd, 1) == -1) {
- perror("listen()");
- socket_close(sfd);
- return -1;
- }
-
- 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;
- u_long l_no = 0;
- 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 = 0;
- 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;
- }
-
- 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
- fcntl(sfd, F_SETFL, 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;
- }
-
-#ifdef WIN32
- ioctlsocket(sfd, FIONBIO, &l_no);
-#else
- flags = fcntl(sfd, F_GETFL, 0);
- fcntl(sfd, F_SETFL, flags & (~O_NONBLOCK));
-#endif
-
-#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, 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_in addr;
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- addr.sin_port = htons(port);
-
- 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;
-#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 e31de6b..0000000
--- a/common/socket.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * socket.h
- *
- * Copyright (C) 2012 Martin Szulecki <m.szulecki@libimobiledevice.org>
- * Copyright (C) 2012 Nikias Bassen <nikias@gmx.li>
- *
- * 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(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 size);
-int socket_peek(int fd, void *data, size_t size);
-int socket_receive_timeout(int fd, void *data, size_t size, int flags,
- unsigned int timeout);
-
-int socket_send(int fd, void *data, size_t size);
-
-void socket_set_verbose(int level);
-
-#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 4a45d95..0000000
--- a/common/utils.c
+++ /dev/null
@@ -1,483 +0,0 @@
-/*
- * utils.c
- * Miscellaneous utilities for string manipulation
- *
- * 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_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;
- 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 8426bc0..0000000
--- a/common/utils.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * utils.h
- * Miscellaneous utilities for string manipulation
- *
- * 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_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 41fabbc..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.2.1], [https://github.com/libimobiledevice/libimobiledevice/issues],, [http://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,30 +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=1.1.0
-LIBPLIST_VERSION=1.11
-LIBPLISTMM_VERSION=1.11
+LIBUSBMUXD_VERSION=2.0.2
+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(LIBPLISTMM_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 >= $LIBUSBMUXD_VERSION)
-PKG_CHECK_MODULES(libplist, libplist >= $LIBPLIST_VERSION)
-PKG_CHECK_MODULES(libplistmm, libplist++ >= $LIBPLISTMM_VERSION)
+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
@@ -51,7 +68,7 @@ AC_TYPE_UINT32_T
AC_TYPE_UINT8_T
# Checks for library functions.
-AC_CHECK_FUNCS([asprintf strcasecmp strdup strerror strndup stpcpy vasprintf])
+AC_CHECK_FUNCS([asprintf strcasecmp strdup strerror strndup stpcpy vasprintf getifaddrs])
AC_CHECK_HEADER(endian.h, [ac_cv_have_endian_h="yes"], [ac_cv_have_endian_h="no"])
if test "x$ac_cv_have_endian_h" = "xno"; then
@@ -65,15 +82,19 @@ 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
*mingw32*|*cygwin*)
AC_MSG_RESULT([${host_os}])
win32=true
+ AC_DEFINE(WINVER, 0x0501, [minimum Windows version])
;;
darwin*)
AC_MSG_RESULT([${host_os}])
+ darwin=true
;;
*)
AC_MSG_RESULT([${host_os}])
@@ -82,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>])
@@ -89,24 +129,34 @@ AC_CHECK_MEMBER(struct dirent.d_type, AC_DEFINE(HAVE_DIRENT_D_TYPE, 1, [define i
AC_ARG_WITH([cython],
[AS_HELP_STRING([--without-cython],
[build Python bindings using Cython (default is yes)])],
- [build_cython=$withval],
- [build_cython=yes])
-if test "$build_cython" = "yes"; then
- AM_PATH_PYTHON(2.3)
- AC_PROG_CYTHON(0.17.0)
- CYTHON_PYTHON
+ [build_cython=false],
+ [build_cython=true])
+if test "$build_cython" = "true"; then
+ AC_PROG_CYTHON([3.0.0])
+ if [test "x$CYTHON" != "xfalse"]; then
+ AM_PATH_PYTHON([3.0], [
+ CYTHON_PYTHON
+ AS_COMPILER_FLAG([-Wno-cast-function-type -Werror], [
+ CYTHON_CFLAGS+=" -Wno-cast-function-type"
+ AC_SUBST([CYTHON_CFLAGS])
+ ], [])
+ ])
+ else
+ AC_MSG_WARN([Use the "--without-cython" option to avoid this warning.])
+ fi
else
CYTHON=false
fi
if [test "x$CYTHON" != "xfalse"]; then
+ PKG_PROG_PKG_CONFIG
AC_MSG_CHECKING([for libplist Cython bindings])
- CYTHON_PLIST_INCLUDE_DIR=$($PKG_CONFIG --variable=includedir libplist)/plist/cython
+ CYTHON_PLIST_INCLUDE_DIR=$($PKG_CONFIG --variable=includedir libplist-2.0)/plist/cython
if [test ! -d "$CYTHON_PLIST_INCLUDE_DIR"]; then
CYTHON=false
CYTHON_SUB=
cython_python_bindings=no
AC_MSG_RESULT([no])
- AC_MSG_WARN([cannot find libplist Cython bindings. You should install your distribution specific libplist Cython bindings package.])
+ AC_MSG_WARN([Unable to find libplist Cython bindings. You should install your distribution specific libplist Cython bindings package.])
else
AC_SUBST([CYTHON_PLIST_INCLUDE_DIR])
AC_MSG_RESULT([$CYTHON_PLIST_INCLUDE_DIR])
@@ -120,72 +170,166 @@ 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-code],
- [AS_HELP_STRING([--enable-debug-code],
- [enable debug message reporting in library (default is no)])],
+AC_ARG_ENABLE([debug],
+ [AS_HELP_STRING([--enable-debug],
+ [build debug message output code (default is no)])],
[no_debug_code=false],
[no_debug_code=true])
if test "$no_debug_code" = true; then
building_debug_code=no
- AC_DEFINE(STRIP_DEBUG_CODE,1,[Strip debug reporting code])
+ AC_DEFINE(STRIP_DEBUG_CODE,1,[Define if debug message output code should not be built.])
else
building_debug_code=yes
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)
+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")
-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
@@ -195,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 6aeaf08..93ea6ed 100644
--- a/cython/Makefile.am
+++ b/cython/Makefile.am
@@ -1,52 +1,84 @@
-AM_CPPFLAGS = -I$(top_srcdir)/include
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/include
-AM_CFLAGS = $(GLOBAL_CFLAGS) $(libgnutls_CFLAGS) $(libtasn1_CFLAGS) $(openssl_CFLAGS) $(libplist_CFLAGS) $(LFS_CFLAGS) $(PTHREAD_CFLAGS)
-AM_LIBS = $(libgnutls_LIBS) $(libtasn1_LIBS) $(openssl_LIBS) $(libplist_LIBS) $(PTHREAD_LIBS)
+AM_CFLAGS = \
+ $(GLOBAL_CFLAGS) \
+ $(ssl_lib_CFLAGS) \
+ $(LFS_CFLAGS) \
+ $(PTHREAD_CFLAGS) \
+ $(libplist_CFLAGS)
+
+AM_LIBS = \
+ $(ssl_lib_LIBS) \
+ $(PTHREAD_LIBS) \
+ $(libplist_LIBS)
if HAVE_CYTHON
BUILT_SOURCES = imobiledevice.c
-PXDINCLUDES = imobiledevice.pxd $(CYTHON_PLIST_INCLUDE_DIR)/plist.pxd
-PXIINCLUDES = \
- lockdown.pxi \
- mobilesync.pxi \
- notification_proxy.pxi \
- sbservices.pxi \
- mobilebackup.pxi \
- mobilebackup2.pxi \
- afc.pxi \
- file_relay.pxi \
- screenshotr.pxi \
- installation_proxy.pxi \
- webinspector.pxi \
- heartbeat.pxi \
- diagnostics_relay.pxi \
- misagent.pxi \
- house_arrest.pxi \
- restore.pxi \
- mobile_image_mounter.pxi \
+PXDINCLUDES = \
+ imobiledevice.pxd \
+ $(CYTHON_PLIST_INCLUDE_DIR)/plist.pxd
+
+PXIINCLUDES = \
+ lockdown.pxi \
+ mobilesync.pxi \
+ notification_proxy.pxi \
+ sbservices.pxi \
+ mobilebackup.pxi \
+ mobilebackup2.pxi \
+ afc.pxi \
+ file_relay.pxi \
+ screenshotr.pxi \
+ installation_proxy.pxi \
+ webinspector.pxi \
+ heartbeat.pxi \
+ diagnostics_relay.pxi \
+ misagent.pxi \
+ house_arrest.pxi \
+ restore.pxi \
+ mobile_image_mounter.pxi \
debugserver.pxi
-CLEANFILES = \
- *.pyc \
- *.pyo \
+CLEANFILES = \
+ *.pyc \
+ *.pyo \
imobiledevice.c
-EXTRA_DIST = imobiledevice.pyx imobiledevice.pxd $(PXIINCLUDES)
+EXTRA_DIST = \
+ imobiledevice.pyx \
+ imobiledevice.pxd \
+ $(PXIINCLUDES)
imobiledevicedir = $(pyexecdir)
imobiledevice_LTLIBRARIES = imobiledevice.la
imobiledevice_la_SOURCES = imobiledevice.pyx
-imobiledevice_la_CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src $(PYTHON_CPPFLAGS) $(AM_CFLAGS) -Wno-shadow -Wno-redundant-decls -Wno-switch-default -Wno-strict-aliasing -Wno-implicit-function-declaration -fvisibility=default
-imobiledevice_la_LDFLAGS = -module -avoid-version -L$(libdir) $(PYTHON_LIBS) $(AM_LIBS) -no-undefined
-imobiledevice_la_LIBADD = $(top_builddir)/src/libimobiledevice.la
+imobiledevice_la_CFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/src \
+ $(PYTHON_CPPFLAGS) \
+ $(AM_CFLAGS) \
+ -Wno-shadow \
+ -Wno-redundant-decls \
+ -Wno-switch-default \
+ -Wno-strict-aliasing \
+ -Wno-implicit-function-declaration \
+ -fvisibility=default \
+ $(CYTHON_CFLAGS)
+
+imobiledevice_la_LDFLAGS = \
+ -module \
+ -avoid-version \
+ -L$(libdir) \
+ $(PYTHON_LIBS) \
+ $(AM_LIBS) \
+ -no-undefined
+
+imobiledevice_la_LIBADD = $(top_builddir)/src/libimobiledevice-1.0.la
imobiledevice.c: imobiledevice.pyx $(PXDINCLUDES) $(PXIINCLUDES)
.pyx.c:
$(CYTHON) -I$(CYTHON_PLIST_INCLUDE_DIR) -I$(top_srcdir)/src -o $@ $<
-# imobiledevice_private.c: $(IMOBILEDEVICE_PRIVATE_SOURCES) $(IMOBILEDEVICE_INCLUDES) $(PLIST_INCLUDES)
-# $(CYTHON) $(IMOBILEDEVICE_CPPFLAGS) -I$(top_srcdir)/src -o $@ $<
-
endif
diff --git a/cython/afc.pxi b/cython/afc.pxi
index e34588f..6bd8182 100644
--- a/cython/afc.pxi
+++ b/cython/afc.pxi
@@ -52,6 +52,7 @@ cdef extern from "libimobiledevice/afc.h":
afc_error_t afc_read_directory(afc_client_t client, char *dir, char ***list)
afc_error_t afc_get_file_info(afc_client_t client, char *filename, char ***infolist)
afc_error_t afc_remove_path(afc_client_t client, char *path)
+ afc_error_t afc_remove_path_and_contents(afc_client_t client, char *path)
afc_error_t afc_rename_path(afc_client_t client, char *f, char *to)
afc_error_t afc_make_directory(afc_client_t client, char *dir)
afc_error_t afc_truncate(afc_client_t client, char *path, uint64_t newsize)
@@ -235,17 +236,17 @@ cdef class AfcClient(BaseService):
afc_file_mode_t c_mode
uint64_t handle
AfcFile f
- if mode == <bytes>'r':
+ if mode == b'r':
c_mode = AFC_FOPEN_RDONLY
- elif mode == <bytes>'r+':
+ elif mode == b'r+':
c_mode = AFC_FOPEN_RW
- elif mode == <bytes>'w':
+ elif mode == b'w':
c_mode = AFC_FOPEN_WRONLY
- elif mode == <bytes>'w+':
+ elif mode == b'w+':
c_mode = AFC_FOPEN_WR
- elif mode == <bytes>'a':
+ elif mode == b'a':
c_mode = AFC_FOPEN_APPEND
- elif mode == <bytes>'a+':
+ elif mode == b'a+':
c_mode = AFC_FOPEN_RDAPPEND
else:
raise ValueError("mode string must be 'r', 'r+', 'w', 'w+', 'a', or 'a+'")
@@ -282,6 +283,9 @@ cdef class AfcClient(BaseService):
cpdef remove_path(self, bytes path):
self.handle_error(afc_remove_path(self._c_client, path))
+ cpdef remove_path_and_contents(self, bytes path):
+ self.handle_error(afc_remove_path_and_contents(self._c_client, path))
+
cpdef rename_path(self, bytes f, bytes t):
self.handle_error(afc_rename_path(self._c_client, f, t))
@@ -308,17 +312,17 @@ cdef class Afc2Client(AfcClient):
afc_file_mode_t c_mode
uint64_t handle
AfcFile f
- if mode == <bytes>'r':
+ if mode == b'r':
c_mode = AFC_FOPEN_RDONLY
- elif mode == <bytes>'r+':
+ elif mode == b'r+':
c_mode = AFC_FOPEN_RW
- elif mode == <bytes>'w':
+ elif mode == b'w':
c_mode = AFC_FOPEN_WRONLY
- elif mode == <bytes>'w+':
+ elif mode == b'w+':
c_mode = AFC_FOPEN_WR
- elif mode == <bytes>'a':
+ elif mode == b'a':
c_mode = AFC_FOPEN_APPEND
- elif mode == <bytes>'a+':
+ elif mode == b'a+':
c_mode = AFC_FOPEN_RDAPPEND
else:
raise ValueError("mode string must be 'r', 'r+', 'w', 'w+', 'a', or 'a+'")
diff --git a/cython/debugserver.pxi b/cython/debugserver.pxi
index ddbe066..a3b7d1e 100644
--- a/cython/debugserver.pxi
+++ b/cython/debugserver.pxi
@@ -17,10 +17,10 @@ cdef extern from "libimobiledevice/debugserver.h":
debugserver_error_t debugserver_client_free(debugserver_client_t client)
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_command(debugserver_client_t client, debugserver_command_t command, char** response)
+ 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_receive(debugserver_client_t client, char *data, uint32_t size, uint32_t *received)
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_response(debugserver_client_t client, char** response)
+ debugserver_error_t debugserver_client_receive_response(debugserver_client_t client, char** response, size_t* response_size)
debugserver_error_t debugserver_client_set_argv(debugserver_client_t client, int argc, char* argv[], char** response)
debugserver_error_t debugserver_client_set_environment_hex_encoded(debugserver_client_t client, const char* env, char** response)
@@ -44,7 +44,12 @@ cdef class DebugServerError(BaseError):
# from http://stackoverflow.com/a/17511714
-from cpython.string cimport PyString_AsString
+# https://github.com/libimobiledevice/libimobiledevice/pull/198
+from cpython cimport PY_MAJOR_VERSION
+if PY_MAJOR_VERSION <= 2:
+ from cpython.string cimport PyString_AsString
+else:
+ from cpython.bytes cimport PyBytes_AsString as PyString_AsString
cdef char ** to_cstring_array(list_str):
if not list_str:
return NULL
@@ -119,7 +124,7 @@ cdef class DebugServerClient(BaseService):
bytes result
try:
- self.handle_error(debugserver_client_send_command(self._c_client, command._c_command, &c_response))
+ self.handle_error(debugserver_client_send_command(self._c_client, command._c_command, &c_response, NULL))
if c_response:
result = c_response
return result
@@ -166,7 +171,7 @@ cdef class DebugServerClient(BaseService):
bytes result
try:
- self.handle_error(debugserver_client_receive_response(self._c_client, &c_response))
+ self.handle_error(debugserver_client_receive_response(self._c_client, &c_response, NULL))
if c_response:
result = c_response
return result
diff --git a/cython/diagnostics_relay.pxi b/cython/diagnostics_relay.pxi
index 155e5b7..0e6bd20 100644
--- a/cython/diagnostics_relay.pxi
+++ b/cython/diagnostics_relay.pxi
@@ -15,7 +15,7 @@ cdef extern from "libimobiledevice/diagnostics_relay.h":
DIAGNOSTICS_RELAY_E_MUX_ERROR = -3
DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST = -4
DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR = -256
- cdef enum:
+ ctypedef enum diagnostics_relay_action_t:
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)
@@ -25,8 +25,8 @@ cdef extern from "libimobiledevice/diagnostics_relay.h":
diagnostics_relay_error_t diagnostics_relay_goodbye(diagnostics_relay_client_t client)
diagnostics_relay_error_t diagnostics_relay_sleep(diagnostics_relay_client_t client)
- diagnostics_relay_error_t diagnostics_relay_restart(diagnostics_relay_client_t client, int flags)
- diagnostics_relay_error_t diagnostics_relay_shutdown(diagnostics_relay_client_t client, int flags)
+ diagnostics_relay_error_t diagnostics_relay_restart(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)
diagnostics_relay_error_t diagnostics_relay_request_diagnostics(diagnostics_relay_client_t client, char* type, plist.plist_t* diagnostics)
diagnostics_relay_error_t diagnostics_relay_query_mobilegestalt(diagnostics_relay_client_t client, plist.plist_t keys, plist.plist_t* result)
diagnostics_relay_error_t diagnostics_relay_query_ioregistry_entry(diagnostics_relay_client_t client, char* name, char* class_name, plist.plist_t* result)
@@ -66,10 +66,10 @@ cdef class DiagnosticsRelayClient(PropertyListService):
cpdef sleep(self):
self.handle_error(diagnostics_relay_sleep(self._c_client))
- cpdef restart(self, int flags):
+ cpdef restart(self, diagnostics_relay_action_t flags):
self.handle_error(diagnostics_relay_restart(self._c_client, flags))
- cpdef shutdown(self, int flags):
+ cpdef shutdown(self, diagnostics_relay_action_t flags):
self.handle_error(diagnostics_relay_shutdown(self._c_client, flags))
cpdef plist.Node request_diagnostics(self, bytes type):
diff --git a/cython/imobiledevice.pxd b/cython/imobiledevice.pxd
index 8523c94..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 *
@@ -23,13 +26,17 @@ cdef extern from "libimobiledevice/libimobiledevice.h":
cdef struct idevice_connection_private:
pass
ctypedef idevice_connection_private* idevice_connection_t
+ cdef enum idevice_connection_type:
+ CONNECTION_USBMUXD = 1
+ CONNECTION_NETWORK
cdef enum idevice_event_type:
- IDEVICE_DEVICE_ADD = 1,
+ IDEVICE_DEVICE_ADD = 1
IDEVICE_DEVICE_REMOVE
+ IDEVICE_DEVICE_PAIRED
ctypedef struct idevice_event_t:
idevice_event_type event
char *udid
- int conn_type
+ idevice_connection_type conn_type
ctypedef idevice_event_t* const_idevice_event_t "const idevice_event_t*"
cdef class iDeviceEvent:
diff --git a/cython/imobiledevice.pyx b/cython/imobiledevice.pyx
index 141f67c..8da2296 100644
--- a/cython/imobiledevice.pyx
+++ b/cython/imobiledevice.pyx
@@ -40,6 +40,10 @@ cdef extern from "libimobiledevice/libimobiledevice.h":
IDEVICE_E_NOT_ENOUGH_DATA = -4
IDEVICE_E_SSL_ERROR = -6
IDEVICE_E_TIMEOUT = -7
+ cdef enum idevice_options:
+ IDEVICE_LOOKUP_USBMUX = 1 << 1
+ IDEVICE_LOOKUP_NETWORK = 1 << 2
+ IDEVICE_LOOKUP_PREFER_NETWORK = 1 << 3
ctypedef void (*idevice_event_cb_t) (const_idevice_event_t event, void *user_data)
cdef extern idevice_error_t idevice_event_subscribe(idevice_event_cb_t callback, void *user_data)
cdef extern idevice_error_t idevice_event_unsubscribe()
@@ -47,6 +51,7 @@ cdef extern from "libimobiledevice/libimobiledevice.h":
idevice_error_t idevice_device_list_free(char **devices)
void idevice_set_debug_level(int level)
idevice_error_t idevice_new(idevice_t *device, char *udid)
+ idevice_error_t idevice_new_with_options(idevice_t *device, const char *udid, idevice_options options);
idevice_error_t idevice_free(idevice_t device)
idevice_error_t idevice_get_udid(idevice_t device, char** udid)
idevice_error_t idevice_get_handle(idevice_t device, uint32_t *handle)
@@ -89,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)
@@ -171,7 +176,7 @@ from libc.stdlib cimport *
cdef class iDevice(Base):
def __cinit__(self, object udid=None, *args, **kwargs):
cdef char* c_udid = NULL
- if isinstance(udid, basestring):
+ if isinstance(udid, (str, bytes)):
c_udid = <bytes>udid
elif udid is not None:
raise TypeError("iDevice's constructor takes a string or None as the udid argument")
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 f249049..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))
@@ -230,12 +239,13 @@ cdef class LockdownClient(PropertyListService):
if issubclass(service, BaseService) and \
service.__service_name__ is not None \
- and isinstance(service.__service_name__, basestring):
- c_service_name = <bytes>service.__service_name__
- elif isinstance(service, basestring):
- c_service_name = <bytes>service
+ and isinstance(service.__service_name__, (str, bytes)):
+ c_service_name_str = service.__service_name__.encode('utf-8')
+ elif isinstance(service, (str, bytes)):
+ 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))
@@ -253,7 +263,7 @@ cdef class LockdownClient(PropertyListService):
if not hasattr(service_class, '__service_name__') and \
not service_class.__service_name__ is not None \
- and not isinstance(service_class.__service_name__, basestring):
+ and not isinstance(service_class.__service_name__, (str, bytes)):
raise TypeError("LockdownClient.get_service_client() takes a BaseService as its first argument")
descriptor = self.start_service(service_class)
diff --git a/cython/mobilebackup.pxi b/cython/mobilebackup.pxi
index 5a6fea6..f2d58d4 100644
--- a/cython/mobilebackup.pxi
+++ b/cython/mobilebackup.pxi
@@ -8,8 +8,10 @@ cdef extern from "libimobiledevice/mobilebackup.h":
MOBILEBACKUP_E_INVALID_ARG = -1
MOBILEBACKUP_E_PLIST_ERROR = -2
MOBILEBACKUP_E_MUX_ERROR = -3
- MOBILEBACKUP_E_BAD_VERSION = -4
- MOBILEBACKUP_E_REPLY_NOT_OK = -5
+ MOBILEBACKUP_E_SSL_ERROR = -4
+ MOBILEBACKUP_E_RECEIVE_TIMEOUT = -5
+ MOBILEBACKUP_E_BAD_VERSION = -6
+ MOBILEBACKUP_E_REPLY_NOT_OK = -7
MOBILEBACKUP_E_UNKNOWN_ERROR = -256
ctypedef enum mobilebackup_flags_t:
@@ -36,6 +38,8 @@ cdef class MobileBackupError(BaseError):
MOBILEBACKUP_E_INVALID_ARG: "Invalid argument",
MOBILEBACKUP_E_PLIST_ERROR: "Property list error",
MOBILEBACKUP_E_MUX_ERROR: "MUX error",
+ MOBILEBACKUP_E_SSL_ERROR: "SSL error",
+ MOBILEBACKUP_E_RECEIVE_TIMEOUT: "Receive timeout",
MOBILEBACKUP_E_BAD_VERSION: "Bad version",
MOBILEBACKUP_E_REPLY_NOT_OK: "Reply not OK",
MOBILEBACKUP_E_UNKNOWN_ERROR: "Unknown error"
diff --git a/cython/mobilebackup2.pxi b/cython/mobilebackup2.pxi
index aac5358..4b47e5b 100644
--- a/cython/mobilebackup2.pxi
+++ b/cython/mobilebackup2.pxi
@@ -8,9 +8,11 @@ cdef extern from "libimobiledevice/mobilebackup2.h":
MOBILEBACKUP2_E_INVALID_ARG = -1
MOBILEBACKUP2_E_PLIST_ERROR = -2
MOBILEBACKUP2_E_MUX_ERROR = -3
- MOBILEBACKUP2_E_BAD_VERSION = -4
- MOBILEBACKUP2_E_REPLY_NOT_OK = -5
- MOBILEBACKUP2_E_NO_COMMON_VERSION = -6
+ MOBILEBACKUP2_E_SSL_ERROR = -4
+ MOBILEBACKUP2_E_RECEIVE_TIMEOUT = -5
+ MOBILEBACKUP2_E_BAD_VERSION = -6
+ MOBILEBACKUP2_E_REPLY_NOT_OK = -7
+ MOBILEBACKUP2_E_NO_COMMON_VERSION = -8
MOBILEBACKUP2_E_UNKNOWN_ERROR = -256
mobilebackup2_error_t mobilebackup2_client_new(idevice_t device, lockdownd_service_descriptor_t descriptor, mobilebackup2_client_t * client)
@@ -31,6 +33,8 @@ cdef class MobileBackup2Error(BaseError):
MOBILEBACKUP2_E_INVALID_ARG: "Invalid argument",
MOBILEBACKUP2_E_PLIST_ERROR: "Property list error",
MOBILEBACKUP2_E_MUX_ERROR: "MUX error",
+ MOBILEBACKUP2_E_SSL_ERROR: "SSL error",
+ MOBILEBACKUP2_E_RECEIVE_TIMEOUT: "Receive timeout",
MOBILEBACKUP2_E_BAD_VERSION: "Bad version",
MOBILEBACKUP2_E_REPLY_NOT_OK: "Reply not OK",
MOBILEBACKUP2_E_NO_COMMON_VERSION: "No common version",
@@ -54,10 +58,10 @@ cdef class MobileBackup2Client(PropertyListService):
cdef inline BaseError _error(self, int16_t ret):
return MobileBackup2Error(ret)
- cdef send_message(self, bytes message, plist.Node options):
+ cpdef send_message(self, bytes message, plist.Node options):
self.handle_error(mobilebackup2_send_message(self._c_client, message, options._c_node))
- cdef tuple receive_message(self):
+ cpdef tuple receive_message(self):
cdef:
char* dlmessage = NULL
plist.plist_t c_node = NULL
@@ -73,29 +77,34 @@ cdef class MobileBackup2Client(PropertyListService):
free(dlmessage)
raise
- cdef int send_raw(self, bytes data, int length):
+ cpdef int send_raw(self, bytes data, int length):
cdef:
- uint32_t bytes = 0
+ uint32_t bytes_recvd = 0
mobilebackup2_error_t err
- err = mobilebackup2_send_raw(self._c_client, data, length, &bytes)
+ err = mobilebackup2_send_raw(self._c_client, data, length, &bytes_recvd)
try:
self.handle_error(err)
- return <bint>bytes
+ return <bint>bytes_recvd
except BaseError, e:
raise
- cdef int receive_raw(self, bytes data, int length):
+ cpdef int receive_raw(self, bytearray data, int length):
cdef:
- uint32_t bytes = 0
+ uint32_t bytes_recvd = 0
mobilebackup2_error_t err
- err = mobilebackup2_receive_raw(self._c_client, data, length, &bytes)
+ err = mobilebackup2_receive_raw(self._c_client, data, length, &bytes_recvd)
+
+ # Throwing an exception when we test if theres more data to read is excessive
+ if err == -1 and bytes_recvd == 0:
+ return 0
+
try:
self.handle_error(err)
- return <bint>bytes
+ return <bint>bytes_recvd
except BaseError, e:
raise
- cdef float version_exchange(self, double[::1] local_versions):
+ cpdef float version_exchange(self, double[::1] local_versions):
cdef:
double[::1] temp = None
double remote_version = 0.0
@@ -107,8 +116,8 @@ cdef class MobileBackup2Client(PropertyListService):
except BaseError, e:
raise
- cdef send_request(self, bytes request, bytes target_identifier, bytes source_identifier, plist.Node options):
+ cpdef send_request(self, bytes request, bytes target_identifier, bytes source_identifier, plist.Node options):
self.handle_error(mobilebackup2_send_request(self._c_client, request, target_identifier, source_identifier, options._c_node))
- cdef send_status_response(self, int status_code, bytes status1, plist.Node status2):
+ cpdef send_status_response(self, int status_code, bytes status1, plist.Node status2):
self.handle_error(mobilebackup2_send_status_response(self._c_client, status_code, status1, status2._c_node))
diff --git a/cython/mobilesync.pxi b/cython/mobilesync.pxi
index ba9d585..23f0005 100644
--- a/cython/mobilesync.pxi
+++ b/cython/mobilesync.pxi
@@ -7,11 +7,13 @@ cdef extern from "libimobiledevice/mobilesync.h":
MOBILESYNC_E_INVALID_ARG = -1
MOBILESYNC_E_PLIST_ERROR = -2
MOBILESYNC_E_MUX_ERROR = -3
- MOBILESYNC_E_BAD_VERSION = -4
- MOBILESYNC_E_SYNC_REFUSED = -5
- MOBILESYNC_E_CANCELLED = -6
- MOBILESYNC_E_WRONG_DIRECTION = -7
- MOBILESYNC_E_NOT_READY = -8
+ MOBILESYNC_E_SSL_ERROR = -4
+ MOBILESYNC_E_RECEIVE_TIMEOUT = -5
+ MOBILESYNC_E_BAD_VERSION = -6
+ MOBILESYNC_E_SYNC_REFUSED = -7
+ MOBILESYNC_E_CANCELLED = -8
+ MOBILESYNC_E_WRONG_DIRECTION = -9
+ MOBILESYNC_E_NOT_READY = -10
MOBILESYNC_E_UNKNOWN_ERROR = -256
ctypedef enum mobilesync_sync_type_t:
@@ -60,6 +62,8 @@ cdef class MobileSyncError(BaseError):
MOBILESYNC_E_INVALID_ARG: "Invalid argument",
MOBILESYNC_E_PLIST_ERROR: "Property list error",
MOBILESYNC_E_MUX_ERROR: "MUX error",
+ MOBILESYNC_E_SSL_ERROR: "SSL error",
+ MOBILESYNC_E_RECEIVE_TIMEOUT: "Receive timeout",
MOBILESYNC_E_BAD_VERSION: "Bad version",
MOBILESYNC_E_SYNC_REFUSED: "Sync refused",
MOBILESYNC_E_CANCELLED: "Sync cancelled",
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/cython/restore.pxi b/cython/restore.pxi
index 7d3d80e..9d03935 100644
--- a/cython/restore.pxi
+++ b/cython/restore.pxi
@@ -6,12 +6,10 @@ cdef extern from "libimobiledevice/restore.h":
ctypedef enum restored_error_t:
RESTORE_E_SUCCESS = 0
RESTORE_E_INVALID_ARG = -1
- RESTORE_E_INVALID_CONF = -2
- RESTORE_E_PLIST_ERROR = -3
- RESTORE_E_DICT_ERROR = -4
- RESTORE_E_NOT_ENOUGH_DATA = -5
- RESTORE_E_MUX_ERROR = -6
- RESTORE_E_START_RESTORE_FAILED = -7
+ RESTORE_E_PLIST_ERROR = -2
+ RESTORE_E_MUX_ERROR = -3
+ RESTORE_E_NOT_ENOUGH_DATA = -4
+ RESTORE_E_RECEIVE_TIMEOUT = -5
RESTORE_E_UNKNOWN_ERROR = -256
restored_error_t restored_client_new(idevice_t device, restored_client_t *client, char *label)
@@ -34,12 +32,10 @@ cdef class RestoreError(BaseError):
self._lookup_table = {
RESTORE_E_SUCCESS: "Success",
RESTORE_E_INVALID_ARG: "Invalid argument",
- RESTORE_E_INVALID_CONF: "Invalid configuration",
RESTORE_E_PLIST_ERROR: "Property list error",
- RESTORE_E_DICT_ERROR: "Dict error",
- RESTORE_E_NOT_ENOUGH_DATA: "Not enough data",
RESTORE_E_MUX_ERROR: "MUX Error",
- RESTORE_E_START_RESTORE_FAILED: "Starting restore failed",
+ RESTORE_E_NOT_ENOUGH_DATA: "Not enough data",
+ RESTORE_E_RECEIVE_TIMEOUT: "Receive timeout",
RESTORE_E_UNKNOWN_ERROR: "Unknown error"
}
BaseError.__init__(self, *args, **kwargs)
diff --git a/cython/screenshotr.pxi b/cython/screenshotr.pxi
index 2b2d53d..a1e82e2 100644
--- a/cython/screenshotr.pxi
+++ b/cython/screenshotr.pxi
@@ -8,7 +8,9 @@ cdef extern from "libimobiledevice/screenshotr.h":
SCREENSHOTR_E_INVALID_ARG = -1
SCREENSHOTR_E_PLIST_ERROR = -2
SCREENSHOTR_E_MUX_ERROR = -3
- SCREENSHOTR_E_BAD_VERSION = -4
+ SCREENSHOTR_E_SSL_ERROR = -4
+ SCREENSHOTR_E_RECEIVE_TIMEOUT = 5
+ SCREENSHOTR_E_BAD_VERSION = -6
SCREENSHOTR_E_UNKNOWN_ERROR = -256
screenshotr_error_t screenshotr_client_new(idevice_t device, lockdownd_service_descriptor_t descriptor, screenshotr_client_t * client)
@@ -22,6 +24,8 @@ cdef class ScreenshotrError(BaseError):
SCREENSHOTR_E_INVALID_ARG: "Invalid argument",
SCREENSHOTR_E_PLIST_ERROR: "Property list error",
SCREENSHOTR_E_MUX_ERROR: "MUX error",
+ SCREENSHOTR_E_SSL_ERROR: "SSL error",
+ SCREENSHOTR_E_RECEIVE_TIMEOUT: "Receive timeout",
SCREENSHOTR_E_BAD_VERSION: "Bad version",
SCREENSHOTR_E_UNKNOWN_ERROR: "Unknown error"
}
diff --git a/docs/Makefile.am b/docs/Makefile.am
index d788297..4a4c56f 100644
--- a/docs/Makefile.am
+++ b/docs/Makefile.am
@@ -1,4 +1,24 @@
-man_MANS = idevice_id.1 ideviceinfo.1 idevicesyslog.1 idevicebackup.1 idevicebackup2.1 ideviceimagemounter.1 idevicescreenshot.1 idevicepair.1 ideviceenterrecovery.1 idevicedate.1 ideviceprovision.1 idevicedebugserverproxy.1 idevicediagnostics.1 idevicecrashreport.1 idevicename.1 idevicedebug.1 idevicenotificationproxy.1
+man_MANS = \
+ idevice_id.1 \
+ ideviceinfo.1 \
+ idevicebtlogger.1 \
+ idevicesyslog.1 \
+ idevicebackup.1 \
+ idevicebackup2.1 \
+ ideviceimagemounter.1 \
+ idevicescreenshot.1 \
+ idevicepair.1 \
+ ideviceenterrecovery.1 \
+ idevicedate.1 \
+ ideviceprovision.1 \
+ idevicedebugserverproxy.1 \
+ idevicediagnostics.1 \
+ idevicecrashreport.1 \
+ idevicename.1 \
+ idevicedebug.1 \
+ idevicedevmodectl.1 \
+ idevicenotificationproxy.1 \
+ idevicesetlocation.1
EXTRA_DIST = $(man_MANS)
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/doxygen/custom.css b/docs/doxygen/custom.css
new file mode 100644
index 0000000..62183bf
--- /dev/null
+++ b/docs/doxygen/custom.css
@@ -0,0 +1,1722 @@
+body, table, div, p, dl {
+ font: 14px -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;
+ line-height: 1.5;
+}
+
+/* @group Heading Levels */
+
+h1.groupheader {
+ font-size: 28px;
+}
+
+.title {
+ font: inherit;
+ font-size: 2rem;
+ font-weight: bold;
+ margin: 0;
+ padding-bottom: 0.3rem;
+ border-bottom: 1px solid #eaecef;
+}
+
+h2.groupheader {
+ border-bottom: none;
+ color: rgb(36, 41, 46);
+ font-size: 1.5rem;
+ font-weight: bold;
+ margin: 1.75rem 0px 1rem 0px;
+ padding: 0 0.3rem 0 0;
+ border-bottom: 1px solid #eaecef;
+ width: 100%;
+}
+
+h3.groupheader {
+ font-size: 100%;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ -webkit-transition: text-shadow 0.5s linear;
+ -moz-transition: text-shadow 0.5s linear;
+ -ms-transition: text-shadow 0.5s linear;
+ -o-transition: text-shadow 0.5s linear;
+ transition: text-shadow 0.5s linear;
+}
+
+.textblock h1,
+.textblock h2,
+.textblock h3,
+.textblock h4,
+.textblock h5,
+.textblock h6 {
+ margin: 1.75rem 0px 1rem 0px;
+ padding: 0 0.3rem 0 0;
+ border-bottom: 1px solid #eaecef;
+}
+
+h1 {
+ font-size: 1.75rem;
+}
+
+h2 {
+ color: rgb(36, 41, 46);
+ font-size: 1.5rem;
+ font-weight: bold;
+ margin: 1.75rem 0 1rem 0px;
+}
+
+h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow {
+ text-shadow: 0 0 15px #1fa4a9;
+}
+
+dt {
+ font-weight: bold;
+}
+
+div.multicol {
+ -moz-column-gap: 1em;
+ -webkit-column-gap: 1em;
+ -moz-column-count: 3;
+ -webkit-column-count: 3;
+}
+
+p.startli, p.startdd, p.starttd {
+ margin-top: 2px;
+}
+
+p.endli {
+ margin-bottom: 0px;
+}
+
+p.enddd {
+ margin-bottom: 4px;
+}
+
+p.endtd {
+ margin-bottom: 2px;
+}
+
+/* @end */
+
+caption {
+ font-weight: bold;
+}
+
+span.legend {
+ font-size: 70%;
+ text-align: center;
+}
+
+h3.version {
+ font-size: 90%;
+ text-align: center;
+}
+
+div.qindex, div.navtab {
+ background-color: #fff;
+ border: 1px solid #d1d5da;
+ padding: 0;
+ border-radius: 3px;
+ text-align: left;
+}
+
+div.qindex, div.navpath {
+ width: auto;
+ line-height: 140%;
+}
+
+div.navtab {
+ margin-right: 2rem;
+}
+
+@media (max-width: 576px) {
+ .contents td.top:not(.mempage),
+ div.navtab {
+ display: none;
+ }
+}
+
+div.navtab table {
+ border-spacing: 0;
+}
+
+div.navtab table td.navtab {
+ position: relative;
+ display: block;
+ padding: 8px 10px;
+ border-bottom: 1px solid #e1e4e8;
+}
+
+div.navtab table td.navtab:hover {
+ background-color: #f6f8fa;
+}
+
+/* @group Link Styling */
+
+a {
+ color: #005082;
+ font-weight: normal;
+ text-decoration: none;
+}
+
+.contents a:visited {
+ color: #005082;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+a.qindex {
+ font-weight: bold;
+}
+
+a.qindexHL {
+ font-weight: bold;
+ background-color: #fff;
+ color: inherit;
+ border: none;
+}
+
+a.qindexHL:before {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ width: 2px;
+ content: "";
+ background-color: #f7ae1a;
+}
+
+.contents a.qindexHL:visited {
+ color: inherit;
+}
+
+a.el {
+ font-weight: normal;
+}
+
+a.elRef {
+}
+
+a.code, a.code:visited {
+ color: #3465a4;
+}
+
+a.codeRef, a.codeRef:visited {
+ color: #3465a4;
+}
+
+/* @end */
+
+dl.el {
+ margin-left: -1cm;
+}
+
+pre.fragment {
+ border: 1px solid rgb(221, 221, 221);
+ border-radius: 3px;
+ background-color: rgb(248, 248, 248);
+ padding: 1rem;
+ margin: 1rem 0px;
+ overflow: auto;
+ word-wrap: break-word;
+ font-size: inherit;
+ line-height: inherit;
+ font-family: SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;
+}
+
+div.fragment {
+ padding: 1rem;
+ margin: 1rem 0px;
+ border: solid 1px rgb(221, 221, 221);
+ border-radius: 3px;
+ background-color: rgb(248, 248, 248);
+}
+
+div.line {
+ font-family: SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;
+ font-size: inherit;
+ min-height: 1rem;
+ line-height: inherit;
+ text-wrap: unrestricted;
+ white-space: -moz-pre-wrap; /* Moz */
+ white-space: -pre-wrap; /* Opera 4-6 */
+ white-space: -o-pre-wrap; /* Opera 7 */
+ white-space: pre-wrap; /* CSS3 */
+ word-wrap: break-word; /* IE 5.5+ */
+ text-indent: initial;
+ padding-left: initial;
+ padding-bottom: 0px;
+ margin: 0px;
+ -webkit-transition-property: background-color, box-shadow;
+ -webkit-transition-duration: 0.5s;
+ -moz-transition-property: background-color, box-shadow;
+ -moz-transition-duration: 0.5s;
+ -ms-transition-property: background-color, box-shadow;
+ -ms-transition-duration: 0.5s;
+ -o-transition-property: background-color, box-shadow;
+ -o-transition-duration: 0.5s;
+ transition-property: background-color, box-shadow;
+ transition-duration: 0.5s;
+ display: inline-block;
+ min-width: 100%;
+}
+
+div.line.glow {
+ background-color: cyan;
+ box-shadow: 0 0 10px cyan;
+}
+
+
+span.lineno {
+ padding-right: 4px;
+ text-align: right;
+ border-right: 2px solid #0F0;
+ background-color: #E8E8E8;
+ white-space: pre;
+}
+span.lineno a {
+ background-color: #D8D8D8;
+}
+
+span.lineno a:hover {
+ background-color: #C8C8C8;
+}
+
+div.ah {
+ background-color: black;
+ font-weight: bold;
+ color: #ffffff;
+ margin-bottom: 3px;
+ margin-top: 3px;
+ padding: 0.2em;
+ border: solid thin #333;
+ border-radius: 0.5em;
+ -webkit-border-radius: .5em;
+ -moz-border-radius: .5em;
+ box-shadow: 2px 2px 3px #999;
+ -webkit-box-shadow: 2px 2px 3px #999;
+ -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444));
+ background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000);
+}
+
+div.groupHeader {
+ margin-left: 0px;
+ margin-top: 9px;
+ margin-bottom: 4.7px;
+
+ font-size: 19px;
+ font-weight: normal;
+}
+
+div.groupText {
+ margin-left: 16px;
+ font-style: italic;
+}
+
+body {
+ background-color: white;
+ color: rgb(36, 41, 46);
+ margin: 0;
+}
+
+div.contents {
+ padding: 1rem 2rem;
+ margin: 0;
+}
+
+td.indexkey {
+ background-color: #EBEFF6;
+ font-weight: bold;
+ border: 1px solid #C4CFE5;
+ margin: 2px 0px 2px 0;
+ padding: 2px 10px;
+ white-space: nowrap;
+ vertical-align: top;
+}
+
+td.indexvalue {
+ background-color: #EBEFF6;
+ border: 1px solid #C4CFE5;
+ padding: 2px 10px;
+ margin: 2px 0px;
+}
+
+tr.memlist {
+ background-color: #EEF1F7;
+}
+
+p.formulaDsp {
+ text-align: center;
+}
+
+img.formulaDsp {
+}
+
+img.formulaInl {
+ vertical-align: middle;
+}
+
+div.center {
+ text-align: center;
+ margin-top: 0px;
+ margin-bottom: 0px;
+ padding: 0px;
+}
+
+div.center img {
+ border: 0px;
+}
+
+address.footer {
+ text-align: left;
+ margin-left: 2rem;
+ margin-right: 2rem;
+ margin-bottom: 1rem;
+}
+
+img.footer {
+ border: 0px;
+ vertical-align: middle;
+}
+
+/* @group Code Colorization */
+
+span.keyword {
+ color: #008000;
+}
+
+span.keywordtype {
+ color: #604020;
+}
+
+span.keywordflow {
+ color: #e08000;
+}
+
+span.comment {
+ color: #800000;
+}
+
+span.preprocessor {
+ color: #806020;
+}
+
+span.stringliteral {
+ color: #002080;
+}
+
+span.charliteral {
+ color: #008080;
+}
+
+span.vhdldigit {
+ color: #ff00ff;
+}
+
+span.vhdlchar {
+ color: #000000;
+}
+
+span.vhdlkeyword {
+ color: #700070;
+}
+
+span.vhdllogic {
+ color: #ff0000;
+}
+
+blockquote {
+ background-color: #F7F8FB;
+ border-left: 2px solid #9CAFD4;
+ margin: 0 24px 0 4px;
+ padding: 0 12px 0 16px;
+}
+
+/* @end */
+
+td.tiny {
+ font-size: 75%;
+}
+
+.dirtab {
+ padding: 4px;
+ border-collapse: collapse;
+ border: 1px solid #A3B4D7;
+}
+
+th.dirtab {
+ background: #EBEFF6;
+ font-weight: bold;
+}
+
+hr {
+ height: 0px;
+ border: none;
+ border-top: 1px solid #e1e4e8;
+}
+
+hr.footer {
+ height: 0px;
+ border-top: 1px solid #e1e4e8;
+ margin-left: 2rem;
+ margin-right: 2rem;
+}
+
+/* @group Member Descriptions */
+
+table.memberdecls {
+ border-spacing: inherit;
+ padding: 0px;
+ background-color: transparent;
+ border-color: #c8e1ff;
+}
+
+table.memberdecls tr:not(.heading) {
+ background-color: #f1f8ff;
+}
+
+table.memberdecls tr:not(.heading) td.ititle {
+ background-color: #fff;
+ border: none;
+}
+
+.memberdecls td, .fieldtable tr {
+ -webkit-transition-property: background-color, box-shadow;
+ -webkit-transition-duration: 0.5s;
+ -moz-transition-property: background-color, box-shadow;
+ -moz-transition-duration: 0.5s;
+ -ms-transition-property: background-color, box-shadow;
+ -ms-transition-duration: 0.5s;
+ -o-transition-property: background-color, box-shadow;
+ -o-transition-duration: 0.5s;
+ transition-property: background-color, box-shadow;
+ transition-duration: 0.5s;
+}
+
+.memberdecls td.glow, .fieldtable tr.glow {
+ background-color: #1fa4a9;
+ box-shadow: none;
+}
+
+.mdescLeft, .mdescRight,
+.memItemLeft, .memItemRight,
+.memTemplItemLeft, .memTemplItemRight, .memTemplParams {
+ background-color: transparent;
+ border: none;
+ margin: 0;
+ padding: 1rem 1rem 0.5rem 1rem;
+ font-family: SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;
+}
+
+.mdescLeft,
+.memItemLeft,
+.memTemplItemLeft {
+ border-left: 1px solid #c8e1ff;
+}
+
+.mdescRight,
+.memItemRight,
+.memTemplItemRight {
+ border-right: 1px solid #c8e1ff;
+}
+
+.memberdecls tr:nth-child(2) td {
+ border-top: 1px solid #c8e1ff;
+ padding-bottom: 1rem;
+}
+
+.memberdecls tr:last-child td {
+ border-bottom: none;
+ padding-bottom: 1rem;
+}
+
+.memberdecls tr:nth-last-child(2) td {
+ padding-bottom: 1rem;
+}
+
+.mdescLeft, .mdescRight {
+ padding: 0 1rem 1rem 1rem;
+ color: black;
+
+ /* font-family: "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, Verdana, sans-serif; */
+ font-style: normal;
+}
+
+.memSeparator {
+ background-color: #fff;
+ border-top: 1px solid #c8e1ff;
+ border-bottom: 1px solid #c8e1ff;
+ line-height: 0.5rem;
+ margin: 0px;
+ padding: 0px;
+}
+
+tr:last-child .memSeparator {
+ border-bottom: none;
+}
+
+.memItemLeft, .memTemplItemLeft {
+ white-space: nowrap;
+}
+
+.memItemRight {
+ width: 100%;
+}
+
+.mdescRight a.el:first-child,
+.memItemRight a.el:first-child,
+.memTemplItemRight a.el:first-child {
+ font-weight: bold;
+}
+
+.memTemplParams {
+ color: #005082;
+ white-space: nowrap;
+ font-size: 80%;
+}
+
+/* @end */
+
+/* @group Member Details */
+
+/* Styles for detailed member documentation */
+
+.memtitle {
+ padding: 0 0.3rem 0 0;
+ border: none;
+ border-bottom: 1px solid #eaecef;
+ margin: 0 0 1.75rem 0;
+ line-height: inherit;
+ background: none;
+ font-weight: bold;
+ font-size: 2rem;
+ width: 100%;
+ float: left;
+}
+
+.permalink {
+ font-size: 65%;
+ display: inline-block;
+ vertical-align: middle;
+ display: none;
+}
+
+.permalink a:hover {
+ text-decoration: none;
+}
+
+.memtemplate {
+ font-size: 100%;
+ color: black;
+ font-weight: normal;
+ margin-left: 1px;
+}
+
+.memnav {
+ background-color: #EBEFF6;
+ border: 1px solid #A3B4D7;
+ text-align: center;
+ margin: 2px;
+ margin-right: 15px;
+ padding: 2px;
+}
+
+.mempage {
+ width: 100%;
+}
+
+.memitem {
+ padding: 0;
+ margin-bottom: 2rem;
+ margin-right: 0;
+ -webkit-transition: box-shadow 0.5s linear;
+ -moz-transition: box-shadow 0.5s linear;
+ -ms-transition: box-shadow 0.5s linear;
+ -o-transition: box-shadow 0.5s linear;
+ transition: box-shadow 0.5s linear;
+ display: table !important;
+ width: 100%;
+ background-color: #f1f8ff;
+ border-color: #c8e1ff;
+}
+
+.memitem.glow {
+ box-shadow: 0 0 15px #1fa4a9;
+}
+
+.memname {
+ font-family: SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;
+ margin-left: 0px;
+ border-spacing: initial;
+}
+
+.memname td {
+ font-weight: bold;
+ vertical-align: bottom;
+}
+
+.memproto, dl.reflist dt {
+ border: none;
+ border: 1px solid #c8e1ff;
+ padding: 1rem;
+ color: black;
+ font-weight: bold;
+ text-shadow: none;
+ background-image: none;
+ background-color: #f1f8ff;
+ /* opera specific markup */
+ box-shadow: none;
+ border-top-right-radius: 0px;
+ border-top-left-radius: 0px;
+ /* firefox specific markup */
+ -moz-box-shadow: none;
+ -moz-border-radius-topright: 0px;
+ -moz-border-radius-topleft: 0px;
+ /* webkit specific markup */
+ -webkit-box-shadow: none;
+ -webkit-border-top-right-radius: 0px;
+ -webkit-border-top-left-radius: 0px;
+}
+
+.memdoc, dl.reflist dd {
+ border: none;
+ padding: 6px;
+ background-color: #FBFCFD;
+ border-top-width: 0;
+ background-image: none;
+ background-color: #FFFFFF;
+ /* opera specific markup */
+ border-bottom-left-radius: 0px;
+ border-bottom-right-radius: 0px;
+ box-shadow: none;
+ /* firefox specific markup */
+ -moz-border-radius-bottomleft: 0px;
+ -moz-border-radius-bottomright: 0px;
+ -moz-box-shadow: none;
+ /* webkit specific markup */
+ -webkit-border-bottom-left-radius: 0px;
+ -webkit-border-bottom-right-radius: 0px;
+ -webkit-box-shadow: none;
+}
+
+dl.reflist dt {
+ padding: 5px;
+}
+
+dl.reflist dd {
+ margin: 0px 0px 10px 0px;
+ padding: 5px;
+}
+
+.paramkey {
+ text-align: right;
+}
+
+.paramtype {
+ white-space: nowrap;
+}
+
+.paramname {
+ color: #01496d;
+ white-space: nowrap;
+}
+.paramname em {
+ font-style: italic;
+ font-weight: normal;
+}
+.paramname code {
+ line-height: 14px;
+}
+
+.params, .retval, .exception, .tparams {
+ margin-left: 0px;
+ padding-left: 0px;
+}
+
+.params .paramname, .retval .paramname {
+ font-family: SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;
+ font-style: italic;
+ font-weight: normal;
+ text-shadow: none;
+ padding-right: 1rem;
+}
+
+.params .paramtype {
+ font-style: italic;
+ vertical-align: top;
+}
+
+.params .paramdir {
+ font-family: SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;
+ vertical-align: top;
+}
+
+table.mlabels {
+ border-spacing: 0px;
+}
+
+td.mlabels-left {
+ width: 100%;
+ padding: 0px;
+}
+
+td.mlabels-right {
+ vertical-align: middle;
+ padding: 0px;
+ white-space: nowrap;
+}
+
+span.mlabels {
+ margin-left: 8px;
+}
+
+span.mlabel {
+ background-color: rgb(172, 172, 172);;
+ border: none;
+ text-shadow: none;
+ color: white;
+ margin-right: 4px;
+ padding: 2px 3px;
+ border-radius: 4px;
+ font-size: 9pt;
+ white-space: nowrap;
+ vertical-align: middle;
+}
+
+/* @end */
+
+/* these are for tree view when not used as main index */
+
+div.directory {
+ border-top: 1px solid #eaecef;
+ border-left: 1px solid #eaecef;
+ border-right: 1px solid #eaecef;
+ border-bottom: 1px solid #eaecef;
+ margin: 10px 0px;
+ width: 100%;
+}
+
+.directory table {
+ border-collapse:collapse;
+}
+
+.directory td {
+ margin: 0px;
+ padding: 8px;
+ vertical-align: middle;
+ line-height: 1.5rem;
+}
+
+.directory tr {
+ border-top: 1px solid #eaecef;
+}
+
+.directory tr:first-child {
+ border-top: none;
+}
+
+.directory td.entry {
+ white-space: nowrap;
+ padding: 8px;
+}
+
+@media (max-width: 576px) {
+ .directory td.entry > span:first-child {
+ display: none !important;
+ }
+}
+
+.directory td.entry a {
+ outline: none;
+}
+
+.directory td.entry a img {
+ border: none;
+}
+
+.directory td.desc {
+ width: 100%;
+ padding: 8px;
+ border-left: 1px solid rgba(0,0,0,0.05);
+}
+
+.directory tr.even {
+ padding-left: 0;
+ background-color: inherit;
+}
+
+.directory tr:not(.even) {
+ background-color: #f6f8fa;
+}
+
+.directory img {
+ vertical-align: -30%;
+}
+
+.directory .levels {
+ display: none;
+ white-space: nowrap;
+ width: auto;
+ text-align: right;
+ font-size: 0.75rem;
+ font-weight: bold;
+ padding: 8px;
+ border-bottom: 1px solid #eaecef;
+}
+
+.directory .levels span {
+ cursor: pointer;
+ padding: 0 0.5rem;
+ color: #3d578c;
+}
+
+.arrow {
+ color: #6c757d;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ cursor: pointer;
+ font-size: inherit;
+ display: inline-block;
+ width: 16px;
+ height: 16px;
+}
+
+.icon {
+ display: inline-block;
+ margin: 0;
+
+ font-family: Arial, Helvetica;
+ font-weight: bold;
+ font-size: 0.75rem;
+ text-align: center;
+
+ width: 16px;
+ height: 16px;
+ line-height: 16px;
+
+ border-radius: 4px;
+ background-color: #6194cb;
+ color: white;
+}
+
+.icona {
+ width: 16px;
+ height: 16px;
+ display: inline-block;
+ margin-left: 0.25rem;
+ margin-right: 0.25rem;
+}
+
+.iconfopen {
+ width: 16px;
+ height: 16px;
+ margin-bottom: 0;
+ background-image:url('folder-open.png');
+ background-position: 0px -1px;
+ background-repeat: no-repeat;
+ vertical-align: middle;
+ display: inline-block;
+ margin-left: 0.25rem;
+ margin-right: 0.25rem;
+}
+
+.iconfclosed {
+ width: 16px;
+ height: 16px;
+ margin-bottom: 0;
+ background-image:url('folder.png');
+ background-position: 0px 0px;
+ background-repeat: no-repeat;
+ vertical-align: middle;
+ display: inline-block;
+ margin-left: 0.25rem;
+ margin-right: 0.25rem;
+}
+
+.icondoc {
+ width: 16px;
+ height: 16px;
+ margin-bottom: 0;
+ background-image:url('text-x-generic.png');
+ background-position: 0px 0px;
+ background-repeat: no-repeat;
+ vertical-align: middle;
+ display: inline-block;
+ margin-left: 0.25rem;
+ margin-right: 0.25rem;
+}
+
+/* @end */
+
+div.dynheader {
+ margin-top: 8px;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+address {
+ font-style: normal;
+ color: #2A3D61;
+}
+
+table.doxtable {
+ border-collapse:collapse;
+ margin-top: 4px;
+ margin-bottom: 4px;
+}
+
+table.doxtable td, table.doxtable th {
+ border: 1px solid #2D4068;
+ padding: 3px 7px 2px;
+}
+
+table.doxtable th {
+ background-color: #374F7F;
+ color: #FFFFFF;
+ font-size: 110%;
+ padding-bottom: 4px;
+ padding-top: 5px;
+}
+
+table.fieldtable {
+ margin-bottom: 10px;
+ border: 1px solid #c6cbd1;
+ border-spacing: 0px;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ -moz-box-shadow: none;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ font-size: 1rem;
+}
+
+.fieldtable td, .fieldtable th {
+ padding: 0.5rem 1rem;
+}
+
+.fieldtable td.fieldtype, .fieldtable td.fieldname {
+ white-space: nowrap;
+ border-right: 1px solid #c6cbd1;
+ border-bottom: 1px solid #c6cbd1;
+ vertical-align: middle;
+}
+
+.fieldtable td.fieldname {
+ padding-top: 0.5rem;
+ font-style: italic;
+}
+
+.fieldtable td.fielddoc {
+ border-bottom: 1px solid #c6cbd1;
+}
+
+.fieldtable td.fielddoc p {
+ font-size: 1rem;
+}
+
+.fieldtable td.fielddoc p:first-child {
+ margin-top: 0px;
+}
+
+.fieldtable td.fielddoc p:last-child {
+ margin-bottom: 2px;
+}
+
+.fieldtable tr:last-child td {
+ border-bottom: none;
+}
+
+.fieldtable tbody tr:nth-of-type(odd) {
+ background-color: #f6f8fa;
+}
+
+.fieldtable th {
+ background-image: none;
+ background-repeat:repeat-x;
+ background-color: #fff;
+ font-size: inherit;
+ font-weight: bold;
+ color: inherit;
+ padding: 0.5rem 1rem;
+ text-align: inherit;
+ -moz-border-radius-topleft: 3px;
+ -moz-border-radius-topright: 3px;
+ -webkit-border-top-left-radius: 3px;
+ -webkit-border-top-right-radius: 3px;
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+ border-bottom: 1px solid #c6cbd1;
+}
+
+
+.tabsearch {
+ top: 0px;
+ left: 10px;
+ height: 36px;
+ background-image: none;
+ z-index: 101;
+ overflow: hidden;
+ font-size: 13px;
+}
+
+.navpath ul {
+ font-size: 1rem;
+ background-image: none;
+ background-repeat: repeat-x;
+ background-position: 0 -5px;
+ height:30px;
+ line-height:30px;
+ color: inherit;
+ border: none;
+ overflow:hidden;
+ margin:0px;
+ padding: 0px;
+}
+
+.navpath li {
+ list-style-type: none;
+ float: left;
+ background-image: none;
+ background-repeat: no-repeat;
+ background-position: right;
+ color: inherit;
+}
+
+#top .navpath li+li {
+ padding-left: .5rem;
+}
+
+#top .navpath li+li::before {
+ display: inline-block;
+ padding-right: .5rem;
+ color: #6c757d;
+ content: "/";
+}
+
+@media (min-width: 576px) {
+ address.footer .navpath li+li {
+ padding-left: .5rem;
+ }
+
+ address.footer .navpath li+li::before {
+ display: inline-block;
+ padding-right: .5rem;
+ color: #6c757d;
+ content: "/";
+ }
+}
+
+.navpath li.navelem a {
+ height:32px;
+ display: inline-block;
+ text-decoration: none;
+ outline: none;
+ color: inherit;
+ font-family: inherit;
+ text-shadow: none;
+ text-decoration: none;
+}
+
+.navpath li.navelem a:hover {
+ color: inherit;
+}
+
+address.footer {
+ text-align: left;
+ padding-right: 0;
+}
+
+address.footer ul.navpath {
+ display: inline-block;
+ padding: 0;
+}
+
+.navpath li.footer {
+ list-style-type: none;
+ float: left;
+ padding-left: 0.5rem;
+ padding-right: 0;
+ background-image: none;
+ background-repeat: no-repeat;
+ background-position: right;
+ color: inherit;
+ font-size: 0.75rem;
+}
+
+div.summary {
+ float: none;
+ font-size: 0.75rem;
+ padding-right: 5px;
+ width: 100%;
+ text-align: left;
+}
+
+div.summary a {
+ white-space: nowrap;
+}
+
+div.ingroups {
+ font-size: 0.75rem;
+ width: 50%;
+ text-align: left;
+}
+
+div.ingroups a {
+ white-space: nowrap;
+}
+
+div.header {
+ background-image: none;
+ background-color: white;
+ padding: 1rem 2rem 0 2rem;
+ margin: 0px;
+ border: none;
+}
+
+div.headertitle {
+ margin: 1rem 0px 0rem 0px;
+ padding: 0 0.3rem 0 0;
+}
+
+dl {
+ padding: 0 0 0 10px;
+}
+
+/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug */
+dl.section {
+ margin-left: 0px;
+ padding-left: 0px;
+}
+
+dl.note {
+ margin-left: 0px;
+ padding: 1rem;
+ border-left: 6px solid;
+ border: 1px solid rgba(27,31,35,.15);
+ background-color: #fffbdd;
+ color: #735c0f;
+}
+
+dl.section.note dd {
+ margin-left: 0;
+ margin-bottom: 0;
+}
+
+dl.warning, dl.attention {
+ margin-left: 0px;
+ padding: 1rem;
+
+ border-left: 6px solid;
+ border-color: #ab2333;
+}
+
+dl.pre, dl.post, dl.invariant {
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #4e9a06;
+}
+
+dl.deprecated {
+ margin-left: 0px;
+ padding: 1rem;
+ border-left: 6px solid;
+ border-color: #505050;
+}
+
+dl.deprecated dt a.el {
+}
+
+dl.todo {
+ margin-left: 0px;
+ padding: 1rem;
+ border-left:4px solid;
+ border-color: #04898e;
+}
+
+dl.test {
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #21376d;
+}
+
+dl.bug {
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #8f5902;
+}
+
+dl.section dd {
+ margin-bottom: 0.5rem;
+}
+
+
+#projectlogo {
+ text-align: center;
+ vertical-align: bottom;
+ border-collapse: separate;
+ padding-right: 1rem;
+}
+
+#projectlogo img {
+ border: 0px none;
+ width: 8rem;
+ height: auto;
+}
+
+#projectname {
+ font: inherit;
+ font-size: 300%;
+ margin: 0px;
+ padding: 2px 0px;
+}
+
+#projectbrief {
+ font: inherit;
+ font-size: 120%;
+ margin: 0px;
+ padding: 0px;
+}
+
+#projectnumber {
+ font: inherit;
+ font-size: 50%;
+ margin: 0px;
+ padding: 0px;
+}
+
+#titlearea {
+ padding: 1rem;
+ margin: 0px;
+ width: auto;
+ border-bottom: none;
+ background-color: #fafbfc;
+}
+
+.image {
+ text-align: center;
+}
+
+.dotgraph {
+ text-align: center;
+}
+
+.mscgraph {
+ text-align: center;
+}
+
+.caption {
+ font-weight: bold;
+}
+
+div.zoom {
+ border: 1px solid #90A5CE;
+}
+
+dl.citelist {
+ margin-bottom:50px;
+}
+
+dl.citelist dt {
+ color:#334975;
+ float:left;
+ font-weight:bold;
+ margin-right:10px;
+ padding:5px;
+}
+
+dl.citelist dd {
+ margin:2px 0;
+ padding:5px 0;
+}
+
+div.toc {
+ padding: 14px 25px;
+ background-color: #F4F6FA;
+ border: 1px solid #D8DFEE;
+ border-radius: 7px 7px 7px 7px;
+ float: right;
+ height: auto;
+ margin: 0 20px 10px 10px;
+ width: 200px;
+}
+
+div.toc li {
+ background: url("bdwn.png") no-repeat scroll 0 5px transparent;
+ font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif;
+ margin-top: 5px;
+ padding-left: 10px;
+ padding-top: 2px;
+}
+
+div.toc h3 {
+ font: bold 12px/1.2 Arial,FreeSans,sans-serif;
+ color: #4665A2;
+ border-bottom: 0 none;
+ margin: 0;
+}
+
+div.toc ul {
+ list-style: none outside none;
+ border: medium none;
+ padding: 0px;
+}
+
+div.toc li.level1 {
+ margin-left: 0px;
+}
+
+div.toc li.level2 {
+ margin-left: 15px;
+}
+
+div.toc li.level3 {
+ margin-left: 30px;
+}
+
+div.toc li.level4 {
+ margin-left: 45px;
+}
+
+.inherit_header {
+ font-weight: bold;
+ color: gray;
+ cursor: pointer;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.inherit_header td {
+ padding: 6px 0px 2px 5px;
+}
+
+.inherit {
+ display: none;
+}
+
+tr.heading h2 {
+ padding-top: 1.75rem;
+ margin-top: 0;
+ margin-bottom: 1rem;
+}
+
+@media print
+{
+ #top { display: none; }
+ #side-nav { display: none; }
+ #nav-path { display: none; }
+ body { overflow:visible; }
+ h1, h2, h3, h4, h5, h6 { page-break-after: avoid; }
+ .summary { display: none; }
+ .memitem { page-break-inside: avoid; }
+ #doc-content {
+ margin-left:0 !important;
+ height:auto !important;
+ width:auto !important;
+ overflow:inherit;
+ display:inline;
+ }
+}
+
+
+.tabs, .tabs2, .tabs3 {
+ background-image: none;
+ background-color: #fafbfc;
+ color: #24292e;
+ padding: 0 1rem;
+ font-family: inherit;
+ font-size: inherit;
+ width: auto;
+}
+
+.tabs {
+ border-bottom: 1px solid #e1e4e8;
+}
+
+.tablist {
+ position: relative;
+ top: 1px;
+}
+
+.tabs2 {
+ margin-top: 1rem;
+ border-bottom: 1px solid #e1e4e8;
+ background-color: #fff;
+}
+
+.tabs3 {
+ margin-top: 1rem;
+ border-bottom: 1px solid #e1e4e8;
+ background-color: #fff;
+}
+
+.tablist li {
+ background-image: none;
+}
+
+.tablist a {
+ background-image: none;
+ text-shadow: none;
+ color: #586069;
+ border: 1px solid transparent;
+ border-top: 3px solid transparent;
+ border-radius: 3px 3px 0 0;
+ padding: 0 1rem;
+}
+
+.tablist a:hover {
+ background-image: none;
+ text-shadow: none;
+ color: #24292e;
+}
+
+.tablist li.current a {
+ text-shadow: none;
+ background-image: none;
+ background-color: #fff;
+ color: #24292e;
+}
+
+#navrow1 .tablist li.current a {
+ border-color: #f7ae1a #e1e4e8 transparent;
+}
+
+#navrow2 .tablist li.current a {
+ border-color: #e45e25 #e1e4e8 transparent;
+}
+
+#navrow3 .tablist li.current a {
+ border-color: #1fa4a9 #e1e4e8 transparent;
+}
+
+#navrow4 .tablist li.current a {
+ border-color: #01496d #e1e4e8 transparent;
+}
+
+.tabs li.current {
+ background-color: #fff;
+}
+
+.tabs2 li.current {
+ background-color: #fff;
+}
+
+.navpath {
+ border: none;
+ margin-top: 1rem;
+ padding: 0 2rem;
+}
+
+.navpath ul {
+ background-color: transparent;
+ border: none;
+}
+
+.navpath li {
+ padding: 0;
+}
+
+.navpath li.navelem a {
+ color: #005082;
+ text-shadow: none;
+ padding: 0 0.25rem;
+ font-size: 1rem;
+}
+
+.navpath li.navelem a:hover {
+ color: #005082;
+ text-shadow: none;
+ text-decoration: underline;
+}
+
+/* @group Markdown */
+
+table.markdownTable td,
+table.markdownTable th {
+ border: 1px solid #c6cbd1;
+ padding: 0.5rem 1rem;
+}
+
+.markdownTable tbody tr:nth-of-type(odd) {
+ background-color: #f6f8fa;
+}
+
+th.markdownTableHeadLeft,
+th.markdownTableHeadRight,
+th.markdownTableHeadCenter,
+th.markdownTableHeadNone {
+ background-color: #fff;
+ color: inherit;
+ font-size: inherit;
+ font-weight: bold;
+ padding: 0.5rem 1rem;
+ text-align: inherit;
+ -moz-border-radius-topleft: 3px;
+ -moz-border-radius-topright: 3px;
+ -webkit-border-top-left-radius: 3px;
+ -webkit-border-top-right-radius: 3px;
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+ border-bottom: 1px solid #c6cbd1;
+}
+
+/* @end */
+
+@media (max-width: 576px) {
+ .navpath {
+ padding: 0 1rem;
+ }
+
+ .navpath li.navelem a {
+ padding: 0;
+ }
+
+ div.header {
+ padding: 1rem 1rem 0 1rem;
+ }
+
+ div.contents {
+ padding: 1rem 1rem 0 1rem;
+ }
+
+ hr.footer {
+ margin-left: 1rem;
+ margin-right: 1rem;
+ }
+
+ address.footer {
+ margin-left: 1rem;
+ margin-right: 1rem;
+ }
+
+ .memtitle {
+ font-size: 1.5rem;
+ word-break: break-all;
+ }
+
+ .memname td {
+ float: left;
+ word-break: break-all;
+ }
+
+ div.memitem {
+ margin-bottom: 1rem;
+ }
+
+ .memdoc table.params {
+ word-break: break-word;
+ }
+
+ div.memproto {
+ display: table;
+ }
+
+ dl.section dt {
+ margin-bottom: 0.5rem;
+ }
+
+ dl.section dd {
+ margin-left: 0;
+ word-break: break-word;
+ }
+
+ .contents > table,
+ .contents > table thead,
+ .contents > table tbody,
+ .contents > table th,
+ .contents > table td,
+ .contents > table tr {
+ display: block;
+ }
+
+ .contents table.directory,
+ .contents table.directory thead,
+ .contents table.directory tbody,
+ .contents table.directory th,
+ .contents table.directory td {
+ display: block;
+ }
+
+ .contents table.directory tr {
+ }
+
+ div:not(.PageDoc) .contents table,
+ div:not(.PageDoc) .contents thead,
+ div:not(.PageDoc) .contents tbody,
+ div:not(.PageDoc) .contents th,
+ div:not(.PageDoc) .contents td,
+ div:not(.PageDoc) .contents tr {
+ display: block;
+ }
+
+ .mdescLeft,
+ .memItemLeft,
+ .memTemplItemLeft {
+ text-align: left;
+ border-left: 1px solid #c8e1ff;
+ border-right: 1px solid #c8e1ff;
+ word-break: break-word;
+ white-space: normal;
+ padding-bottom: 0;
+ }
+
+ table td.mdescLeft {
+ display: none;
+ }
+
+ table td.mdescRight,
+ table td.memItemRight,
+ table td.memTemplItemRight {
+ border-top: none !important;
+ border-left: 1px solid #c8e1ff;
+ border-right: 1px solid #c8e1ff;
+ display: table-cell;
+ word-break: break-word;
+ padding-top: 0;
+ }
+
+ .directory td.desc {
+ display: table-cell;
+ }
+
+ dl.params dd {
+ margin-left: 0;
+ }
+
+ table.params td.paramname {
+ margin-top: 0.5rem;
+ }
+
+ #projectlogo img {
+ border: 0px none;
+ width: 4rem;
+ height: auto;
+ }
+
+ #projectname {
+ font-size: 1rem;
+ }
+
+ #projectbrief {
+ font-size: 0.75rem;
+ }
+
+ #projectnumber {
+ font-size: 0.75rem;
+ }
+} \ No newline at end of file
diff --git a/docs/doxygen/favicon.ico b/docs/doxygen/favicon.ico
new file mode 100644
index 0000000..b542c5b
--- /dev/null
+++ b/docs/doxygen/favicon.ico
Binary files differ
diff --git a/docs/doxygen/folder-open.png b/docs/doxygen/folder-open.png
new file mode 100644
index 0000000..b67403d
--- /dev/null
+++ b/docs/doxygen/folder-open.png
Binary files differ
diff --git a/docs/doxygen/folder.png b/docs/doxygen/folder.png
new file mode 100644
index 0000000..901edc9
--- /dev/null
+++ b/docs/doxygen/folder.png
Binary files differ
diff --git a/docs/doxygen/footer.html b/docs/doxygen/footer.html
new file mode 100644
index 0000000..9eef78d
--- /dev/null
+++ b/docs/doxygen/footer.html
@@ -0,0 +1,9 @@
+<hr class="footer"/>
+<address class="footer">
+ <ul class="navpath">
+ <li class="footer">&copy; 2007-$year <a href="https://libimobiledevice.org">$projectname</a>&nbsp;&nbsp;All rights reserved</li>
+ <li class="footer">Generated on <em>$datetime</em> by <a href="https://www.doxygen.org">doxygen $doxygenversion</a></li>
+ <li class="footer">Icons by <a href="http://tango-project.org/">Tango</a></li>
+ <li class="footer">Design &copy; $year by <a href="https://mirell.com" target="_blank">Mirell</a></li>
+ </ui>
+</address> \ No newline at end of file
diff --git a/docs/doxygen/header.html b/docs/doxygen/header.html
new file mode 100644
index 0000000..bc41a11
--- /dev/null
+++ b/docs/doxygen/header.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<meta http-equiv="X-UA-Compatible" content="IE=9"/>
+<meta name="generator" content="doxygen $doxygenversion"/>
+<meta name="viewport" content="width=device-width, initial-scale=1"/>
+<!--BEGIN PROJECT_NAME--><title>$title - $projectname $projectnumber</title><!--END PROJECT_NAME-->
+<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
+
+<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
+
+<meta property="og:locale" content="en_US" />
+<meta property="og:type" content="website" />
+<meta property="og:title" content="$projectbrief - $projectname" />
+<meta property="og:url" content="https://libimobiledevice.org/docs/$projectname/$projectnumber/" />
+<meta property="og:site_name" content="$projectname - $projectbrief" />
+<meta name="twitter:card" content="summary_large_image" />
+
+<script type="text/javascript" src="$relpath^jquery.js"></script>
+<script type="text/javascript" src="$relpath^dynsections.js"></script>
+$treeview
+$search
+$mathjax
+<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
+$extrastylesheet
+</head>
+<body>
+<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
+
+<!--BEGIN TITLEAREA-->
+<div id="titlearea">
+<table cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr style="height: 56px;">
+ <!--BEGIN PROJECT_LOGO-->
+ <td id="projectlogo"><a href="$relpath^index.html"><img alt="Logo" src="$relpath^$projectlogo"/></a></td>
+ <!--END PROJECT_LOGO-->
+ <!--BEGIN PROJECT_NAME-->
+ <td id="projectalign" style="padding-left: 0.5em;">
+ <div id="projectname">$projectname
+ <!--BEGIN PROJECT_NUMBER-->&#160;<span id="projectnumber">$projectnumber</span><!--END PROJECT_NUMBER-->
+ </div>
+ <!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief - <a href="https://libimobiledevice.org"><small>Return to Homepage</small></a></div><!--END PROJECT_BRIEF-->
+ </td>
+ <!--END PROJECT_NAME-->
+ <!--BEGIN !PROJECT_NAME-->
+ <!--BEGIN PROJECT_BRIEF-->
+ <td style="padding-left: 0.5em;">
+ <div id="projectbrief">$projectbrief</div>
+ </td>
+ <!--END PROJECT_BRIEF-->
+ <!--END !PROJECT_NAME-->
+ <!--BEGIN DISABLE_INDEX-->
+ <!--BEGIN SEARCHENGINE-->
+ <td>$searchbox</td>
+ <!--END SEARCHENGINE-->
+ <!--END DISABLE_INDEX-->
+ </tr>
+ </tbody>
+</table>
+</div>
+<!--END TITLEAREA-->
+<!-- end header part --> \ No newline at end of file
diff --git a/docs/doxygen/layout.xml b/docs/doxygen/layout.xml
new file mode 100644
index 0000000..46f068d
--- /dev/null
+++ b/docs/doxygen/layout.xml
@@ -0,0 +1,226 @@
+<doxygenlayout version="1.0">
+ <!-- Generated by doxygen 1.8.16 -->
+ <!-- Navigation index tabs for HTML output -->
+ <navindex>
+ <tab type="mainpage" visible="yes" title="About"/>
+ <tab type="modules" visible="yes" title="" intro=""/>
+ <tab type="namespaces" visible="yes" title="">
+ <tab type="namespacelist" visible="yes" title="" intro=""/>
+ <tab type="namespacemembers" visible="yes" title="" intro=""/>
+ </tab>
+ <tab type="interfaces" visible="yes" title="">
+ <tab type="interfacelist" visible="yes" title="" intro=""/>
+ <tab type="interfaceindex" visible="$ALPHABETICAL_INDEX" title=""/>
+ <tab type="interfacehierarchy" visible="yes" title="" intro=""/>
+ </tab>
+ <tab type="classes" visible="yes" title="">
+ <tab type="classlist" visible="yes" title="" intro=""/>
+ <tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
+ <tab type="hierarchy" visible="yes" title="" intro=""/>
+ <tab type="classmembers" visible="yes" title="" intro=""/>
+ </tab>
+ <tab type="structs" visible="yes" title="">
+ <tab type="structlist" visible="yes" title="" intro=""/>
+ <tab type="structindex" visible="$ALPHABETICAL_INDEX" title=""/>
+ </tab>
+ <tab type="exceptions" visible="yes" title="">
+ <tab type="exceptionlist" visible="yes" title="" intro=""/>
+ <tab type="exceptionindex" visible="$ALPHABETICAL_INDEX" title=""/>
+ <tab type="exceptionhierarchy" visible="yes" title="" intro=""/>
+ </tab>
+ <tab type="files" visible="yes" title="">
+ <tab type="filelist" visible="yes" title="" intro=""/>
+ <tab type="globals" visible="yes" title="" intro=""/>
+ </tab>
+ <tab type="examples" visible="yes" title="" intro=""/>
+ <tab type="pages" visible="yes" title="" intro=""/>
+ </navindex>
+
+ <!-- Layout definition for a class page -->
+ <class>
+ <briefdescription visible="no"/>
+ <detaileddescription title="Description"/>
+ <includes visible="$SHOW_INCLUDE_FILES"/>
+ <inheritancegraph visible="$CLASS_GRAPH"/>
+ <collaborationgraph visible="$COLLABORATION_GRAPH"/>
+ <memberdecl>
+ <nestedclasses visible="yes" title=""/>
+ <publictypes title=""/>
+ <services title=""/>
+ <interfaces title=""/>
+ <publicslots title=""/>
+ <signals title=""/>
+ <publicmethods title=""/>
+ <publicstaticmethods title=""/>
+ <publicattributes title=""/>
+ <publicstaticattributes title=""/>
+ <protectedtypes title=""/>
+ <protectedslots title=""/>
+ <protectedmethods title=""/>
+ <protectedstaticmethods title=""/>
+ <protectedattributes title=""/>
+ <protectedstaticattributes title=""/>
+ <packagetypes title=""/>
+ <packagemethods title=""/>
+ <packagestaticmethods title=""/>
+ <packageattributes title=""/>
+ <packagestaticattributes title=""/>
+ <properties title=""/>
+ <events title=""/>
+ <privatetypes title=""/>
+ <privateslots title=""/>
+ <privatemethods title=""/>
+ <privatestaticmethods title=""/>
+ <privateattributes title=""/>
+ <privatestaticattributes title=""/>
+ <friends title=""/>
+ <related title="" subtitle=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <memberdef>
+ <inlineclasses title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <services title=""/>
+ <interfaces title=""/>
+ <constructors title=""/>
+ <functions title=""/>
+ <related title=""/>
+ <variables title=""/>
+ <properties title=""/>
+ <events title=""/>
+ </memberdef>
+ <allmemberslink visible="yes"/>
+ <usedfiles visible="$SHOW_USED_FILES"/>
+ <authorsection visible="yes"/>
+ </class>
+
+ <!-- Layout definition for a namespace page -->
+ <namespace>
+ <briefdescription visible="no"/>
+ <detaileddescription title="Description"/>
+ <memberdecl>
+ <nestednamespaces visible="yes" title=""/>
+ <constantgroups visible="yes" title=""/>
+ <interfaces visible="yes" title=""/>
+ <classes visible="yes" title=""/>
+ <structs visible="yes" title=""/>
+ <exceptions visible="yes" title=""/>
+ <typedefs title=""/>
+ <sequences title=""/>
+ <dictionaries title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <memberdef>
+ <inlineclasses title=""/>
+ <typedefs title=""/>
+ <sequences title=""/>
+ <dictionaries title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ </memberdef>
+ <authorsection visible="yes"/>
+ </namespace>
+
+ <!-- Layout definition for a file page -->
+ <file>
+ <briefdescription visible="no"/>
+ <detaileddescription title="Description"/>
+ <includes visible="$SHOW_INCLUDE_FILES"/>
+ <includegraph visible="$INCLUDE_GRAPH"/>
+ <includedbygraph visible="$INCLUDED_BY_GRAPH"/>
+ <memberdecl>
+ <interfaces visible="yes" title=""/>
+ <classes visible="yes" title=""/>
+ <structs visible="yes" title=""/>
+ <exceptions visible="yes" title=""/>
+ <namespaces visible="yes" title=""/>
+ <constantgroups visible="yes" title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <sequences title=""/>
+ <dictionaries title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <memberdef>
+ <inlineclasses title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <sequences title=""/>
+ <dictionaries title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ </memberdef>
+ <authorsection/>
+ <sourcelink visible="yes"/>
+ </file>
+
+ <!-- Layout definition for a group page -->
+ <group>
+ <briefdescription visible="no"/>
+ <detaileddescription title="Description"/>
+ <groupgraph visible="$GROUP_GRAPHS"/>
+ <memberdecl>
+ <nestedgroups visible="yes" title=""/>
+ <dirs visible="yes" title=""/>
+ <files visible="yes" title=""/>
+ <namespaces visible="yes" title=""/>
+ <classes visible="yes" title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <sequences title=""/>
+ <dictionaries title=""/>
+ <enums title=""/>
+ <enumvalues title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <signals title=""/>
+ <publicslots title=""/>
+ <protectedslots title=""/>
+ <privateslots title=""/>
+ <events title=""/>
+ <properties title=""/>
+ <friends title=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <memberdef>
+ <pagedocs/>
+ <inlineclasses title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <sequences title=""/>
+ <dictionaries title=""/>
+ <enums title=""/>
+ <enumvalues title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <signals title=""/>
+ <publicslots title=""/>
+ <protectedslots title=""/>
+ <privateslots title=""/>
+ <events title=""/>
+ <properties title=""/>
+ <friends title=""/>
+ </memberdef>
+ <authorsection visible="yes"/>
+ </group>
+
+ <!-- Layout definition for a directory page -->
+ <directory>
+ <briefdescription visible="no"/>
+ <detaileddescription title="Description"/>
+ <directorygraph visible="yes"/>
+ <memberdecl>
+ <dirs visible="yes"/>
+ <files visible="yes"/>
+ </memberdecl>
+ </directory>
+</doxygenlayout> \ No newline at end of file
diff --git a/docs/doxygen/logo-vector-clean.svg b/docs/doxygen/logo-vector-clean.svg
new file mode 100644
index 0000000..a953115
--- /dev/null
+++ b/docs/doxygen/logo-vector-clean.svg
@@ -0,0 +1 @@
+<svg enable-background="new 0 0 283.5 283.5" height="793.7" viewBox="0 0 793.7 793.7" width="793.7" xmlns="http://www.w3.org/2000/svg"><g stroke-width=".10005" transform="matrix(13.831 0 0 13.831 -1173.2 -291.34)"><path d="m94.968 35.193v-10.71l9.2751 5.355z" fill="#f7ae1a"/><path d="m94.968 35.193 9.2751-5.355v10.71z" fill="#e45e25"/><path d="m94.968 42.414 9.2751 5.355-9.2751 5.355z" fill="#d2343e"/><path d="m94.968 53.124 9.2751-5.355v10.71z" fill="#bb2033"/><path d="m94.968 53.124 9.2751 5.355-9.2751 5.355z" fill="#ab2333"/></g><g fill="#2e3436" fill-opacity=".19964" transform="matrix(13.831 0 0 13.831 -1361.02498 -319.002)"><path d="m57.472 29.867h-55.452l27.726-48.023z" stroke-width=".518" transform="matrix(-.16726 .09657 -.09657 -.16726 121.04 71.121)"/><path d="m148.27 69.213h-10.71l5.355-9.2751z" stroke-width=".10005" transform="matrix(-.86603 .5 .5 .86603 211.62 -57.046)"/><path d="m142.92-59.938h-10.71l5.355-9.2751z" stroke-width=".10005" transform="matrix(-.8660254 .5 -.5 -.8660254 211.614597 -57.0459)"/><path d="m57.472 29.867h-55.452l27.726-48.023z" stroke-width=".518" transform="matrix(0 .19314 -.19314 0 132.86 60.576)"/><path d="m57.472 29.867h-55.452l27.726-48.023z" stroke-width=".518" transform="matrix(.16726 .09657 -.09657 .16726 129.64 55.775)"/><path d="m57.472 29.867h-55.452l27.726-48.023z" transform="matrix(0 .19314 -.19314 0 142.13 55.221)"/></g><g transform="matrix(13.831 0 0 13.831 -1173.2 -291.34)"><g stroke-width=".10005"><path d="m94.968 63.834 9.2751-5.355v10.71z" fill="#7b2f44"/><path d="m104.24 69.189 9.2751-5.355-9.2751-5.355z" fill="#21376d"/><path d="m104.24 58.479 9.2751-5.355v10.71z" fill="#005082"/><path d="m113.52 63.834v-10.71l9.2751 5.355z" fill="#023e49"/><path d="m122.79 58.479-9.2751-5.355 9.2751-5.355z" fill="#007e96"/></g><path d="m122.79 58.479v-10.71l9.2751 5.355z" fill="#0a9197"/></g><g fill="#ccc" transform="translate(2.808 194.51)"><polygon/><polygon/></g></svg> \ No newline at end of file
diff --git a/docs/doxygen/text-x-generic.png b/docs/doxygen/text-x-generic.png
new file mode 100644
index 0000000..2d7f2d6
--- /dev/null
+++ b/docs/doxygen/text-x-generic.png
Binary files differ
diff --git a/docs/idevice_id.1 b/docs/idevice_id.1
index e223dcb..caded75 100644
--- a/docs/idevice_id.1
+++ b/docs/idevice_id.1
@@ -1,52 +1,43 @@
.TH "idevice_id" 1
.SH NAME
-idevice_id \- Prints device name or a list of attached devices.
+idevice_id \- List attached devices or print device name of given device.
.SH SYNOPSIS
.B idevice_id
[OPTIONS] [UDID]
.SH DESCRIPTION
-Prints device name or a list of attached devices.
-UDID is the unique device identifier of the device
-for which the name should be retrieved.
+\f[B]idevice_id\f[] prints a list of attached devices. If a UDID is given,
+the name of the connected device with that UDID will be retrieved.
+
+Without any options, \f[B]idevice_id\f[] will list all available devices,
+USB and network.
+The output can be further controlled with the following OPTIONS.
.SH OPTIONS
.TP
.B \-l, \-\-list
-list UDID of all attached devices
-.TP
+List UDIDs of all devices attached via USB.
+.TP
+.B \-n, \-\-network
+List UDIDs of all devices available via network.
+.TP
.B \-d, \-\-debug
-enable communication debugging.
-.TP
+Enable communication debugging.
+.TP
.B \-h, \-\-help
-prints usage information.
-.TP
-
-.SH AUTHORS
- Zach C.
-
- Jonathan Beck
-
- Matt Colyer
-
- Martin Aumueller
-
- Christophe Fergeau
-
- Martin S.
-
- Paul Sladen
-
- Patrick Walton
-
- Zoltan Balaton
-
- Nikias Bassen
+Prints usage information.
+.TP
+.B \-v, \-\-version
+Prints version information.
+.TP
- Todd Zullinger
+.SH AUTHOR
+Nikias Bassen
Man page written to conform with Debian by Julien Lavergne.
.SH ON THE WEB
-http://libimobiledevice.org
+https://libimobiledevice.org
+
+https://github.com/libimobiledevice/libimobiledevice
diff --git a/docs/idevicebackup.1 b/docs/idevicebackup.1
index 517ca2a..6f2a8f9 100644
--- a/docs/idevicebackup.1
+++ b/docs/idevicebackup.1
@@ -7,18 +7,26 @@ 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.
.SH OPTIONS
.TP
.B \-u, \-\-udid UDID
target specific device by UDID.
-.TP
+.TP
+.B \-n, \-\-network
+connect to network device.
+.TP
.B \-d, \-\-debug
enable communication debugging.
.TP
.B \-h, \-\-help
prints usage information.
+.TP
+.B \-v, \-\-version
+prints version information.
.SH COMMANDS
.TP
@@ -35,5 +43,10 @@ Nikias Bassen
Man page written to conform with Debian by Julien Lavergne.
+.SH SEE ALSO
+idevicebackup2(1)
+
.SH ON THE WEB
-http://libimobiledevice.org
+https://libimobiledevice.org
+
+https://github.com/libimobiledevice/libimobiledevice
diff --git a/docs/idevicebackup2.1 b/docs/idevicebackup2.1
index 6c40929..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
@@ -19,26 +19,35 @@ use backup data from device specified by UDID.
.TP
.B \-i, \-\-interactive
request passwords interactively on the command line.
-.TP
+.TP
+.B \-n, \-\-network
+connect to network device.
+.TP
.B \-d, \-\-debug
enable communication debugging.
-.TP
+.TP
.B \-h, \-\-help
prints usage information.
+.TP
+.B \-v, \-\-version
+prints version information.
.SH COMMANDS
.TP
.B backup
create backup for the device.
.TP
+.B \t\-\-full
+force full backup from device.
+.TP
.B restore
restore last backup to the device.
.TP
.B \t\-\-system
restore system files, too.
.TP
-.BI \t\-\-reboot
-reboot the system when done.
+.B \t\-\-no\-reboot
+do NO reboot the system when done.
.TP
.B \t\-\-copy
create a copy of backup folder before restoring.
@@ -49,8 +58,13 @@ restore device settings from the backup.
.B \t\-\-remove
remove items which are not being restored.
.TP
+.B \t\-\-skip-apps
+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.
@@ -58,18 +72,33 @@ show details about last completed backup of device.
.B list
list files of last completed backup in CSV format.
.TP
+.B unback
+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
Nikias Bassen
-.SH SEE ALSO
-idevicebackup(1)
-
.SH ON THE WEB
-http://libimobiledevice.org
+https://libimobiledevice.org
+
+https://github.com/libimobiledevice/libimobiledevice
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 a3742e7..6acd6e9 100644
--- a/docs/idevicecrashreport.1
+++ b/docs/idevicecrashreport.1
@@ -15,6 +15,12 @@ the device to the target DIRECTORY.
.SH OPTIONS
.TP
+.B \-u, \-\-udid UDID
+target specific device by UDID.
+.TP
+.B \-n, \-\-network
+connect to network device.
+.TP
.B \-e, \-\-extract
extract raw crash report into separate '.crash' files.
.TP
@@ -24,11 +30,14 @@ copy but do not remove crash reports from device.
.B \-d, \-\-debug
enable communication debugging.
.TP
-.B \-u, \-\-udid UDID
-target specific device by UDID.
+.B \-f, \-\-filter NAME
+filter crash reports by NAME (case sensitive)
.TP
.B \-h, \-\-help
prints usage information.
+.TP
+.B \-v, \-\-version
+prints version information.
.SH AUTHOR
Martin Szulecki
@@ -36,4 +45,6 @@ Martin Szulecki
Nikias Bassen
.SH ON THE WEB
-http://libimobiledevice.org
+https://libimobiledevice.org
+
+https://github.com/libimobiledevice/libimobiledevice
diff --git a/docs/idevicedate.1 b/docs/idevicedate.1
index adb091a..dcdc57e 100644
--- a/docs/idevicedate.1
+++ b/docs/idevicedate.1
@@ -11,12 +11,15 @@ Simple utility to manage the clock on a device.
.SH OPTIONS
.TP
-.B \-d, \-\-debug
-enable communication debugging.
-.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 \-s, \-\-set TIMESTAMP
set UTC time described by TIMESTAMP
.TP
@@ -25,9 +28,14 @@ set time of device to current system time
.TP
.B \-h, \-\-help
prints usage information
+.TP
+.B \-v, \-\-version
+prints version information.
.SH AUTHOR
Martin Szulecki
.SH ON THE WEB
-http://libimobiledevice.org
+https://libimobiledevice.org
+
+https://github.com/libimobiledevice/libimobiledevice
diff --git a/docs/idevicedebug.1 b/docs/idevicedebug.1
index 2024842..7314baa 100644
--- a/docs/idevicedebug.1
+++ b/docs/idevicedebug.1
@@ -12,18 +12,24 @@ command is "run" and allows execution of developer apps and watch the
stdout/stderr of the process.
.SH OPTIONS
-.TP
-.B \-e, \-\-env NAME=VALUE
-set environment variable NAME to VALUE.
.TP
.B \-u, \-\-udid UDID
target specific device by UDID.
-.TP
+.TP
+.B \-n, \-\-network
+connect to network device.
+.TP
+.B \-e, \-\-env NAME=VALUE
+set environment variable NAME to VALUE.
+.TP
.B \-d, \-\-debug
enable communication debugging.
-.TP
+.TP
.B \-h, \-\-help
prints usage information.
+.TP
+.B \-v, \-\-version
+prints version information.
.SH COMMANDS
.TP
@@ -34,4 +40,6 @@ run app with BUNDLEID and optional ARGS on device.
Martin Szulecki
.SH ON THE WEB
-http://libimobiledevice.org
+https://libimobiledevice.org
+
+https://github.com/libimobiledevice/libimobiledevice
diff --git a/docs/idevicedebugserverproxy.1 b/docs/idevicedebugserverproxy.1
index e2372e6..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
@@ -18,20 +18,32 @@ The developer disk image needs to be mounted for this service to be available.
.TP
.B \-u, \-\-udid UDID
target specific device by UDID.
-.TP
+.TP
+.B \-n, \-\-network
+connect to network device.
+.TP
+.B \-l, \-\-lldb
+Enable lldb support.
+.TP
.B \-d, \-\-debug
enable communication debugging.
-.TP
+.TP
.B \-h, \-\-help
prints usage information.
+.TP
+.B \-v, \-\-version
+prints version information.
.SH USAGE
.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
.SH ON THE WEB
-http://libimobiledevice.org
+https://libimobiledevice.org
+
+https://github.com/libimobiledevice/libimobiledevice
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/idevicediagnostics.1 b/docs/idevicediagnostics.1
index 3230310..2f28b8d 100644
--- a/docs/idevicediagnostics.1
+++ b/docs/idevicediagnostics.1
@@ -17,12 +17,18 @@ iOS 5 and later.
.TP
.B \-u, \-\-udid UDID
target specific device by UDID.
-.TP
+.TP
+.B \-n, \-\-network
+connect to network device.
+.TP
.B \-d, \-\-debug
enable communication debugging.
-.TP
+.TP
.B \-h, \-\-help
prints usage information.
+.TP
+.B \-v, \-\-version
+prints version information.
.SH COMMANDS
.TP
@@ -51,4 +57,6 @@ put device into sleep mode which also disconnects it from the host.
Martin Szulecki
.SH ON THE WEB
-http://libimobiledevice.org
+https://libimobiledevice.org
+
+https://github.com/libimobiledevice/libimobiledevice
diff --git a/docs/ideviceenterrecovery.1 b/docs/ideviceenterrecovery.1
index cbceb36..d455826 100644
--- a/docs/ideviceenterrecovery.1
+++ b/docs/ideviceenterrecovery.1
@@ -16,6 +16,9 @@ enable communication debugging.
.TP
.B \-h, \-\-help
prints usage information.
+.TP
+.B \-v, \-\-version
+prints version information.
.SH AUTHORS
Martin Szulecki
@@ -23,4 +26,6 @@ Martin Szulecki
Man page written to conform with Debian by Julien Lavergne.
.SH ON THE WEB
-http://libimobiledevice.org
+https://libimobiledevice.org
+
+https://github.com/libimobiledevice/libimobiledevice
diff --git a/docs/ideviceimagemounter.1 b/docs/ideviceimagemounter.1
index 322bd34..832850a 100644
--- a/docs/ideviceimagemounter.1
+++ b/docs/ideviceimagemounter.1
@@ -11,12 +11,15 @@ Mounts the specified disk image on the device.
.SH OPTIONS
.TP
-.B \-d, \-\-debug
-enable communication debugging.
-.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 \-l, \-\-list
list mount information
.TP
@@ -29,6 +32,9 @@ use XML output
.B \-h, \-\-help
prints usage information
.TP
+.B \-v, \-\-version
+prints version information.
+.TP
.B IMAGE_FILE
the image filename to mount
.TP
@@ -41,4 +47,6 @@ Nikias Bassen
Man page written to conform with Debian by Julien Lavergne.
.SH ON THE WEB
-http://libimobiledevice.org
+https://libimobiledevice.org
+
+https://github.com/libimobiledevice/libimobiledevice
diff --git a/docs/ideviceinfo.1 b/docs/ideviceinfo.1
index d4ecbf0..3944612 100644
--- a/docs/ideviceinfo.1
+++ b/docs/ideviceinfo.1
@@ -11,12 +11,18 @@ Show information about the first connected device.
.SH OPTIONS
.TP
-.B \-d, \-\-debug
-enable communication debugging.
+.B \-s, \-\-simple
+use a simple connection to avoid auto-pairing with the device.
.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 \-q, \-\-domain NAME
set domain of query to NAME. Default: None.
.TP
@@ -27,7 +33,10 @@ only query key specified by NAME. Default: All keys.
output information as xml plist instead of key/value pairs.
.TP
.B \-h, \-\-help
-prints usage information
+prints usage information.
+.TP
+.B \-v, \-\-version
+prints version information.
.SH AUTHOR
Martin Szulecki
@@ -35,4 +44,6 @@ Martin Szulecki
Man page written to conform with Debian by Julien Lavergne.
.SH ON THE WEB
-http://libimobiledevice.org
+https://libimobiledevice.org
+
+https://github.com/libimobiledevice/libimobiledevice
diff --git a/docs/idevicename.1 b/docs/idevicename.1
index ee7cd02..34ce490 100644
--- a/docs/idevicename.1
+++ b/docs/idevicename.1
@@ -17,17 +17,25 @@ is given the device name will be set to the name specified.
.SH OPTIONS
.TP
-.B \-d, \-\-debug
-enable communication debugging.
-.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
prints usage information
+.TP
+.B \-v, \-\-version
+prints version information.
.SH AUTHOR
Nikias Bassen
.SH ON THE WEB
-http://libimobiledevice.org
+https://libimobiledevice.org
+
+https://github.com/libimobiledevice/libimobiledevice
diff --git a/docs/idevicenotificationproxy.1 b/docs/idevicenotificationproxy.1
index 19cf02e..56dd0b0 100644
--- a/docs/idevicenotificationproxy.1
+++ b/docs/idevicenotificationproxy.1
@@ -14,11 +14,17 @@ Post or observe notifications on an iOS device from the command line.
.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
prints usage information.
+.TP
+.B \-v, \-\-version
+prints version information.
.SH COMMANDS
.TP
@@ -33,4 +39,6 @@ observe notification IDs in the foreground until CTRL+C or signal is received.
Martin Szulecki
.SH ON THE WEB
-http://libimobiledevice.org
+https://libimobiledevice.org
+
+https://github.com/libimobiledevice/libimobiledevice
diff --git a/docs/idevicepair.1 b/docs/idevicepair.1
index 5c567ee..eb6e7d4 100644
--- a/docs/idevicepair.1
+++ b/docs/idevicepair.1
@@ -13,12 +13,21 @@ 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
+.TP
.B \-h, \-\-help
prints usage information.
+.TP
+.B \-v, \-\-version
+prints version information.
.SH COMMANDS
.TP
@@ -40,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
@@ -48,4 +75,6 @@ Martin Szulecki
Julien Lavergne
.SH ON THE WEB
-http://libimobiledevice.org
+https://libimobiledevice.org
+
+https://github.com/libimobiledevice/libimobiledevice
diff --git a/docs/ideviceprovision.1 b/docs/ideviceprovision.1
index 5f312a5..3597d6e 100644
--- a/docs/ideviceprovision.1
+++ b/docs/ideviceprovision.1
@@ -13,6 +13,9 @@ Manage provisioning profiles on a device.
.TP
.B \-u, \-\-udid UDID
target specific device by UDID.
+.TP
+.B \-n, \-\-network
+connect to network device.
.TP
.B \-x, \-\-xml
print XML output when using the 'dump' command.
@@ -22,6 +25,9 @@ enable communication debugging.
.TP
.B \-h, \-\-help
prints usage information.
+.TP
+.B \-v, \-\-version
+prints version information.
.SH COMMANDS
.TP
@@ -47,4 +53,6 @@ Prints detailed information about the provisioning profile specified by FILE.
Nikias Bassen
.SH ON THE WEB
-http://libimobiledevice.org
+https://libimobiledevice.org
+
+https://github.com/libimobiledevice/libimobiledevice
diff --git a/docs/idevicescreenshot.1 b/docs/idevicescreenshot.1
index 7b6794c..4da78af 100644
--- a/docs/idevicescreenshot.1
+++ b/docs/idevicescreenshot.1
@@ -18,14 +18,20 @@ the screenshotr service is not available.
.SH OPTIONS
.TP
-.B \-d, \-\-debug
-enable communication debugging.
-.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
prints usage information
+.TP
+.B \-v, \-\-version
+prints version information.
.SH AUTHOR
Nikias Bassen
@@ -33,4 +39,6 @@ Nikias Bassen
Man page written to conform with Debian by Julien Lavergne.
.SH ON THE WEB
-http://libimobiledevice.org
+https://libimobiledevice.org
+
+https://github.com/libimobiledevice/libimobiledevice
diff --git a/docs/idevicesetlocation.1 b/docs/idevicesetlocation.1
new file mode 100644
index 0000000..941a6e5
--- /dev/null
+++ b/docs/idevicesetlocation.1
@@ -0,0 +1,38 @@
+.TH "idevicesetlocation" 1
+.SH NAME
+idevicesetlocation \- Simulate location on iOS device.
+.SH SYNOPSIS
+.B idevicesetlocation
+[OPTIONS] -- <LAT> <LONG>
+
+.B idevicesetlocation
+[OPTIONS] reset
+
+.SH DESCRIPTION
+
+Simulate location on iOS device with mounted developer disk image.
+
+.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
+prints usage information
+.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/idevicesyslog.1 b/docs/idevicesyslog.1
index aa24339..66ae2e4 100644
--- a/docs/idevicesyslog.1
+++ b/docs/idevicesyslog.1
@@ -10,20 +10,119 @@ idevicesyslog \- Relay syslog of a connected device.
Relay syslog of a connected device.
.SH OPTIONS
-.TP
-.B \-d, \-\-debug
-enable communication debugging.
.TP
.B \-u, \-\-udid UDID
-target specific device by UDID.
-.TP
+target specific device by UDID
+.TP
+.B \-n, \-\-network
+connect to network device
+.TP
+.B \-x, \-\-exit
+exit when device disconnects
+.TP
+.B \-d, \-\-debug
+enable communication debugging
+.TP
.B \-h, \-\-help
-prints usage information.
+prints usage information
+.TP
+.B \-v, \-\-version
+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
+.B \-m, \-\-match STRING
+only print messages that contain STRING
+
+This option will set a filter to only printed log messages that contain the given string.
+.TP
+.B \-t, \-\-trigger STRING
+start logging when matching STRING
+
+When specified, logging will start as soon as a log messages is encountered that contains the given string. See also
+\f[B]\-T, \-\-untrigger\f[]. Other filters are still applied but obviously filtered messages are only printed after logging has started.
+.TP
+.B \-T, \-\-untrigger STRING
+stop logging when matching STRING
+
+When specified logging will halt as soon as a log message is encountered that contains the given string. See also
+\f[B]\-t, \-\-trigger\f[]. Other filters are still applied but obviously filtered messages are only printed before logging stops.
+
+NOTE: If no \f[B]\-\-trigger\f[] is given, idevicesyslog will exit after a matching log message was encountered.
+.TP
+.B \-p, \-\-process PROCESS
+only print messages from matching process(es)
+
+PROCESS is a string that can either be a numeric pid or a process name. It also supports multiple process names or pids in one string, separated by | (make sure to use quotes!).
+.TP
+.B \-e, \-\-exclude PROCESS
+print all messages except matching process(es)
+
+PROCESS is a string that can either be a numeric pid or a process name. It also supports multiple process names or pids in one string, separated by | (make sure to use quotes!).
+.TP
+.B \-q, \-\-quiet
+set a filter to exclude common noisy processes
+
+Since the syslog can be quite noisy, this quick command line switch allows silencing a predefined set of commonly known processes. The list of processes that are silenced can be retrieved with \f[B]\-\-quiet\-list\f[].
+.TP
+.B \-\-quiet\-list
+prints the list of processes for \f[B]\-\-quiet\f[] and exits
+.TP
+.B \-k, \-\-kernel
+only print kernel messages
+
+This is actually equivalent to passing \f[B]\-\-process kernel\f[] with the exception that it can be used with \f[B]\-\-quiet\f[] to silence out the noisy process but still get all the kernel log messages.
+.TP
+.B \-K, \-\-no\-kernel
+suppress kernel messages
+
+This is equivalent to passing \f[B]\-\-exclude kernel\f[].
+
+.SH EXAMPLES
+.TP
+.B idevicesyslog \-u 00008030\-0000111ABC000DEF
+Relay syslog of device with UDID 00008030-0000111ABC000DEF.
+.TP
+.B idevicesyslog \-x
+Relay syslog of device and exit when the device is unplugged.
+.TP
+.B idevicesyslog \-m '####' \-e 'identityservicesd' \-K
+Only print log messages that contain the string #### and do NOT originate from identityservicesd or the kernel.
+.TP
+.B idevicesyslog \-p MyApp \-p ReportCrash
+Only print log messages from the process named 'MyApp' and 'ReportCrash'.
+.TP
+.B idevicesyslog \-p 'MyApp|ReportCrash'
+Same as previous example with different syntax.
+.TP
+.B idevicesyslog \-e 'backboardd|CommCenter|mDNSResponder'
+Suppress log messages from backboardd, CommCenter, and mDNSResponder.
+.TP
+.B idevicesyslog \-q \-k
+Suppress log messages from common noisy processes, but DO print kernel log messages.
+.TP
+.B idevicesyslog \-K
+Suppress log messages from kernel, but print everything else
+.TP
+.B idevicesyslog \-t 'backlight on' \-T 'backlight off' \-q
+Start logging when the device turns on backlight and stop logging when it turns backlight off, and suppress noisy processes
-.SH AUTHOR
-Martin Szulecki
+.SH AUTHORS
+Nikias Bassen, Martin Szulecki
Man page written to conform with Debian by Julien Lavergne.
.SH ON THE WEB
-http://libimobiledevice.org
+https://libimobiledevice.org
+
+https://github.com/libimobiledevice/libimobiledevice
diff --git a/doxygen.cfg.in b/doxygen.cfg.in
index dfe354a..4cbbb2d 100644
--- a/doxygen.cfg.in
+++ b/doxygen.cfg.in
@@ -1,4 +1,4 @@
-# Doxyfile 1.8.8
+# Doxyfile 1.8.16
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
@@ -17,11 +17,11 @@
# Project related configuration options
#---------------------------------------------------------------------------
-# This tag specifies the encoding used for all characters in the config file
-# that follow. The default is UTF-8 which is also the encoding used for all text
-# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
-# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
-# for the list of possible encodings.
+# This tag specifies the encoding used for all characters in the configuration
+# file that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
# The default value is: UTF-8.
DOXYFILE_ENCODING = UTF-8
@@ -44,14 +44,14 @@ PROJECT_NUMBER = @VERSION@
# for a project that appears at the top of each page and should give viewer a
# quick idea about the purpose of the project. Keep the description short.
-PROJECT_BRIEF =
+PROJECT_BRIEF = "API Documentation"
-# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
-# the documentation. The maximum height of the logo should not exceed 55 pixels
-# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
-# to the output directory.
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
-PROJECT_LOGO =
+PROJECT_LOGO = docs/doxygen/logo-vector-clean.svg
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
# into which the generated documentation will be written. If a relative path is
@@ -60,7 +60,7 @@ PROJECT_LOGO =
OUTPUT_DIRECTORY = docs
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and
# will distribute the generated files over these directories. Enabling this
# option can be useful when feeding doxygen a huge amount of source files, where
@@ -93,14 +93,14 @@ ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English
-# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# 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.
# The default value is: YES.
BRIEF_MEMBER_DESC = YES
-# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
# description of a member or function before the detailed description
#
# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
@@ -135,7 +135,7 @@ ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
-# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
# before files name in the file list and in the header files. If set to NO the
# shortest path that makes the file name unique will be used
# The default value is: YES.
@@ -179,6 +179,16 @@ SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = YES
+# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
+# such as
+# /***************
+# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
+# Javadoc-style will behave just like regular comments and it will not be
+# interpreted by doxygen.
+# The default value is: NO.
+
+JAVADOC_BANNER = NO
+
# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
# line (until the first dot) of a Qt-style comment as the brief description. If
# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
@@ -205,12 +215,12 @@ MULTILINE_CPP_IS_BRIEF = NO
INHERIT_DOCS = YES
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
-# new page for each member. If set to NO, the documentation of a member will be
-# part of the file/class/namespace that contains it.
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
# The default value is: NO.
-SEPARATE_MEMBER_PAGES = NO
+SEPARATE_MEMBER_PAGES = YES
# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
# uses this value to replace tabs by spaces in code fragments.
@@ -226,16 +236,15 @@ TAB_SIZE = 8
# will allow you to put the command \sideeffect (or @sideeffect) in the
# documentation, which will result in a user-defined paragraph with heading
# "Side Effects:". You can put \n's in the value part of an alias to insert
-# newlines.
+# newlines (in the resulting output). You can put ^^ in the value part of an
+# alias to insert a newline as if a physical newline was in the original file.
+# When you need a literal { or } or , in the value part of an alias you have to
+# escape them by means of a backslash (\), this can lead to conflicts with the
+# commands \{ and \} for these it is advised to use the version @{ and @} or use
+# a double escape (\\{ and \\})
ALIASES =
-# 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
@@ -264,19 +273,28 @@ OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
+# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
+# sources only. Doxygen will then generate output that is more tailored for that
+# language. For instance, namespaces will be presented as modules, types will be
+# separated into more groups, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_SLICE = YES
+
# Doxygen selects the parser to use depending on the extension of the files it
# parses. With this tag you can assign which parser to use for a given
# extension. Doxygen has a built-in mapping, but you can override or extend it
# using this tag. The format is ext=language, where ext is a file extension, and
# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
-# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
-# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
-# Fortran. In the later case the parser tries to guess whether the code is fixed
-# or free formatted code, this is the default for Fortran type files), VHDL. For
-# instance to make doxygen treat .inc files as Fortran files (default is PHP),
-# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice,
+# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
+# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
+# tries to guess whether the code is fixed or free formatted code, this is the
+# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is
+# Fortran), use: inc=Fortran f=C.
#
-# Note For files without extension you can use no_extension as a placeholder.
+# Note: For files without extension you can use no_extension as a placeholder.
#
# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
# the files are not read by doxygen.
@@ -285,7 +303,7 @@ EXTENSION_MAPPING =
# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
# according to the Markdown format, which allows for more readable
-# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# documentation. See https://daringfireball.net/projects/markdown/ for details.
# The output of markdown processing is further processed by doxygen, so you can
# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
# case of backward compatibilities issues.
@@ -293,10 +311,19 @@ EXTENSION_MAPPING =
MARKDOWN_SUPPORT = YES
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 5.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS = 5
+
# When enabled doxygen tries to link words that correspond to documented
# classes, or namespaces to their corresponding documentation. Such a link can
-# be prevented in individual cases by by putting a % sign in front of the word
-# or globally by setting AUTOLINK_SUPPORT to NO.
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
# The default value is: YES.
AUTOLINK_SUPPORT = YES
@@ -318,7 +345,7 @@ BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO
# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
-# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
# will parse them like normal C++ but will assume all classes use public instead
# of private inheritance when no explicit protection keyword is present.
# The default value is: NO.
@@ -336,13 +363,20 @@ SIP_SUPPORT = NO
IDL_PROPERTY_SUPPORT = YES
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES, then doxygen will reuse the documentation of the first
+# tag is set to YES then doxygen will reuse the documentation of the first
# member in the group (if any) for the other members of the group. By default
# all members of a group must be documented explicitly.
# The default value is: NO.
DISTRIBUTE_GROUP_DOC = NO
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
# Set the SUBGROUPING tag to YES to allow class member groups of the same type
# (for instance a group of public functions) to be put as a subgroup of that
# type (e.g. under the Public Functions section). Set it to NO to prevent
@@ -401,7 +435,7 @@ LOOKUP_CACHE_SIZE = 0
# Build related configuration options
#---------------------------------------------------------------------------
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
# documentation are documented, even if no documentation was available. Private
# class members and static file members will be hidden unless the
# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
@@ -411,35 +445,41 @@ LOOKUP_CACHE_SIZE = 0
EXTRACT_ALL = NO
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
# be included in the documentation.
# The default value is: NO.
EXTRACT_PRIVATE = NO
-# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
+# methods of a class will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIV_VIRTUAL = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
# scope will be included in the documentation.
# The default value is: NO.
EXTRACT_PACKAGE = NO
-# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
# included in the documentation.
# The default value is: NO.
EXTRACT_STATIC = NO
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
-# locally in source files will be included in the documentation. If set to NO
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
# only classes defined in header files are included. Does not have any effect
# for Java sources.
# The default value is: YES.
EXTRACT_LOCAL_CLASSES = NO
-# This flag is only useful for Objective-C code. When set to YES local methods,
+# This flag is only useful for Objective-C code. If set to YES, local methods,
# which are defined in the implementation section but not in the interface are
-# included in the documentation. If set to NO only methods in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
# included.
# The default value is: NO.
@@ -464,21 +504,21 @@ HIDE_UNDOC_MEMBERS = NO
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy. If set
-# to NO these classes will be included in the various overviews. This option has
-# no effect if EXTRACT_ALL is enabled.
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
# The default value is: NO.
HIDE_UNDOC_CLASSES = NO
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
-# (class|struct|union) declarations. If set to NO these declarations will be
+# (class|struct|union) declarations. If set to NO, these declarations will be
# included in the documentation.
# The default value is: NO.
HIDE_FRIEND_COMPOUNDS = NO
# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
-# documentation blocks found inside the body of a function. If set to NO these
+# documentation blocks found inside the body of a function. If set to NO, these
# blocks will be appended to the function's detailed documentation block.
# The default value is: NO.
@@ -492,21 +532,28 @@ HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
-# names in lower-case letters. If set to YES upper-case letters are also
+# names in lower-case letters. If set to YES, upper-case letters are also
# allowed. This is useful if you have classes or files whose names only differ
# in case and if your file system supports case sensitive file names. Windows
-# and Mac users are advised to set this option to NO.
+# (including Cygwin) ands Mac users are advised to set this option to NO.
# The default value is: system dependent.
CASE_SENSE_NAMES = NO
# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
-# their full class and namespace scopes in the documentation. If set to YES the
+# their full class and namespace scopes in the documentation. If set to YES, the
# scope will be hidden.
# The default value is: NO.
HIDE_SCOPE_NAMES = NO
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
# the files that are included by a file in the documentation of that file.
# The default value is: YES.
@@ -534,14 +581,14 @@ INLINE_INFO = YES
# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
# (detailed) documentation of file and class members alphabetically by member
-# name. If set to NO the members will appear in declaration order.
+# name. If set to NO, the members will appear in declaration order.
# The default value is: YES.
SORT_MEMBER_DOCS = YES
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
# descriptions of file, namespace and class members alphabetically by member
-# name. If set to NO the members will appear in declaration order. Note that
+# name. If set to NO, the members will appear in declaration order. Note that
# this will also influence the order of the classes in the class list.
# The default value is: NO.
@@ -586,27 +633,25 @@ SORT_BY_SCOPE_NAME = NO
STRICT_PROTO_MATCHING = NO
-# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
-# todo list. This list is created by putting \todo commands in the
-# documentation.
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
# The default value is: YES.
GENERATE_TODOLIST = YES
-# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
-# test list. This list is created by putting \test commands in the
-# documentation.
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
# The default value is: YES.
GENERATE_TESTLIST = YES
-# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
# list. This list is created by putting \bug commands in the documentation.
# The default value is: YES.
GENERATE_BUGLIST = YES
-# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
# the deprecated list. This list is created by putting \deprecated commands in
# the documentation.
# The default value is: YES.
@@ -631,11 +676,11 @@ ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
-# the bottom of the documentation of classes and structs. If set to YES the list
-# will mention the files that were used to generate the documentation.
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
# The default value is: YES.
-SHOW_USED_FILES = YES
+SHOW_USED_FILES = NO
# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
# will remove the Files entry from the Quick Index and from the Folder Tree View
@@ -672,12 +717,12 @@ FILE_VERSION_FILTER =
# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
# tag is left empty.
-LAYOUT_FILE =
+LAYOUT_FILE = docs/doxygen/layout.xml
# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
# the reference definitions. This must be a list of .bib files. The .bib
# extension is automatically appended if omitted. This requires the bibtex tool
-# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
# For LaTeX the style of the bibliography can be controlled using
# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
# search path. See also \cite for info how to create references.
@@ -696,7 +741,7 @@ CITE_BIB_FILES =
QUIET = NO
# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
# this implies that the warnings are on.
#
# Tip: Turn warnings on while writing the documentation.
@@ -704,7 +749,7 @@ QUIET = NO
WARNINGS = YES
-# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
# will automatically be disabled.
# The default value is: YES.
@@ -721,12 +766,19 @@ WARN_IF_DOC_ERROR = YES
# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
# are documented, but have no documentation for their parameters or return
-# value. If set to NO doxygen will only warn about wrong or incomplete parameter
-# documentation, but not about the absence of documentation.
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation. If
+# EXTRACT_ALL is set to YES then this flag will automatically be disabled.
# The default value is: NO.
WARN_NO_PARAMDOC = NO
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR = NO
+
# The WARN_FORMAT tag determines the format of the warning messages that doxygen
# can produce. The string should contain the $file, $line, and $text tags, which
# will be replaced by the file and line number from which the warning originated
@@ -750,15 +802,17 @@ WARN_LOGFILE =
# The INPUT tag is used to specify the files and/or directories that contain
# documented source files. You may enter file names like myfile.cpp or
# directories like /usr/src/myproject. Separate the files or directories with
-# spaces.
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
-INPUT = include/@PACKAGE@
+INPUT = \
+ include/@PACKAGE@ \
+ README.md
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
-# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
# possible encodings.
# The default value is: UTF-8.
@@ -766,12 +820,17 @@ INPUT_ENCODING = UTF-8
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
-# *.h) to filter out the source-files in the directories. If left blank the
-# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
-# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
-# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
-# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
-# *.qsf, *.as and *.js.
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
+# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
FILE_PATTERNS =
@@ -815,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
@@ -857,6 +916,10 @@ IMAGE_PATH =
# Note that the filter must not add or remove lines; it is applied before the
# code is scanned, but not when the output code is generated. If lines are added
# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
INPUT_FILTER =
@@ -866,11 +929,15 @@ INPUT_FILTER =
# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
FILTER_PATTERNS =
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER ) will also be used to filter the input files that are used for
+# INPUT_FILTER) will also be used to filter the input files that are used for
# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
# The default value is: NO.
@@ -889,7 +956,7 @@ FILTER_SOURCE_PATTERNS =
# (index.html). This can be useful if you have a project on for instance GitHub
# and want to reuse the introduction page also for the doxygen output.
-USE_MDFILE_AS_MAINPAGE =
+USE_MDFILE_AS_MAINPAGE = README.md
#---------------------------------------------------------------------------
# Configuration options related to source browsing
@@ -918,7 +985,7 @@ INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
-# function all documented functions referencing it will be listed.
+# entity all documented functions referencing it will be listed.
# The default value is: NO.
REFERENCED_BY_RELATION = YES
@@ -930,7 +997,7 @@ REFERENCED_BY_RELATION = YES
REFERENCES_RELATION = YES
# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
-# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
# link to the documentation.
# The default value is: YES.
@@ -950,12 +1017,12 @@ SOURCE_TOOLTIPS = YES
# If the USE_HTAGS tag is set to YES then the references to source code will
# point to the HTML generated by the htags(1) tool instead of doxygen built-in
# source browser. The htags tool is part of GNU's global source tagging system
-# (see http://www.gnu.org/software/global/global.html). You will need version
+# (see https://www.gnu.org/software/global/global.html). You will need version
# 4.8.6 or higher.
#
# To use it do the following:
# - Install the latest version of global
-# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
# - Make sure the INPUT points to the root of the source tree
# - Run doxygen as normal
#
@@ -988,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
@@ -1007,7 +1067,7 @@ IGNORE_PREFIX =
# Configuration options related to the HTML output
#---------------------------------------------------------------------------
-# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
# The default value is: YES.
GENERATE_HTML = YES
@@ -1045,7 +1105,7 @@ HTML_FILE_EXTENSION = .html
# of the possible markers and block names see the documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
-HTML_HEADER =
+HTML_HEADER = docs/doxygen/header.html
# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
# generated HTML page. If the tag is left blank doxygen will generate a standard
@@ -1055,7 +1115,7 @@ HTML_HEADER =
# that doxygen normally uses.
# This tag requires that the tag GENERATE_HTML is set to YES.
-HTML_FOOTER =
+HTML_FOOTER = docs/doxygen/footer.html
# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
# sheet that is used by each HTML page. It can be used to fine-tune the look of
@@ -1073,14 +1133,15 @@ HTML_STYLESHEET =
# cascading style sheets that are included after the standard style sheets
# created by doxygen. Using this option one can overrule certain style aspects.
# This is preferred over using HTML_STYLESHEET since it does not replace the
-# standard style sheet and is therefor more robust against future updates.
+# standard style sheet and is therefore more robust against future updates.
# Doxygen will copy the style sheet files to the output directory.
-# Note: The order of the extra stylesheet files is of importance (e.g. the last
-# stylesheet in the list overrules the setting of the previous ones in the
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
# list). For an example see the documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
-HTML_EXTRA_STYLESHEET =
+HTML_EXTRA_STYLESHEET = \
+ docs/doxygen/custom.css
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
# other source files which should be copied to the HTML output directory. Note
@@ -1090,12 +1151,16 @@ HTML_EXTRA_STYLESHEET =
# files will be copied as-is; there are no commands or markers available.
# This tag requires that the tag GENERATE_HTML is set to YES.
-HTML_EXTRA_FILES =
+HTML_EXTRA_FILES = \
+ docs/doxygen/favicon.ico \
+ docs/doxygen/folder.png \
+ docs/doxygen/folder-open.png \
+ docs/doxygen/text-x-generic.png
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
-# will adjust the colors in the stylesheet and background images according to
+# will adjust the colors in the style sheet and background images according to
# this color. Hue is specified as an angle on a colorwheel, see
-# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
# purple, and 360 is red again.
# Minimum value: 0, maximum value: 359, default value: 220.
@@ -1124,12 +1189,24 @@ HTML_COLORSTYLE_GAMMA = 80
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
# page will contain the date and time when the page was generated. Setting this
-# to NO can help when comparing the output of multiple runs.
-# The default value is: YES.
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_TIMESTAMP = YES
+# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
+# documentation will contain a main index with vertical navigation menus that
+# are dynamically created via Javascript. If disabled, the navigation index will
+# consists of multiple levels of tabs that are statically embedded in every HTML
+# page. Disable this option to support browsers that do not have Javascript,
+# like the Qt help browser.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_MENUS = NO
+
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
# documentation will contain sections that can be hidden and shown after the
# page has loaded.
@@ -1153,13 +1230,13 @@ HTML_INDEX_NUM_ENTRIES = 100
# If the GENERATE_DOCSET tag is set to YES, additional index files will be
# generated that can be used as input for Apple's Xcode 3 integrated development
-# environment (see: http://developer.apple.com/tools/xcode/), introduced with
-# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# environment (see: https://developer.apple.com/xcode/), introduced with OSX
+# 10.5 (Leopard). To create a documentation set, doxygen will generate a
# Makefile in the HTML output directory. Running make will produce the docset in
# that directory and running make install will install the docset in
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
-# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
-# for more information.
+# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
+# genXcode/_index.html for more information.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
@@ -1198,7 +1275,7 @@ DOCSET_PUBLISHER_NAME = Publisher
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
-# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on
# Windows.
#
# The HTML Help Workshop contains a compiler that can convert all HTML output
@@ -1221,28 +1298,28 @@ GENERATE_HTMLHELP = NO
CHM_FILE =
# The HHC_LOCATION tag can be used to specify the location (absolute path
-# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
# doxygen will try to run the HTML help compiler on the generated index.hhp.
# The file has to be specified with full path.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
HHC_LOCATION =
-# The GENERATE_CHI flag controls if a separate .chi index file is generated (
-# YES) or that it should be included in the master .chm file ( NO).
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
GENERATE_CHI = NO
-# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
# and project file content.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
CHM_INDEX_ENCODING =
-# The BINARY_TOC flag controls whether a binary table of contents is generated (
-# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
# enables the Previous and Next buttons.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
@@ -1274,7 +1351,7 @@ QCH_FILE =
# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
# Project output. For more information please see Qt Help Project / Namespace
-# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
# The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_QHP is set to YES.
@@ -1282,7 +1359,7 @@ QHP_NAMESPACE = org.doxygen.Project
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
# Help Project output. For more information please see Qt Help Project / Virtual
-# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-
# folders).
# The default value is: doc.
# This tag requires that the tag GENERATE_QHP is set to YES.
@@ -1291,7 +1368,7 @@ QHP_VIRTUAL_FOLDER = doc
# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
# filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
# filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
@@ -1299,7 +1376,7 @@ QHP_CUST_FILTER_NAME =
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
# custom filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
# filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
@@ -1307,7 +1384,7 @@ QHP_CUST_FILTER_ATTRS =
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
# project's filter section matches. Qt Help Project / Filter Attributes (see:
-# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_SECT_FILTER_ATTRS =
@@ -1356,7 +1433,7 @@ DISABLE_INDEX = NO
# index structure (just like the one that is generated for HTML Help). For this
# to work a browser that supports JavaScript, DHTML, CSS and frames is required
# (i.e. any modern browser). Windows users are probably better off using the
-# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
# further fine-tune the look of the index. As an example, the default style
# sheet generated by doxygen has an example that shows how to put an image at
# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
@@ -1384,7 +1461,7 @@ ENUM_VALUES_PER_LINE = 1
TREEVIEW_WIDTH = 250
-# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
# external symbols imported via tag files in a separate window.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
@@ -1400,7 +1477,7 @@ EXT_LINKS_IN_WINDOW = NO
FORMULA_FONTSIZE = 10
-# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
# generated for formulas are transparent PNGs. Transparent PNGs are not
# supported properly for IE 6.0, but are supported on all modern browsers.
#
@@ -1412,8 +1489,8 @@ FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
-# http://www.mathjax.org) which uses client side Javascript for the rendering
-# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# https://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
# installed or if you want to formulas look prettier in the HTML output. When
# enabled you may also need to install MathJax separately and configure the path
# to it using the MATHJAX_RELPATH option.
@@ -1439,8 +1516,8 @@ MATHJAX_FORMAT = HTML-CSS
# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
# Content Delivery Network so you can quickly see the result without installing
# MathJax. However, it is strongly recommended to install a local copy of
-# MathJax from http://www.mathjax.org before deployment.
-# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# MathJax from https://www.mathjax.org before deployment.
+# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/.
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
@@ -1499,9 +1576,9 @@ SERVER_BASED_SEARCH = NO
# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
# search results.
#
-# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: http://xapian.org/).
+# Xapian (see: https://xapian.org/).
#
# See the section "External Indexing and Searching" for details.
# The default value is: NO.
@@ -1512,9 +1589,9 @@ EXTERNAL_SEARCH = NO
# The SEARCHENGINE_URL should point to a search engine hosted by a web server
# which will return the search results when EXTERNAL_SEARCH is enabled.
#
-# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Xapian (see: https://xapian.org/). See the section "External Indexing and
# Searching" for details.
# This tag requires that the tag SEARCHENGINE is set to YES.
@@ -1550,7 +1627,7 @@ EXTRA_SEARCH_MAPPINGS =
# Configuration options related to the LaTeX output
#---------------------------------------------------------------------------
-# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
# The default value is: YES.
GENERATE_LATEX = NO
@@ -1566,22 +1643,36 @@ LATEX_OUTPUT = latex
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
# invoked.
#
-# Note that when enabling USE_PDFLATEX this option is only used for generating
-# bitmaps for formulas in the HTML output, but not in the Makefile that is
-# written to the output directory.
-# The default file is: latex.
+# Note that when not enabling USE_PDFLATEX the default is latex when enabling
+# USE_PDFLATEX the default is pdflatex and when in the later case latex is
+# chosen this is overwritten by pdflatex. For specific output languages the
+# default can have been set differently, this depends on the implementation of
+# the output language.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_CMD_NAME = latex
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
# index for LaTeX.
+# Note: This tag is used in the Makefile / make.bat.
+# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
+# (.tex).
# The default file is: makeindex.
# This tag requires that the tag GENERATE_LATEX is set to YES.
MAKEINDEX_CMD_NAME = makeindex
-# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
+# generate index for LaTeX. In case there is no backslash (\) as first character
+# it will be automatically added in the LaTeX code.
+# Note: This tag is used in the generated output file (.tex).
+# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
+# The default value is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_MAKEINDEX_CMD = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
# documents. This may be useful for small projects and may help to save some
# trees in general.
# The default value is: NO.
@@ -1596,12 +1687,15 @@ 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. To get the times font for
-# instance you can specify
-# EXTRA_PACKAGES=times
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
# If left blank no extra packages will be included.
# This tag requires that the tag GENERATE_LATEX is set to YES.
@@ -1616,9 +1710,9 @@ EXTRA_PACKAGES =
# Note: Only use a user-defined header if you know what you are doing! The
# following commands have a special meaning inside the header: $title,
# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
-# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string,
-# for the replacement values of the other commands the user is refered to
-# HTML_HEADER.
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_HEADER =
@@ -1634,6 +1728,17 @@ LATEX_HEADER =
LATEX_FOOTER =
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
# other source files which should be copied to the LATEX_OUTPUT output
# directory. Note that the files will be copied as-is; there are no commands or
@@ -1652,7 +1757,7 @@ LATEX_EXTRA_FILES =
PDF_HYPERLINKS = NO
# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
-# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
# higher quality PDF documentation.
# The default value is: YES.
# This tag requires that the tag GENERATE_LATEX is set to YES.
@@ -1675,29 +1780,35 @@ 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
-# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
# The default value is: plain.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_BIB_STYLE = plain
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP = NO
+
+# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
+# path from which the emoji images will be read. If a relative path is entered,
+# it will be relative to the LATEX_OUTPUT directory. If left blank the
+# LATEX_OUTPUT directory will be used.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EMOJI_DIRECTORY =
+
#---------------------------------------------------------------------------
# Configuration options related to the RTF output
#---------------------------------------------------------------------------
-# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
# RTF output is optimized for Word 97 and may not look too pretty with other RTF
# readers/editors.
# The default value is: NO.
@@ -1712,7 +1823,7 @@ GENERATE_RTF = NO
RTF_OUTPUT = rtf
-# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
# documents. This may be useful for small projects and may help to save some
# trees in general.
# The default value is: NO.
@@ -1732,9 +1843,9 @@ COMPACT_RTF = NO
RTF_HYPERLINKS = NO
-# Load stylesheet definitions from file. Syntax is similar to doxygen's config
-# file, i.e. a series of assignments. You only have to provide replacements,
-# missing definitions are set to their default value.
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# configuration file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
#
# See also section "Doxygen usage" for information on how to generate the
# default style sheet that doxygen normally uses.
@@ -1743,8 +1854,8 @@ RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
# Set optional variables used in the generation of an RTF document. Syntax is
-# similar to doxygen's config file. A template extensions file can be generated
-# using doxygen -e rtf extensionFile.
+# similar to doxygen's configuration file. A template extensions file can be
+# generated using doxygen -e rtf extensionFile.
# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_EXTENSIONS_FILE =
@@ -1753,7 +1864,7 @@ RTF_EXTENSIONS_FILE =
# Configuration options related to the man page output
#---------------------------------------------------------------------------
-# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
# classes and files.
# The default value is: NO.
@@ -1797,7 +1908,7 @@ MAN_LINKS = NO
# Configuration options related to the XML output
#---------------------------------------------------------------------------
-# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
# captures the structure of the code including all documentation.
# The default value is: NO.
@@ -1811,7 +1922,7 @@ GENERATE_XML = NO
XML_OUTPUT = xml
-# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
# listings (including syntax highlighting and cross-referencing information) to
# the XML output. Note that enabling this will significantly increase the size
# of the XML output.
@@ -1820,11 +1931,18 @@ XML_OUTPUT = xml
XML_PROGRAMLISTING = YES
+# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
+# namespace members in file scope as well, matching the HTML output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_NS_MEMB_FILE_SCOPE = NO
+
#---------------------------------------------------------------------------
# Configuration options related to the DOCBOOK output
#---------------------------------------------------------------------------
-# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
# that can be used to generate PDF.
# The default value is: NO.
@@ -1838,23 +1956,14 @@ 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
#---------------------------------------------------------------------------
-# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
-# Definitions (see http://autogen.sf.net) file that captures the structure of
-# the code including all documentation. Note that this feature is still
-# experimental and incomplete at the moment.
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
+# the structure of the code including all documentation. Note that this feature
+# is still experimental and incomplete at the moment.
# The default value is: NO.
GENERATE_AUTOGEN_DEF = NO
@@ -1863,7 +1972,7 @@ GENERATE_AUTOGEN_DEF = NO
# Configuration options related to the Perl module output
#---------------------------------------------------------------------------
-# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
# file that captures the structure of the code including all documentation.
#
# Note that this feature is still experimental and incomplete at the moment.
@@ -1871,7 +1980,7 @@ GENERATE_AUTOGEN_DEF = NO
GENERATE_PERLMOD = NO
-# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
# output from the Perl module output.
# The default value is: NO.
@@ -1879,9 +1988,9 @@ GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
# formatted so it can be parsed by a human reader. This is useful if you want to
-# understand what is going on. On the other hand, if this tag is set to NO the
+# understand what is going on. On the other hand, if this tag is set to NO, the
# size of the Perl module output will be much smaller and Perl will parse it
# just the same.
# The default value is: YES.
@@ -1901,20 +2010,20 @@ PERLMOD_MAKEVAR_PREFIX =
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
-# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
# C-preprocessor directives found in the sources and include files.
# The default value is: YES.
ENABLE_PREPROCESSING = YES
-# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
-# in the source code. If set to NO only conditional compilation will be
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
# performed. Macro expansion can be done in a controlled way by setting
# EXPAND_ONLY_PREDEF to 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
@@ -1922,9 +2031,9 @@ 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 includes files in the
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
# INCLUDE_PATH will be searched if a #include is found.
# The default value is: YES.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
@@ -1963,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
@@ -2000,37 +2109,32 @@ TAGFILES =
GENERATE_TAGFILE =
-# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
-# class index. If set to NO only the inherited external classes will be listed.
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
# The default value is: NO.
ALLEXTERNALS = NO
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
-# the modules index. If set to NO, only the current project's groups will be
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
# listed.
# The default value is: YES.
EXTERNAL_GROUPS = YES
-# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
# the related pages index. If set to NO, only the current project's pages will
# be listed.
# The default value is: YES.
EXTERNAL_PAGES = YES
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of 'which perl').
-# The default file (with absolute path) is: /usr/bin/perl.
-
-PERL_PATH = /usr/bin/perl
-
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
-# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
# NO turns the diagrams off. Note that this option also works with HAVE_DOT
# disabled, but it is recommended to install and use dot, since it yields more
@@ -2039,15 +2143,6 @@ PERL_PATH = /usr/bin/perl
CLASS_DIAGRAMS = YES
-# You can define message sequence charts within doxygen comments using the \msc
-# command. Doxygen will then run the mscgen tool (see:
-# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
-# documentation. The MSCGEN_PATH tag allows you to specify the directory where
-# the mscgen tool resides. If left empty the tool is assumed to be found in the
-# default search path.
-
-MSCGEN_PATH =
-
# You can include diagrams made with dia in doxygen documentation. Doxygen will
# then run dia to produce the diagram and insert it in the documentation. The
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
@@ -2055,7 +2150,7 @@ MSCGEN_PATH =
DIA_PATH =
-# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# If set to YES the inheritance and collaboration graphs will hide inheritance
# and usage relations if the target is undocumented or is not a class.
# The default value is: YES.
@@ -2088,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.
@@ -2128,7 +2223,7 @@ COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
# collaboration diagrams in a style similar to the OMG's Unified Modeling
# Language.
# The default value is: NO.
@@ -2180,7 +2275,8 @@ INCLUDED_BY_GRAPH = YES
#
# Note that enabling this option will significantly increase the time of a run.
# So in most cases it will be better to enable call graphs for selected
-# functions only using the \callgraph command.
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
@@ -2191,7 +2287,8 @@ CALL_GRAPH = NO
#
# Note that enabling this option will significantly increase the time of a run.
# So in most cases it will be better to enable caller graphs for selected
-# functions only using the \callergraph command.
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
@@ -2214,11 +2311,15 @@ GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot.
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
# to make the SVG files visible in IE 9+ (other browsers do not have this
# requirement).
-# Possible values are: png, jpg, gif and svg.
+# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
# The default value is: png.
# This tag requires that the tag HAVE_DOT is set to YES.
@@ -2266,10 +2367,19 @@ DIAFILE_DIRS =
# PlantUML is not used or called during a preprocessing step. Doxygen will
# generate a warning when it encounters a \startuml command in this case and
# will not generate output for the diagram.
-# This tag requires that the tag HAVE_DOT is set to YES.
PLANTUML_JAR_PATH =
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
# that will be shown in the graph. If the number of nodes in a graph becomes
# larger than this value, doxygen will truncate the graph, which is visualized
@@ -2306,7 +2416,7 @@ MAX_DOT_GRAPH_DEPTH = 0
DOT_TRANSPARENT = NO
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This
# makes dot run faster, but since only newer versions of dot (>1.8.10) support
# this, this feature is disabled by default.
@@ -2323,7 +2433,7 @@ DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
-# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
# files that are used to generate the various graphs.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
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 eaf052a..2abaf49 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -1,26 +1,31 @@
-EXTRA_DIST = asprintf.h endianness.h
+EXTRA_DIST = \
+ asprintf.h \
+ endianness.h
-nobase_include_HEADERS = libimobiledevice/libimobiledevice.h \
- libimobiledevice/lockdown.h \
- libimobiledevice/afc.h \
- libimobiledevice/file_relay.h \
- libimobiledevice/notification_proxy.h \
- libimobiledevice/installation_proxy.h \
- libimobiledevice/sbservices.h \
- libimobiledevice/mobile_image_mounter.h \
- libimobiledevice/screenshotr.h \
- libimobiledevice/mobilesync.h \
- libimobiledevice/mobilebackup.h \
- libimobiledevice/house_arrest.h \
- libimobiledevice/mobilebackup2.h \
- libimobiledevice/misagent.h \
- libimobiledevice/restore.h\
- libimobiledevice/webinspector.h\
- libimobiledevice/heartbeat.h\
- libimobiledevice/diagnostics_relay.h\
- libimobiledevice/debugserver.h\
- libimobiledevice/syslog_relay.h\
- libimobiledevice/mobileactivation.h\
- libimobiledevice/preboard.h\
- libimobiledevice/property_list_service.h\
- libimobiledevice/service.h
+nobase_include_HEADERS = \
+ libimobiledevice/libimobiledevice.h \
+ libimobiledevice/lockdown.h \
+ libimobiledevice/afc.h \
+ libimobiledevice/file_relay.h \
+ libimobiledevice/notification_proxy.h \
+ libimobiledevice/installation_proxy.h \
+ libimobiledevice/sbservices.h \
+ libimobiledevice/mobile_image_mounter.h \
+ libimobiledevice/screenshotr.h \
+ libimobiledevice/mobilesync.h \
+ libimobiledevice/mobilebackup.h \
+ libimobiledevice/house_arrest.h \
+ libimobiledevice/mobilebackup2.h \
+ libimobiledevice/misagent.h \
+ libimobiledevice/restore.h \
+ libimobiledevice/webinspector.h \
+ libimobiledevice/heartbeat.h \
+ libimobiledevice/diagnostics_relay.h \
+ libimobiledevice/debugserver.h \
+ libimobiledevice/syslog_relay.h \
+ 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 13cffd4..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 *filename, 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 *filename, char **
*
* @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
new file mode 100644
index 0000000..544322a
--- /dev/null
+++ b/include/libimobiledevice/companion_proxy.h
@@ -0,0 +1,212 @@
+/**
+ * @file libimobiledevice/companion_proxy.h
+ * @brief Companion proxy support.
+ * \internal
+ *
+ * Copyright (c) 2019-2020 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 ICOMPANION_PROXY_H
+#define ICOMPANION_PROXY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#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 */
+typedef enum {
+ COMPANION_PROXY_E_SUCCESS = 0,
+ COMPANION_PROXY_E_INVALID_ARG = -1,
+ COMPANION_PROXY_E_PLIST_ERROR = -2,
+ COMPANION_PROXY_E_MUX_ERROR = -3,
+ COMPANION_PROXY_E_SSL_ERROR = -4,
+ COMPANION_PROXY_E_NOT_ENOUGH_DATA = -5,
+ COMPANION_PROXY_E_TIMEOUT = -6,
+ COMPANION_PROXY_E_OP_IN_PROGRESS = -7,
+ COMPANION_PROXY_E_NO_DEVICES = -100,
+ COMPANION_PROXY_E_UNSUPPORTED_KEY = -101,
+ COMPANION_PROXY_E_TIMEOUT_REPLY = -102,
+ COMPANION_PROXY_E_UNKNOWN_ERROR = -256
+} companion_proxy_error_t;
+
+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);
+
+/**
+ * Connects to the companion_proxy 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
+ * companion_proxy_client_t upon successful return. Must be freed using
+ * companion_proxy_client_free() after use.
+ *
+ * @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.
+ */
+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.
+ *
+ * @param device The device to connect to.
+ * @param client Pointer that will point to a newly allocated
+ * companion_proxy_client_t upon successful return. Must be freed using
+ * companion_proxy_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 COMPANION_PROXY_E_SUCCESS on success, or an COMPANION_PROXY_E_* error
+ * code otherwise.
+ */
+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
+ * companion_proxy client data.
+ *
+ * @param client The companion_proxy client to disconnect and free.
+ *
+ * @return COMPANION_PROXY_E_SUCCESS on success, COMPANION_PROXY_E_INVALID_ARG when
+ * client is NULL, or an COMPANION_PROXY_E_* error code otherwise.
+ */
+LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_client_free(companion_proxy_client_t client);
+
+/**
+ * Sends a plist to the service.
+ *
+ * @param client The companion_proxy client
+ * @param plist The plist to send
+ *
+ * @return COMPANION_PROXY_E_SUCCESS on success,
+ * COMPANION_PROXY_E_INVALID_ARG when client or plist is NULL
+ */
+LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_send(companion_proxy_client_t client, plist_t plist);
+
+/**
+ * Receives a plist from the service.
+ *
+ * @param client The companion_proxy client
+ * @param plist The plist to store the received data
+ *
+ * @return COMPANION_PROXY_E_SUCCESS on success,
+ * COMPANION_PROXY_E_INVALID_ARG when client or plist is NULL
+ */
+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 paired_devices Point that will receive a PLIST_ARRAY with paired device UDIDs
+ *
+ * @note The device closes the connection after sending the reply.
+ *
+ * @return COMPANION_PROXY_E_SUCCESS on success,
+ * COMPANION_PROXY_E_NO_DEVICES if no devices are paired,
+ * or a COMPANION_PROXY_E_* error code otherwise.
+ */
+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.
+ *
+ * @param client The companion_proxy client
+ * @param callback Callback function that will be called when a new device is detected
+ * @param userdata Pointer that that will be passed to the callback function
+ *
+ * @note The event parameter that gets passed to the callback function is
+ * freed internally after returning from the callback. The consumer needs
+ * to make a copy if required.
+ *
+ * @return COMPANION_PROXY_E_SUCCESS on success,
+ * or a COMPANION_PROXY_E_* error code otherwise.
+ */
+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
+ *
+ * @param client The companion_proxy client
+ *
+ * @return COMPANION_PROXY_E_SUCCESS on success,
+ * or a COMPANION_PROXY_E_* error code otherwise.
+ */
+LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_stop_listening_for_devices(companion_proxy_client_t client);
+
+/**
+ * Returns a value for the given key.
+ *
+ * @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.
+ *
+ * @return COMPANION_PROXY_E_SUCCESS on success,
+ * COMPANION_PROXY_E_INVALID_ARG when client or paired_devices is invalid,
+ * COMPANION_PROXY_E_UNSUPPORTED_KEY if the companion device doesn't support the given key,
+ * or a COMPANION_PROXY_E_* error code otherwise.
+ */
+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.
+ *
+ * @see companion_proxy_stop_forwarding_service_port
+ *
+ * @param client The companion_proxy client
+ * @param remote_port remote port
+ * @param service_name The name of the service that shall be forwarded
+ * @param forward_port Pointer that will receive the newly-assigned port accessible via USB/Network on the idevice
+ * @param options PLIST_DICT with additional options. Currently known are
+ * IsServiceLowPriority (boolean) and PreferWifi (boolean).
+ *
+ * @return COMPANION_PROXY_E_SUCCESS on success,
+ * or a COMPANION_PROXY_E_* error code otherwise.
+ */
+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.
+ *
+ * @see companion_proxy_start_forwarding_service_port
+ *
+ * @param client The companion_proxy client
+ * @param remote_port remote port
+ *
+ * @return COMPANION_PROXY_E_SUCCESS on success,
+ * or a COMPANION_PROXY_E_* error code otherwise.
+ */
+LIBIMOBILEDEVICE_API companion_proxy_error_t companion_proxy_stop_forwarding_service_port(companion_proxy_client_t client, uint16_t remote_port);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/libimobiledevice/debugserver.h b/include/libimobiledevice/debugserver.h
index 19a4f5d..809b97f 100644
--- a/include/libimobiledevice/debugserver.h
+++ b/include/libimobiledevice/debugserver.h
@@ -30,7 +30,10 @@ 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 */
typedef enum {
@@ -39,13 +42,14 @@ typedef enum {
DEBUGSERVER_E_MUX_ERROR = -2,
DEBUGSERVER_E_SSL_ERROR = -3,
DEBUGSERVER_E_RESPONSE_ERROR = -4,
+ DEBUGSERVER_E_TIMEOUT = -5,
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 */
@@ -62,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.
@@ -77,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
@@ -88,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.
@@ -103,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.
@@ -117,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.
@@ -134,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.
@@ -142,22 +147,24 @@ debugserver_error_t debugserver_client_receive(debugserver_client_t client, char
* @param client The debugserver client
* @param command Command to process and send
* @param response Response received for the command (can be NULL to ignore)
+ * @param response_size Pointer to receive response size. Set to NULL to ignore.
*
* @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);
+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.
*
* @param client The debugserver client
* @param response Response received for last command (can be NULL to ignore)
+ * @param response_size Pointer to receive response size. Set to NULL to ignore.
*
* @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);
+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.
@@ -171,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.
@@ -184,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.
@@ -196,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.
@@ -209,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.
@@ -219,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.
@@ -228,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.
@@ -237,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 97ac363..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,16 +43,19 @@ typedef enum {
DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR = -256
} diagnostics_relay_error_t;
-#define DIAGNOSTICS_RELAY_ACTION_FLAG_WAIT_FOR_DISCONNECT (1 << 1)
-#define DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_PASS (1 << 2)
-#define DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_FAIL (1 << 3)
+/** 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. */
/**
@@ -66,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.
@@ -81,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
@@ -94,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);
/**
@@ -107,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.
@@ -119,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.
@@ -136,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, int 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.
@@ -153,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, int 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* name, const char* 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 1ff82dc..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.
@@ -228,10 +229,10 @@ instproxy_error_t instproxy_lookup(instproxy_client_t client, const char** appid
*
* @note If a callback function is given (async mode), this function returns
* INSTPROXY_E_SUCCESS immediately if the status updater thread has been
- * created successfully; any error occuring during the command has to be
+ * 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
@@ -256,10 +257,10 @@ instproxy_error_t instproxy_install(instproxy_client_t client, const char *pkg_p
*
* @note If a callback function is given (async mode), this function returns
* INSTPROXY_E_SUCCESS immediately if the status updater thread has been
- * created successfully; any error occuring during the command has to be
+ * 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.
@@ -277,10 +278,10 @@ instproxy_error_t instproxy_upgrade(instproxy_client_t client, const char *pkg_p
*
* @note If a callback function is given (async mode), this function returns
* INSTPROXY_E_SUCCESS immediately if the status updater thread has been
- * created successfully; any error occuring during the command has to be
+ * 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.
@@ -319,10 +320,10 @@ instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist_t c
*
* @note If a callback function is given (async mode), this function returns
* INSTPROXY_E_SUCCESS immediately if the status updater thread has been
- * created successfully; any error occuring during the command has to be
+ * 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.
@@ -343,10 +344,10 @@ instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid
*
* @note If a callback function is given (async mode), this function returns
* INSTPROXY_E_SUCCESS immediately if the status updater thread has been
- * created successfully; any error occuring during the command has to be
+ * 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.
@@ -366,10 +367,10 @@ instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid
*
* @note If a callback function is given (async mode), this function returns
* INSTPROXY_E_SUCCESS immediately if the status updater thread has been
- * created successfully; any error occuring during the command has to be
+ * 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 8f8589d..a9d270b 100644
--- a/include/libimobiledevice/libimobiledevice.h
+++ b/include/libimobiledevice/libimobiledevice.h
@@ -3,6 +3,7 @@
* @brief Device/Connection handling and communication
* \internal
*
+ * Copyright (c) 2010-2019 Nikias Bassen All Rights Reserved.
* Copyright (c) 2010-2014 Martin Szulecki All Rights Reserved.
* Copyright (c) 2014 Christophe Fergeau All Rights Reserved.
* Copyright (c) 2008 Jonathan Beck All Rights Reserved.
@@ -34,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,
@@ -41,22 +52,44 @@ 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() */
+enum idevice_options {
+ IDEVICE_LOOKUP_USBMUX = 1 << 1, /**< include USBMUX devices during lookup */
+ IDEVICE_LOOKUP_NETWORK = 1 << 2, /**< include network devices during lookup */
+ IDEVICE_LOOKUP_PREFER_NETWORK = 1 << 3 /**< prefer network connection if device is available via USBMUX *and* network */
+};
+
+/** Type of connection a device is available on */
+enum idevice_connection_type {
+ 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; /**< 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 */
@@ -64,13 +97,16 @@ enum idevice_event_type {
typedef struct {
enum idevice_event_type event; /**< The event type. */
const char *udid; /**< The device unique id. */
- int conn_type; /**< The connection type. Currently only 1 for usbmuxd. */
+ enum idevice_connection_type conn_type; /**< The connection type. */
} idevice_event_t;
/* event callback function prototype */
/** 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 */
/**
@@ -78,58 +114,115 @@ 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);
+
+/**
+ * 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.
+ */
+LIBIMOBILEDEVICE_API idevice_error_t idevice_events_subscribe(idevice_subscription_context_t *context, idevice_event_cb_t callback, void *user_data);
/**
- * Register a callback function that will be called when device add/remove
+ * 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.
*/
-idevice_error_t idevice_event_subscribe(idevice_event_cb_t callback, void *user_data);
+LIBIMOBILEDEVICE_API idevice_error_t idevice_event_subscribe(idevice_event_cb_t callback, void *user_data);
/**
- * Release the event callback function that has been registered with
+ * (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) */
/**
- * Get a list of currently available devices.
+ * Get a list of UDIDs of currently available devices (USBMUX devices only).
*
- * @param devices List of udids of devices that are currently available.
+ * @param devices List of UDIDs of devices that are currently available.
* This list is terminated by a NULL pointer.
* @param count Number of devices found.
*
* @return IDEVICE_E_SUCCESS on success or an error value when an error occurred.
+ *
+ * @note This function only returns the UDIDs of USBMUX devices. To also include
+ * 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.
+ * Free a list of device UDIDs.
*
- * @param devices List of udids to free.
+ * @param devices List of UDIDs to free.
*
* @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
+ *
+ * @param devices List of idevice_info_t records with device information.
+ * This list is terminated by a NULL pointer.
+ * @param count Number of devices included in the list.
+ *
+ * @return IDEVICE_E_SUCCESS on success or an error value when an error occurred.
+ */
+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().
+ *
+ * @param devices Device list to free.
+ *
+ * @return IDEVICE_E_SUCCESS on success or an error value when an error occurred.
+ */
+LIBIMOBILEDEVICE_API idevice_error_t idevice_device_list_extended_free(idevice_info_t *devices);
/* device structure creation and destruction */
/**
- * Creates an idevice_t structure for the device specified by udid,
- * if the device is available.
+ * Creates an idevice_t structure for the device specified by UDID,
+ * if the device is available (USBMUX devices only).
*
* @note The resulting idevice_t structure has to be freed with
* idevice_free() if it is no longer used.
+ * If you need to connect to a device available via network, use
+ * idevice_new_with_options() and include IDEVICE_LOOKUP_NETWORK in options.
+ *
+ * @see idevice_new_with_options
*
* @param device Upon calling this function, a pointer to a location of type
* idevice_t. On successful return, this location will be populated.
@@ -137,16 +230,37 @@ idevice_error_t idevice_device_list_free(char **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,
+ * if the device is available, with the given lookup options.
+ *
+ * @note The resulting idevice_t structure has to be freed with
+ * idevice_free() if it is no longer used.
+ *
+ * @param device Upon calling this function, a pointer to a location of type
+ * idevice_t. On successful return, this location will be populated.
+ * @param udid The UDID to match.
+ * @param options Specifies what connection types should be considered
+ * when looking up devices. Accepts bitwise or'ed values of idevice_options.
+ * If 0 (no option) is specified it will default to IDEVICE_LOOKUP_USBMUX.
+ * To lookup both USB and network-connected devices, pass
+ * IDEVICE_LOOKUP_USBMUX | IDEVICE_LOOKUP_NETWORK. If a device is available
+ * both via USBMUX *and* network, it will select the USB connection.
+ * This behavior can be changed by adding IDEVICE_LOOKUP_PREFER_NETWORK
+ * to the options in which case it will select the network connection.
+ *
+ * @return IDEVICE_E_SUCCESS if ok, otherwise an error code.
+ */
+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.
- * This is a library-level function; deals directly with the device to tear
- * down relations, but otherwise is mostly internal.
*
* @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 */
@@ -160,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.
@@ -169,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 */
@@ -184,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.
@@ -201,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.
@@ -216,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.
@@ -227,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.
@@ -238,7 +352,21 @@ 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.
+ *
+ * @param connection The connection to disable SSL for.
+ * @param sslBypass if true ssl connection will not be terminated but just cleaned up, allowing
+ * plain text data going on underlying connection
+ *
+ * @return IDEVICE_E_SUCCESS on success, IDEVICE_E_INVALID_ARG when connection
+ * is NULL. This function also returns IDEVICE_E_SUCCESS when SSL is not
+ * enabled and does no further error checking on cleanup.
+ */
+LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_disable_bypass_ssl(idevice_connection_t connection, uint8_t sslBypass);
+
/**
* Get the underlying file descriptor for a connection
@@ -248,19 +376,36 @@ idevice_error_t idevice_connection_disable_ssl(idevice_connection_t connection);
*
* @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 b5c126c..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,17 +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;
+ 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 */
/**
@@ -116,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.
@@ -135,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
@@ -145,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);
/**
@@ -157,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.
@@ -169,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.
@@ -182,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.
@@ -195,21 +209,21 @@ 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.
*
* @param client The lockdownd client
* @param identifier The identifier of the service to start
- * @param descriptor The service descriptor on success or NULL on failure
+ * @param service The service descriptor on success or NULL on failure
*
* @return LOCKDOWN_E_SUCCESS on success, LOCKDOWN_E_INVALID_ARG if a parameter
* is NULL, LOCKDOWN_E_INVALID_SERVICE if the requested service is not known
* 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.
@@ -217,7 +231,7 @@ lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char
*
* @param client The lockdownd client
* @param identifier The identifier of the service to start
- * @param descriptor The service descriptor on success or NULL on failure
+ * @param service The service descriptor on success or NULL on failure
*
* @return LOCKDOWN_E_SUCCESS on success, LOCKDOWN_E_INVALID_ARG if a parameter
* is NULL, LOCKDOWN_E_INVALID_SERVICE if the requested service is not known
@@ -225,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.
@@ -240,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.
@@ -252,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.
@@ -266,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.
@@ -277,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.
@@ -293,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.
@@ -312,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
@@ -331,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
@@ -347,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.
@@ -364,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”
@@ -376,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.
@@ -385,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.
@@ -396,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 */
@@ -407,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.
@@ -418,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 control, 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.
@@ -429,7 +526,7 @@ lockdownd_error_t lockdownd_get_device_udid(lockdownd_client_t control, char **u
*
* @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.
@@ -444,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()
@@ -453,16 +550,25 @@ 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()
*
- * @param sevice A service descriptor instance to free.
+ * @param service A service descriptor instance to free.
*
* @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.
+ *
+ * @param err A lockdownd error code
+ *
+ * @returns A readable error string
+ */
+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 8d783c4..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 */
@@ -40,10 +41,11 @@ typedef enum {
MOBILE_IMAGE_MOUNTER_E_PLIST_ERROR = -2,
MOBILE_IMAGE_MOUNTER_E_CONN_FAILED = -3,
MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED = -4,
+ MOBILE_IMAGE_MOUNTER_E_DEVICE_LOCKED = -5,
MOBILE_IMAGE_MOUNTER_E_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 */
@@ -64,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.
@@ -79,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
@@ -90,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);
/**
@@ -106,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.
@@ -125,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.
@@ -148,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.
@@ -161,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 b7f8064..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_result The handshake result 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_result, 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 6da3bed..2ecb60c 100644
--- a/include/libimobiledevice/mobilebackup.h
+++ b/include/libimobiledevice/mobilebackup.h
@@ -3,8 +3,8 @@
* @brief Backup and restore of all device data.
* \internal
*
- * Copyright (c) 2009-2014 Martin Szulecki All Rights Reserved.
- * Copyright (c) 2010 Nikias Bassen All Rights Reserved.
+ * Copyright (c) 2010-2019 Nikias Bassen, All Rights Reserved.
+ * Copyright (c) 2009-2014 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
@@ -31,22 +31,26 @@ 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 */
typedef enum {
- MOBILEBACKUP_E_SUCCESS = 0,
- MOBILEBACKUP_E_INVALID_ARG = -1,
- MOBILEBACKUP_E_PLIST_ERROR = -2,
- MOBILEBACKUP_E_MUX_ERROR = -3,
- MOBILEBACKUP_E_BAD_VERSION = -4,
- MOBILEBACKUP_E_REPLY_NOT_OK = -5,
- MOBILEBACKUP_E_UNKNOWN_ERROR = -256
+ MOBILEBACKUP_E_SUCCESS = 0,
+ MOBILEBACKUP_E_INVALID_ARG = -1,
+ MOBILEBACKUP_E_PLIST_ERROR = -2,
+ MOBILEBACKUP_E_MUX_ERROR = -3,
+ MOBILEBACKUP_E_SSL_ERROR = -4,
+ MOBILEBACKUP_E_RECEIVE_TIMEOUT = -5,
+ MOBILEBACKUP_E_BAD_VERSION = -6,
+ MOBILEBACKUP_E_REPLY_NOT_OK = -7,
+ 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,
@@ -65,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.
@@ -80,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
@@ -91,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);
/**
@@ -102,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
@@ -115,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.
@@ -134,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.
@@ -145,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.
@@ -168,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
@@ -188,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
@@ -208,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
@@ -221,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.
@@ -233,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 0c42334..2e9222d 100644
--- a/include/libimobiledevice/mobilebackup2.h
+++ b/include/libimobiledevice/mobilebackup2.h
@@ -3,8 +3,8 @@
* @brief Backup and restore of all device data (mobilebackup2, iOS4+ only)
* \internal
*
- * Copyright (c) 2011-2014 Martin Szulecki All Rights Reserved.
- * Copyright (c) 2010-2012 Nikias Bassen All Rights Reserved.
+ * Copyright (c) 2010-2019 Nikias Bassen, All Rights Reserved.
+ * Copyright (c) 2011-2014 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
@@ -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 */
@@ -39,13 +40,15 @@ typedef enum {
MOBILEBACKUP2_E_INVALID_ARG = -1,
MOBILEBACKUP2_E_PLIST_ERROR = -2,
MOBILEBACKUP2_E_MUX_ERROR = -3,
- MOBILEBACKUP2_E_BAD_VERSION = -4,
- MOBILEBACKUP2_E_REPLY_NOT_OK = -5,
- MOBILEBACKUP2_E_NO_COMMON_VERSION = -6,
+ MOBILEBACKUP2_E_SSL_ERROR = -4,
+ MOBILEBACKUP2_E_RECEIVE_TIMEOUT = -5,
+ MOBILEBACKUP2_E_BAD_VERSION = -6,
+ MOBILEBACKUP2_E_REPLY_NOT_OK = -7,
+ MOBILEBACKUP2_E_NO_COMMON_VERSION = -8,
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. */
@@ -61,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.
@@ -76,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
@@ -87,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);
/**
@@ -102,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.
@@ -122,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.
@@ -140,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.
@@ -154,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.
@@ -173,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.
@@ -188,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.
@@ -202,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 e6885c7..c3bc53d 100644
--- a/include/libimobiledevice/mobilesync.h
+++ b/include/libimobiledevice/mobilesync.h
@@ -3,8 +3,8 @@
* @brief Synchronize data classes with a device and computer.
* \internal
*
+ * Copyright (c) 2010-2019 Nikias Bassen, All Rights Reserved.
* Copyright (c) 2010-2014 Martin Szulecki All Rights Reserved.
- * Copyright (c) 2010-2011 Nikias Bassen All Rights Reserved.
* Copyright (c) 2014 Christophe Fergeau All Rights Reserved.
* Copyright (c) 2010 Bryan Forbes All Rights Reserved.
* Copyright (c) 2009 Jonathan Beck All Rights Reserved.
@@ -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 */
@@ -42,11 +43,13 @@ typedef enum {
MOBILESYNC_E_INVALID_ARG = -1,
MOBILESYNC_E_PLIST_ERROR = -2,
MOBILESYNC_E_MUX_ERROR = -3,
- MOBILESYNC_E_BAD_VERSION = -4,
- MOBILESYNC_E_SYNC_REFUSED = -5,
- MOBILESYNC_E_CANCELLED = -6,
- MOBILESYNC_E_WRONG_DIRECTION = -7,
- MOBILESYNC_E_NOT_READY = -8,
+ MOBILESYNC_E_SSL_ERROR = -4,
+ MOBILESYNC_E_RECEIVE_TIMEOUT = -5,
+ MOBILESYNC_E_BAD_VERSION = -6,
+ MOBILESYNC_E_SYNC_REFUSED = -7,
+ MOBILESYNC_E_CANCELLED = -8,
+ MOBILESYNC_E_WRONG_DIRECTION = -9,
+ MOBILESYNC_E_NOT_READY = -10,
MOBILESYNC_E_UNKNOWN_ERROR = -256
} mobilesync_error_t;
@@ -57,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 */
@@ -81,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.
@@ -96,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
@@ -107,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);
/**
@@ -118,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
@@ -131,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);
/**
@@ -154,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.
@@ -165,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.
@@ -178,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);
/**
@@ -191,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.
@@ -203,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
@@ -216,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);
/**
@@ -232,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
@@ -242,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);
/**
@@ -262,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);
/**
@@ -279,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.
@@ -296,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 */
@@ -309,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);
/**
@@ -324,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.
@@ -338,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 897c07c..859dc98 100644
--- a/include/libimobiledevice/restore.h
+++ b/include/libimobiledevice/restore.h
@@ -35,17 +35,14 @@ extern "C" {
typedef enum {
RESTORE_E_SUCCESS = 0,
RESTORE_E_INVALID_ARG = -1,
- RESTORE_E_INVALID_CONF = -2,
- RESTORE_E_PLIST_ERROR = -3,
- RESTORE_E_DICT_ERROR = -4,
- RESTORE_E_NOT_ENOUGH_DATA = -5,
- RESTORE_E_MUX_ERROR = -6,
- RESTORE_E_START_RESTORE_FAILED = -7,
- RESTORE_E_DEVICE_ERROR = -8,
+ RESTORE_E_PLIST_ERROR = -2,
+ RESTORE_E_MUX_ERROR = -3,
+ RESTORE_E_NOT_ENOUGH_DATA = -4,
+ RESTORE_E_RECEIVE_TIMEOUT = -5,
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 */
@@ -59,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
@@ -69,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);
/**
@@ -82,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.
@@ -93,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.
@@ -104,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.
@@ -118,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.
@@ -129,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.
@@ -139,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);
/**
@@ -152,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.
@@ -162,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 */
@@ -173,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 c12646b..db3c969 100644
--- a/include/libimobiledevice/screenshotr.h
+++ b/include/libimobiledevice/screenshotr.h
@@ -4,8 +4,8 @@
* @note Requires a mounted developer image.
* \internal
*
- * Copyright (c) 2010-2014 Martin Szulecki All Rights Reserved.
- * Copyright (c) 2010 Nikias Bassen All Rights Reserved.
+ * Copyright (c) 2010-2019 Nikias Bassen, All Rights Reserved.
+ * Copyright (c) 2010-2014 Martin Szulecki, All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -32,19 +32,22 @@ 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 */
typedef enum {
- SCREENSHOTR_E_SUCCESS = 0,
- SCREENSHOTR_E_INVALID_ARG = -1,
- SCREENSHOTR_E_PLIST_ERROR = -2,
- SCREENSHOTR_E_MUX_ERROR = -3,
- SCREENSHOTR_E_BAD_VERSION = -4,
- SCREENSHOTR_E_UNKNOWN_ERROR = -256
+ SCREENSHOTR_E_SUCCESS = 0,
+ SCREENSHOTR_E_INVALID_ARG = -1,
+ SCREENSHOTR_E_PLIST_ERROR = -2,
+ SCREENSHOTR_E_MUX_ERROR = -3,
+ SCREENSHOTR_E_SSL_ERROR = -4,
+ SCREENSHOTR_E_RECEIVE_TIMEOUT = -5,
+ SCREENSHOTR_E_BAD_VERSION = -6,
+ 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. */
@@ -63,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.
@@ -78,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
@@ -89,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);
/**
@@ -106,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 84c5092..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,18 +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, optionally without sending SSL terminate messages.
+ *
+ * @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.
+ */
+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 ea7b649..0f6487a 100644
--- a/include/libimobiledevice/syslog_relay.h
+++ b/include/libimobiledevice/syslog_relay.h
@@ -3,7 +3,8 @@
* @brief Capture the syslog output from a device.
* \internal
*
- * Copyright (c) 2013-2014 Martin Szulecki All Rights Reserved.
+ * Copyright (c) 2019-2020 Nikias Bassen, All Rights Reserved.
+ * Copyright (c) 2013-2014 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
@@ -30,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 */
@@ -43,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. */
@@ -63,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.
@@ -78,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
@@ -89,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);
/**
@@ -106,7 +108,28 @@ 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.
+ * This function is like syslog_relay_start_capture with the difference that
+ * it will neither check nor process the received data before passing it to
+ * the callback function.
+ *
+ * Use syslog_relay_stop_capture() to stop receiving the syslog.
+ *
+ * @note Use syslog_relay_start_capture for a safer implementation.
+ *
+ * @param client The syslog_relay client to use
+ * @param callback Callback to receive each character from the syslog.
+ * @param user_data Custom pointer passed to the callback function.
+ *
+ * @return SYSLOG_RELAY_E_SUCCESS on success,
+ * SYSLOG_RELAY_E_INVALID_ARG when one or more parameters are
+ * invalid or SYSLOG_RELAY_E_UNKNOWN_ERROR when an unspecified
+ * error occurs or a syslog capture has already been started.
+ */
+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.
@@ -120,7 +143,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_stop_capture(syslog_relay_client_t client);
+LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_stop_capture(syslog_relay_client_t client);
/* Receiving */
@@ -139,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.
@@ -148,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 3b4c9a7..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([cannot 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])
@@ -59,7 +59,7 @@ AC_DEFUN([AC_PROG_CYTHON],[
CYTHON='echo "Error: Cython version >= $1 is required. You have '"$cython_version"'. You should look at http://www.cython.org" ; false'
fi
else
- AC_MSG_WARN([cannot determine Cython version])
+ AC_MSG_WARN([Unable to determine Cython version])
CYTHON=false
fi
fi
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 5fcf097..58cf07c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,40 +1,68 @@
-AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)
+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) $(libusbmuxd_CFLAGS) $(libgnutls_CFLAGS) $(libtasn1_CFLAGS) $(libplist_CFLAGS) $(LFS_CFLAGS) $(openssl_CFLAGS) $(PTHREAD_CFLAGS)
-AM_LDFLAGS = $(libgnutls_LIBS) $(libtasn1_LIBS) $(libplist_LIBS) $(libusbmuxd_LIBS) $(libgcrypt_LIBS) $(openssl_LIBS) $(PTHREAD_LIBS)
+AM_CFLAGS = \
+ $(GLOBAL_CFLAGS) \
+ $(ssl_lib_CFLAGS) \
+ $(LFS_CFLAGS) \
+ $(PTHREAD_CFLAGS) \
+ $(libusbmuxd_CFLAGS) \
+ $(libplist_CFLAGS) \
+ $(limd_glue_CFLAGS)
-lib_LTLIBRARIES = libimobiledevice.la
-libimobiledevice_la_LIBADD = $(top_builddir)/common/libinternalcommon.la
-libimobiledevice_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(LIBIMOBILEDEVICE_SO_VERSION) -no-undefined
-libimobiledevice_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\
- afc.c afc.h\
- file_relay.c file_relay.h\
- notification_proxy.c notification_proxy.h\
- installation_proxy.c installation_proxy.h\
- sbservices.c sbservices.h\
- mobile_image_mounter.c mobile_image_mounter.h\
- screenshotr.c screenshotr.h\
- mobilesync.c mobilesync.h\
- mobilebackup.c mobilebackup.h\
- house_arrest.c house_arrest.h\
- mobilebackup2.c mobilebackup2.h\
- misagent.c misagent.h\
- restore.c restore.h\
- diagnostics_relay.c diagnostics_relay.h\
- heartbeat.c heartbeat.h\
- debugserver.c debugserver.h\
- webinspector.c webinspector.h\
- mobileactivation.c mobileactivation.h\
- preboard.c preboard.h \
- syslog_relay.c syslog_relay.h
+AM_LDFLAGS = \
+ $(ssl_lib_LIBS) \
+ $(PTHREAD_LIBS) \
+ $(libusbmuxd_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 \
+ installation_proxy.c installation_proxy.h \
+ sbservices.c sbservices.h \
+ mobile_image_mounter.c mobile_image_mounter.h \
+ screenshotr.c screenshotr.h \
+ mobilesync.c mobilesync.h \
+ mobilebackup.c mobilebackup.h \
+ house_arrest.c house_arrest.h \
+ mobilebackup2.c mobilebackup2.h \
+ misagent.c misagent.h \
+ restore.c restore.h \
+ diagnostics_relay.c diagnostics_relay.h \
+ heartbeat.c heartbeat.h \
+ debugserver.c debugserver.h \
+ webinspector.c webinspector.h \
+ mobileactivation.c mobileactivation.h \
+ preboard.c preboard.h \
+ companion_proxy.c companion_proxy.h \
+ reverse_proxy.c reverse_proxy.h \
+ syslog_relay.c syslog_relay.h \
+ bt_packet_logger.c bt_packet_logger.h
if WIN32
-libimobiledevice_la_LDFLAGS += -avoid-version
-libimobiledevice_la_LIBADD += -lole32 -lws2_32 -lgdi32
+libimobiledevice_1_0_la_LDFLAGS += -avoid-version -static-libgcc
+libimobiledevice_1_0_la_LIBADD += -lole32 -lws2_32 -lgdi32
endif
pkgconfigdir = $(libdir)/pkgconfig
diff --git a/src/afc.c b/src/afc.c
index d83b50d..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;
@@ -78,25 +78,23 @@ LIBIMOBILEDEVICE_API afc_error_t afc_client_new_with_service_client(service_clie
client_loc->free_parent = 0;
/* allocate a packet */
- client_loc->afc_packet = (AFCPacket *) malloc(sizeof(AFCPacket));
+ client_loc->packet_extra = 1024;
+ client_loc->afc_packet = (AFCPacket *) malloc(sizeof(AFCPacket) + client_loc->packet_extra);
if (!client_loc->afc_packet) {
free(client_loc);
return AFC_E_NO_MEM;
}
-
client_loc->afc_packet->packet_num = 0;
client_loc->afc_packet->entire_length = 0;
client_loc->afc_packet->this_length = 0;
memcpy(client_loc->afc_packet->magic, AFC_MAGIC, AFC_MAGIC_LEN);
- client_loc->file_handle = 0;
- client_loc->lock = 0;
mutex_init(&client_loc->mutex);
*client = client_loc;
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;
@@ -115,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;
@@ -150,7 +148,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_client_free(afc_client_t client)
*
* @return AFC_E_SUCCESS on success or an AFC_E_* error value.
*/
-static afc_error_t afc_dispatch_packet(afc_client_t client, uint64_t operation, const char *data, uint32_t data_length, const char* payload, uint32_t payload_length, uint32_t *bytes_sent)
+static afc_error_t afc_dispatch_packet(afc_client_t client, uint64_t operation, uint32_t data_length, const char* payload, uint32_t payload_length, uint32_t *bytes_sent)
{
uint32_t sent = 0;
@@ -159,8 +157,6 @@ static afc_error_t afc_dispatch_packet(afc_client_t client, uint64_t operation,
*bytes_sent = 0;
- if (!data || !data_length)
- data_length = 0;
if (!payload || !payload_length)
payload_length = 0;
@@ -171,34 +167,26 @@ static afc_error_t afc_dispatch_packet(afc_client_t client, uint64_t operation,
debug_info("packet length = %i", client->afc_packet->this_length);
- debug_buffer((char*)client->afc_packet, sizeof(AFCPacket));
-
- /* send AFC packet header */
+ /* send AFC packet header and data */
AFCPacket_to_LE(client->afc_packet);
+ debug_buffer((char*)client->afc_packet, sizeof(AFCPacket) + data_length);
sent = 0;
- service_send(client->parent, (void*)client->afc_packet, sizeof(AFCPacket), &sent);
+ service_send(client->parent, (void*)client->afc_packet, sizeof(AFCPacket) + data_length, &sent);
AFCPacket_from_LE(client->afc_packet);
*bytes_sent += sent;
- if (sent < sizeof(AFCPacket)) {
- return AFC_E_SUCCESS;
- }
-
- /* send AFC packet data (if there's data to send) */
- sent = 0;
- if (data_length > 0) {
- debug_info("packet data follows");
- debug_buffer(data, data_length);
- service_send(client->parent, data, data_length, &sent);
- }
- *bytes_sent += sent;
- if (sent < data_length) {
+ if (sent < sizeof(AFCPacket) + data_length) {
return AFC_E_SUCCESS;
}
sent = 0;
if (payload_length > 0) {
- debug_info("packet payload follows");
- debug_buffer(payload, payload_length);
+ if (payload_length > 256) {
+ debug_info("packet payload follows (256/%u)", payload_length);
+ debug_buffer(payload, 256);
+ } else {
+ debug_info("packet payload follows");
+ debug_buffer(payload, payload_length);
+ }
service_send(client->parent, payload, payload_length, &sent);
}
*bytes_sent += sent;
@@ -225,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;
@@ -235,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 ")!");
}
@@ -261,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);
@@ -277,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;
}
@@ -295,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);
@@ -308,12 +301,17 @@ 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);
- debug_info("packet data follows");
- debug_buffer(dump_here, current_count);
+ if (current_count > 256) {
+ debug_info("packet data follows (256/%u)", current_count);
+ debug_buffer(buf, 256);
+ } else {
+ debug_info("packet data follows");
+ debug_buffer(buf, current_count);
+ }
/* check operation types */
if (header.operation == AFC_OP_STATUS) {
@@ -323,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) {
@@ -337,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
@@ -349,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;
@@ -361,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;
@@ -402,7 +399,22 @@ static char **make_strings_list(char *tokens, uint32_t length)
return list;
}
-LIBIMOBILEDEVICE_API afc_error_t afc_read_directory(afc_client_t client, const char *path, char ***directory_information)
+static int _afc_check_packet_buffer(afc_client_t client, uint32_t data_len)
+{
+ if (data_len > client->packet_extra) {
+ client->packet_extra = (data_len & ~8) + 8;
+ AFCPacket* newpkt = (AFCPacket*)realloc(client->afc_packet, sizeof(AFCPacket) + client->packet_extra);
+ if (!newpkt) {
+ return -1;
+ }
+ client->afc_packet = newpkt;
+ }
+ return 0;
+}
+
+#define AFC_PACKET_DATA_PTR ((char*)client->afc_packet + sizeof(AFCPacket))
+
+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;
@@ -413,8 +425,16 @@ LIBIMOBILEDEVICE_API afc_error_t afc_read_directory(afc_client_t client, const c
afc_lock(client);
+ uint32_t data_len = (uint32_t)strlen(path)+1;
+ if (_afc_check_packet_buffer(client, data_len) < 0) {
+ afc_unlock(client);
+ debug_info("Failed to realloc packet buffer");
+ return AFC_E_NO_MEM;
+ }
+
/* Send the command */
- ret = afc_dispatch_packet(client, AFC_OP_READ_DIR, path, strlen(path)+1, NULL, 0, &bytes);
+ memcpy(AFC_PACKET_DATA_PTR, path, data_len);
+ ret = afc_dispatch_packet(client, AFC_OP_READ_DIR, data_len, NULL, 0, &bytes);
if (ret != AFC_E_SUCCESS) {
afc_unlock(client);
return AFC_E_NOT_ENOUGH_DATA;
@@ -438,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;
@@ -450,7 +470,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_get_device_info(afc_client_t client, char *
afc_lock(client);
/* Send the command */
- ret = afc_dispatch_packet(client, AFC_OP_GET_DEVINFO, NULL, 0, NULL, 0, &bytes);
+ ret = afc_dispatch_packet(client, AFC_OP_GET_DEVINFO, 0, NULL, 0, &bytes);
if (ret != AFC_E_SUCCESS) {
afc_unlock(client);
return AFC_E_NOT_ENOUGH_DATA;
@@ -475,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;
@@ -502,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;
@@ -512,8 +532,16 @@ LIBIMOBILEDEVICE_API afc_error_t afc_remove_path(afc_client_t client, const char
afc_lock(client);
+ uint32_t data_len = (uint32_t)strlen(path)+1;
+ if (_afc_check_packet_buffer(client, data_len) < 0) {
+ afc_unlock(client);
+ debug_info("Failed to realloc packet buffer");
+ return AFC_E_NO_MEM;
+ }
+
/* Send command */
- ret = afc_dispatch_packet(client, AFC_OP_REMOVE_PATH, path, strlen(path)+1, NULL, 0, &bytes);
+ memcpy(AFC_PACKET_DATA_PTR, path, data_len);
+ ret = afc_dispatch_packet(client, AFC_OP_REMOVE_PATH, data_len, NULL, 0, &bytes);
if (ret != AFC_E_SUCCESS) {
afc_unlock(client);
return AFC_E_NOT_ENOUGH_DATA;
@@ -530,23 +558,30 @@ 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;
- char *buffer = (char *) malloc(sizeof(char) * (strlen(from) + strlen(to) + 1 + sizeof(uint32_t)));
uint32_t bytes = 0;
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
+ size_t from_len = strlen(from);
+ size_t to_len = strlen(to);
+
afc_lock(client);
- /* Send command */
- memcpy(buffer, from, strlen(from) + 1);
- memcpy(buffer + strlen(from) + 1, to, strlen(to) + 1);
- ret = afc_dispatch_packet(client, AFC_OP_RENAME_PATH, buffer, strlen(to)+1 + strlen(from)+1, NULL, 0, &bytes);
- free(buffer);
+ uint32_t data_len = (uint32_t)(from_len+1 + to_len+1);
+ if (_afc_check_packet_buffer(client, data_len) < 0) {
+ afc_unlock(client);
+ debug_info("Failed to realloc packet buffer");
+ return AFC_E_NO_MEM;
+ }
+ /* Send command */
+ memcpy(AFC_PACKET_DATA_PTR, from, from_len+1);
+ memcpy(AFC_PACKET_DATA_PTR + from_len+1, to, to_len+1);
+ ret = afc_dispatch_packet(client, AFC_OP_RENAME_PATH, data_len, NULL, 0, &bytes);
if (ret != AFC_E_SUCCESS) {
afc_unlock(client);
return AFC_E_NOT_ENOUGH_DATA;
@@ -559,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;
@@ -569,8 +604,16 @@ LIBIMOBILEDEVICE_API afc_error_t afc_make_directory(afc_client_t client, const c
afc_lock(client);
+ uint32_t data_len = (uint32_t)strlen(path)+1;
+ if (_afc_check_packet_buffer(client, data_len) < 0) {
+ afc_unlock(client);
+ debug_info("Failed to realloc packet buffer");
+ return AFC_E_NO_MEM;
+ }
+
/* Send command */
- ret = afc_dispatch_packet(client, AFC_OP_MAKE_DIR, path, strlen(path)+1, NULL, 0, &bytes);
+ memcpy(AFC_PACKET_DATA_PTR, path, data_len);
+ ret = afc_dispatch_packet(client, AFC_OP_MAKE_DIR, data_len, NULL, 0, &bytes);
if (ret != AFC_E_SUCCESS) {
afc_unlock(client);
return AFC_E_NOT_ENOUGH_DATA;
@@ -583,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;
@@ -594,8 +637,18 @@ LIBIMOBILEDEVICE_API afc_error_t afc_get_file_info(afc_client_t client, const ch
afc_lock(client);
+ uint32_t data_len = (uint32_t)strlen(path)+1;
+ if (_afc_check_packet_buffer(client, data_len) < 0) {
+ afc_unlock(client);
+ debug_info("Failed to realloc packet buffer");
+ return AFC_E_NO_MEM;
+ }
+
+ debug_info("We got %p and %p", client->afc_packet, AFC_PACKET_DATA_PTR);
+
/* Send command */
- ret = afc_dispatch_packet(client, AFC_OP_GET_FILE_INFO, path, strlen(path)+1, NULL, 0, &bytes);
+ memcpy(AFC_PACKET_DATA_PTR, path, data_len);
+ ret = afc_dispatch_packet(client, AFC_OP_GET_FILE_INFO, data_len, NULL, 0, &bytes);
if (ret != AFC_E_SUCCESS) {
afc_unlock(client);
return AFC_E_NOT_ENOUGH_DATA;
@@ -613,14 +666,13 @@ 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;
- uint64_t file_mode_loc = htole64(file_mode);
+ //uint64_t file_mode_loc = htole64(file_mode);
uint32_t bytes = 0;
- char *data = (char *) malloc(sizeof(char) * (8 + strlen(filename) + 1));
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
/* set handle to 0 so in case an error occurs, the handle is invalid */
@@ -628,20 +680,25 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_open(afc_client_t client, const char *
afc_lock(client);
- /* Send command */
- memcpy(data, &file_mode_loc, 8);
- memcpy(data + 8, filename, strlen(filename));
- data[8 + strlen(filename)] = '\0';
- ret = afc_dispatch_packet(client, AFC_OP_FILE_OPEN, data, 8 + strlen(filename) + 1, NULL, 0, &bytes);
- free(data);
+ uint32_t data_len = (uint32_t)(strlen(filename)+1 + 8);
+ if (_afc_check_packet_buffer(client, data_len) < 0) {
+ afc_unlock(client);
+ debug_info("Failed to realloc packet buffer");
+ return AFC_E_NO_MEM;
+ }
+ /* Send command */
+ //memcpy(AFC_PACKET_DATA_PTR, &file_mode_loc, 8);
+ *(uint64_t*)(AFC_PACKET_DATA_PTR) = htole64(file_mode);
+ memcpy(AFC_PACKET_DATA_PTR + 8, filename, data_len-8);
+ ret = afc_dispatch_packet(client, AFC_OP_FILE_OPEN, data_len, NULL, 0, &bytes);
if (ret != AFC_E_SUCCESS) {
debug_info("Didn't receive a response to the command");
afc_unlock(client);
return AFC_E_NOT_ENOUGH_DATA;
}
/* Receive the data */
- data = NULL;
+ char* data = NULL;
ret = afc_receive_data(client, &data, &bytes);
if ((ret == AFC_E_SUCCESS) && (bytes > 0) && data) {
afc_unlock(client);
@@ -661,27 +718,29 @@ 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;
+ struct readinfo {
+ uint64_t handle;
+ uint64_t size;
+ };
afc_error_t ret = AFC_E_SUCCESS;
if (!client || !client->afc_packet || !client->parent || handle == 0)
return AFC_E_INVALID_ARG;
debug_info("called for length %i", length);
+ //uint32_t data_len = 8 + 8;
+
afc_lock(client);
/* Send the read command */
- struct {
- uint64_t handle;
- uint64_t size;
- } readinfo;
- readinfo.handle = handle;
- readinfo.size = htole64(length);
- ret = afc_dispatch_packet(client, AFC_OP_FILE_READ, (const char*)&readinfo, sizeof(readinfo), NULL, 0, &bytes_loc);
-
+ struct readinfo* readinfo = (struct readinfo*)(AFC_PACKET_DATA_PTR);
+ readinfo->handle = handle;
+ readinfo->size = htole64(length);
+ ret = afc_dispatch_packet(client, AFC_OP_FILE_READ, sizeof(struct readinfo), NULL, 0, &bytes_loc);
if (ret != AFC_E_SUCCESS) {
afc_unlock(client);
return AFC_E_NOT_ENOUGH_DATA;
@@ -693,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;
@@ -723,11 +783,14 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_write(afc_client_t client, uint64_t ha
if (!client || !client->afc_packet || !client->parent || !bytes_written || (handle == 0))
return AFC_E_INVALID_ARG;
+ uint32_t data_len = 8;
+
afc_lock(client);
debug_info("Write length: %i", length);
- ret = afc_dispatch_packet(client, AFC_OP_FILE_WRITE, (const char*)&handle, 8, data, length, &bytes_loc);
+ *(uint64_t*)(AFC_PACKET_DATA_PTR) = handle;
+ ret = afc_dispatch_packet(client, AFC_OP_FILE_WRITE, data_len, data, length, &bytes_loc);
current_count += bytes_loc - (sizeof(AFCPacket) + 8);
@@ -740,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;
@@ -754,12 +817,15 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_close(afc_client_t client, uint64_t ha
if (!client || (handle == 0))
return AFC_E_INVALID_ARG;
+ uint32_t data_len = 8;
+
afc_lock(client);
debug_info("File handle %i", handle);
/* Send command */
- ret = afc_dispatch_packet(client, AFC_OP_FILE_CLOSE, (const char*)&handle, 8, NULL, 0, &bytes);
+ *(uint64_t*)(AFC_PACKET_DATA_PTR) = handle;
+ ret = afc_dispatch_packet(client, AFC_OP_FILE_CLOSE, data_len, NULL, 0, &bytes);
if (ret != AFC_E_SUCCESS) {
afc_unlock(client);
@@ -774,13 +840,13 @@ 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 {
+ struct lockinfo {
uint64_t handle;
uint64_t op;
- } lockinfo;
+ };
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
if (!client || (handle == 0))
@@ -791,10 +857,10 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_lock(afc_client_t client, uint64_t han
debug_info("file handle %i", handle);
/* Send command */
- lockinfo.handle = handle;
- lockinfo.op = htole64(operation);
- ret = afc_dispatch_packet(client, AFC_OP_FILE_LOCK, (const char*)&lockinfo, sizeof(lockinfo), NULL, 0, &bytes);
-
+ struct lockinfo* lockinfo = (struct lockinfo*)(AFC_PACKET_DATA_PTR);
+ lockinfo->handle = handle;
+ lockinfo->op = htole64(operation);
+ ret = afc_dispatch_packet(client, AFC_OP_FILE_LOCK, sizeof(struct lockinfo), NULL, 0, &bytes);
if (ret != AFC_E_SUCCESS) {
afc_unlock(client);
debug_info("could not send lock command");
@@ -808,14 +874,14 @@ 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 {
+ struct seekinfo {
uint64_t handle;
uint64_t whence;
int64_t offset;
- } seekinfo;
+ };
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
if (!client || (handle == 0))
@@ -824,10 +890,11 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_seek(afc_client_t client, uint64_t han
afc_lock(client);
/* Send the command */
- seekinfo.handle = handle;
- seekinfo.whence = htole64(whence);
- seekinfo.offset = (int64_t)htole64(offset);
- ret = afc_dispatch_packet(client, AFC_OP_FILE_SEEK, (const char*)&seekinfo, sizeof(seekinfo), NULL, 0, &bytes);
+ struct seekinfo* seekinfo = (struct seekinfo*)(AFC_PACKET_DATA_PTR);
+ seekinfo->handle = handle;
+ seekinfo->whence = htole64(whence);
+ seekinfo->offset = (int64_t)htole64(offset);
+ ret = afc_dispatch_packet(client, AFC_OP_FILE_SEEK, sizeof(struct seekinfo), NULL, 0, &bytes);
if (ret != AFC_E_SUCCESS) {
afc_unlock(client);
@@ -841,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;
@@ -850,11 +917,13 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_tell(afc_client_t client, uint64_t han
if (!client || (handle == 0))
return AFC_E_INVALID_ARG;
+ uint32_t data_len = 8;
+
afc_lock(client);
/* Send the command */
- ret = afc_dispatch_packet(client, AFC_OP_FILE_TELL, (const char*)&handle, 8, NULL, 0, &bytes);
-
+ *(uint64_t*)(AFC_PACKET_DATA_PTR) = handle;
+ ret = afc_dispatch_packet(client, AFC_OP_FILE_TELL, data_len, NULL, 0, &bytes);
if (ret != AFC_E_SUCCESS) {
afc_unlock(client);
return AFC_E_NOT_ENOUGH_DATA;
@@ -874,13 +943,13 @@ 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 {
+ struct truncinfo {
uint64_t handle;
uint64_t newsize;
- } truncinfo;
+ };
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
if (!client || (handle == 0))
@@ -889,9 +958,10 @@ LIBIMOBILEDEVICE_API afc_error_t afc_file_truncate(afc_client_t client, uint64_t
afc_lock(client);
/* Send command */
- truncinfo.handle = handle;
- truncinfo.newsize = htole64(newsize);
- ret = afc_dispatch_packet(client, AFC_OP_FILE_SET_SIZE, (const char*)&truncinfo, sizeof(truncinfo), NULL, 0, &bytes);
+ struct truncinfo* truncinfo = (struct truncinfo*)(AFC_PACKET_DATA_PTR);
+ truncinfo->handle = handle;
+ truncinfo->newsize = htole64(newsize);
+ ret = afc_dispatch_packet(client, AFC_OP_FILE_SET_SIZE, sizeof(struct truncinfo), NULL, 0, &bytes);
if (ret != AFC_E_SUCCESS) {
afc_unlock(client);
@@ -905,24 +975,27 @@ 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;
- char *buffer = (char *) malloc(sizeof(char) * (strlen(path) + 1 + 8));
uint32_t bytes = 0;
- uint64_t size_requested = htole64(newsize);
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
afc_lock(client);
- /* Send command */
- memcpy(buffer, &size_requested, 8);
- memcpy(buffer + 8, path, strlen(path) + 1);
- ret = afc_dispatch_packet(client, AFC_OP_TRUNCATE, buffer, 8 + strlen(path) + 1, NULL, 0, &bytes);
- free(buffer);
+ uint32_t data_len = 8 + (uint32_t)(strlen(path)+1);
+ if (_afc_check_packet_buffer(client, data_len) < 0) {
+ afc_unlock(client);
+ debug_info("Failed to realloc packet buffer");
+ return AFC_E_NO_MEM;
+ }
+ /* Send command */
+ *(uint64_t*)(AFC_PACKET_DATA_PTR) = htole64(newsize);
+ memcpy(AFC_PACKET_DATA_PTR + 8, path, data_len-8);
+ ret = afc_dispatch_packet(client, AFC_OP_TRUNCATE, data_len, NULL, 0, &bytes);
if (ret != AFC_E_SUCCESS) {
afc_unlock(client);
return AFC_E_NOT_ENOUGH_DATA;
@@ -935,28 +1008,35 @@ 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;
- char *buffer = (char *) malloc(sizeof(char) * (strlen(target)+1 + strlen(linkname)+1 + 8));
uint32_t bytes = 0;
- uint64_t type = htole64(linktype);
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
+ size_t target_len = strlen(target);
+ size_t link_len = strlen(linkname);
+
afc_lock(client);
- debug_info("link type: %lld", type);
- debug_info("target: %s, length:%d", target, strlen(target));
- debug_info("linkname: %s, length:%d", linkname, strlen(linkname));
+ uint32_t data_len = 8 + target_len + 1 + link_len + 1;
+ if (_afc_check_packet_buffer(client, data_len) < 0) {
+ afc_unlock(client);
+ debug_info("Failed to realloc packet buffer");
+ return AFC_E_NO_MEM;
+ }
+
+ 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);
/* Send command */
- memcpy(buffer, &type, 8);
- memcpy(buffer + 8, target, strlen(target) + 1);
- memcpy(buffer + 8 + strlen(target) + 1, linkname, strlen(linkname) + 1);
- ret = afc_dispatch_packet(client, AFC_OP_MAKE_LINK, buffer, 8 + strlen(linkname) + 1 + strlen(target) + 1, NULL, 0, &bytes);
- free(buffer);
+ *(uint64_t*)(AFC_PACKET_DATA_PTR) = htole64(linktype);
+ memcpy(AFC_PACKET_DATA_PTR + 8, target, target_len + 1);
+ memcpy(AFC_PACKET_DATA_PTR + 8 + target_len + 1, linkname, link_len + 1);
+ ret = afc_dispatch_packet(client, AFC_OP_MAKE_LINK, data_len, NULL, 0, &bytes);
if (ret != AFC_E_SUCCESS) {
afc_unlock(client);
return AFC_E_NOT_ENOUGH_DATA;
@@ -969,23 +1049,27 @@ 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;
- char *buffer = (char *) malloc(sizeof(char) * (strlen(path) + 1 + 8));
uint32_t bytes = 0;
- uint64_t mtime_loc = htole64(mtime);
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
afc_lock(client);
+ uint32_t data_len = 8 + strlen(path) + 1;
+ if (_afc_check_packet_buffer(client, data_len) < 0) {
+ afc_unlock(client);
+ debug_info("Failed to realloc packet buffer");
+ return AFC_E_NO_MEM;
+ }
+
/* Send command */
- memcpy(buffer, &mtime_loc, 8);
- memcpy(buffer + 8, path, strlen(path) + 1);
- ret = afc_dispatch_packet(client, AFC_OP_SET_FILE_MOD_TIME, buffer, 8 + strlen(path) + 1, NULL, 0, &bytes);
- free(buffer);
+ *(uint64_t*)(AFC_PACKET_DATA_PTR) = htole64(mtime);
+ memcpy(AFC_PACKET_DATA_PTR + 8, path, data_len-8);
+ ret = afc_dispatch_packet(client, AFC_OP_SET_FILE_MOD_TIME, data_len, NULL, 0, &bytes);
if (ret != AFC_E_SUCCESS) {
afc_unlock(client);
return AFC_E_NOT_ENOUGH_DATA;
@@ -998,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;
@@ -1008,8 +1092,16 @@ LIBIMOBILEDEVICE_API afc_error_t afc_remove_path_and_contents(afc_client_t clien
afc_lock(client);
+ uint32_t data_len = strlen(path) + 1;
+ if (_afc_check_packet_buffer(client, data_len) < 0) {
+ afc_unlock(client);
+ debug_info("Failed to realloc packet buffer");
+ return AFC_E_NO_MEM;
+ }
+
/* Send command */
- ret = afc_dispatch_packet(client, AFC_OP_REMOVE_PATH_AND_CONTENTS, path, strlen(path)+1, NULL, 0, &bytes);
+ memcpy(AFC_PACKET_DATA_PTR, path, data_len);
+ ret = afc_dispatch_packet(client, AFC_OP_REMOVE_PATH_AND_CONTENTS, data_len, NULL, 0, &bytes);
if (ret != AFC_E_SUCCESS) {
afc_unlock(client);
return AFC_E_NOT_ENOUGH_DATA;
@@ -1022,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;
@@ -1036,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 99c31ca..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)
@@ -53,8 +53,7 @@ typedef struct {
struct afc_client_private {
service_client_t parent;
AFCPacket *afc_packet;
- int file_handle;
- int lock;
+ uint32_t packet_extra;
mutex_t mutex;
int free_parent;
};
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
new file mode 100644
index 0000000..421fa9a
--- /dev/null
+++ b/src/companion_proxy.c
@@ -0,0 +1,380 @@
+/*
+ * companion_proxy.c
+ * com.apple.companion_proxy service implementation.
+ *
+ * Copyright (c) 2019-2020 Nikias Bassen, All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <string.h>
+#include <stdlib.h>
+#include <plist/plist.h>
+
+#include "companion_proxy.h"
+#include "lockdown.h"
+#include "common/debug.h"
+
+/**
+ * Convert a property_list_service_error_t value to a companion_proxy_error_t value.
+ * Used internally to get correct error codes.
+ *
+ * @param err An property_list_service_error_t error code
+ *
+ * @return A matching companion_proxy_error_t error code,
+ * COMPANION_PROXY_E_UNKNOWN_ERROR otherwise.
+ */
+static companion_proxy_error_t companion_proxy_error(property_list_service_error_t err)
+{
+ switch (err) {
+ case PROPERTY_LIST_SERVICE_E_SUCCESS:
+ return COMPANION_PROXY_E_SUCCESS;
+ case PROPERTY_LIST_SERVICE_E_INVALID_ARG:
+ return COMPANION_PROXY_E_INVALID_ARG;
+ case PROPERTY_LIST_SERVICE_E_PLIST_ERROR:
+ return COMPANION_PROXY_E_PLIST_ERROR;
+ case PROPERTY_LIST_SERVICE_E_MUX_ERROR:
+ return COMPANION_PROXY_E_MUX_ERROR;
+ case PROPERTY_LIST_SERVICE_E_SSL_ERROR:
+ return COMPANION_PROXY_E_SSL_ERROR;
+ case PROPERTY_LIST_SERVICE_E_NOT_ENOUGH_DATA:
+ return COMPANION_PROXY_E_NOT_ENOUGH_DATA;
+ case PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT:
+ return COMPANION_PROXY_E_TIMEOUT;
+ default:
+ break;
+ }
+ return COMPANION_PROXY_E_UNKNOWN_ERROR;
+}
+
+companion_proxy_error_t companion_proxy_client_new(idevice_t device, lockdownd_service_descriptor_t service, companion_proxy_client_t * client)
+{
+ *client = NULL;
+
+ if (!device || !service || service->port == 0 || !client || *client) {
+ debug_info("Incorrect parameter passed to companion_proxy_client_new.");
+ return COMPANION_PROXY_E_INVALID_ARG;
+ }
+
+ debug_info("Creating companion_proxy_client, port = %d.", service->port);
+
+ property_list_service_client_t plclient = NULL;
+ companion_proxy_error_t ret = companion_proxy_error(property_list_service_client_new(device, service, &plclient));
+ if (ret != COMPANION_PROXY_E_SUCCESS) {
+ debug_info("Creating a property list client failed. Error: %i", ret);
+ return ret;
+ }
+
+ companion_proxy_client_t client_loc = (companion_proxy_client_t) malloc(sizeof(struct companion_proxy_client_private));
+ client_loc->parent = plclient;
+ client_loc->event_thread = THREAD_T_NULL;
+
+ *client = client_loc;
+
+ debug_info("Created companion_proxy_client successfully.");
+ return COMPANION_PROXY_E_SUCCESS;
+}
+
+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;
+}
+
+companion_proxy_error_t companion_proxy_client_free(companion_proxy_client_t client)
+{
+ if (!client)
+ return COMPANION_PROXY_E_INVALID_ARG;
+
+ property_list_service_client_t parent = client->parent;
+ client->parent = NULL;
+ if (client->event_thread) {
+ debug_info("joining event thread");
+ thread_join(client->event_thread);
+ thread_free(client->event_thread);
+ client->event_thread = THREAD_T_NULL;
+ }
+ companion_proxy_error_t err = companion_proxy_error(property_list_service_client_free(parent));
+ free(client);
+
+ return err;
+}
+
+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;
+
+ res = companion_proxy_error(property_list_service_send_binary_plist(client->parent, plist));
+ if (res != COMPANION_PROXY_E_SUCCESS) {
+ debug_info("Sending plist failed with error %d", res);
+ return res;
+ }
+
+ return res;
+}
+
+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;
+ res = companion_proxy_error(property_list_service_receive_plist_with_timeout(client->parent, &outplist, 10000));
+ if (res != COMPANION_PROXY_E_SUCCESS && res != COMPANION_PROXY_E_TIMEOUT) {
+ debug_info("Could not receive plist, error %d", res);
+ plist_free(outplist);
+ } else if (res == COMPANION_PROXY_E_SUCCESS) {
+ *plist = outplist;
+ }
+ return res;
+}
+
+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;
+ }
+
+ plist_t dict = plist_new_dict();
+ plist_dict_set_item(dict, "Command", plist_new_string("GetDeviceRegistry"));
+
+ companion_proxy_error_t res = companion_proxy_send(client, dict);
+ plist_free(dict);
+ dict = NULL;
+ if (res != COMPANION_PROXY_E_SUCCESS) {
+ return res;
+ }
+
+ res = companion_proxy_receive(client, &dict);
+ if (res != COMPANION_PROXY_E_SUCCESS) {
+ return res;
+ }
+ if (!dict || !PLIST_IS_DICT(dict)) {
+ return COMPANION_PROXY_E_PLIST_ERROR;
+ }
+ plist_t val = plist_dict_get_item(dict, "PairedDevicesArray");
+ if (val) {
+ *paired_devices = plist_copy(val);
+ res = COMPANION_PROXY_E_SUCCESS;
+ } else {
+ res = COMPANION_PROXY_E_UNKNOWN_ERROR;
+ val = plist_dict_get_item(dict, "Error");
+ if (val) {
+ if (plist_string_val_compare(val, "NoPairedWatches")) {
+ res = COMPANION_PROXY_E_NO_DEVICES;
+ }
+ }
+ }
+ plist_free(dict);
+ return res;
+}
+
+struct companion_proxy_cb_data {
+ companion_proxy_client_t client;
+ companion_proxy_device_event_cb_t cbfunc;
+ void* user_data;
+};
+
+static void* companion_proxy_event_thread(void* arg)
+{
+ struct companion_proxy_cb_data* data = (struct companion_proxy_cb_data*)arg;
+ companion_proxy_client_t client = data->client;
+ companion_proxy_error_t res;
+
+ plist_t command = plist_new_dict();
+ plist_dict_set_item(command, "Command", plist_new_string("StartListeningForDevices"));
+ res = companion_proxy_send(client, command);
+ plist_free(command);
+
+ if (res != COMPANION_PROXY_E_SUCCESS) {
+ free(data);
+ client->event_thread = THREAD_T_NULL;
+ return NULL;
+ }
+
+ while (client && client->parent) {
+ plist_t node = NULL;
+ res = companion_proxy_error(property_list_service_receive_plist_with_timeout(client->parent, &node, 1000));
+ if (res != COMPANION_PROXY_E_SUCCESS && res != COMPANION_PROXY_E_TIMEOUT) {
+ debug_info("could not receive plist, error %d", res);
+ break;
+ }
+
+ if (node) {
+ data->cbfunc(node, data->user_data);
+ }
+ plist_free(node);
+ }
+
+ client->event_thread = THREAD_T_NULL;
+ free(data);
+
+ return NULL;
+}
+
+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;
+ }
+
+ if (client->event_thread) {
+ return COMPANION_PROXY_E_OP_IN_PROGRESS;
+ }
+
+ companion_proxy_error_t res = COMPANION_PROXY_E_UNKNOWN_ERROR;
+ struct companion_proxy_cb_data *data = (struct companion_proxy_cb_data*)malloc(sizeof(struct companion_proxy_cb_data));
+ if (data) {
+ data->client = client;
+ data->cbfunc = callback;
+ data->user_data = userdata;
+
+ if (thread_new(&client->event_thread, companion_proxy_event_thread, data) == 0) {
+ res = COMPANION_PROXY_E_SUCCESS;
+ } else {
+ free(data);
+ }
+ }
+ return res;
+}
+
+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;
+ if (client->event_thread) {
+ debug_info("joining event thread");
+ thread_join(client->event_thread);
+ thread_free(client->event_thread);
+ client->event_thread = THREAD_T_NULL;
+ }
+ client->parent = parent;
+ return COMPANION_PROXY_E_SUCCESS;
+}
+
+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;
+ }
+
+ plist_t dict = plist_new_dict();
+ plist_dict_set_item(dict, "Command", plist_new_string("GetValueFromRegistry"));
+ plist_dict_set_item(dict, "GetValueGizmoUDIDKey", plist_new_string(companion_udid));
+ plist_dict_set_item(dict, "GetValueKeyKey", plist_new_string(key));
+
+ companion_proxy_error_t res = companion_proxy_send(client, dict);
+ plist_free(dict);
+ dict = NULL;
+ if (res != COMPANION_PROXY_E_SUCCESS) {
+ return res;
+ }
+
+ res = companion_proxy_receive(client, &dict);
+ if (res != COMPANION_PROXY_E_SUCCESS) {
+ return res;
+ }
+ if (!dict || !PLIST_IS_DICT(dict)) {
+ return COMPANION_PROXY_E_PLIST_ERROR;
+ }
+ plist_t val = plist_dict_get_item(dict, "RetrievedValueDictionary");
+ if (val) {
+ *value = plist_copy(val);
+ res = COMPANION_PROXY_E_SUCCESS;
+ } else {
+ res = COMPANION_PROXY_E_UNKNOWN_ERROR;
+ val = plist_dict_get_item(dict, "Error");
+ if (val) {
+ if (!plist_string_val_compare(val, "UnsupportedWatchKey")) {
+ res = COMPANION_PROXY_E_UNSUPPORTED_KEY;
+ } else if (plist_string_val_compare(val, "TimeoutReply")) {
+ res = COMPANION_PROXY_E_TIMEOUT_REPLY;
+ }
+ }
+ }
+ plist_free(dict);
+ return res;
+}
+
+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;
+ }
+
+ plist_t dict = plist_new_dict();
+ plist_dict_set_item(dict, "Command", plist_new_string("StartForwardingServicePort"));
+ plist_dict_set_item(dict, "GizmoRemotePortNumber", plist_new_uint(remote_port));
+ if (service_name) {
+ plist_dict_set_item(dict, "ForwardedServiceName", plist_new_string(service_name));
+ }
+ 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);
+ }
+
+ companion_proxy_error_t res = companion_proxy_send(client, dict);
+ plist_free(dict);
+ dict = NULL;
+ if (res != COMPANION_PROXY_E_SUCCESS) {
+ return res;
+ }
+
+ res = companion_proxy_receive(client, &dict);
+ if (res != COMPANION_PROXY_E_SUCCESS) {
+ return res;
+ }
+ plist_t val = plist_dict_get_item(dict, "CompanionProxyServicePort");
+ if (val) {
+ uint64_t u64val = 0;
+ plist_get_uint_val(val, &u64val);
+ *forward_port = (uint16_t)u64val;
+ res = COMPANION_PROXY_E_SUCCESS;
+ } else {
+ res = COMPANION_PROXY_E_UNKNOWN_ERROR;
+ }
+ plist_free(dict);
+
+ return res;
+}
+
+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;
+ }
+
+ plist_t dict = plist_new_dict();
+ plist_dict_set_item(dict, "Command", plist_new_string("StopForwardingServicePort"));
+ plist_dict_set_item(dict, "GizmoRemotePortNumber", plist_new_uint(remote_port));
+
+ companion_proxy_error_t res = companion_proxy_send(client, dict);
+ plist_free(dict);
+ dict = NULL;
+ if (res != COMPANION_PROXY_E_SUCCESS) {
+ return res;
+ }
+
+ res = companion_proxy_receive(client, &dict);
+ if (res != COMPANION_PROXY_E_SUCCESS) {
+ return res;
+ }
+ plist_free(dict);
+
+ return res;
+}
diff --git a/src/companion_proxy.h b/src/companion_proxy.h
new file mode 100644
index 0000000..e36932a
--- /dev/null
+++ b/src/companion_proxy.h
@@ -0,0 +1,35 @@
+/*
+ * companion_proxy.h
+ * com.apple.companion_proxy service header file.
+ *
+ * Copyright (c) 2019-2020 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 __COMPANION_PROXY_H
+#define __COMPANION_PROXY_H
+
+#include "idevice.h"
+#include "libimobiledevice/companion_proxy.h"
+#include "property_list_service.h"
+#include <libimobiledevice-glue/thread.h>
+
+struct companion_proxy_client_private {
+ property_list_service_client_t parent;
+ THREAD_T event_thread;
+};
+
+#endif
diff --git a/src/debugserver.c b/src/debugserver.c
index 1e06233..74ade8a 100644
--- a/src/debugserver.c
+++ b/src/debugserver.c
@@ -2,7 +2,8 @@
* debugserver.c
* com.apple.debugserver service implementation.
*
- * Copyright (c) 2014 Martin Szulecki All Rights Reserved.
+ * Copyright (c) 2019 Nikias Bassen, All Rights Reserved.
+ * Copyright (c) 2014-2015 Martin Szulecki All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -28,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"
/**
@@ -54,13 +56,15 @@ static debugserver_error_t debugserver_error(service_error_t err)
return DEBUGSERVER_E_MUX_ERROR;
case SERVICE_E_SSL_ERROR:
return DEBUGSERVER_E_SSL_ERROR;
+ case SERVICE_E_TIMEOUT:
+ return DEBUGSERVER_E_TIMEOUT;
default:
break;
}
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;
@@ -77,11 +81,16 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_new(idevice_t device
debug_info("Creating base service client failed. Error: %i", ret);
return ret;
}
- service_disable_ssl(parent);
+
+ if (service->identifier && (strcmp(service->identifier, DEBUGSERVER_SECURE_SERVICE_NAME) != 0)) {
+ service_disable_bypass_ssl(parent, 1);
+ }
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;
@@ -89,14 +98,18 @@ 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_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(debugserver_client_new), &err);
+ service_client_factory_start_service(device, DEBUGSERVER_SECURE_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(debugserver_client_new), &err);
+ if (err != DEBUGSERVER_E_SUCCESS) {
+ err = DEBUGSERVER_E_UNKNOWN_ERROR;
+ service_client_factory_start_service(device, DEBUGSERVER_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(debugserver_client_new), &err);
+ }
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;
@@ -108,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;
@@ -129,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;
@@ -139,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));
@@ -179,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;
@@ -221,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)
{
@@ -257,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;
@@ -273,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;
@@ -332,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;
@@ -344,119 +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)
+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 = 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 = strdup(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);
+ debug_info("skip_prefix: %d", 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) {
- memcpy(buffer, command_prefix, sizeof(char));
- } else {
- buffer = strdup(command_prefix);
- buffer_size += sizeof(char);
- }
+ 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);
+ uint32_t checksum_length = DEBUGSERVER_CHECKSUM_HASH_LENGTH;
+ int receiving_checksum_response = 0;
+ debug_info("attempting to read up response until checksum");
- 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");
- 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--;
+ while ((checksum_length > 0)) {
+ res = debugserver_client_receive_internal_char(client, &data);
+ if (res != DEBUGSERVER_E_SUCCESS) {
+ goto cleanup;
+ }
+ 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;
}
- char* newbuffer = string_concat(buffer, data, NULL);
- buffer_size += sizeof(char);
- free(buffer);
- buffer = NULL;
buffer = newbuffer;
- newbuffer = NULL;
+ buffer_capacity += 1024;
}
- debug_info("validating response checksum...");
- int valid_response = debugserver_response_is_checksum_valid(buffer, buffer_size);
- if (valid_response) {
- if (response) {
- /* assemble response string */
- uint32_t response_size = sizeof(char) * (buffer_size - DEBUGSERVER_CHECKSUM_HASH_LENGTH - 1);
- *response = (char*)malloc(response_size + 1);
- memcpy(*response, buffer + 1, response_size);
- (*response)[response_size] = '\0';
- }
- 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);
- }
+ 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);
}
@@ -464,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)
+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;
@@ -482,25 +515,15 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_send_command(debugse
char* command_arguments = NULL;
/* concat all arguments */
- char* tmp = NULL;
- char* newtmp = NULL;
for (i = 0; i < command->argc; i++) {
debug_info("argv[%d]: %s", i, command->argv[i]);
- if (!tmp) {
- tmp = strdup(command->argv[i]);
- } else {
- newtmp = string_concat(tmp, command->argv[i], NULL);
- free(tmp);
- tmp = newtmp;
- }
+ command_arguments = string_append(command_arguments, command->argv[i], NULL);
}
- command_arguments = tmp;
- tmp = NULL;
debug_info("command_arguments(%d): %s", command->argc, command_arguments);
/* encode command arguments, add checksum if required and assemble entire command */
- debugserver_format_command("$", command->name, command_arguments, !client->noack_mode, &send_buffer, &send_buffer_size);
+ debugserver_format_command("$", command->name, command_arguments, 1, &send_buffer, &send_buffer_size);
debug_info("sending encoded command: %s", send_buffer);
@@ -511,7 +534,7 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_send_command(debugse
}
/* receive response */
- res = debugserver_client_receive_response(client, response);
+ res = debugserver_client_receive_response(client, response, response_size);
debug_info("response result: %d", res);
if (res != DEBUGSERVER_E_SUCCESS) {
goto cleanup;
@@ -536,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;
@@ -547,7 +570,7 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_environment_hex_
debugserver_command_t command = NULL;
debugserver_command_new("QEnvironmentHexEncoded:", 1, env_arg, &command);
- result = debugserver_client_send_command(client, command, response);
+ result = debugserver_client_send_command(client, command, response, NULL);
debugserver_command_free(command);
free(env_tmp);
@@ -555,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++;
}
@@ -586,17 +613,21 @@ 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;
char *q = (char*)argv[i];
while (*q) {
- *p++ = debugserver_int2hex(*q >> 4);
- *p++ = debugserver_int2hex(*q & 0xf);
+ *p++ = DEBUGSERVER_HEX_ENCODE_FIRST_BYTE(*q);
+ *p++ = DEBUGSERVER_HEX_ENCODE_SECOND_BYTE(*q);
q++;
}
@@ -616,7 +647,7 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_argv(debugserver
debugserver_command_t command = NULL;
debugserver_command_new(pkt, 0, NULL, &command);
- result = debugserver_client_send_command(client, command, response);
+ result = debugserver_client_send_command(client, command, response, NULL);
debugserver_command_free(command);
if (pkt)
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 007223e..66c2461 100644
--- a/src/device_link_service.c
+++ b/src/device_link_service.c
@@ -2,7 +2,7 @@
* device_link_service.c
* DeviceLink service implementation.
*
- * Copyright (c) 2010 Nikias Bassen, All Rights Reserved.
+ * Copyright (c) 2010-2019 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
@@ -18,12 +18,37 @@
* 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 "device_link_service.h"
#include "property_list_service.h"
#include "common/debug.h"
+static device_link_service_error_t device_link_error(property_list_service_error_t err)
+{
+ switch (err) {
+ case PROPERTY_LIST_SERVICE_E_SUCCESS:
+ return DEVICE_LINK_SERVICE_E_SUCCESS;
+ case PROPERTY_LIST_SERVICE_E_INVALID_ARG:
+ return DEVICE_LINK_SERVICE_E_INVALID_ARG;
+ case PROPERTY_LIST_SERVICE_E_PLIST_ERROR:
+ return DEVICE_LINK_SERVICE_E_PLIST_ERROR;
+ case PROPERTY_LIST_SERVICE_E_MUX_ERROR:
+ return DEVICE_LINK_SERVICE_E_MUX_ERROR;
+ case PROPERTY_LIST_SERVICE_E_SSL_ERROR:
+ return DEVICE_LINK_SERVICE_E_SSL_ERROR;
+ case PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT:
+ return DEVICE_LINK_SERVICE_E_RECEIVE_TIMEOUT;
+ default:
+ break;
+ }
+ return DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR;
+}
+
/**
* Internally used function to extract the message string from a DL* message
* plist.
@@ -58,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;
}
@@ -89,18 +114,15 @@ device_link_service_error_t device_link_service_client_new(idevice_t device, loc
}
property_list_service_client_t plistclient = NULL;
- if (property_list_service_client_new(device, service, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
- return DEVICE_LINK_SERVICE_E_MUX_ERROR;
+ device_link_service_error_t err = device_link_error(property_list_service_client_new(device, service, &plistclient));
+ if (err != DEVICE_LINK_SERVICE_E_SUCCESS) {
+ return err;
}
/* create client object */
device_link_service_client_t client_loc = (device_link_service_client_t) malloc(sizeof(struct device_link_service_client_private));
client_loc->parent = plistclient;
- /* enable SSL if requested */
- if (service->ssl_enabled)
- property_list_service_enable_ssl(client_loc->parent);
-
/* all done, return success */
*client = client_loc;
return DEVICE_LINK_SERVICE_E_SUCCESS;
@@ -121,11 +143,10 @@ device_link_service_error_t device_link_service_client_free(device_link_service_
if (!client)
return DEVICE_LINK_SERVICE_E_INVALID_ARG;
- if (property_list_service_client_free(client->parent) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
- return DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR;
- }
+ device_link_service_error_t err = device_link_error(property_list_service_client_free(client->parent));
free(client);
- return DEVICE_LINK_SERVICE_E_SUCCESS;
+
+ return err;
}
/**
@@ -157,13 +178,13 @@ device_link_service_error_t device_link_service_version_exchange(device_link_ser
char *msg = NULL;
/* receive DLMessageVersionExchange from device */
- if (property_list_service_receive_plist(client->parent, &array) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
+ err = device_link_error(property_list_service_receive_plist(client->parent, &array));
+ if (err != DEVICE_LINK_SERVICE_E_SUCCESS) {
debug_info("Did not receive initial message from device!");
- err = DEVICE_LINK_SERVICE_E_MUX_ERROR;
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;
@@ -203,22 +224,22 @@ device_link_service_error_t device_link_service_version_exchange(device_link_ser
plist_array_append_item(array, plist_new_string("DLMessageVersionExchange"));
plist_array_append_item(array, plist_new_string("DLVersionsOk"));
plist_array_append_item(array, plist_new_uint(version_major));
- if (property_list_service_send_binary_plist(client->parent, array) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
+ err = device_link_error(property_list_service_send_binary_plist(client->parent, array));
+ if (err != DEVICE_LINK_SERVICE_E_SUCCESS) {
debug_info("Error when sending DLVersionsOk");
- err = DEVICE_LINK_SERVICE_E_MUX_ERROR;
goto leave;
}
plist_free(array);
/* receive DeviceReady message */
array = NULL;
- if (property_list_service_receive_plist(client->parent, &array) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
+ err = device_link_error(property_list_service_receive_plist(client->parent, &array));
+ if (err != DEVICE_LINK_SERVICE_E_SUCCESS) {
debug_info("Error when receiving DLMessageDeviceReady!");
- err = DEVICE_LINK_SERVICE_E_MUX_ERROR;
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;
@@ -258,11 +279,9 @@ device_link_service_error_t device_link_service_disconnect(device_link_service_c
else
plist_array_append_item(array, plist_new_string("___EmptyParameterString___"));
- device_link_service_error_t err = DEVICE_LINK_SERVICE_E_SUCCESS;
- if (property_list_service_send_binary_plist(client->parent, array) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
- err = DEVICE_LINK_SERVICE_E_MUX_ERROR;
- }
+ device_link_service_error_t err = device_link_error(property_list_service_send_binary_plist(client->parent, array));
plist_free(array);
+
return err;
}
@@ -286,11 +305,9 @@ device_link_service_error_t device_link_service_send_ping(device_link_service_cl
plist_array_append_item(array, plist_new_string("DLMessagePing"));
plist_array_append_item(array, plist_new_string(message));
- device_link_service_error_t err = DEVICE_LINK_SERVICE_E_SUCCESS;
- if (property_list_service_send_binary_plist(client->parent, array) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
- err = DEVICE_LINK_SERVICE_E_MUX_ERROR;
- }
+ device_link_service_error_t err = device_link_error(property_list_service_send_binary_plist(client->parent, array));
plist_free(array);
+
return err;
}
@@ -317,11 +334,9 @@ device_link_service_error_t device_link_service_send_process_message(device_link
plist_array_append_item(array, plist_new_string("DLMessageProcessMessage"));
plist_array_append_item(array, plist_copy(message));
- device_link_service_error_t err = DEVICE_LINK_SERVICE_E_SUCCESS;
- if (property_list_service_send_binary_plist(client->parent, array) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
- err = DEVICE_LINK_SERVICE_E_MUX_ERROR;
- }
+ device_link_service_error_t err = device_link_error(property_list_service_send_binary_plist(client->parent, array));
plist_free(array);
+
return err;
}
@@ -348,8 +363,9 @@ device_link_service_error_t device_link_service_receive_message(device_link_serv
return DEVICE_LINK_SERVICE_E_INVALID_ARG;
*msg_plist = NULL;
- if (property_list_service_receive_plist(client->parent, msg_plist) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
- return DEVICE_LINK_SERVICE_E_MUX_ERROR;
+ device_link_service_error_t err = device_link_error(property_list_service_receive_plist(client->parent, msg_plist));
+ if (err != DEVICE_LINK_SERVICE_E_SUCCESS) {
+ return err;
}
if (!device_link_service_get_message(*msg_plist, dlmessage)) {
@@ -378,15 +394,16 @@ device_link_service_error_t device_link_service_receive_process_message(device_l
return DEVICE_LINK_SERVICE_E_INVALID_ARG;
plist_t pmsg = NULL;
- if (property_list_service_receive_plist(client->parent, &pmsg) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
- return DEVICE_LINK_SERVICE_E_MUX_ERROR;
+ device_link_service_error_t err = device_link_error(property_list_service_receive_plist(client->parent, &pmsg));
+ if (err != DEVICE_LINK_SERVICE_E_SUCCESS) {
+ return err;
}
- device_link_service_error_t err = DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR;
+ err = DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR;
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;
@@ -432,10 +449,7 @@ device_link_service_error_t device_link_service_send(device_link_service_client_
if (!client || !plist) {
return DEVICE_LINK_SERVICE_E_INVALID_ARG;
}
- if (property_list_service_send_binary_plist(client->parent, plist) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
- return DEVICE_LINK_SERVICE_E_MUX_ERROR;
- }
- return DEVICE_LINK_SERVICE_E_SUCCESS;
+ return device_link_error(property_list_service_send_binary_plist(client->parent, plist));
}
/* Generic device link service receive function.
@@ -455,9 +469,6 @@ device_link_service_error_t device_link_service_receive(device_link_service_clie
return DEVICE_LINK_SERVICE_E_INVALID_ARG;
}
- if (property_list_service_receive_plist(client->parent, plist) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
- return DEVICE_LINK_SERVICE_E_MUX_ERROR;
- }
- return DEVICE_LINK_SERVICE_E_SUCCESS;
+ return device_link_error(property_list_service_receive_plist(client->parent, plist));
}
diff --git a/src/device_link_service.h b/src/device_link_service.h
index a0c8390..0255b21 100644
--- a/src/device_link_service.h
+++ b/src/device_link_service.h
@@ -2,7 +2,7 @@
* device_link_service.h
* Definitions for the DeviceLink service
*
- * Copyright (c) 2010 Nikias Bassen, All Rights Reserved.
+ * Copyright (c) 2010-2019 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
@@ -22,19 +22,20 @@
#ifndef __DEVICE_LINK_SERVICE_H
#define __DEVICE_LINK_SERVICE_H
+#include "idevice.h"
#include "property_list_service.h"
/* Error Codes */
-#define DEVICE_LINK_SERVICE_E_SUCCESS 0
-#define DEVICE_LINK_SERVICE_E_INVALID_ARG -1
-#define DEVICE_LINK_SERVICE_E_PLIST_ERROR -2
-#define DEVICE_LINK_SERVICE_E_MUX_ERROR -3
-#define DEVICE_LINK_SERVICE_E_BAD_VERSION -4
-
-#define DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR -256
-
-/** Represents an error code. */
-typedef int16_t device_link_service_error_t;
+typedef enum {
+ DEVICE_LINK_SERVICE_E_SUCCESS = 0,
+ DEVICE_LINK_SERVICE_E_INVALID_ARG = -1,
+ DEVICE_LINK_SERVICE_E_PLIST_ERROR = -2,
+ DEVICE_LINK_SERVICE_E_MUX_ERROR = -3,
+ DEVICE_LINK_SERVICE_E_SSL_ERROR = -4,
+ DEVICE_LINK_SERVICE_E_RECEIVE_TIMEOUT = -5,
+ DEVICE_LINK_SERVICE_E_BAD_VERSION = -6,
+ DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR = -256
+} device_link_service_error_t;
struct device_link_service_client_private {
property_list_service_client_t parent;
diff --git a/src/diagnostics_relay.c b/src/diagnostics_relay.c
index 0834700..6ee3150 100644
--- a/src/diagnostics_relay.c
+++ b/src/diagnostics_relay.c
@@ -18,6 +18,10 @@
* 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 "diagnostics_relay.h"
@@ -69,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;
@@ -89,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;
@@ -163,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;
@@ -197,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;
@@ -229,7 +233,7 @@ LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_sleep(diagnosti
return ret;
}
-static diagnostics_relay_error_t internal_diagnostics_relay_action(diagnostics_relay_client_t client, const char* name, int flags)
+static diagnostics_relay_error_t internal_diagnostics_relay_action(diagnostics_relay_client_t client, const char* name, diagnostics_relay_action_t flags)
{
if (!client)
return DIAGNOSTICS_RELAY_E_INVALID_ARG;
@@ -273,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, int 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, int 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;
@@ -295,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) {
@@ -324,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;
@@ -337,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) {
@@ -366,22 +376,25 @@ 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* name, const char* 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 || (name == NULL && class == NULL) || result == NULL)
+ if (!client || (entry_name == NULL && entry_class == NULL) || result == NULL)
return DIAGNOSTICS_RELAY_E_INVALID_ARG;
diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
plist_t dict = plist_new_dict();
- if (name)
- plist_dict_set_item(dict,"EntryName", plist_new_string(name));
- if (class)
- plist_dict_set_item(dict,"EntryClass", plist_new_string(class));
+ if (entry_name)
+ plist_dict_set_item(dict,"EntryName", plist_new_string(entry_name));
+ if (entry_class)
+ plist_dict_set_item(dict,"EntryClass", plist_new_string(entry_class));
plist_dict_set_item(dict,"Request", plist_new_string("IORegistry"));
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) {
@@ -411,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 455855b..fbe7cbf 100644
--- a/src/file_relay.c
+++ b/src/file_relay.c
@@ -18,13 +18,17 @@
* 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 "file_relay.h"
#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;
@@ -44,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;
@@ -63,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;
@@ -139,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;
}
@@ -155,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 135fc01..caad731 100644
--- a/src/house_arrest.c
+++ b/src/house_arrest.c
@@ -19,6 +19,9 @@
* 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 <unistd.h>
@@ -55,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));
@@ -71,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;
@@ -93,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;
@@ -109,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;
@@ -129,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;
@@ -147,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 382e9d2..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.
*
@@ -28,25 +28,50 @@
#include <stdlib.h>
#include <string.h>
#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
@@ -101,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();
@@ -119,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) {
@@ -147,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) {
@@ -171,56 +216,103 @@ 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;
ev.udid = event->device.udid;
- ev.conn_type = CONNECTION_USBMUXD;
+ ev.conn_type = 0;
+ if (event->device.conn_type == CONNECTION_TYPE_USB) {
+ ev.conn_type = CONNECTION_USBMUXD;
+ } else if (event->device.conn_type == CONNECTION_TYPE_NETWORK) {
+ ev.conn_type = CONNECTION_NETWORK;
+ } else {
+ 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(char ***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;
@@ -232,17 +324,89 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_get_device_list(char ***devices, in
return IDEVICE_E_NO_DEVICE;
}
- char **newlist = NULL;
+ idevice_info_t *newlist = NULL;
int i, newcount = 0;
for (i = 0; dev_list[i].handle > 0; i++) {
- newlist = realloc(*devices, sizeof(char*) * (newcount+1));
- newlist[newcount++] = strdup(dev_list[i].udid);
+ newlist = realloc(*devices, sizeof(idevice_info_t) * (newcount+1));
+ newlist[newcount] = malloc(sizeof(struct idevice_info));
+ newlist[newcount]->udid = strdup(dev_list[i].udid);
+ if (dev_list[i].conn_type == CONNECTION_TYPE_USB) {
+ newlist[newcount]->conn_type = CONNECTION_USBMUXD;
+ newlist[newcount]->conn_data = NULL;
+ } else if (dev_list[i].conn_type == CONNECTION_TYPE_NETWORK) {
+ newlist[newcount]->conn_type = CONNECTION_NETWORK;
+ 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);
+ }
+ newcount++;
*devices = newlist;
}
usbmuxd_device_list_free(&dev_list);
*count = newcount;
+ newlist = realloc(*devices, sizeof(idevice_info_t) * (newcount+1));
+ newlist[newcount] = NULL;
+ *devices = newlist;
+
+ return IDEVICE_E_SUCCESS;
+}
+
+idevice_error_t idevice_device_list_extended_free(idevice_info_t *devices)
+{
+ if (devices) {
+ int i = 0;
+ while (devices[i]) {
+ free(devices[i]->udid);
+ free(devices[i]->conn_data);
+ free(devices[i]);
+ i++;
+ }
+ free(devices);
+ }
+ return IDEVICE_E_SUCCESS;
+}
+
+idevice_error_t idevice_get_device_list(char ***devices, int *count)
+{
+ usbmuxd_device_info_t *dev_list;
+
+ *devices = NULL;
+ *count = 0;
+
+ if (usbmuxd_get_device_list(&dev_list) < 0) {
+ debug_info("ERROR: usbmuxd is not running!", __func__);
+ return IDEVICE_E_NO_DEVICE;
+ }
+
+ char **newlist = NULL;
+ int i, newcount = 0;
+
+ for (i = 0; dev_list[i].handle > 0; i++) {
+ if (dev_list[i].conn_type == CONNECTION_TYPE_USB) {
+ newlist = realloc(*devices, sizeof(char*) * (newcount+1));
+ newlist[newcount++] = strdup(dev_list[i].udid);
+ *devices = newlist;
+ }
+ }
+ usbmuxd_device_list_free(&dev_list);
+
+ *count = newcount;
newlist = realloc(*devices, sizeof(char*) * (newcount+1));
newlist[newcount] = NULL;
*devices = newlist;
@@ -250,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;
@@ -263,31 +427,89 @@ 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);
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_new(idevice_t * device, const char *udid)
+static idevice_t idevice_from_mux_device(usbmuxd_device_info_t *muxdev)
+{
+ if (!muxdev)
+ return NULL;
+
+ idevice_t device = (idevice_t)malloc(sizeof(struct idevice_private));
+ if (!device)
+ return NULL;
+
+ 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;
+ device->conn_data = NULL;
+ break;
+ case CONNECTION_TYPE_NETWORK:
+ device->conn_type = CONNECTION_NETWORK;
+ 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;
+ device->conn_data = NULL;
+ break;
+ }
+ return device;
+}
+
+idevice_error_t idevice_new_with_options(idevice_t * device, const char *udid, enum idevice_options options)
{
usbmuxd_device_info_t muxdev;
- int res = usbmuxd_get_device_by_udid(udid, &muxdev);
+ int usbmux_options = 0;
+ if (options & IDEVICE_LOOKUP_USBMUX) {
+ usbmux_options |= DEVICE_LOOKUP_USBMUX;
+ }
+ if (options & IDEVICE_LOOKUP_NETWORK) {
+ usbmux_options |= DEVICE_LOOKUP_NETWORK;
+ }
+ if (options & IDEVICE_LOOKUP_PREFER_NETWORK) {
+ usbmux_options |= DEVICE_LOOKUP_PREFER_NETWORK;
+ }
+ int res = usbmuxd_get_device(udid, &muxdev, usbmux_options);
if (res > 0) {
- idevice_t dev = (idevice_t) malloc(sizeof(struct idevice_private));
- dev->udid = strdup(muxdev.udid);
- dev->mux_id = muxdev.handle;
- dev->conn_type = CONNECTION_USBMUXD;
- dev->conn_data = NULL;
- dev->version = 0;
- *device = dev;
+ *device = idevice_from_mux_device(&muxdev);
+ if (!*device) {
+ return IDEVICE_E_UNKNOWN_ERROR;
+ }
return IDEVICE_E_SUCCESS;
}
- /* other connection types could follow here */
-
return IDEVICE_E_NO_DEVICE;
}
-LIBIMOBILEDEVICE_API idevice_error_t idevice_free(idevice_t device)
+idevice_error_t idevice_new(idevice_t * device, const char *udid)
+{
+ return idevice_new_with_options(device, udid, 0);
+}
+
+idevice_error_t idevice_free(idevice_t device)
{
if (!device)
return IDEVICE_E_INVALID_ARG;
@@ -304,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;
@@ -313,24 +535,79 @@ 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));
new_connection->type = CONNECTION_USBMUXD;
new_connection->data = (void*)(long)sfd;
new_connection->ssl_data = NULL;
- idevice_get_udid(device, &new_connection->udid);
+ 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 {
- debug_info("Unknown connection type %d", device->conn_type);
+ }
+ if (device->conn_type == CONNECTION_NETWORK) {
+ struct sockaddr* saddr = (struct sockaddr*)(device->conn_data);
+ switch (saddr->sa_family) {
+ case AF_INET:
+#ifdef AF_INET6
+ case AF_INET6:
+#endif
+ break;
+ default:
+ debug_info("Unsupported address family 0x%02x", saddr->sa_family);
+ return IDEVICE_E_UNKNOWN_ERROR;
+ }
+
+ char addrtxt[48];
+ addrtxt[0] = '\0';
+
+ if (!socket_addr_to_string(saddr, addrtxt, sizeof(addrtxt))) {
+ debug_info("Failed to convert network address: %d (%s)", errno, strerror(errno));
+ }
+
+ debug_info("Connecting to %s port %d...", addrtxt, port);
+
+ int sfd = socket_connect_addr(saddr, port);
+ if (sfd < 0) {
+ 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;
+ }
+
+ idevice_connection_t new_connection = (idevice_connection_t)malloc(sizeof(struct idevice_connection_private));
+ new_connection->type = CONNECTION_NETWORK;
+ new_connection->data = (void*)(long)sfd;
+ new_connection->ssl_data = NULL;
+ new_connection->device = device;
+ new_connection->ssl_recv_timeout = (unsigned int)-1;
+
+ *connection = new_connection;
+
+ return IDEVICE_E_SUCCESS;
}
+ 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;
@@ -344,13 +621,14 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_disconnect(idevice_connection_t con
usbmuxd_disconnect((int)(long)connection->data);
connection->data = NULL;
result = IDEVICE_E_SUCCESS;
+ } else if (connection->type == CONNECTION_NETWORK) {
+ socket_close((int)(long)connection->data);
+ connection->data = NULL;
+ result = IDEVICE_E_SUCCESS;
} else {
debug_info("Unknown connection type %d", connection->type);
}
- if (connection->udid)
- free(connection->udid);
-
free(connection);
connection = NULL;
@@ -367,48 +645,103 @@ static idevice_error_t internal_connection_send(idevice_connection_t connection,
}
if (connection->type == CONNECTION_USBMUXD) {
- int res = usbmuxd_send((int)(long)connection->data, data, len, sent_bytes);
+ int res;
+ do {
+ res = usbmuxd_send((int)(long)connection->data, data, len, sent_bytes);
+ } while (res == -EAGAIN);
if (res < 0) {
debug_info("ERROR: usbmuxd_send returned %d (%s)", res, strerror(-res));
return IDEVICE_E_UNKNOWN_ERROR;
}
return IDEVICE_E_SUCCESS;
- } else {
- debug_info("Unknown connection type %d", connection->type);
}
+ if (connection->type == CONNECTION_NETWORK) {
+ int s = socket_send((int)(long)connection->data, (void*)data, len);
+ if (s < 0) {
+ *sent_bytes = 0;
+ return IDEVICE_E_UNKNOWN_ERROR;
+ }
+ *sent_bytes = s;
+ return IDEVICE_E_SUCCESS;
+ }
+
+ 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) {
-#ifdef HAVE_OPENSSL
- int sent = SSL_write(connection->ssl_data->session, (const void*)data, (int)len);
- debug_info("SSL_write %d, sent %d", len, sent);
-#else
- ssize_t sent = gnutls_record_send(connection->ssl_data->session, (void*)data, (size_t)len);
+ connection->status = IDEVICE_E_SUCCESS;
+ uint32_t sent = 0;
+ while (sent < len) {
+#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);
+ if (sslerr == SSL_ERROR_WANT_WRITE) {
+ continue;
+ }
+ break;
+ }
+#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 ((uint32_t)sent == (uint32_t)len) {
- *sent_bytes = sent;
- return IDEVICE_E_SUCCESS;
+ if (s < 0) {
+ break;
+ }
+ sent += s;
}
- *sent_bytes = 0;
- return IDEVICE_E_SSL_ERROR;
+ debug_info("SSL_write %d, sent %d", len, sent);
+ if (sent < len) {
+ *sent_bytes = 0;
+ return connection->status == IDEVICE_E_SUCCESS ? IDEVICE_E_SSL_ERROR : connection->status;
+ }
+ *sent_bytes = sent;
+ return IDEVICE_E_SUCCESS;
}
- return internal_connection_send(connection, data, len, sent_bytes);
+ 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;
+ 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;
@@ -416,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;
}
@@ -433,64 +765,88 @@ 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 {
- debug_info("Unknown connection type %d", connection->type);
}
+ if (connection->type == CONNECTION_NETWORK) {
+ int res = socket_receive_timeout((int)(long)connection->data, data, len, 0, timeout);
+ idevice_error_t error = socket_recv_to_idevice_error(res, 0, 0);
+ if (error == IDEVICE_E_SUCCESS) {
+ *recv_bytes = (uint32_t)res;
+ } else if (error == IDEVICE_E_UNKNOWN_ERROR) {
+ debug_info("ERROR: socket_receive_timeout returned %d (%s)", res, strerror(-res));
+ }
+ 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;
+ if (connection->ssl_recv_timeout != (unsigned int)-1) {
+ debug_info("WARNING: ssl_recv_timeout was not properly reset in idevice_connection_receive_timeout");
+ }
+
+ // 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) {
-#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:
- debug_info("ERROR: socket_check_fd returned %d (%s)", conn_error, strerror(-conn_error));
- default:
- return error;
+#if defined(HAVE_OPENSSL)
+ int r = SSL_read(connection->ssl_data->session, (void*)((char*)(data+received)), (int)len-received);
+ if (r > 0) {
+ received += r;
+ } else {
+ 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;
}
-
-#ifdef HAVE_OPENSSL
- int r = SSL_read(connection->ssl_data->session, (void*)((char*)(data+received)), (int)len-received);
-#else
+#elif defined(HAVE_GNUTLS)
ssize_t r = gnutls_record_recv(connection->ssl_data->session, (void*)(data+received), (size_t)len-received);
-#endif
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;
return IDEVICE_E_SUCCESS;
}
@@ -512,26 +868,44 @@ static idevice_error_t internal_connection_receive(idevice_connection_t connecti
debug_info("ERROR: usbmuxd_recv returned %d (%s)", res, strerror(-res));
return IDEVICE_E_UNKNOWN_ERROR;
}
-
return IDEVICE_E_SUCCESS;
- } else {
- debug_info("Unknown connection type %d", connection->type);
}
+ 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));
+ return IDEVICE_E_UNKNOWN_ERROR;
+ }
+ *recv_bytes = (uint32_t)res;
+ return IDEVICE_E_SUCCESS;
+ }
+
+ 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;
@@ -543,23 +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 {
- debug_info("Unknown connection type %d", connection->type);
+ return IDEVICE_E_SUCCESS;
}
- return result;
+ if (connection->type == CONNECTION_NETWORK) {
+ *fd = (int)(long)connection->data;
+ return IDEVICE_E_SUCCESS;
+ }
+
+ 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;
@@ -568,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.
@@ -649,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);
}
@@ -675,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;
@@ -691,7 +1122,7 @@ static const char *ssl_error_to_string(int e)
case SSL_ERROR_NONE:
return "SSL_ERROR_NONE";
case SSL_ERROR_SSL:
- return "SSL_ERROR_SSL";
+ return ERR_error_string(ERR_get_error(), NULL);
case SSL_ERROR_WANT_READ:
return "SSL_ERROR_WANT_READ";
case SSL_ERROR_WANT_WRITE:
@@ -713,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.
*/
@@ -744,28 +1175,40 @@ 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;
idevice_error_t ret = IDEVICE_E_SSL_ERROR;
-#ifdef HAVE_OPENSSL
- uint32_t return_me = 0;
-#else
- int return_me = 0;
-#endif
plist_t pair_record = NULL;
- userpref_read_pair_record(connection->udid, &pair_record);
- if (!pair_record) {
- debug_info("ERROR: Failed enabling SSL. Unable to read pair record for udid %s.", connection->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 };
@@ -775,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) {
@@ -789,16 +1231,61 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_conne
return ret;
}
- /* force use of TLSv1 */
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) || \
+ (defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER >= 0x3060000fL))
+ SSL_CTX_set_security_level(ssl_ctx, 0);
+#endif
+
+#if OPENSSL_VERSION_NUMBER < 0x10100002L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x2060000fL))
+ /* force use of TLSv1 for older devices */
+ if (connection->device->version < DEVICE_VERSION(10,0,0)) {
#ifdef SSL_OP_NO_TLSv1_1
- int 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;
+ 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
- SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL | opts);
#endif
BIO* membp;
@@ -812,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);
@@ -820,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);
@@ -833,9 +1331,22 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_conne
SSL_set_verify(ssl, 0, ssl_verify_callback);
SSL_set_bio(ssl, ssl_bio, ssl_bio);
- return_me = SSL_do_handshake(ssl);
- if (return_me != 1) {
- debug_info("ERROR in SSL_do_handshake: %s", ssl_error_to_string(SSL_get_error(ssl, return_me)));
+ debug_info("Performing SSL handshake");
+ int ssl_error = 0;
+ do {
+ ssl_error = SSL_get_error(ssl, SSL_do_handshake(ssl));
+ if (ssl_error == 0 || ssl_error != SSL_ERROR_WANT_READ) {
+ break;
+ }
+#ifdef WIN32
+ Sleep(100);
+#else
+ struct timespec ts = { 0, 100000000 };
+ nanosleep(&ts, NULL);
+#endif
+ } while (1);
+ if (ssl_error != 0) {
+ debug_info("ERROR during SSL handshake: %s", ssl_error_to_string(ssl_error));
SSL_free(ssl);
SSL_CTX_free(ssl_ctx);
} else {
@@ -848,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... */
@@ -889,6 +1400,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_conne
debug_info("WARNING: errno says %s before handshake!", strerror(errno));
}
+ int return_me = 0;
do {
return_me = gnutls_handshake(ssl_data_loc->session);
} while(return_me == GNUTLS_E_AGAIN || return_me == GNUTLS_E_INTERRUPTED);
@@ -905,11 +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);
+}
+
+idevice_error_t idevice_connection_disable_bypass_ssl(idevice_connection_t connection, uint8_t sslBypass)
{
if (!connection)
return IDEVICE_E_INVALID_ARG;
@@ -918,18 +1511,31 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_disable_ssl(idevice_conn
return IDEVICE_E_SUCCESS;
}
-#ifdef 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) {
- SSL_shutdown(connection->ssl_data->session);
+ // some services require plain text communication after SSL handshake
+ // sending out SSL_shutdown will cause bytes
+ if (!sslBypass) {
+#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) {
+ /* Only try bidirectional shutdown if we know it can complete */
+ int ssl_error;
+ 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", ssl_error);
+ }
+ }
}
- }
-#else
- if (connection->ssl_data->session) {
- gnutls_bye(connection->ssl_data->session, GNUTLS_SHUT_RDWR);
- }
+#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
+ }
+
internal_ssl_cleanup(connection->ssl_data);
free(connection->ssl_data);
connection->ssl_data = NULL;
diff --git a/src/idevice.h b/src/idevice.h
index 94e828b..dd72f9d 100644
--- a/src/idevice.h
+++ b/src/idevice.h
@@ -26,58 +26,79 @@
#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"
#include "libimobiledevice/libimobiledevice.h"
-enum connection_type {
- CONNECTION_USBMUXD = 1
-};
+#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;
struct idevice_connection_private {
- char *udid;
- enum connection_type type;
+ idevice_t device;
+ enum idevice_connection_type type;
void *data;
ssl_data_t ssl_data;
+ unsigned int ssl_recv_timeout;
+ idevice_error_t status;
};
struct idevice_private {
char *udid;
uint32_t mux_id;
- enum connection_type conn_type;
+ 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 dfcdd8a..f00c392 100644
--- a/src/libimobiledevice-1.0.pc.in
+++ b/src/libimobiledevice-1.0.pc.in
@@ -6,7 +6,7 @@ includedir=@includedir@
Name: @PACKAGE_NAME@
Description: A library to communicate with services running on Apple iOS devices.
Version: @PACKAGE_VERSION@
-Libs: -L${libdir} -limobiledevice
+Libs: -L${libdir} -limobiledevice-1.0
Cflags: -I${includedir}
-Requires: libplist >= @LIBPLIST_VERSION@
-Requires.private: libusbmuxd >= @LIBUSBMUXD_VERSION@ @ssl_requires@ \ No newline at end of file
+Requires: libplist-2.0 >= @LIBPLIST_VERSION@
+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 23f2782..256bff0 100644
--- a/src/lockdown.c
+++ b/src/lockdown.c
@@ -33,23 +33,14 @@
#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
-#ifdef HAVE_OPENSSL
-#include <openssl/pem.h>
-#include <openssl/x509.h>
-#include <openssl/x509v3.h>
-#else
-#include <libtasn1.h>
-#include <gnutls/x509.h>
-#include <gnutls/crypto.h>
-#endif
#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
@@ -57,6 +48,46 @@
#define sleep(x) Sleep(x*1000)
#endif
+struct st_lockdownd_error_str_map {
+ const char *lockdown_errstr;
+ const char *errstr;
+ lockdownd_error_t errcode;
+};
+
+static struct st_lockdownd_error_str_map lockdownd_error_str_map[] = {
+ { "InvalidResponse", "Invalid response", LOCKDOWN_E_INVALID_RESPONSE },
+ { "MissingKey", "Missing key", LOCKDOWN_E_MISSING_KEY },
+ { "MissingValue", "Missing value", LOCKDOWN_E_MISSING_VALUE },
+ { "GetProhibited", "Get value prohibited", LOCKDOWN_E_GET_PROHIBITED },
+ { "SetProhibited", "Set value prohibited", LOCKDOWN_E_SET_PROHIBITED },
+ { "RemoveProhibited", "Remove value prohibited", LOCKDOWN_E_REMOVE_PROHIBITED },
+ { "ImmutableValue", "Immutable value", LOCKDOWN_E_IMMUTABLE_VALUE },
+ { "PasswordProtected", "Password protected", LOCKDOWN_E_PASSWORD_PROTECTED },
+ { "UserDeniedPairing", "User denied pairing", LOCKDOWN_E_USER_DENIED_PAIRING },
+ { "PairingDialogResponsePending", "Pairing dialog response pending", LOCKDOWN_E_PAIRING_DIALOG_RESPONSE_PENDING },
+ { "MissingHostID", "Missing HostID", LOCKDOWN_E_MISSING_HOST_ID },
+ { "InvalidHostID", "Invalid HostID", LOCKDOWN_E_INVALID_HOST_ID },
+ { "SessionActive", "Session active", LOCKDOWN_E_SESSION_ACTIVE },
+ { "SessionInactive", "Session inactive", LOCKDOWN_E_SESSION_INACTIVE },
+ { "MissingSessionID", "Missing session ID", LOCKDOWN_E_MISSING_SESSION_ID },
+ { "InvalidSessionID", "Invalid session ID", LOCKDOWN_E_INVALID_SESSION_ID },
+ { "MissingService", "Missing service", LOCKDOWN_E_MISSING_SERVICE },
+ { "InvalidService", "Invalid service", LOCKDOWN_E_INVALID_SERVICE },
+ { "ServiceLimit", "Service limit reached", LOCKDOWN_E_SERVICE_LIMIT },
+ { "MissingPairRecord", "Missing pair record", LOCKDOWN_E_MISSING_PAIR_RECORD },
+ { "SavePairRecordFailed", "Saving pair record failed", LOCKDOWN_E_SAVE_PAIR_RECORD_FAILED },
+ { "InvalidPairRecord", "Invalid pair record", LOCKDOWN_E_INVALID_PAIR_RECORD },
+ { "InvalidActivationRecord", "Invalid activation record", LOCKDOWN_E_INVALID_ACTIVATION_RECORD },
+ { "MissingActivationRecord", "Missing activation record", LOCKDOWN_E_MISSING_ACTIVATION_RECORD },
+ { "ServiceProhibited", "Service prohibited", LOCKDOWN_E_SERVICE_PROHIBITED },
+ { "EscrowLocked", "Escrow lockded", LOCKDOWN_E_ESCROW_LOCKED },
+ { "PairingProhibitedOverThisConnection", "Pairing prohibited over this connection", LOCKDOWN_E_PAIRING_PROHIBITED_OVER_THIS_CONNECTION },
+ { "FMiPProtected", "Find My iPhone/iPod/iPad protected", LOCKDOWN_E_FMIP_PROTECTED },
+ { "MCProtected", "MC protected" , LOCKDOWN_E_MC_PROTECTED },
+ { "MCChallengeRequired", "MC challenge required", LOCKDOWN_E_MC_CHALLENGE_REQUIRED },
+ { NULL, NULL, 0 }
+};
+
/**
* Convert an error string identifier to a lockdownd_error_t value.
* Used internally to get correct error codes from a response.
@@ -69,69 +100,13 @@
static lockdownd_error_t lockdownd_strtoerr(const char* name)
{
lockdownd_error_t err = LOCKDOWN_E_UNKNOWN_ERROR;
-
- if (strcmp(name, "InvalidResponse") == 0) {
- err = LOCKDOWN_E_INVALID_RESPONSE;
- } else if (strcmp(name, "MissingKey") == 0) {
- err = LOCKDOWN_E_MISSING_KEY;
- } else if (strcmp(name, "MissingValue") == 0) {
- err = LOCKDOWN_E_MISSING_VALUE;
- } else if (strcmp(name, "GetProhibited") == 0) {
- err = LOCKDOWN_E_GET_PROHIBITED;
- } else if (strcmp(name, "SetProhibited") == 0) {
- err = LOCKDOWN_E_SET_PROHIBITED;
- } else if (strcmp(name, "RemoveProhibited") == 0) {
- err = LOCKDOWN_E_REMOVE_PROHIBITED;
- } else if (strcmp(name, "ImmutableValue") == 0) {
- err = LOCKDOWN_E_IMMUTABLE_VALUE;
- } else if (strcmp(name, "PasswordProtected") == 0) {
- err = LOCKDOWN_E_PASSWORD_PROTECTED;
- } else if (strcmp(name, "UserDeniedPairing") == 0) {
- err = LOCKDOWN_E_USER_DENIED_PAIRING;
- } else if (strcmp(name, "PairingDialogResponsePending") == 0) {
- err = LOCKDOWN_E_PAIRING_DIALOG_RESPONSE_PENDING;
- } else if (strcmp(name, "MissingHostID") == 0) {
- err = LOCKDOWN_E_MISSING_HOST_ID;
- } else if (strcmp(name, "InvalidHostID") == 0) {
- err = LOCKDOWN_E_INVALID_HOST_ID;
- } else if (strcmp(name, "SessionActive") == 0) {
- err = LOCKDOWN_E_SESSION_ACTIVE;
- } else if (strcmp(name, "SessionInactive") == 0) {
- err = LOCKDOWN_E_SESSION_INACTIVE;
- } else if (strcmp(name, "MissingSessionID") == 0) {
- err = LOCKDOWN_E_MISSING_SESSION_ID;
- } else if (strcmp(name, "InvalidSessionID") == 0) {
- err = LOCKDOWN_E_INVALID_SESSION_ID;
- } else if (strcmp(name, "MissingService") == 0) {
- err = LOCKDOWN_E_MISSING_SERVICE;
- } else if (strcmp(name, "InvalidService") == 0) {
- err = LOCKDOWN_E_INVALID_SERVICE;
- } else if (strcmp(name, "ServiceLimit") == 0) {
- err = LOCKDOWN_E_SERVICE_LIMIT;
- } else if (strcmp(name, "MissingPairRecord") == 0) {
- err = LOCKDOWN_E_MISSING_PAIR_RECORD;
- } else if (strcmp(name, "SavePairRecordFailed") == 0) {
- err = LOCKDOWN_E_SAVE_PAIR_RECORD_FAILED;
- } else if (strcmp(name, "InvalidPairRecord") == 0) {
- err = LOCKDOWN_E_INVALID_PAIR_RECORD;
- } else if (strcmp(name, "InvalidActivationRecord") == 0) {
- err = LOCKDOWN_E_INVALID_ACTIVATION_RECORD;
- } else if (strcmp(name, "MissingActivationRecord") == 0) {
- err = LOCKDOWN_E_MISSING_ACTIVATION_RECORD;
- } else if (strcmp(name, "ServiceProhibited") == 0) {
- err = LOCKDOWN_E_SERVICE_PROHIBITED;
- } else if (strcmp(name, "EscrowLocked") == 0) {
- err = LOCKDOWN_E_ESCROW_LOCKED;
- } else if (strcmp(name, "PairingProhibitedOverThisConnection") == 0) {
- err = LOCKDOWN_E_PAIRING_PROHIBITED_OVER_THIS_CONNECTION;
- } else if (strcmp(name, "FMiPProtected") == 0) {
- err = LOCKDOWN_E_FMIP_PROTECTED;
- } else if (strcmp(name, "MCProtected") == 0) {
- err = LOCKDOWN_E_MC_PROTECTED;
- } else if (strcmp(name, "MCChallengeRequired") == 0) {
- err = LOCKDOWN_E_MC_CHALLENGE_REQUIRED;
+ int i = 0;
+ while (lockdownd_error_str_map[i].lockdown_errstr) {
+ if (strcmp(lockdownd_error_str_map[i].lockdown_errstr, name) == 0) {
+ return lockdownd_error_str_map[i].errcode;
+ }
+ i++;
}
-
return err;
}
@@ -177,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;
@@ -188,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;
@@ -244,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;
@@ -267,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;
@@ -336,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;
@@ -349,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;
@@ -365,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)
@@ -375,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;
@@ -383,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;
@@ -391,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;
@@ -436,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;
@@ -490,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;
@@ -538,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;
@@ -585,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;
@@ -631,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;
@@ -648,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;
@@ -668,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;
@@ -682,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;
@@ -703,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);
@@ -715,14 +676,43 @@ LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_new_with_handshake(idevi
char *s_version = NULL;
plist_get_string_val(p_version, &s_version);
if (s_version && sscanf(s_version, "%d.%d.%d", &vers[0], &vers[1], &vers[2]) >= 2) {
- device->version = ((vers[0] & 0xFF) << 16) | ((vers[1] & 0xFF) << 8) | (vers[2] & 0xFF);
+ device->version = DEVICE_VERSION(vers[0], vers[1], vers[2]);
}
free(s_version);
}
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);
}
@@ -732,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 < 0x070000) {
+ 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);
@@ -755,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);
@@ -919,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;
}
}
}
@@ -984,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 */
@@ -1002,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 {
@@ -1044,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();
@@ -1057,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;
@@ -1102,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;
@@ -1136,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;
@@ -1251,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;
}
@@ -1332,6 +1352,7 @@ static lockdownd_error_t lockdownd_do_start_service(lockdownd_client_t client, c
*service = (lockdownd_service_descriptor_t)malloc(sizeof(struct lockdownd_service_descriptor));
(*service)->port = 0;
(*service)->ssl_enabled = 0;
+ (*service)->identifier = strdup(identifier);
/* read service port number */
plist_t node = plist_dict_get_item(dict, "Port");
@@ -1371,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;
@@ -1420,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;
@@ -1467,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;
@@ -1522,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;
@@ -1534,10 +1555,50 @@ 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)
+ if (service) {
+ free(service->identifier);
free(service);
+ }
return LOCKDOWN_E_SUCCESS;
}
+
+const char* lockdownd_strerror(lockdownd_error_t err)
+{
+ switch (err) {
+ case LOCKDOWN_E_SUCCESS:
+ return "Success";
+ case LOCKDOWN_E_INVALID_ARG:
+ return "Invalid argument";
+ case LOCKDOWN_E_INVALID_CONF:
+ return "Invalid configuration";
+ case LOCKDOWN_E_PLIST_ERROR:
+ return "PropertyList error";
+ case LOCKDOWN_E_PAIRING_FAILED:
+ return "Pairing failed";
+ case LOCKDOWN_E_SSL_ERROR:
+ return "SSL error";
+ case LOCKDOWN_E_DICT_ERROR:
+ return "Invalid dictionary";
+ case LOCKDOWN_E_RECEIVE_TIMEOUT:
+ return "Receive timeout";
+ case LOCKDOWN_E_MUX_ERROR:
+ return "Mux error";
+ case LOCKDOWN_E_NO_RUNNING_SESSION:
+ return "No running session";
+ case LOCKDOWN_E_UNKNOWN_ERROR:
+ return "Unknown Error";
+ default: {
+ int i = 0;
+ while (lockdownd_error_str_map[i].lockdown_errstr) {
+ if (lockdownd_error_str_map[i].errcode == err) {
+ return lockdownd_error_str_map[i].errstr;
+ }
+ i++;
+ }
+ } break;
+ }
+ return "Unknown Error";
+}
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 91b8acb..e3da997 100644
--- a/src/misagent.c
+++ b/src/misagent.c
@@ -19,6 +19,9 @@
* 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 <unistd.h>
@@ -82,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));
@@ -103,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;
@@ -125,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;
@@ -162,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;
@@ -202,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;
@@ -242,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;
@@ -279,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 c8c4c6f..5df8e86 100644
--- a/src/mobile_image_mounter.c
+++ b/src/mobile_image_mounter.c
@@ -2,7 +2,7 @@
* mobile_image_mounter.c
* com.apple.mobile.mobile_image_mounter service implementation.
*
- * Copyright (c) 2010 Nikias Bassen, All Rights Reserved.
+ * Copyright (c) 2010-2019 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
@@ -19,6 +19,9 @@
* 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 <unistd.h>
@@ -75,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));
@@ -92,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;
@@ -112,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;
@@ -141,7 +144,44 @@ leave_unlock:
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)
+static mobile_image_mounter_error_t process_result(plist_t result, const char *expected_status)
+{
+ mobile_image_mounter_error_t res = MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED;
+ char* strval = NULL;
+ plist_t node;
+
+ node = plist_dict_get_item(result, "Error");
+ if (node && plist_get_node_type(node) == PLIST_STRING) {
+ plist_get_string_val(node, &strval);
+ }
+ if (strval) {
+ if (!strcmp(strval, "DeviceLocked")) {
+ debug_info("Device is locked, can't mount");
+ res = MOBILE_IMAGE_MOUNTER_E_DEVICE_LOCKED;
+ } else {
+ debug_info("Unhandled error '%s' received", strval);
+ }
+ free(strval);
+ return res;
+ }
+
+ node = plist_dict_get_item(result, "Status");
+ if (node && plist_get_node_type(node) == PLIST_STRING) {
+ plist_get_string_val(node, &strval);
+ }
+ if (!strval) {
+ debug_info("Error: Unexpected response received!");
+ } else if (strcmp(strval, expected_status) == 0) {
+ res = MOBILE_IMAGE_MOUNTER_E_SUCCESS;
+ } else {
+ debug_info("Error: didn't get %s but %s", expected_status, strval);
+ }
+ free(strval);
+
+ return res;
+}
+
+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;
@@ -169,23 +209,10 @@ LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_upload_im
debug_info("Error receiving response from device!");
goto leave_unlock;
}
- res = MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED;
-
- char* strval = NULL;
- plist_t node = plist_dict_get_item(result, "Status");
- if (node && plist_get_node_type(node) == PLIST_STRING) {
- plist_get_string_val(node, &strval);
- }
- if (!strval) {
- debug_info("Error: Unexpected response received!");
- goto leave_unlock;
- }
- if (strcmp(strval, "ReceiveBytesAck") != 0) {
- debug_info("Error: didn't get ReceiveBytesAck but %s", strval);
- free(strval);
+ res = process_result(result, "ReceiveBytesAck");
+ if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
goto leave_unlock;
}
- free(strval);
size_t tx = 0;
size_t bufsize = 65536;
@@ -223,26 +250,7 @@ LIBIMOBILEDEVICE_API mobile_image_mounter_error_t mobile_image_mounter_upload_im
debug_info("Error receiving response from device!");
goto leave_unlock;
}
- res = MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED;
-
- strval = NULL;
- node = plist_dict_get_item(result, "Status");
- if (node && plist_get_node_type(node) == PLIST_STRING) {
- plist_get_string_val(node, &strval);
- }
- if (!strval) {
- debug_info("Error: Unexpected response received!");
- goto leave_unlock;
- }
- if (strcmp(strval, "Complete") != 0) {
- debug_info("Error: didn't get Complete but %s", strval);
- free(strval);
- goto leave_unlock;
- } else {
- res = MOBILE_IMAGE_MOUNTER_E_SUCCESS;
- }
- free(strval);
-
+ res = process_result(result, "Complete");
leave_unlock:
mobile_image_mounter_unlock(client);
@@ -252,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;
@@ -284,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 010484e..fce5f16 100644
--- a/src/mobileactivation.c
+++ b/src/mobileactivation.c
@@ -18,6 +18,10 @@
* 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 "mobileactivation.h"
@@ -50,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;
@@ -70,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;
@@ -105,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;
}
@@ -114,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)
@@ -175,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;
@@ -197,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;
@@ -217,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;
@@ -239,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;
@@ -260,10 +261,10 @@ LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_create_activation
plist_free(result);
result = NULL;
- return ret;
+ 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;
@@ -276,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;
@@ -299,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 b32e0ba..36986a4 100644
--- a/src/mobilebackup.c
+++ b/src/mobilebackup.c
@@ -2,6 +2,7 @@
* mobilebackup.c
* Contains functions for the built-in MobileBackup client.
*
+ * Copyright (c) 2010-2019 Nikias Bassen, All Rights Reserved.
* Copyright (c) 2009 Martin Szulecki All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
@@ -19,9 +20,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
#include <plist/plist.h>
#include <string.h>
#include <stdlib.h>
+#include <stdio.h>
#include "mobilebackup.h"
#include "device_link_service.h"
@@ -30,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.
@@ -52,6 +57,10 @@ static mobilebackup_error_t mobilebackup_error(device_link_service_error_t err)
return MOBILEBACKUP_E_PLIST_ERROR;
case DEVICE_LINK_SERVICE_E_MUX_ERROR:
return MOBILEBACKUP_E_MUX_ERROR;
+ case DEVICE_LINK_SERVICE_E_SSL_ERROR:
+ return MOBILEBACKUP_E_SSL_ERROR;
+ case DEVICE_LINK_SERVICE_E_RECEIVE_TIMEOUT:
+ return MOBILEBACKUP_E_RECEIVE_TIMEOUT;
case DEVICE_LINK_SERVICE_E_BAD_VERSION:
return MOBILEBACKUP_E_BAD_VERSION;
default:
@@ -60,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;
@@ -87,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;
@@ -107,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;
@@ -115,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;
@@ -232,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;
@@ -271,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);
@@ -292,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;
@@ -338,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);
@@ -351,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) {
@@ -406,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 19b9999..04ec479 100644
--- a/src/mobilebackup.h
+++ b/src/mobilebackup.h
@@ -2,6 +2,7 @@
* mobilebackup.h
* Definitions for the mobilebackup service
*
+ * Copyright (c) 2010-2019 Nikias Bassen, All Rights Reserved.
* Copyright (c) 2009 Martin Szulecki All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
@@ -22,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 08ce22b..a8d673f 100644
--- a/src/mobilebackup2.c
+++ b/src/mobilebackup2.c
@@ -2,7 +2,7 @@
* mobilebackup2.c
* Contains functions for the built-in MobileBackup2 client (iOS4+ only)
*
- * Copyright (c) 2010 Nikias Bassen All Rights Reserved.
+ * Copyright (c) 2010-2019 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
@@ -19,6 +19,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
#include <plist/plist.h>
#include <string.h>
#include <stdlib.h>
@@ -27,10 +30,10 @@
#include "device_link_service.h"
#include "common/debug.h"
-#define MBACKUP2_VERSION_INT1 300
+#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.
@@ -53,6 +56,10 @@ static mobilebackup2_error_t mobilebackup2_error(device_link_service_error_t err
return MOBILEBACKUP2_E_PLIST_ERROR;
case DEVICE_LINK_SERVICE_E_MUX_ERROR:
return MOBILEBACKUP2_E_MUX_ERROR;
+ case DEVICE_LINK_SERVICE_E_SSL_ERROR:
+ return MOBILEBACKUP2_E_SSL_ERROR;
+ case DEVICE_LINK_SERVICE_E_RECEIVE_TIMEOUT:
+ return MOBILEBACKUP2_E_RECEIVE_TIMEOUT;
case DEVICE_LINK_SERVICE_E_BAD_VERSION:
return MOBILEBACKUP2_E_BAD_VERSION;
default:
@@ -61,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)
@@ -89,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;
@@ -109,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;
@@ -207,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;
@@ -233,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;
@@ -258,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;
@@ -323,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;
@@ -354,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 4dba22a..e232b97 100644
--- a/src/mobilebackup2.h
+++ b/src/mobilebackup2.h
@@ -2,7 +2,7 @@
* mobilebackup2.h
* Definitions for the mobilebackup2 service (iOS4+)
*
- * Copyright (c) 2010 Nikias Bassen All Rights Reserved.
+ * Copyright (c) 2010-2019 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
@@ -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 d903cfe..9b81a49 100644
--- a/src/mobilesync.c
+++ b/src/mobilesync.c
@@ -20,9 +20,11 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
#define _GNU_SOURCE 1
#define __USE_GNU 1
-
#include <plist/plist.h>
#include <string.h>
#include <stdlib.h>
@@ -32,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___"
@@ -57,6 +59,10 @@ static mobilesync_error_t mobilesync_error(device_link_service_error_t err)
return MOBILESYNC_E_PLIST_ERROR;
case DEVICE_LINK_SERVICE_E_MUX_ERROR:
return MOBILESYNC_E_MUX_ERROR;
+ case DEVICE_LINK_SERVICE_E_SSL_ERROR:
+ return MOBILESYNC_E_SSL_ERROR;
+ case DEVICE_LINK_SERVICE_E_RECEIVE_TIMEOUT:
+ return MOBILESYNC_E_RECEIVE_TIMEOUT;
case DEVICE_LINK_SERVICE_E_BAD_VERSION:
return MOBILESYNC_E_BAD_VERSION;
default:
@@ -65,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)
@@ -95,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;
@@ -112,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;
@@ -120,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) {
@@ -253,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;
@@ -338,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;
@@ -415,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;
@@ -467,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;
}
@@ -484,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;
@@ -518,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;
@@ -585,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;
@@ -613,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;
@@ -682,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;
@@ -708,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) {
@@ -725,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);
@@ -739,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;
@@ -776,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 eea01ca..60b2e03 100644
--- a/src/notification_proxy.c
+++ b/src/notification_proxy.c
@@ -19,6 +19,9 @@
* 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 <unistd.h>
@@ -86,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));
@@ -104,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;
@@ -165,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;
@@ -201,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;
@@ -212,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;
@@ -343,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 1cb8dc9..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);
}
@@ -197,6 +197,11 @@ static property_list_service_error_t internal_plist_receive_timeout(property_lis
return service_to_property_list_service_error(serr);
}
+ if (bytes == 0) {
+ /* success but 0 bytes length, assume timeout */
+ return PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT;
+ }
+
debug_info("initial read=%i", bytes);
uint32_t curlen = 0;
@@ -219,6 +224,7 @@ static property_list_service_error_t internal_plist_receive_timeout(property_lis
debug_info("received %d bytes", bytes);
curlen += bytes;
}
+
if (curlen < pktlen) {
debug_info("received incomplete packet (%d of %d bytes)", curlen, pktlen);
if (curlen > 0) {
@@ -228,6 +234,7 @@ static property_list_service_error_t internal_plist_receive_timeout(property_lis
free(content);
return res;
}
+
if ((pktlen > 8) && !memcmp(content, "bplist00", 8)) {
plist_from_bin(content, pktlen, plist);
} else if ((pktlen > 5) && !memcmp(content, "<?xml", 5)) {
@@ -241,39 +248,48 @@ static property_list_service_error_t internal_plist_receive_timeout(property_lis
debug_info("WARNING: received unexpected non-plist content");
debug_buffer(content, pktlen);
}
+
if (*plist) {
debug_plist(*plist);
res = PROPERTY_LIST_SERVICE_E_SUCCESS;
} else {
res = PROPERTY_LIST_SERVICE_E_PLIST_ERROR;
}
+
free(content);
content = NULL;
-
+
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, 10000);
+ 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 6571a2f..d13a28a 100644
--- a/src/restore.c
+++ b/src/restore.c
@@ -19,6 +19,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
#include <errno.h>
#include <string.h>
#include <stdlib.h>
@@ -89,7 +92,26 @@ static void plist_dict_add_label(plist_t plist, const char *label)
}
}
-LIBIMOBILEDEVICE_API restored_error_t restored_client_free(restored_client_t client)
+static restored_error_t restored_error(property_list_service_error_t err)
+{
+ switch (err) {
+ case PROPERTY_LIST_SERVICE_E_SUCCESS:
+ return RESTORE_E_SUCCESS;
+ case PROPERTY_LIST_SERVICE_E_INVALID_ARG:
+ return RESTORE_E_INVALID_ARG;
+ case PROPERTY_LIST_SERVICE_E_PLIST_ERROR:
+ return RESTORE_E_PLIST_ERROR;
+ case PROPERTY_LIST_SERVICE_E_MUX_ERROR:
+ return RESTORE_E_MUX_ERROR;
+ case PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT:
+ return RESTORE_E_RECEIVE_TIMEOUT;
+ default:
+ break;
+ }
+ return RESTORE_E_UNKNOWN_ERROR;
+}
+
+restored_error_t restored_client_free(restored_client_t client)
{
if (!client)
return RESTORE_E_INVALID_ARG;
@@ -99,9 +121,7 @@ LIBIMOBILEDEVICE_API restored_error_t restored_client_free(restored_client_t cli
if (client->parent) {
restored_goodbye(client);
- if (property_list_service_client_free(client->parent) == PROPERTY_LIST_SERVICE_E_SUCCESS) {
- ret = RESTORE_E_SUCCESS;
- }
+ ret = restored_error(property_list_service_client_free(client->parent));
}
if (client->udid) {
@@ -119,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)
@@ -129,41 +149,23 @@ 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;
- restored_error_t ret = RESTORE_E_SUCCESS;
- property_list_service_error_t err;
-
- err = property_list_service_receive_plist(client->parent, plist);
- if (err != PROPERTY_LIST_SERVICE_E_SUCCESS) {
- ret = RESTORE_E_UNKNOWN_ERROR;
- }
-
- if (!*plist)
- ret = RESTORE_E_PLIST_ERROR;
-
- return ret;
+ 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;
- restored_error_t ret = RESTORE_E_SUCCESS;
- property_list_service_error_t err;
-
- err = property_list_service_send_xml_plist(client->parent, plist);
- if (err != PROPERTY_LIST_SERVICE_E_SUCCESS) {
- ret = RESTORE_E_UNKNOWN_ERROR;
- }
- return ret;
+ 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;
@@ -222,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;
@@ -264,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;
@@ -305,9 +305,10 @@ LIBIMOBILEDEVICE_API restored_error_t restored_client_new(idevice_t device, rest
};
property_list_service_client_t plistclient = NULL;
- if (property_list_service_client_new(device, (lockdownd_service_descriptor_t)&service, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
+ ret = restored_error(property_list_service_client_new(device, (lockdownd_service_descriptor_t)&service, &plistclient));
+ if (ret != RESTORE_E_SUCCESS) {
debug_info("could not connect to restored (device %s)", device->udid);
- return RESTORE_E_MUX_ERROR;
+ return ret;
}
restored_client_t client_loc = (restored_client_t) malloc(sizeof(struct restored_client_private));
@@ -321,7 +322,7 @@ LIBIMOBILEDEVICE_API restored_error_t restored_client_new(idevice_t device, rest
idev_ret = idevice_get_udid(device, &client_loc->udid);
if (IDEVICE_E_SUCCESS != idev_ret) {
debug_info("failed to get device udid.");
- ret = RESTORE_E_DEVICE_ERROR;
+ ret = RESTORE_E_UNKNOWN_ERROR;
}
debug_info("device udid: %s", client_loc->udid);
@@ -334,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;
@@ -366,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;
@@ -390,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 0591f4a..365e130 100644
--- a/src/sbservices.c
+++ b/src/sbservices.c
@@ -19,6 +19,9 @@
* 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 <unistd.h>
@@ -76,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));
@@ -92,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;
@@ -112,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;
@@ -152,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;
@@ -169,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);
@@ -178,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;
@@ -215,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;
@@ -253,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 5c4a53f..c3cc9ba 100644
--- a/src/screenshotr.c
+++ b/src/screenshotr.c
@@ -2,7 +2,7 @@
* screenshotr.c
* com.apple.mobile.screenshotr service implementation.
*
- * Copyright (c) 2010 Nikias Bassen All Rights Reserved.
+ * Copyright (c) 2010-2019 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
@@ -19,6 +19,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
#include <plist/plist.h>
#include <string.h>
#include <stdlib.h>
@@ -27,7 +30,7 @@
#include "device_link_service.h"
#include "common/debug.h"
-#define SCREENSHOTR_VERSION_INT1 300
+#define SCREENSHOTR_VERSION_INT1 400
#define SCREENSHOTR_VERSION_INT2 0
/**
@@ -50,6 +53,10 @@ static screenshotr_error_t screenshotr_error(device_link_service_error_t err)
return SCREENSHOTR_E_PLIST_ERROR;
case DEVICE_LINK_SERVICE_E_MUX_ERROR:
return SCREENSHOTR_E_MUX_ERROR;
+ case DEVICE_LINK_SERVICE_E_SSL_ERROR:
+ return SCREENSHOTR_E_SSL_ERROR;
+ case DEVICE_LINK_SERVICE_E_RECEIVE_TIMEOUT:
+ return SCREENSHOTR_E_RECEIVE_TIMEOUT;
case DEVICE_LINK_SERVICE_E_BAD_VERSION:
return SCREENSHOTR_E_BAD_VERSION;
default:
@@ -58,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)
@@ -86,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;
@@ -103,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;
@@ -135,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 091b599..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,22 +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, 10000);
+ 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);
+}
+
+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_ssl(client->connection));
+ 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 579908c..9f4296e 100644
--- a/src/syslog_relay.c
+++ b/src/syslog_relay.c
@@ -2,7 +2,8 @@
* syslog_relay.c
* com.apple.syslog_relay service implementation.
*
- * Copyright (c) 2013 Martin Szulecki All Rights Reserved.
+ * Copyright (c) 2019-2020 Nikias Bassen, All Rights Reserved.
+ * Copyright (c) 2013-2015 Martin Szulecki, All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -33,6 +34,7 @@ struct syslog_relay_worker_thread {
syslog_relay_client_t client;
syslog_relay_receive_cb_t cbfunc;
void *user_data;
+ int is_raw;
};
/**
@@ -65,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;
@@ -93,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;
@@ -111,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;
@@ -152,11 +154,14 @@ 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(c != 0) {
+ if (srwt->is_raw) {
+ srwt->cbfunc(c, srwt->user_data);
+ } else if (c != 0) {
srwt->cbfunc(c, srwt->user_data);
}
}
@@ -170,7 +175,35 @@ 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;
+
+ syslog_relay_error_t res = SYSLOG_RELAY_E_UNKNOWN_ERROR;
+
+ if (client->worker) {
+ debug_info("Another syslog capture thread appears to be running already.");
+ return res;
+ }
+
+ /* start worker thread */
+ struct syslog_relay_worker_thread *srwt = (struct syslog_relay_worker_thread*)malloc(sizeof(struct syslog_relay_worker_thread));
+ if (srwt) {
+ srwt->client = client;
+ srwt->cbfunc = callback;
+ srwt->user_data = user_data;
+ srwt->is_raw = 0;
+
+ if (thread_new(&client->worker, syslog_relay_worker, srwt) == 0) {
+ res = SYSLOG_RELAY_E_SUCCESS;
+ }
+ }
+
+ return res;
+}
+
+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;
@@ -188,6 +221,7 @@ LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_start_capture(syslog_rela
srwt->client = client;
srwt->cbfunc = callback;
srwt->user_data = user_data;
+ srwt->is_raw = 1;
if (thread_new(&client->worker, syslog_relay_worker, srwt) == 0) {
res = SYSLOG_RELAY_E_SUCCESS;
@@ -197,7 +231,7 @@ LIBIMOBILEDEVICE_API syslog_relay_error_t syslog_relay_start_capture(syslog_rela
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 db929bb..4cac1fc 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,91 +1,144 @@
-AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)
-
-AM_CFLAGS = $(GLOBAL_CFLAGS) $(libgnutls_CFLAGS) $(libtasn1_CFLAGS) $(libgcrypt_CFLAGS) $(openssl_CFLAGS) $(libplist_CFLAGS) $(LFS_CFLAGS)
-AM_LDFLAGS = $(libgnutls_LIBS) $(libtasn1_LIBS) $(libgcrypt_LIBS) $(openssl_LIBS) $(libplist_LIBS)
-
-bin_PROGRAMS = idevice_id ideviceinfo idevicename idevicepair idevicesyslog ideviceimagemounter idevicescreenshot ideviceenterrecovery idevicedate idevicebackup idevicebackup2 ideviceprovision idevicedebugserverproxy idevicediagnostics idevicedebug idevicenotificationproxy idevicecrashreport
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)
+
+AM_CFLAGS = \
+ $(GLOBAL_CFLAGS) \
+ $(ssl_lib_CFLAGS) \
+ $(libplist_CFLAGS) \
+ $(LFS_CFLAGS)
+
+AM_LDFLAGS = \
+ $(libplist_LIBS)
+
+bin_PROGRAMS = \
+ idevicebtlogger\
+ idevice_id \
+ ideviceinfo \
+ idevicename \
+ idevicepair \
+ idevicesyslog \
+ ideviceimagemounter \
+ idevicescreenshot \
+ ideviceenterrecovery \
+ idevicedate \
+ idevicebackup \
+ idevicebackup2 \
+ ideviceprovision \
+ idevicedebugserverproxy \
+ idevicediagnostics \
+ idevicedebug \
+ idevicedevmodectl \
+ idevicenotificationproxy \
+ idevicecrashreport \
+ 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_LDADD = $(top_builddir)/src/libimobiledevice.la
+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
idevicename_CFLAGS = $(AM_CFLAGS)
idevicename_LDFLAGS = $(AM_LDFLAGS)
-idevicename_LDADD = $(top_builddir)/src/libimobiledevice.la
+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.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_LDADD = $(top_builddir)/src/libimobiledevice.la
+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
idevice_id_CFLAGS = $(AM_CFLAGS)
idevice_id_LDFLAGS = $(AM_LDFLAGS)
-idevice_id_LDADD = $(top_builddir)/src/libimobiledevice.la
+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_LDADD = $(top_builddir)/src/libimobiledevice.la
+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_LDADD = $(top_builddir)/src/libimobiledevice.la
+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_LDADD = $(top_builddir)/src/libimobiledevice.la
+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
idevicescreenshot_CFLAGS = $(AM_CFLAGS)
idevicescreenshot_LDFLAGS = $(AM_LDFLAGS)
-idevicescreenshot_LDADD = $(top_builddir)/src/libimobiledevice.la
+idevicescreenshot_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la
ideviceenterrecovery_SOURCES = ideviceenterrecovery.c
ideviceenterrecovery_CFLAGS = $(AM_CFLAGS)
ideviceenterrecovery_LDFLAGS = $(AM_LDFLAGS)
-ideviceenterrecovery_LDADD = $(top_builddir)/src/libimobiledevice.la
+ideviceenterrecovery_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la
idevicedate_SOURCES = idevicedate.c
idevicedate_CFLAGS = $(AM_CFLAGS)
idevicedate_LDFLAGS = $(AM_LDFLAGS)
-idevicedate_LDADD = $(top_builddir)/src/libimobiledevice.la
+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_LDADD = $(top_builddir)/src/libimobiledevice.la
+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_LDADD = $(top_builddir)/src/libimobiledevice.la
+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
idevicediagnostics_CFLAGS = $(AM_CFLAGS)
idevicediagnostics_LDFLAGS = $(AM_LDFLAGS)
-idevicediagnostics_LDADD = $(top_builddir)/src/libimobiledevice.la
+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.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)
idevicenotificationproxy_LDFLAGS = $(AM_LDFLAGS)
-idevicenotificationproxy_LDADD = $(top_builddir)/src/libimobiledevice.la
+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_LDADD = $(top_builddir)/src/libimobiledevice.la
+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 = $(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 558dcbe..540a6f2 100644
--- a/tools/idevice_id.c
+++ b/tools/idevice_id.c
@@ -2,7 +2,7 @@
* idevice_id.c
* Prints device name or a list of attached devices
*
- * Copyright (C) 2010 Nikias Bassen <nikias@gmx.li>
+ * Copyright (C) 2010-2018 Nikias Bassen <nikias@gmx.li>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -23,9 +23,12 @@
#include <config.h>
#endif
+#define TOOL_NAME "idevice_id"
+
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <getopt.h>
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
@@ -33,68 +36,96 @@
#define MODE_SHOW_ID 1
#define MODE_LIST_DEVICES 2
-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("Prints device name or a list of attached devices.\n\n");
- printf(" UDID is the unique device identifier of the device\n");
- printf(" for which the name should be retrieved.\n\n");
- printf(" -l, --list\t\tlist UDID of all attached devices\n");
- printf(" -d, --debug\t\tenable communication debugging\n");
- printf(" -h, --help\t\tprints usage information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\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"
+ "List attached devices or print device name of given device.\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"
+ "Bug Reports: <" PACKAGE_BUGREPORT ">\n"
+ );
}
int main(int argc, char **argv)
{
idevice_t device = NULL;
lockdownd_client_t client = NULL;
- char **dev_list = NULL;
+ idevice_info_t *dev_list = NULL;
char *device_name = NULL;
int ret = 0;
int i;
- int mode = MODE_SHOW_ID;
+ int mode = MODE_LIST_DEVICES;
+ int include_usb = 0;
+ int include_network = 0;
const char* udid = NULL;
- /* parse cmdline args */
- for (i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) {
+ int c = 0;
+ const struct option longopts[] = {
+ { "debug", no_argument, NULL, 'd' },
+ { "help", no_argument, NULL, 'h' },
+ { "list", no_argument, NULL, 'l' },
+ { "network", no_argument, NULL, 'n' },
+ { "version", no_argument, NULL, 'v' },
+ { NULL, 0, NULL, 0}
+ };
+
+ while ((c = getopt_long(argc, argv, "dhlnv", longopts, NULL)) != -1) {
+ switch (c) {
+ case 'd':
idevice_set_debug_level(1);
- continue;
- }
- else if (!strcmp(argv[i], "-l") || !strcmp(argv[i], "--list")) {
+ break;
+ case 'h':
+ print_usage(argc, argv, 0);
+ exit(EXIT_SUCCESS);
+ case 'l':
mode = MODE_LIST_DEVICES;
- continue;
- }
- else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
- print_usage(argc, argv);
+ include_usb = 1;
+ break;
+ case 'n':
+ mode = MODE_LIST_DEVICES;
+ include_network = 1;
+ break;
+ case 'v':
+ printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION);
return 0;
+ default:
+ print_usage(argc, argv, 1);
+ exit(EXIT_FAILURE);
}
}
+ argc -= optind;
+ argv += optind;
- /* check if udid was passed */
- if (mode == MODE_SHOW_ID) {
- i--;
- if (argc < 2 || !argv[i] || !*argv[i]) {
- print_usage(argc, argv);
- return 0;
- }
- udid = argv[i];
+ if (argc == 1) {
+ mode = MODE_SHOW_ID;
+ } else if (argc == 0 && optind == 1) {
+ include_usb = 1;
+ include_network = 1;
}
+ udid = argv[0];
switch (mode) {
case MODE_SHOW_ID:
- idevice_new(&device, udid);
+ idevice_new_with_options(&device, udid, IDEVICE_LOOKUP_USBMUX | IDEVICE_LOOKUP_NETWORK);
if (!device) {
fprintf(stderr, "ERROR: No device with UDID %s attached.\n", udid);
return -2;
}
- if (LOCKDOWN_E_SUCCESS != lockdownd_client_new(device, &client, "idevice_id")) {
+ if (LOCKDOWN_E_SUCCESS != lockdownd_client_new(device, &client, TOOL_NAME)) {
idevice_free(device);
fprintf(stderr, "ERROR: Connecting to device failed!\n");
return -2;
@@ -115,18 +146,29 @@ int main(int argc, char **argv)
if (device_name) {
free(device_name);
}
+ break;
- return ret;
case MODE_LIST_DEVICES:
default:
- if (idevice_get_device_list(&dev_list, &i) < 0) {
+ if (idevice_get_device_list_extended(&dev_list, &i) < 0) {
fprintf(stderr, "ERROR: Unable to retrieve device list!\n");
return -1;
}
for (i = 0; dev_list[i] != NULL; i++) {
- printf("%s\n", dev_list[i]);
+ if (dev_list[i]->conn_type == CONNECTION_USBMUXD && !include_usb) continue;
+ if (dev_list[i]->conn_type == CONNECTION_NETWORK && !include_network) continue;
+ printf("%s", dev_list[i]->udid);
+ if (include_usb && include_network) {
+ if (dev_list[i]->conn_type == CONNECTION_NETWORK) {
+ printf(" (Network)");
+ } else {
+ printf(" (USB)");
+ }
+ }
+ printf("\n");
}
- idevice_device_list_free(dev_list);
- return 0;
+ idevice_device_list_extended_free(dev_list);
+ break;
}
+ return ret;
}
diff --git a/tools/idevicebackup.c b/tools/idevicebackup.c
index de08295..5694c12 100644
--- a/tools/idevicebackup.c
+++ b/tools/idevicebackup.c
@@ -24,15 +24,31 @@
#include <config.h>
#endif
+#define TOOL_NAME "idevicebackup"
+
#include <stdio.h>
#include <string.h>
#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>
@@ -43,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"
@@ -76,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
}
@@ -94,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) {
@@ -107,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
}
@@ -329,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;
@@ -343,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");
@@ -466,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");
@@ -546,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);
}
@@ -557,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);
}
@@ -606,20 +613,20 @@ static void do_post_notification(const char *notification)
np_client_t np;
if (!client) {
- if (lockdownd_client_new_with_handshake(device, &client, "idevicebackup") != LOCKDOWN_E_SUCCESS) {
+ if (lockdownd_client_new_with_handshake(device, &client, TOOL_NAME) != LOCKDOWN_E_SUCCESS) {
return;
}
}
- 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) {
@@ -660,21 +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("Create or restore backup from the current or specified directory.\n\n");
- printf("commands:\n");
- printf(" backup\tSaves a device backup into DIRECTORY\n");
- printf(" restore\tRestores a device backup from DIRECTORY.\n\n");
- printf("options:\n");
- printf(" -d, --debug\t\tenable communication debugging\n");
- printf(" -u, --udid UDID\ttarget specific device by UDID\n");
- printf(" -h, --help\t\tprints usage information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\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[])
@@ -683,6 +697,7 @@ int main(int argc, char *argv[])
lockdownd_error_t ldret = LOCKDOWN_E_UNKNOWN_ERROR;
int i;
char* udid = NULL;
+ int use_network = 0;
lockdownd_service_descriptor_t service = NULL;
int cmd = -1;
int is_full_backup = 0;
@@ -697,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);
@@ -708,52 +731,59 @@ 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], "-h") || !strcmp(argv[i], "--help")) {
- print_usage(argc, argv);
+ udid = strdup(optarg);
+ break;
+ case 'n':
+ use_network = 1;
+ break;
+ case 'h':
+ print_usage(argc, argv, 0);
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);
+ case 'v':
+ printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION);
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) {
printf("ERROR: Backup directory \"%s\" does not exist!\n", backup_directory);
@@ -772,25 +802,24 @@ int main(int argc, char *argv[])
printf("Backup directory is \"%s\"\n", backup_directory);
- if (udid) {
- ret = idevice_new(&device, udid);
- if (ret != IDEVICE_E_SUCCESS) {
- printf("No device found with udid %s, is it plugged in?\n", udid);
- return -1;
+ 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;
}
- else
- {
- ret = idevice_new(&device, NULL);
- if (ret != IDEVICE_E_SUCCESS) {
- printf("No device found, is it plugged in?\n");
- return -1;
- }
+
+ if (!udid) {
+ idevice_get_udid(device, &udid);
}
- if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &client, "idevicebackup"))) {
+ 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;
}
@@ -810,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;
}
}
@@ -830,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;
@@ -838,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));
}
}
@@ -853,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);
@@ -869,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");
@@ -880,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;
@@ -913,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");
@@ -945,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;
@@ -963,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);
@@ -995,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;
}
@@ -1017,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 {
@@ -1048,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");
@@ -1101,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);
}
@@ -1143,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);
}
}
@@ -1214,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;
@@ -1245,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;
@@ -1372,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");
@@ -1592,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;
}
@@ -1613,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 58fda8d..c73b269 100644
--- a/tools/idevicebackup2.c
+++ b/tools/idevicebackup2.c
@@ -2,8 +2,8 @@
* idevicebackup2.c
* Command line interface to use the device's backup and restore service
*
- * Copyright (c) 2010-2018 Nikias Bassen All Rights Reserved.
- * Copyright (c) 2009-2010 Martin Szulecki 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
* modify it under the terms of the GNU Lesser General Public
@@ -24,6 +24,8 @@
#include <config.h>
#endif
+#define TOOL_NAME "idevicebackup2"
+
#include <stdio.h>
#include <string.h>
#include <errno.h>
@@ -34,6 +36,7 @@
#include <libgen.h>
#include <ctype.h>
#include <time.h>
+#include <getopt.h>
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
@@ -42,7 +45,9 @@
#include <libimobiledevice/afc.h>
#include <libimobiledevice/installation_proxy.h>
#include <libimobiledevice/sbservices.h>
-#include "common/utils.h"
+#include <libimobiledevice/diagnostics_relay.h>
+#include <libimobiledevice-glue/utils.h>
+#include <plist/plist.h>
#include <endianness.h>
@@ -53,6 +58,9 @@
#include <windows.h>
#include <conio.h>
#define sleep(x) Sleep(x*1000)
+#ifndef ELOOP
+#define ELOOP 114
+#endif
#else
#include <termios.h>
#include <sys/statvfs.h>
@@ -177,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);
@@ -345,7 +352,7 @@ static plist_t mobilebackup_factory_info_plist_new(const char* udid, idevice_t d
char *udid_uppercase = NULL;
lockdownd_client_t lockdown = NULL;
- if (lockdownd_client_new_with_handshake(device, &lockdown, "idevicebackup2") != LOCKDOWN_E_SUCCESS) {
+ if (lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME) != LOCKDOWN_E_SUCCESS) {
return NULL;
}
@@ -366,7 +373,7 @@ static plist_t mobilebackup_factory_info_plist_new(const char* udid, idevice_t d
plist_t app_dict = plist_new_dict();
plist_t installed_apps = plist_new_array();
instproxy_client_t ip = NULL;
- if (instproxy_client_start_service(device, &ip, "idevicebackup2") == INSTPROXY_E_SUCCESS) {
+ if (instproxy_client_start_service(device, &ip, TOOL_NAME) == INSTPROXY_E_SUCCESS) {
plist_t client_opts = instproxy_client_options_new();
instproxy_client_options_add(client_opts, "ApplicationType", "User", NULL);
instproxy_client_options_set_return_attributes(client_opts, "CFBundleIdentifier", "ApplicationSINF", "iTunesMetadata", NULL);
@@ -375,7 +382,7 @@ static plist_t mobilebackup_factory_info_plist_new(const char* udid, idevice_t d
instproxy_browse(ip, client_opts, &apps);
sbservices_client_t sbs = NULL;
- if (sbservices_client_start_service(device, &sbs, "idevicebackup2") != SBSERVICES_E_SUCCESS) {
+ if (sbservices_client_start_service(device, &sbs, TOOL_NAME) != SBSERVICES_E_SUCCESS) {
printf("Couldn't establish sbservices connection. Continuing anyway.\n");
}
@@ -545,9 +552,11 @@ static int write_restore_applications(plist_t info_plist, afc_client_t afc)
uint32_t applications_plist_xml_length = 0;
plist_t applications_plist = plist_dict_get_item(info_plist, "Applications");
- if (applications_plist) {
- plist_to_xml(applications_plist, &applications_plist_xml, &applications_plist_xml_length);
+ if (!applications_plist) {
+ printf("No Applications in Info.plist, skipping creation of RestoreApplications.plist\n");
+ return 0;
}
+ plist_to_xml(applications_plist, &applications_plist_xml, &applications_plist_xml_length);
if (!applications_plist_xml) {
printf("Error preparing RestoreApplications.plist\n");
goto leave;
@@ -598,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");
@@ -626,19 +635,19 @@ static void do_post_notification(idevice_t device, const char *notification)
lockdownd_client_t lockdown = NULL;
- if (lockdownd_client_new_with_handshake(device, &lockdown, "idevicebackup2") != LOCKDOWN_E_SUCCESS) {
+ if (lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME) != LOCKDOWN_E_SUCCESS) {
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) {
@@ -737,8 +746,18 @@ static int errno_to_device_error(int errno_value)
return -6;
case EEXIST:
return -7;
+ case ENOTDIR:
+ return -8;
+ case EISDIR:
+ return -9;
+ case ELOOP:
+ return -10;
+ case EIO:
+ return -11;
+ case ENOSPC:
+ return -15;
default:
- return -errno_value;
+ return -1;
}
}
@@ -954,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;
@@ -1349,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);
@@ -1397,49 +1419,60 @@ 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("Create or restore backup from the current or specified directory.\n\n");
- printf("commands:\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 system 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(" -d, --debug\t\tenable communication debugging\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(" -i, --interactive\trequest passwords interactively\n");
- printf(" -h, --help\t\tprints usage information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\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))
+
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;
lockdownd_service_descriptor_t service = NULL;
int cmd = -1;
int cmd_flags = 0;
@@ -1453,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);
@@ -1464,212 +1536,207 @@ 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], "-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], "backup")) {
- cmd = CMD_BACKUP;
- }
- else if (!strcmp(argv[i], "restore")) {
- cmd = CMD_RESTORE;
- }
- else if (!strcmp(argv[i], "--system")) {
+ case 'v':
+ printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION);
+ return 0;
+ 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;
- if (udid) {
- ret = idevice_new(&device, udid);
- if (ret != IDEVICE_E_SUCCESS) {
- printf("No device found with udid %s, is it plugged in?\n", udid);
- return -1;
+ 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;
}
- else
- {
- ret = idevice_new(&device, NULL);
- if (ret != IDEVICE_E_SUCCESS) {
- printf("No device found, is it plugged in?\n");
- return -1;
- }
+
+ if (!udid) {
idevice_get_udid(device, &udid);
}
@@ -1680,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");
@@ -1700,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);
@@ -1721,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);
}
@@ -1739,8 +1826,7 @@ int main(int argc, char *argv[])
}
}
- lockdownd_client_t lockdown = NULL;
- if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &lockdown, "idevicebackup2"))) {
+ 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);
return -1;
@@ -1757,8 +1843,26 @@ int main(int argc, char *argv[])
node_tmp = NULL;
}
+ /* get ProductVersion */
+ char *product_version = NULL;
+ int device_version = 0;
+ node_tmp = NULL;
+ lockdownd_get_value(lockdown, NULL, "ProductVersion", &node_tmp);
+ if (node_tmp) {
+ if (plist_get_node_type(node_tmp) == PLIST_STRING) {
+ plist_get_string_val(node_tmp, &product_version);
+ }
+ plist_free(node_tmp);
+ node_tmp = NULL;
+ }
+ if (product_version) {
+ int vers[3] = { 0, 0, 0 };
+ if (sscanf(product_version, "%d.%d.%d", &vers[0], &vers[1], &vers[2]) >= 2) {
+ device_version = DEVICE_VERSION(vers[0], vers[1], vers[2]);
+ }
+ }
+
/* 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);
@@ -1772,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;
}
}
@@ -1792,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;
@@ -1827,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");
@@ -1842,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);
@@ -1855,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");
@@ -1921,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);
@@ -1982,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));
}
@@ -1998,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 */
@@ -2055,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) {
@@ -2071,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 {
@@ -2108,6 +2228,32 @@ checkpoint:
}
if (newpw || backup_password) {
mobilebackup2_send_message(mobilebackup2, "ChangePassword", opts);
+ uint8_t passcode_hint = 0;
+ if (device_version >= DEVICE_VERSION(13,0,0)) {
+ diagnostics_relay_client_t diag = NULL;
+ if (diagnostics_relay_client_start_service(device, &diag, TOOL_NAME) == DIAGNOSTICS_RELAY_E_SUCCESS) {
+ plist_t dict = NULL;
+ plist_t keys = plist_new_array();
+ plist_array_append_item(keys, plist_new_string("PasswordConfigured"));
+ if (diagnostics_relay_query_mobilegestalt(diag, keys, &dict) == DIAGNOSTICS_RELAY_E_SUCCESS) {
+ plist_t node = plist_access_path(dict, 2, "MobileGestalt", "PasswordConfigured");
+ plist_get_bool_val(node, &passcode_hint);
+ }
+ plist_free(keys);
+ plist_free(dict);
+ diagnostics_relay_goodbye(diag);
+ diagnostics_relay_client_free(diag);
+ }
+ }
+ if (passcode_hint) {
+ if (cmd_flags & CMD_FLAG_ENCRYPTION_CHANGEPW) {
+ PRINT_VERBOSE(1, "Please confirm changing the backup password by entering the passcode on the device.\n");
+ } else if (cmd_flags & CMD_FLAG_ENCRYPTION_ENABLE) {
+ PRINT_VERBOSE(1, "Please confirm enabling the backup encryption by entering the passcode on the device.\n");
+ } else if (cmd_flags & CMD_FLAG_ENCRYPTION_DISABLE) {
+ PRINT_VERBOSE(1, "Please confirm disabling the backup encryption by entering the passcode on the device.\n");
+ }
+ }
/*if (cmd_flags & CMD_FLAG_ENCRYPTION_ENABLE) {
int retr = 10;
while ((retr-- >= 0) && !backup_domain_changed) {
@@ -2128,6 +2274,7 @@ checkpoint:
int operation_ok = 0;
plist_t message = NULL;
+ mobilebackup2_error_t mberr;
char *dlmsg = NULL;
int file_count = 0;
int errcode = 0;
@@ -2138,10 +2285,13 @@ checkpoint:
do {
free(dlmsg);
dlmsg = NULL;
- mobilebackup2_receive_message(mobilebackup2, &message, &dlmsg);
- if (!message || !dlmsg) {
- PRINT_VERBOSE(1, "Device is not ready yet. Going to try again in 2 seconds...\n");
- sleep(2);
+ mberr = mobilebackup2_receive_message(mobilebackup2, &message, &dlmsg);
+ if (mberr == MOBILEBACKUP2_E_RECEIVE_TIMEOUT) {
+ PRINT_VERBOSE(2, "Device is not ready yet, retrying...\n");
+ goto files_out;
+ } else if (mberr != MOBILEBACKUP2_E_SUCCESS) {
+ PRINT_VERBOSE(0, "ERROR: Could not receive from mobilebackup2 (%d)\n", mberr);
+ quit_flag++;
goto files_out;
}
@@ -2172,6 +2322,11 @@ checkpoint:
plist_t freespace_item = plist_new_uint(freespace);
mobilebackup2_send_status_response(mobilebackup2, res, NULL, freespace_item);
plist_free(freespace_item);
+ } else if (!strcmp(dlmsg, "DLMessagePurgeDiskSpace")) {
+ /* device wants to purge disk space on the host - not supported */
+ plist_t empty_dict = plist_new_dict();
+ err = mobilebackup2_send_status_response(mobilebackup2, -1, "Operation not supported", empty_dict);
+ plist_free(empty_dict);
} else if (!strcmp(dlmsg, "DLContentsOfDirectory")) {
/* list directory contents */
mb2_handle_list_directory(mobilebackup2, message, backup_directory);
@@ -2359,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);
@@ -2447,12 +2602,18 @@ files_out:
}
break;
case CMD_RESTORE:
- if ((cmd_flags & CMD_FLAG_RESTORE_NO_REBOOT) == 0)
- PRINT_VERBOSE(1, "The device should reboot now.\n");
if (operation_ok) {
+ if ((cmd_flags & CMD_FLAG_RESTORE_NO_REBOOT) == 0)
+ PRINT_VERBOSE(1, "The device should reboot now.\n");
PRINT_VERBOSE(1, "Restore Successful.\n");
} else {
- PRINT_VERBOSE(1, "Restore Failed (Error Code %d).\n", -result_code);
+ afc_remove_path(afc, "/iTunesRestore/RestoreApplications.plist");
+ afc_remove_path(afc, "/iTunesRestore");
+ if (quit_flag) {
+ PRINT_VERBOSE(1, "Restore Aborted.\n");
+ } else {
+ PRINT_VERBOSE(1, "Restore Failed (Error Code %d).\n", -result_code);
+ }
}
break;
case CMD_INFO:
@@ -2477,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 533265c..09bd537 100644
--- a/tools/idevicecrashreport.c
+++ b/tools/idevicecrashreport.c
@@ -24,11 +24,17 @@
#include <config.h>
#endif
+#define TOOL_NAME "idevicecrashreport"
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include "common/utils.h"
+#include <getopt.h>
+#ifndef WIN32
+#include <signal.h>
+#endif
+#include <libimobiledevice-glue/utils.h>
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
@@ -42,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;
@@ -72,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);
@@ -95,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;
@@ -143,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 {
@@ -226,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) {
@@ -293,20 +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("Move crash reports from device to a local DIRECTORY.\n\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(" -u, --udid UDID\ttarget specific device by UDID\n");
- printf(" -h, --help\t\tprints usage information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\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[])
@@ -319,70 +347,97 @@ 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], "-h") || !strcmp(argv[i], "--help")) {
- print_usage(argc, argv);
+ udid = optarg;
+ break;
+ case 'n':
+ use_network = 1;
+ break;
+ case 'h':
+ print_usage(argc, argv, 0);
return 0;
- }
- else if (!strcmp(argv[i], "-e") || !strcmp(argv[i], "--extract")) {
+ case 'v':
+ printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION);
+ return 0;
+ 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(&device, udid);
+ device_error = idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX);
if (device_error != IDEVICE_E_SUCCESS) {
if (udid) {
- printf("No device found with udid %s, is it plugged in?\n", udid);
+ printf("No device found with udid %s.\n", udid);
} else {
- printf("No device found, is it plugged in?\n");
+ printf("No device found.\n");
}
return -1;
}
- lockdownd_error = lockdownd_client_new_with_handshake(device, &lockdownd, "idevicecrashreport");
+ lockdownd_error = lockdownd_client_new_with_handshake(device, &lockdownd, TOOL_NAME);
if (lockdownd_error != LOCKDOWN_E_SUCCESS) {
fprintf(stderr, "ERROR: Could not connect to lockdownd, error code %d\n", lockdownd_error);
idevice_free(device);
@@ -391,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;
@@ -419,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);
@@ -434,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;
@@ -456,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 2676880..d05f63e 100644
--- a/tools/idevicedate.c
+++ b/tools/idevicedate.c
@@ -23,39 +23,56 @@
#include <config.h>
#endif
+#define TOOL_NAME "idevicedate"
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <getopt.h>
#include <time.h>
#if HAVE_LANGINFO_CODESET
#include <langinfo.h>
#endif
+#ifndef WIN32
+#include <signal.h>
+#endif
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
#ifdef _DATE_FMT
-#define DATE_FMT_LANGINFO() nl_langinfo (_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() ""
+#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("Display the current date or set it on a device.\n\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\n");
- printf(" -d, --debug\t\tenable communication debugging\n");
- printf(" -u, --udid UDID\ttarget specific device by UDID\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(" -h, --help\t\tprints usage information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\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[])
@@ -64,86 +81,95 @@ 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;
plist_t node = NULL;
int node_type = -1;
uint64_t datetime = 0;
time_t rawtime;
struct tm * tmp;
- char const *format = NULL;
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], "-s") || !strcmp(argv[i], "--set")) {
- i++;
- if (!argv[i] || (strlen(argv[i]) <= 1)) {
- print_usage(argc, argv);
- return 0;
+ 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;
+ 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 {
- print_usage(argc, argv);
- return 0;
- }
- }
-
- /* determine a date format */
- if (!format) {
- format = DATE_FMT_LANGINFO ();
- if (!*format) {
- format = "%a %b %e %H:%M:%S %Z %Y";
+ break;
+ default:
+ print_usage(argc, argv, 1);
+ return 2;
}
}
+ argc -= optind;
+ argv += optind;
- 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, is it plugged in?\n", udid);
+ printf("No device found with udid %s.\n", udid);
} else {
- printf("No device found, is it plugged in?\n");
+ printf("No device found.\n");
}
return -1;
}
- if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &client, "idevicedate"))) {
+ if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &client, TOOL_NAME))) {
fprintf(stderr, "ERROR: Could not connect to lockdownd, error code %d\n", ldret);
result = -1;
goto cleanup;
@@ -189,7 +215,7 @@ int main(int argc, char *argv[])
tmp = localtime(&rawtime);
/* finally we format and print the current date */
- strftime(buffer, 80, format, tmp);
+ strftime(buffer, 80, DATE_FMT_LANGINFO, tmp);
puts(buffer);
} else {
datetime = setdate;
@@ -211,7 +237,7 @@ int main(int argc, char *argv[])
if(lockdownd_set_value(client, NULL, "TimeIntervalSince1970", node) == LOCKDOWN_E_SUCCESS) {
tmp = localtime(&setdate);
- strftime(buffer, 80, format, tmp);
+ strftime(buffer, 80, DATE_FMT_LANGINFO, tmp);
puts(buffer);
} else {
printf("ERROR: Failed to set date on device.\n");
diff --git a/tools/idevicedebug.c b/tools/idevicedebug.c
index c7508e3..36c594e 100644
--- a/tools/idevicedebug.c
+++ b/tools/idevicedebug.c
@@ -23,6 +23,8 @@
#include <config.h>
#endif
+#define TOOL_NAME "idevicedebug"
+
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
@@ -30,6 +32,7 @@
#include <time.h>
#include <unistd.h>
#include <libgen.h>
+#include <getopt.h>
#ifdef WIN32
#include <windows.h>
@@ -42,9 +45,14 @@
#include <plist/plist.h>
#include "common/debug.h"
+static int debug_level = 0;
+
+#define log_debug(...) if (debug_level > 0) { printf(__VA_ARGS__); fputc('\n', stdout); }
+
enum cmd_mode {
CMD_NONE = 0,
- CMD_RUN
+ CMD_RUN,
+ CMD_KILL
};
static int quit_flag = 0;
@@ -55,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;
@@ -93,7 +106,7 @@ static instproxy_error_t instproxy_client_get_object_by_key_from_info_directiona
if (object) {
*node = plist_copy(object);
} else {
- debug_info("key %s not found", key);
+ log_debug("key %s not found", key);
return INSTPROXY_E_OP_FAILED;
}
@@ -102,97 +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);
- debug_info("result: %d", dres);
- debugserver_command_free(command);
- command = NULL;
} else if (r[0] == 'T') {
/* thread stopped information */
- debug_info("Thread stopped. Details:\n%s", r + 1);
-
- free(*response);
- *response = NULL;
-
- if (!send_reply)
- return dres;
-
+ log_debug("Thread stopped. Details:\n%s", r + 1);
+ 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);
- debug_info("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);
- debug_info("result: %d", dres);
- debugserver_command_free(command);
- command = NULL;
+ log_debug("empty response");
} else {
- debug_info("ERROR: unhandled response", r);
+ 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("Interact with the debugserver service of a device.\n\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(" -e, --env NAME=VALUE\tset environment variable NAME to VALUE\n");
- printf(" -u, --udid UDID\ttarget specific device by UDID\n");
- printf(" -d, --debug\t\tenable communication debugging\n");
- printf(" -h, --help\t\tprints usage information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\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[])
@@ -203,9 +209,10 @@ int main(int argc, char *argv[])
instproxy_client_t instproxy_client = NULL;
debugserver_client_t debugserver_client = NULL;
int i;
- int debug_level = 0;
int cmd = CMD_NONE;
const char* udid = NULL;
+ int use_network = 0;
+ int detach_after_start = 0;
const char* bundle_identifier = NULL;
char* path = NULL;
char* working_directory = NULL;
@@ -217,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);
@@ -225,26 +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);
+ }
+ break;
+ case 'u':
+ if (!*optarg) {
+ fprintf(stderr, "ERROR: UDID must not be empty!\n");
+ print_usage(argc, argv, 1);
+ return 2;
}
- udid = argv[i];
- 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;
+ udid = optarg;
+ break;
+ case 'n':
+ use_network = 1;
+ break;
+ case 1:
+ detach_after_start = 1;
+ 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 */
@@ -252,238 +278,323 @@ 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], "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);
+ case 'v':
+ printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION);
res = 0;
goto cleanup;
+ break;
+ 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(&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, is it plugged in?\n", udid);
+ printf("No device found with udid %s.\n", udid);
} else {
- printf("No device found, is it plugged in?\n");
+ printf("No device found.\n");
}
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, "idevicerun") != 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);
- debug_info("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;
+ }
+
+ 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;
+ }
+
+ 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;
+
+ 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;
+ }
+
+ /* 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 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;
+ }
- /* start and connect to debugserver */
- if (debugserver_client_start_service(device, &debugserver_client, "idevicerun") != 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");
+ /* 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;
}
+ free(response);
+ response = NULL;
+ }
+ }
- /* enable logging for the session in debug mode */
- if (debug_level) {
- debug_info("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);
- 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;
- }
- }
+ /* 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 maximum packet size */
- debug_info("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);
- 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;
- }
+ /* 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;
+ }
- /* set working directory */
- debug_info("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);
+ 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;
- }
- /* set environment */
- if (environment) {
- debug_info("Setting environment...");
- for (environment_index = 0; environment_index < environment_count; environment_index++) {
- debug_info("setting environment variable: %s", environment[environment_index]);
- debugserver_client_set_environment_hex_encoded(debugserver_client, environment[environment_index], NULL);
- }
- }
+ res = (dres == DEBUGSERVER_E_SUCCESS) ? 0: -1;
+ goto cleanup;
+ }
- /* set arguments and run app */
- debug_info("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;
- debug_info("app_argv[%d] = %s", 0, app_argv[0]);
- app_argc = 1;
- while (i < argc && argv && argv[i]) {
- debug_info("app_argv[%d] = %s", app_argc, argv[i]);
- app_argv[app_argc++] = argv[i];
- i++;
+ /* 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;
}
- app_argv[app_argc] = NULL;
- debugserver_client_set_argv(debugserver_client, app_argc, app_argv, NULL);
- free(app_argv);
-
- /* check if launch succeeded */
- debug_info("Checking if launch succeeded...");
- debugserver_command_new("qLaunchSuccess", 0, NULL, &command);
- dres = debugserver_client_send_command(debugserver_client, command, &response);
- 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;
+ free(response);
+ response = 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);
+
+ /* 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 */
- debug_info("Setting thread...");
- debugserver_command_new("Hc0", 0, NULL, &command);
- dres = debugserver_client_send_command(debugserver_client, command, &response);
- 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 */
- debug_info("Continue running process...");
- debugserver_command_new("c", 0, NULL, &command);
- dres = debugserver_client_send_command(debugserver_client, command, &response);
- debugserver_command_free(command);
- command = NULL;
-
- /* main loop which is parsing/handling packets during the run */
- debug_info("Entering run loop...");
- while (!quit_flag) {
- if (dres != DEBUGSERVER_E_SUCCESS) {
- debug_info("failed to receive response");
- break;
- }
+ dres = debugserver_client_receive_response(debugserver_client, &response, NULL);
+ }
- if (response) {
- debug_info("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 */
- debug_info("Killing process...");
- debugserver_command_new("k", 0, NULL, &command);
- dres = debugserver_client_send_command(debugserver_client, command, &response);
- 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 e99d0bf..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
@@ -23,34 +24,48 @@
#include <config.h>
#endif
+#define TOOL_NAME "idevicedebugserverproxy"
+
#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;
};
@@ -63,167 +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("Proxy debugserver connection from device to a local socket at PORT.\n\n");
- printf(" -d, --debug\t\tenable communication debugging\n");
- printf(" -u, --udid UDID\ttarget specific device by UDID\n");
- printf(" -h, --help\t\tprints usage information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\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);
+static int intercept_packet(char *packet, ssize_t *packet_len) {
+ static const char kReqLaunchServer[] = "$qLaunchGDBServer;#4b";
- 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);
-
- 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, "idevicedebugserverproxy");
- 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__);
@@ -243,10 +205,19 @@ int main(int argc, char *argv[])
idevice_t device = NULL;
thread_info_t *thread_list = NULL;
const char* udid = NULL;
- uint16_t local_port = 0;
+ int use_network = 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;
@@ -271,63 +242,76 @@ 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], "-h") || !strcmp(argv[i], "--help")) {
- print_usage(argc, argv);
- return EXIT_SUCCESS;
- }
- else if (atoi(argv[i]) > 0) {
- local_port = atoi(argv[i]);
- continue;
- }
- else {
- print_usage(argc, argv);
- return EXIT_SUCCESS;
+ udid = optarg;
+ break;
+ case 'n':
+ use_network = 1;
+ 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 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 */
- 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) {
- fprintf(stderr, "No device found with udid %s, is it plugged in?\n", udid);
+ fprintf(stderr, "No device found with udid %s.\n", udid);
} else {
- fprintf(stderr, "No device found, is it plugged in?\n");
+ fprintf(stderr, "No device found.\n");
}
result = EXIT_FAILURE;
goto leave_cleanup;
}
/* create local socket */
- server_fd = socket_create(local_port);
+ server_fd = socket_create("127.0.0.1", local_port);
if (server_fd < 0) {
fprintf(stderr, "Could not create socket\n");
result = EXIT_FAILURE;
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);
@@ -344,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) {
@@ -373,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 08e7c5e..e699bc4 100644
--- a/tools/idevicediagnostics.c
+++ b/tools/idevicediagnostics.c
@@ -23,11 +23,17 @@
#include <config.h>
#endif
+#define TOOL_NAME "idevicediagnostics"
+
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <getopt.h>
#include <errno.h>
#include <time.h>
+#ifndef WIN32
+#include <signal.h>
+#endif
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
@@ -54,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)
{
@@ -63,131 +96,133 @@ int main(int argc, char **argv)
diagnostics_relay_client_t diagnostics_client = NULL;
lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
lockdownd_service_descriptor_t service = NULL;
- int result = -1;
- int i;
+ int result = EXIT_FAILURE;
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 = 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], "sleep")) {
- cmd = CMD_SLEEP;
- }
- else if (!strcmp(argv[i], "restart")) {
- cmd = CMD_RESTART;
- }
- else if (!strcmp(argv[i], "shutdown")) {
- cmd = CMD_SHUTDOWN;
+ 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;
}
- 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("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("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 0;
+ }
+ 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;
}
- if (IDEVICE_E_SUCCESS != idevice_new(&device, udid)) {
+ if (IDEVICE_E_SUCCESS != idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX)) {
if (udid) {
- printf("No device found with udid %s, is it plugged in?\n", udid);
+ printf("No device found with udid %s.\n", udid);
} else {
- printf("No device found, is it plugged in?\n");
+ printf("No device found.\n");
}
goto cleanup;
}
- if (LOCKDOWN_E_SUCCESS != (ret = lockdownd_client_new_with_handshake(device, &lockdown_client, "idevicediagnostics"))) {
+ if (LOCKDOWN_E_SUCCESS != (ret = lockdownd_client_new_with_handshake(device, &lockdown_client, TOOL_NAME))) {
idevice_free(device);
printf("ERROR: Could not connect to lockdownd, error code %d\n", ret);
goto cleanup;
@@ -195,17 +230,23 @@ 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)) {
if (diagnostics_relay_client_new(device, service, &diagnostics_client) != DIAGNOSTICS_RELAY_E_SUCCESS) {
- printf("Could not connect to diagnostics_relay!\n");
- result = -1;
+ printf("ERROR: Could not connect to diagnostics_relay!\n");
} else {
switch (cmd) {
case CMD_SLEEP:
@@ -213,7 +254,7 @@ int main(int argc, char **argv)
printf("Putting device into deep sleep mode.\n");
result = EXIT_SUCCESS;
} else {
- printf("Failed to put device into deep sleep mode.\n");
+ printf("ERROR: Failed to put device into deep sleep mode.\n");
}
break;
case CMD_RESTART:
@@ -221,7 +262,7 @@ int main(int argc, char **argv)
printf("Restarting device.\n");
result = EXIT_SUCCESS;
} else {
- printf("Failed to restart device.\n");
+ printf("ERROR: Failed to restart device.\n");
}
break;
case CMD_SHUTDOWN:
@@ -229,7 +270,7 @@ int main(int argc, char **argv)
printf("Shutting down device.\n");
result = EXIT_SUCCESS;
} else {
- printf("Failed to shutdown device.\n");
+ printf("ERROR: Failed to shutdown device.\n");
}
break;
case CMD_MOBILEGESTALT:
@@ -239,7 +280,7 @@ int main(int argc, char **argv)
result = EXIT_SUCCESS;
}
} else {
- printf("Unable to query mobilegestalt keys.\n");
+ printf("ERROR: Unable to query mobilegestalt keys.\n");
}
break;
case CMD_IOREGISTRY_ENTRY:
@@ -249,7 +290,7 @@ int main(int argc, char **argv)
result = EXIT_SUCCESS;
}
} else {
- printf("Unable to retrieve IORegistry from device.\n");
+ printf("ERROR: Unable to retrieve IORegistry from device.\n");
}
break;
case CMD_IOREGISTRY:
@@ -259,7 +300,7 @@ int main(int argc, char **argv)
result = EXIT_SUCCESS;
}
} else {
- printf("Unable to retrieve IORegistry from device.\n");
+ printf("ERROR: Unable to retrieve IORegistry from device.\n");
}
break;
case CMD_DIAGNOSTICS:
@@ -270,7 +311,7 @@ int main(int argc, char **argv)
result = EXIT_SUCCESS;
}
} else {
- printf("Unable to retrieve diagnostics from device.\n");
+ printf("ERROR: Unable to retrieve diagnostics from device.\n");
}
break;
}
@@ -279,7 +320,7 @@ int main(int argc, char **argv)
diagnostics_relay_client_free(diagnostics_client);
}
} else {
- printf("Could not start diagnostics service!\n");
+ printf("ERROR: Could not start diagnostics service!\n");
}
if (service) {
@@ -301,25 +342,3 @@ cleanup:
}
return result;
}
-
-void print_usage(int argc, char **argv)
-{
- char *name = NULL;
- name = strrchr(argv[0], '/');
- printf("Usage: %s COMMAND [OPTIONS]\n", (name ? name + 1: argv[0]));
- printf("Use diagnostics interface of a device running iOS 4 or later.\n\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\n");
- printf(" The following OPTIONS are accepted:\n");
- printf(" -d, --debug\t\tenable communication debugging\n");
- printf(" -u, --udid UDID\ttarget specific device by UDID\n");
- printf(" -h, --help\t\tprints usage information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\n");
-}
diff --git a/tools/ideviceenterrecovery.c b/tools/ideviceenterrecovery.c
index 69484cc..29cc5c9 100644
--- a/tools/ideviceenterrecovery.c
+++ b/tools/ideviceenterrecovery.c
@@ -23,25 +23,36 @@
#include <config.h>
#endif
+#define TOOL_NAME "ideviceenterrecovery"
+
#include <stdio.h>
#include <string.h>
-#include <errno.h>
#include <stdlib.h>
+#include <getopt.h>
+#include <errno.h>
+#ifndef WIN32
+#include <signal.h>
+#endif
#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("Makes a device with the supplied UDID enter recovery mode immediately.\n\n");
- printf(" -d, --debug\t\tenable communication debugging\n");
- printf(" -h, --help\t\tprints usage information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\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[])
@@ -50,50 +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;
+ 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, is it plugged in?\n", udid);
- return -1;
+ printf("No device found with udid %s.\n", udid);
+ return 1;
}
- if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new(device, &client, "ideviceenterrecovery"))) {
- printf("ERROR: Could not connect to lockdownd, error code %d\n", ldret);
+ if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new(device, &client, TOOL_NAME))) {
+ 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 7101c7e..f551b6c 100644
--- a/tools/ideviceimagemounter.c
+++ b/tools/ideviceimagemounter.c
@@ -23,6 +23,8 @@
#include <config.h>
#endif
+#define TOOL_NAME "ideviceimagemounter"
+
#include <stdlib.h>
#define _GNU_SOURCE 1
#define __USE_GNU 1
@@ -34,6 +36,9 @@
#include <time.h>
#include <sys/time.h>
#include <inttypes.h>
+#ifndef WIN32
+#include <signal.h>
+#endif
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
@@ -41,12 +46,13 @@
#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;
static int xml_mode = 0;
-static char *udid = NULL;
-static char *imagetype = NULL;
+static const char *udid = NULL;
+static const char *imagetype = NULL;
static const char PKG_PATH[] = "PublicStaging";
static const char PATH_PREFIX[] = "/private/var/mobile/Media";
@@ -56,62 +62,70 @@ 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\n", (name ? name + 1: argv[0]));
- printf("Mounts the specified disk image on the device.\n\n");
- printf(" -u, --udid UDID\ttarget specific device by UDID\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("\n");
- printf("Homepage: <" PACKAGE_URL ">\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)
{
static struct option longopts[] = {
- {"help", no_argument, NULL, 'h'},
- {"udid", required_argument, NULL, 'u'},
- {"list", no_argument, NULL, 'l'},
- {"imagetype", required_argument, NULL, 't'},
- {"xml", no_argument, NULL, 'x'},
- {"debug", no_argument, NULL, 'd'},
- {NULL, 0, NULL, 0}
+ { "help", no_argument, NULL, 'h' },
+ { "udid", required_argument, NULL, 'u' },
+ { "network", no_argument, NULL, 'n' },
+ { "list", no_argument, NULL, 'l' },
+ { "imagetype", required_argument, NULL, 't' },
+ { "xml", no_argument, NULL, 'x' },
+ { "debug", no_argument, NULL, 'd' },
+ { "version", no_argument, NULL, 'v' },
+ { NULL, 0, NULL, 0 }
};
int c;
while (1) {
- c = getopt_long(argc, argv, "hu:lt:xd", longopts, NULL);
+ c = getopt_long(argc, argv, "hu:lt:xdnv", longopts, NULL);
if (c == -1) {
break;
}
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);
}
- free(udid);
- udid = strdup(optarg);
+ udid = optarg;
+ break;
+ case 'n':
+ use_network = 1;
break;
case 'l':
list_mode = 1;
break;
case 't':
- if (imagetype)
- free(imagetype);
- imagetype = strdup(optarg);
+ imagetype = optarg;
break;
case 'x':
xml_mode = 1;
@@ -119,22 +133,16 @@ static void parse_opts(int argc, char **argv)
case 'd':
idevice_set_debug_level(1);
break;
+ case 'v':
+ 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);
@@ -153,6 +161,9 @@ int main(int argc, char **argv)
size_t image_size = 0;
char *image_sig_path = NULL;
+#ifndef WIN32
+ signal(SIGPIPE, SIG_IGN);
+#endif
parse_opts(argc, argv);
argc -= optind;
@@ -174,12 +185,16 @@ int main(int argc, char **argv)
}
}
- if (IDEVICE_E_SUCCESS != idevice_new(&device, udid)) {
- printf("No device found, is it plugged in?\n");
+ if (IDEVICE_E_SUCCESS != idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX)) {
+ if (udid) {
+ printf("No device found with udid %s.\n", udid);
+ } else {
+ printf("No device found.\n");
+ }
return -1;
}
- if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &lckd, "ideviceimagemounter"))) {
+ if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &lckd, TOOL_NAME))) {
printf("ERROR: Could not connect to lockdown, error code %d.\n", ldret);
goto leave;
}
@@ -200,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) {
@@ -248,23 +277,18 @@ int main(int argc, char **argv)
lockdownd_client_free(lckd);
lckd = NULL;
- mobile_image_mounter_error_t err;
+ mobile_image_mounter_error_t err = MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR;
plist_t result = NULL;
if (list_mode) {
/* list mounts mode */
if (!imagetype) {
- imagetype = strdup("Developer");
+ imagetype = "Developer";
}
err = mobile_image_mounter_lookup_image(mim, imagetype, &result);
- free(imagetype);
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);
}
@@ -302,7 +326,7 @@ int main(int argc, char **argv)
if (!imagetype) {
- imagetype = strdup("Developer");
+ imagetype = "Developer";
}
switch(disk_image_upload_type) {
@@ -344,7 +368,7 @@ int main(int argc, char **argv)
uint32_t written, total = 0;
while (total < amount) {
written = 0;
- if (afc_file_write(afc, af, buf, amount, &written) !=
+ if (afc_file_write(afc, af, buf + total, amount - total, &written) !=
AFC_E_SUCCESS) {
fprintf(stderr, "AFC Write error!\n");
break;
@@ -368,11 +392,18 @@ int main(int argc, char **argv)
fclose(f);
+ if (err != MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
+ if (err == MOBILE_IMAGE_MOUNTER_E_DEVICE_LOCKED) {
+ printf("ERROR: Device is locked, can't mount. Unlock device and try again.\n");
+ } else {
+ printf("ERROR: Unknown error occurred, can't mount.\n");
+ }
+ goto error_out;
+ }
printf("done.\n");
printf("Mounting...\n");
err = mobile_image_mounter_mount_image(mim, mountname, sig, sig_length, imagetype, &result);
- free(imagetype);
if (err == MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
if (result) {
plist_t node = plist_dict_get_item(result, "Status");
@@ -385,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");
@@ -410,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 {
@@ -435,6 +450,7 @@ int main(int argc, char **argv)
plist_free(result);
}
+error_out:
/* perform hangup command */
mobile_image_mounter_hangup(mim);
/* free client */
diff --git a/tools/ideviceinfo.c b/tools/ideviceinfo.c
index 59fade8..fd45763 100644
--- a/tools/ideviceinfo.c
+++ b/tools/ideviceinfo.c
@@ -2,6 +2,7 @@
* ideviceinfo.c
* Simple utility to show information about an attached device
*
+ * Copyright (c) 2010-2019 Nikias Bassen, All Rights Reserved.
* Copyright (c) 2009 Martin Szulecki All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
@@ -23,14 +24,20 @@
#include <config.h>
#endif
+#define TOOL_NAME "ideviceinfo"
+
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
+#include <getopt.h>
+#ifndef WIN32
+#include <signal.h>
+#endif
#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
@@ -67,10 +74,12 @@ static const char *domains[] = {
"com.apple.iTunes",
"com.apple.mobile.iTunes.store",
"com.apple.mobile.iTunes",
+ "com.apple.fmip",
+ "com.apple.Accessibility",
NULL
};
-static int is_domain_known(char *domain)
+static int is_domain_known(const char *domain)
{
int i = 0;
while (domains[i] != NULL) {
@@ -81,28 +90,36 @@ static int is_domain_known(char *domain)
return 0;
}
-static void print_usage(int argc, char **argv)
+static void print_usage(int argc, char **argv, int is_error)
{
int i = 0;
- char *name = NULL;
-
- name = strrchr(argv[0], '/');
- printf("Usage: %s [OPTIONS]\n", (name ? name + 1: argv[0]));
- printf("Show information about a connected device.\n\n");
- printf(" -d, --debug\t\tenable communication debugging\n");
- printf(" -s, --simple\t\tuse a simple connection to avoid auto-pairing with the device\n");
- printf(" -u, --udid UDID\ttarget specific device by UDID\n");
- printf(" -q, --domain NAME\tset domain of query to NAME. Default: None\n");
- printf(" -k, --key NAME\tonly query key specified by NAME. Default: All keys.\n");
- printf(" -x, --xml\t\toutput information as xml plist instead of key/value pairs\n");
- printf(" -h, --help\t\tprints usage information\n");
- printf("\n");
- printf(" Known domains are:\n\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"
+ "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");
while (domains[i] != NULL) {
- printf(" %s\n", domains[i++]);
+ fprintf(is_error ? stderr : stdout, " %s\n", domains[i++]);
}
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\n");
+ fprintf(is_error ? stderr : stdout,
+ "\n" \
+ "Homepage: <" PACKAGE_URL ">\n"
+ "Bug Reports: <" PACKAGE_BUGREPORT ">\n"
+ );
}
int main(int argc, char *argv[])
@@ -111,88 +128,109 @@ 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;
int simple = 0;
int format = FORMAT_KEY_VALUE;
const char* udid = NULL;
- char *domain = NULL;
- char *key = NULL;
+ int use_network = 0;
+ const char *domain = NULL;
+ const char *key = NULL;
char *xml_doc = NULL;
uint32_t xml_length;
plist_t node = NULL;
- /* parse cmdline args */
- for (i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) {
+ 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' },
+ { "domain", required_argument, NULL, 'q' },
+ { "key", required_argument, NULL, 'k' },
+ { "simple", no_argument, NULL, 's' },
+ { "xml", no_argument, NULL, 'x' },
+ { "version", no_argument, NULL, 'v' },
+ { NULL, 0, NULL, 0}
+ };
+
+#ifndef WIN32
+ signal(SIGPIPE, SIG_IGN);
+#endif
+
+ while ((c = getopt_long(argc, argv, "dhu:nq:k:sxv", 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;
- }
- udid = argv[i];
- continue;
- }
- else if (!strcmp(argv[i], "-q") || !strcmp(argv[i], "--domain")) {
- i++;
- if (!argv[i] || (strlen(argv[i]) < 4)) {
- 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;
}
- if (!is_domain_known(argv[i])) {
- fprintf(stderr, "WARNING: Sending query with unknown domain \"%s\".\n", argv[i]);
+ udid = optarg;
+ break;
+ case 'n':
+ use_network = 1;
+ break;
+ case 'q':
+ if (!*optarg) {
+ fprintf(stderr, "ERROR: 'domain' must not be empty!\n");
+ print_usage(argc, argv, 1);
+ return 2;
}
- domain = strdup(argv[i]);
- continue;
- }
- else if (!strcmp(argv[i], "-k") || !strcmp(argv[i], "--key")) {
- i++;
- if (!argv[i] || (strlen(argv[i]) <= 1)) {
- print_usage(argc, argv);
- return 0;
+ domain = optarg;
+ break;
+ case 'k':
+ if (!*optarg) {
+ fprintf(stderr, "ERROR: 'key' must not be empty!\n");
+ print_usage(argc, argv, 1);
+ return 2;
}
- key = strdup(argv[i]);
- continue;
- }
- else if (!strcmp(argv[i], "-x") || !strcmp(argv[i], "--xml")) {
+ key = optarg;
+ break;
+ case 'x':
format = FORMAT_XML;
- continue;
- }
- else if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--simple")) {
+ break;
+ case 's':
simple = 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 {
- print_usage(argc, argv);
+ case 'v':
+ printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION);
return 0;
+ default:
+ print_usage(argc, argv, 1);
+ return 2;
}
}
- ret = idevice_new(&device, udid);
+ argc -= optind;
+ argv += optind;
+
+ 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, is it plugged in?\n", udid);
+ fprintf(stderr, "ERROR: Device %s not found!\n", udid);
} else {
- printf("No device found, is it plugged in?\n");
+ fprintf(stderr, "ERROR: No device found!\n");
}
return -1;
}
if (LOCKDOWN_E_SUCCESS != (ldret = simple ?
- lockdownd_client_new(device, &client, "ideviceinfo"):
- lockdownd_client_new_with_handshake(device, &client, "ideviceinfo"))) {
- fprintf(stderr, "ERROR: Could not connect to lockdownd, error code %d\n", ldret);
+ lockdownd_client_new(device, &client, TOOL_NAME):
+ lockdownd_client_new_with_handshake(device, &client, TOOL_NAME))) {
+ fprintf(stderr, "ERROR: Could not connect to lockdownd: %s (%d)\n", lockdownd_strerror(ldret), ldret);
idevice_free(device);
return -1;
}
+ if (domain && !is_domain_known(domain)) {
+ fprintf(stderr, "WARNING: Sending query with unknown domain \"%s\".\n", domain);
+ }
+
/* run query and output information */
if(lockdownd_get_value(client, domain, key, &node) == LOCKDOWN_E_SUCCESS) {
if (node) {
@@ -203,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);
@@ -215,8 +253,6 @@ int main(int argc, char *argv[])
}
}
- if (domain != NULL)
- free(domain);
lockdownd_client_free(client);
idevice_free(device);
diff --git a/tools/idevicename.c b/tools/idevicename.c
index ef226f7..69b76f6 100644
--- a/tools/idevicename.c
+++ b/tools/idevicename.c
@@ -23,60 +23,84 @@
#include <config.h>
#endif
+#define TOOL_NAME "idevicename"
+
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <getopt.h>
+#ifndef WIN32
+#include <signal.h>
+#endif
#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("Display the device name or set it to NAME if specified.\n");
- printf("\n");
- printf(" -d, --debug\t\tenable communication debugging\n");
- printf(" -u, --udid UDID\ttarget specific device by UDID\n");
- printf(" -h, --help\t\tprint usage information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\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)
{
- int res = -1;
- char* udid = NULL;
-
int c = 0;
- int optidx = 0;
const struct option longopts[] = {
- { "udid", required_argument, NULL, 'u' },
- { "help", no_argument, NULL, 'h' },
+ { "udid", required_argument, NULL, 'u' },
+ { "network", no_argument, NULL, 'n' },
+ { "debug", no_argument, NULL, 'd' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'v' },
{ NULL, 0, NULL, 0}
};
+ int res = -1;
+ const char* udid = NULL;
+ int use_network = 0;
+
+#ifndef WIN32
+ signal(SIGPIPE, SIG_IGN);
+#endif
- while ((c = getopt_long(argc, argv, "du:h", longopts, &optidx)) != -1) {
+ while ((c = getopt_long(argc, argv, "du:hnv", longopts, NULL)) != -1) {
switch (c) {
case 'u':
if (!*optarg) {
fprintf(stderr, "ERROR: UDID must not be empty!\n");
- print_usage();
+ print_usage(argc, argv, 1);
exit(2);
}
- free(udid);
- udid = strdup(optarg);
+ udid = optarg;
+ break;
+ case 'n':
+ use_network = 1;
break;
case 'h':
- print_usage();
+ print_usage(argc, argv, 0);
return 0;
case 'd':
idevice_set_debug_level(1);
break;
+ case 'v':
+ printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION);
+ return 0;
default:
- print_usage();
- return -1;
+ print_usage(argc, argv, 1);
+ return 2;
}
}
@@ -84,18 +108,22 @@ 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;
- if (idevice_new(&device, udid) != IDEVICE_E_SUCCESS) {
- fprintf(stderr, "ERROR: Could not connect to device\n");
+ if (idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX) != IDEVICE_E_SUCCESS) {
+ if (udid) {
+ fprintf(stderr, "ERROR: No device found with udid %s.\n", udid);
+ } else {
+ fprintf(stderr, "ERROR: No device found.\n");
+ }
return -1;
}
lockdownd_client_t lockdown = NULL;
- lockdownd_error_t lerr = lockdownd_client_new_with_handshake(device, &lockdown, "idevicename");
+ lockdownd_error_t lerr = lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME);
if (lerr != LOCKDOWN_E_SUCCESS) {
idevice_free(device);
fprintf(stderr, "ERROR: Could not connect to lockdownd, error code %d\n", lerr);
@@ -127,9 +155,5 @@ int main(int argc, char** argv)
lockdownd_client_free(lockdown);
idevice_free(device);
- if (udid) {
- free(udid);
- }
-
return res;
}
diff --git a/tools/idevicenotificationproxy.c b/tools/idevicenotificationproxy.c
index 72b406c..d1e25c1 100644
--- a/tools/idevicenotificationproxy.c
+++ b/tools/idevicenotificationproxy.c
@@ -23,11 +23,14 @@
#include <config.h>
#endif
+#define TOOL_NAME "idevicenotificationproxy"
+
#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>
@@ -57,23 +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("Post or observe notifications on a device.\n\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(" -d, --debug\t\tenable communication debugging\n");
- printf(" -u, --udid UDID\ttarget specific device by UDID\n");
- printf(" -h, --help\t\tprints usage information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\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)
@@ -90,8 +99,9 @@ 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;
char* cmd_arg = NULL;
@@ -99,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
@@ -107,83 +127,94 @@ 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;
+ 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;
}
- 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(&device, udid)) {
+ if (IDEVICE_E_SUCCESS != idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX)) {
if (udid) {
- printf("No device found with udid %s, is it plugged in?\n", udid);
+ printf("No device found with udid %s.\n", udid);
} else {
- printf("No device found, is it plugged in?\n");
+ printf("No device found.\n");
}
goto cleanup;
}
- if (LOCKDOWN_E_SUCCESS != (ret = lockdownd_client_new_with_handshake(device, &client, "idevicenotificationproxy"))) {
+ if (LOCKDOWN_E_SUCCESS != (ret = lockdownd_client_new_with_handshake(device, &client, TOOL_NAME))) {
fprintf(stderr, "ERROR: Could not connect to lockdownd, error code %d\n", ret);
goto cleanup;
}
@@ -233,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 be1f373..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
@@ -24,17 +24,93 @@
#include <config.h>
#endif
+#define TOOL_NAME "idevicepair"
+
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
+#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) {
@@ -51,95 +127,188 @@ 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("\n%s - Manage host pairings with devices and usbmuxd.\n\n", (name ? name + 1: argv[0]));
- printf("Usage: %s [OPTIONS] COMMAND\n\n", (name ? name + 1: argv[0]));
- 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\n");
- printf(" The following OPTIONS are accepted:\n");
- printf(" -d, --debug enable communication debugging\n");
- printf(" -u, --udid UDID target specific device by UDID\n");
- printf(" -h, --help prints usage information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\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"
+ );
}
-static void parse_opts(int argc, char **argv)
+int main(int argc, char **argv)
{
+ int c = 0;
static struct option longopts[] = {
- {"help", no_argument, NULL, 'h'},
- {"udid", required_argument, NULL, 'u'},
- {"debug", no_argument, NULL, 'd'},
- {NULL, 0, NULL, 0}
+ { "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}
};
- int c;
+#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;
+ lockdownd_error_t lerr;
+ int result;
- while (1) {
- c = getopt_long(argc, argv, "hu:d", longopts, (int*)0);
- if (c == -1) {
- break;
- }
+ 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, 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);
- exit(2);
+ print_usage(argc, argv, 1);
+ result = EXIT_FAILURE;
+ goto leave;
}
- if (udid)
- free(udid);
+ 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;
+ case 'v':
+ printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION);
+ result = EXIT_SUCCESS;
+ goto leave;
default:
- print_usage(argc, argv);
- exit(EXIT_SUCCESS);
+ print_usage(argc, argv, 1);
+ result = EXIT_FAILURE;
+ goto leave;
}
}
-}
-int main(int argc, char **argv)
-{
- lockdownd_client_t client = NULL;
- idevice_t device = NULL;
- idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR;
- lockdownd_error_t lerr;
- int result;
-
- char *type = NULL;
- 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;
-
- parse_opts(argc, argv);
+#ifndef WIN32
+ signal(SIGPIPE, SIG_IGN);
+#endif
if ((argc - optind) < 1) {
- printf("ERROR: You need to specify a COMMAND!\n");
- print_usage(argc, argv);
- exit(EXIT_FAILURE);
+ 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;
}
cmd = (argv+optind)[0];
@@ -157,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) {
@@ -168,10 +348,10 @@ int main(int argc, char **argv)
printf("%s\n", systembuid);
- if (systembuid)
- free(systembuid);
+ free(systembuid);
- return EXIT_SUCCESS;
+ result = EXIT_SUCCESS;
+ goto leave;
}
if (op == OP_LIST) {
@@ -183,36 +363,29 @@ int main(int argc, char **argv)
printf("%s\n", udids[i]);
free(udids[i]);
}
- if (udids)
- free(udids);
- if (udid)
- free(udid);
- return EXIT_SUCCESS;
- }
-
- if (udid) {
- ret = idevice_new(&device, udid);
- if (ret != IDEVICE_E_SUCCESS) {
- printf("No device found with udid %s, is it plugged in?\n", udid);
- free(udid);
- return EXIT_FAILURE;
- }
- free(udid);
- udid = NULL;
- } else {
- ret = idevice_new(&device, NULL);
- if (ret != IDEVICE_E_SUCCESS) {
- printf("No device found, is it plugged in?\n");
- return EXIT_FAILURE;
- }
+ free(udids);
+ result = EXIT_SUCCESS;
+ goto leave;
}
- ret = idevice_get_udid(device, &udid);
+ ret = idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX);
if (ret != IDEVICE_E_SUCCESS) {
- printf("ERROR: Could not get device udid, error code %d\n", ret);
+ if (udid) {
+ printf("No device found with udid %s.\n", udid);
+ } else {
+ printf("No device found.\n");
+ }
result = EXIT_FAILURE;
goto leave;
}
+ if (!udid) {
+ ret = idevice_get_udid(device, &udid);
+ if (ret != IDEVICE_E_SUCCESS) {
+ printf("ERROR: Could not get device udid, error code %d\n", ret);
+ result = EXIT_FAILURE;
+ goto leave;
+ }
+ }
if (op == OP_HOSTID) {
plist_t pair_record = NULL;
@@ -223,20 +396,18 @@ int main(int argc, char **argv)
printf("%s\n", hostid);
- if (hostid)
- free(hostid);
+ free(hostid);
+ plist_free(pair_record);
- if (pair_record)
- plist_free(pair_record);
-
- return EXIT_SUCCESS;
+ result = EXIT_SUCCESS;
+ goto leave;
}
- lerr = lockdownd_client_new(device, &client, "idevicepair");
+ lerr = lockdownd_client_new(device, &client, TOOL_NAME);
if (lerr != LOCKDOWN_E_SUCCESS) {
- idevice_free(device);
printf("ERROR: Could not connect to lockdownd, error code %d\n", lerr);
- return EXIT_FAILURE;
+ result = EXIT_FAILURE;
+ goto leave;
}
result = EXIT_SUCCESS;
@@ -247,18 +418,26 @@ 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);
}
- if (type) {
- free(type);
- }
+ free(type);
}
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 {
@@ -270,7 +449,7 @@ int main(int argc, char **argv)
case OP_VALIDATE:
lockdownd_client_free(client);
client = NULL;
- lerr = lockdownd_client_new_with_handshake(device, &client, "idevicepair");
+ lerr = lockdownd_client_new_with_handshake(device, &client, TOOL_NAME);
if (lerr == LOCKDOWN_E_SUCCESS) {
printf("SUCCESS: Validated pairing with device %s\n", udid);
} else {
@@ -293,9 +472,8 @@ int main(int argc, char **argv)
leave:
lockdownd_client_free(client);
idevice_free(device);
- if (udid) {
- free(udid);
- }
+ free(udid);
+
return result;
}
diff --git a/tools/ideviceprovision.c b/tools/ideviceprovision.c
index 52efdeb..4080a28 100644
--- a/tools/ideviceprovision.c
+++ b/tools/ideviceprovision.c
@@ -24,11 +24,17 @@
#include <config.h>
#endif
+#define TOOL_NAME "ideviceprovision"
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <getopt.h>
#include <sys/stat.h>
#include <errno.h>
+#ifndef WIN32
+#include <signal.h>
+#endif
#ifdef WIN32
#include <windows.h>
@@ -39,36 +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("Manage provisioning profiles on a device.\n\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\n");
- printf(" The following OPTIONS are accepted:\n");
- printf(" -d, --debug enable communication debugging\n");
- printf(" -u, --udid UDID target specific device by UDID\n");
- printf(" -x, --xml print XML output when using the 'dump' command\n");
- printf(" -h, --help prints usage information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\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 {
@@ -95,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);
@@ -290,91 +302,116 @@ int main(int argc, char *argv[])
const char* udid = NULL;
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;
- }
- udid = argv[i];
- 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;
+ break;
+ case 'u':
+ if (!*optarg) {
+ fprintf(stderr, "ERROR: UDID argument must not be empty!\n");
+ print_usage(argc, argv, 1);
+ return 2;
}
- param = argv[i];
- op = OP_REMOVE;
- continue;
+ 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;
+ case 'x':
+ output_xml = 1;
+ break;
+ default:
+ print_usage(argc, argv, 1);
+ return 2;
}
- else if (!strcmp(argv[i], "remove-all")) {
- i++;
- op = OP_REMOVE;
- 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], "dump")) {
- i++;
- if (!argv[i] || (strlen(argv[i]) < 1)) {
- print_usage(argc, argv);
- return 0;
- }
- param = argv[i];
- op = OP_DUMP;
- 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], "-x") || !strcmp(argv[i], "--xml")) {
- output_xml = 1;
- continue;
+ param = argv[i];
+ i++;
+ if (argv[i] && (strlen(argv[i]) > 0)) {
+ param2 = argv[i];
}
- else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
- print_usage(argc, argv);
- 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) {
@@ -399,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;
@@ -411,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)) {
@@ -420,17 +459,17 @@ int main(int argc, char *argv[])
}
}
- 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, is it plugged in?\n", udid);
+ printf("No device found with udid %s.\n", udid);
} else {
- printf("No device found, is it plugged in?\n");
+ printf("No device found.\n");
}
return -1;
}
- if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &client, "ideviceprovision"))) {
+ if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &client, TOOL_NAME))) {
fprintf(stderr, "ERROR: Could not connect to lockdownd, error code %d\n", ldret);
idevice_free(device);
return -1;
@@ -458,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;
@@ -469,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 f2bcd48..0e694c7 100644
--- a/tools/idevicescreenshot.c
+++ b/tools/idevicescreenshot.c
@@ -23,17 +23,103 @@
#include <config.h>
#endif
+#define TOOL_NAME "idevicescreenshot"
+
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <getopt.h>
#include <errno.h>
#include <time.h>
+#include <unistd.h>
+#ifndef WIN32
+#include <signal.h>
+#endif
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
#include <libimobiledevice/screenshotr.h>
-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)
{
@@ -43,89 +129,99 @@ 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], "-h") || !strcmp(argv[i], "--help")) {
- print_usage(argc, argv);
+ udid = optarg;
+ break;
+ case 'n':
+ use_network = 1;
+ break;
+ case 'h':
+ print_usage(argc, argv, 0);
return 0;
- }
- else if (argv[i][0] != '-' && !filename) {
- filename = strdup(argv[i]);
- continue;
- }
- else {
- print_usage(argc, argv);
+ 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]) {
+ filename = strdup(argv[0]);
+ }
- if (IDEVICE_E_SUCCESS != idevice_new(&device, udid)) {
+ if (IDEVICE_E_SUCCESS != idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX)) {
if (udid) {
- printf("No device found with udid %s, is it plugged in?\n", udid);
+ printf("No device found with udid %s.\n", udid);
} else {
- printf("No device found, is it plugged in?\n");
+ printf("No device found.\n");
}
return -1;
}
- if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &lckd, NULL))) {
+ if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &lckd, TOOL_NAME))) {
idevice_free(device);
printf("ERROR: Could not connect to lockdownd, error code %d\n", ldret);
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 {
char *imgdata = NULL;
uint64_t imgsize = 0;
if (screenshotr_take_screenshot(shotr, &imgdata, &imgsize) == SCREENSHOTR_E_SUCCESS) {
+ get_image_filename(imgdata, &filename);
if (!filename) {
- const char *fileext = NULL;
- if (memcmp(imgdata, "\x89PNG", 4) == 0) {
- fileext = ".png";
- } else if (memcmp(imgdata, "MM\x00*", 4) == 0) {
- fileext = ".tiff";
+ printf("FATAL: Could not find a unique filename!\n");
+ } else {
+ FILE *f = fopen(filename, "wb");
+ if (f) {
+ if (fwrite(imgdata, 1, (size_t)imgsize, f) == (size_t)imgsize) {
+ printf("Screenshot saved to %s\n", filename);
+ result = 0;
+ } else {
+ printf("Could not save screenshot to file %s!\n", filename);
+ }
+ fclose(f);
} else {
- printf("WARNING: screenshot data has unexpected image format.\n");
- fileext = ".dat";
+ printf("Could not open %s for writing: %s\n", filename, strerror(errno));
}
- time_t now = time(NULL);
- filename = (char*)malloc(36);
- size_t pos = strftime(filename, 36, "screenshot-%Y-%m-%d-%H-%M-%S", gmtime(&now));
- sprintf(filename+pos, "%s", fileext);
- }
- FILE *f = fopen(filename, "wb");
- if (f) {
- if (fwrite(imgdata, 1, (size_t)imgsize, f) == (size_t)imgsize) {
- printf("Screenshot saved to %s\n", filename);
- result = 0;
- } else {
- printf("Could not save screenshot to file %s!\n", filename);
- }
- fclose(f);
- } else {
- printf("Could not open %s for writing: %s\n", filename, strerror(errno));
}
} else {
printf("Could not get screenshot!\n");
@@ -133,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)
@@ -144,22 +240,3 @@ int main(int argc, char **argv)
return result;
}
-
-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("Gets a screenshot from a device.\n");
- printf("The screenshot is saved as a TIFF image with the given FILE name,\n");
- printf("where the default name is \"screenshot-DATE.tiff\", e.g.:\n");
- printf(" ./screenshot-2013-12-31-23-59-59.tiff\n\n");
- printf("NOTE: A mounted developer disk image is required on the device, otherwise\n");
- printf("the screenshotr service is not available.\n\n");
- printf(" -d, --debug\t\tenable communication debugging\n");
- printf(" -u, --udid UDID\ttarget specific device by UDID\n");
- printf(" -h, --help\t\tprints usage information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\n");
-}
diff --git a/tools/idevicesetlocation.c b/tools/idevicesetlocation.c
new file mode 100644
index 0000000..69fbaf5
--- /dev/null
+++ b/tools/idevicesetlocation.c
@@ -0,0 +1,192 @@
+/*
+ * idevicesetlocation.c
+ * Simulate location on iOS device with mounted developer disk image
+ *
+ * Copyright (c) 2016-2020 Nikias Bassen, All Rights Reserved.
+ *
+ * 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 Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; 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 "idevicesetlocation"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+
+#include <libimobiledevice/libimobiledevice.h>
+#include <libimobiledevice/lockdown.h>
+#include <libimobiledevice/service.h>
+
+#include <endianness.h>
+
+#define DT_SIMULATELOCATION_SERVICE "com.apple.dt.simulatelocation"
+
+enum {
+ SET_LOCATION = 0,
+ RESET_LOCATION = 1
+};
+
+static void print_usage(int argc, char **argv, int is_error)
+{
+ char *bname = strrchr(argv[0], '/');
+ bname = (bname) ? bname + 1 : argv[0];
+
+ 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"
+ "Bug Reports: <" PACKAGE_BUGREPORT ">\n"
+ );
+}
+
+int main(int argc, char **argv)
+{
+ int c = 0;
+ const struct option longopts[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "udid", required_argument, NULL, 'u' },
+ { "debug", no_argument, NULL, 'd' },
+ { "network", no_argument, NULL, 'n' },
+ { "version", no_argument, NULL, 'v' },
+ { NULL, 0, NULL, 0}
+ };
+ uint32_t mode = 0;
+ const char *udid = NULL;
+ int use_network = 0;
+
+ 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 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 ((argc > 2) || (argc < 1)) {
+ print_usage(argc+optind, argv-optind, 1);
+ return -1;
+ }
+
+ if (argc == 2) {
+ mode = SET_LOCATION;
+ } else if (argc == 1) {
+ if (strcmp(argv[0], "reset") == 0) {
+ mode = RESET_LOCATION;
+ } else {
+ print_usage(argc+optind, argv-optind, 1);
+ return -1;
+ }
+ }
+
+ idevice_t device = NULL;
+
+ if (idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX) != IDEVICE_E_SUCCESS) {
+ if (udid) {
+ printf("ERROR: Device %s not found!\n", udid);
+ } else {
+ printf("ERROR: No device found!\n");
+ }
+ return -1;
+ }
+
+ lockdownd_client_t lockdown;
+ lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME);
+
+ lockdownd_service_descriptor_t svc = NULL;
+ 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: %s\nMake sure a developer disk image is mounted!\n", lockdownd_strerror(lerr));
+ return -1;
+ }
+ lockdownd_client_free(lockdown);
+
+ service_client_t service = NULL;
+
+ service_error_t serr = service_client_new(device, svc, &service);
+
+ lockdownd_service_descriptor_free(svc);
+
+ if (serr != SERVICE_E_SUCCESS) {
+ lockdownd_client_free(lockdown);
+ idevice_free(device);
+ printf("ERROR: Could not connect to simulatelocation service (%d)\n", serr);
+ return -1;
+ }
+
+ uint32_t l;
+ uint32_t s = 0;
+
+ l = htobe32(mode);
+ service_send(service, (const char*)&l, 4, &s);
+ if (mode == SET_LOCATION) {
+ int len = 4 + strlen(argv[0]) + 4 + strlen(argv[1]);
+ char *buf = malloc(len);
+ uint32_t latlen;
+ latlen = strlen(argv[0]);
+ l = htobe32(latlen);
+ memcpy(buf, &l, 4);
+ memcpy(buf+4, argv[0], latlen);
+ uint32_t longlen = strlen(argv[1]);
+ l = htobe32(longlen);
+ memcpy(buf+4+latlen, &l, 4);
+ memcpy(buf+4+latlen+4, argv[1], longlen);
+
+ s = 0;
+ service_send(service, buf, len, &s);
+ }
+
+ idevice_free(device);
+
+ return 0;
+}
diff --git a/tools/idevicesyslog.c b/tools/idevicesyslog.c
index 76de128..a0e641d 100644
--- a/tools/idevicesyslog.c
+++ b/tools/idevicesyslog.c
@@ -2,6 +2,7 @@
* idevicesyslog.c
* Relay the syslog of a device to stdout
*
+ * Copyright (c) 2010-2020 Nikias Bassen, All Rights Reserved.
* Copyright (c) 2009 Martin Szulecki All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
@@ -23,12 +24,15 @@
#include "config.h"
#endif
+#define TOOL_NAME "idevicesyslog"
+
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
+#include <getopt.h>
#ifdef WIN32
#include <windows.h>
@@ -37,34 +41,320 @@
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/syslog_relay.h>
+#include <libimobiledevice-glue/termcolors.h>
static int quit_flag = 0;
-
-void print_usage(int argc, char **argv);
+static int exit_on_disconnect = 0;
+static int show_device_name = 0;
static char* udid = NULL;
+static char** proc_filters = NULL;
+static int num_proc_filters = 0;
+static int proc_filter_excluding = 0;
+
+static int* pid_filters = NULL;
+static int num_pid_filters = 0;
+
+static char** msg_filters = NULL;
+static int num_msg_filters = 0;
+
+static char** trigger_filters = NULL;
+static int num_trigger_filters = 0;
+static char** untrigger_filters = NULL;
+static int num_untrigger_filters = 0;
+static int triggered = 0;
static idevice_t device = NULL;
static syslog_relay_client_t syslog = NULL;
+static const char QUIET_FILTER[] = "CircleJoinRequested|CommCenter|HeuristicInterpreter|MobileMail|PowerUIAgent|ProtectedCloudKeySyncing|SpringBoard|UserEventAgent|WirelessRadioManagerd|accessoryd|accountsd|aggregated|analyticsd|appstored|apsd|assetsd|assistant_service|backboardd|biometrickitd|bluetoothd|calaccessd|callservicesd|cloudd|com.apple.Safari.SafeBrowsing.Service|contextstored|corecaptured|coreduetd|corespeechd|cdpd|dasd|dataaccessd|distnoted|dprivacyd|duetexpertd|findmydeviced|fmfd|fmflocatord|gpsd|healthd|homed|identityservicesd|imagent|itunescloudd|itunesstored|kernel|locationd|maild|mDNSResponder|mediaremoted|mediaserverd|mobileassetd|nanoregistryd|nanotimekitcompaniond|navd|nsurlsessiond|passd|pasted|photoanalysisd|powerd|powerlogHelperd|ptpd|rapportd|remindd|routined|runningboardd|searchd|sharingd|suggestd|symptomsd|timed|thermalmonitord|useractivityd|vmd|wifid|wirelessproxd";
+
+static int use_network = 0;
+
+static char *line = NULL;
+static int line_buffer_size = 0;
+static int lp = 0;
+
+static void add_filter(const char* filterstr)
+{
+ int filter_len = strlen(filterstr);
+ const char* start = filterstr;
+ const char* end = filterstr + filter_len;
+ const char* p = start;
+ while (p <= end) {
+ if ((*p == '|') || (*p == '\0')) {
+ if (p-start > 0) {
+ char* procn = malloc(p-start+1);
+ if (!procn) {
+ fprintf(stderr, "ERROR: malloc() failed\n");
+ exit(EXIT_FAILURE);
+ }
+ memcpy(procn, start, p-start);
+ procn[p-start] = '\0';
+ char* endp = NULL;
+ int pid_value = (int)strtol(procn, &endp, 10);
+ if (!endp || *endp == 0) {
+ int *new_pid_filters = realloc(pid_filters, sizeof(int) * (num_pid_filters+1));
+ if (!new_pid_filters) {
+ fprintf(stderr, "ERROR: realloc() failed\n");
+ exit(EXIT_FAILURE);
+ }
+ pid_filters = new_pid_filters;
+ pid_filters[num_pid_filters] = pid_value;
+ num_pid_filters++;
+ } else {
+ char **new_proc_filters = realloc(proc_filters, sizeof(char*) * (num_proc_filters+1));
+ if (!new_proc_filters) {
+ fprintf(stderr, "ERROR: realloc() failed\n");
+ exit(EXIT_FAILURE);
+ }
+ proc_filters = new_proc_filters;
+ proc_filters[num_proc_filters] = procn;
+ num_proc_filters++;
+ }
+ }
+ start = p+1;
+ }
+ p++;
+ }
+}
+
+static int find_char(char c, char** p, const char* end)
+{
+ while ((**p != c) && (*p < end)) {
+ (*p)++;
+ }
+ return (**p == c);
+}
+
+static void stop_logging(void);
+
static void syslog_callback(char c, void *user_data)
{
- putchar(c);
- if (c == '\n') {
- fflush(stdout);
+ if (lp >= line_buffer_size-1) {
+ line_buffer_size+=1024;
+ char* _line = realloc(line, line_buffer_size);
+ if (!_line) {
+ fprintf(stderr, "ERROR: realloc failed\n");
+ exit(EXIT_FAILURE);
+ }
+ line = _line;
+ }
+ line[lp++] = c;
+ if (c == '\0') {
+ int shall_print = 0;
+ int trigger_off = 0;
+ lp--;
+ char* linep = &line[0];
+ do {
+ if (lp < 16) {
+ shall_print = 1;
+ cprintf(FG_WHITE);
+ break;
+ }
+
+ if (line[3] == ' ' && line[6] == ' ' && line[15] == ' ') {
+ char* end = &line[lp];
+ char* p = &line[16];
+
+ /* device name */
+ char* device_name_start = p;
+ char* device_name_end = p;
+ if (!find_char(' ', &p, end)) break;
+ device_name_end = p;
+ p++;
+
+ /* check if we have any triggers/untriggers */
+ if (num_untrigger_filters > 0 && triggered) {
+ int found = 0;
+ int i;
+ for (i = 0; i < num_untrigger_filters; i++) {
+ if (strstr(device_name_end+1, untrigger_filters[i])) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ shall_print = 1;
+ } else {
+ shall_print = 1;
+ trigger_off = 1;
+ }
+ } else if (num_trigger_filters > 0 && !triggered) {
+ int found = 0;
+ int i;
+ for (i = 0; i < num_trigger_filters; i++) {
+ if (strstr(device_name_end+1, trigger_filters[i])) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ shall_print = 0;
+ break;
+ }
+ triggered = 1;
+ shall_print = 1;
+ } else if (num_trigger_filters == 0 && num_untrigger_filters > 0 && !triggered) {
+ shall_print = 0;
+ quit_flag++;
+ break;
+ }
+
+ /* check message filters */
+ if (num_msg_filters > 0) {
+ int found = 0;
+ int i;
+ for (i = 0; i < num_msg_filters; i++) {
+ if (strstr(device_name_end+1, msg_filters[i])) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ shall_print = 0;
+ break;
+ }
+ shall_print = 1;
+ }
+
+ /* process name */
+ char* proc_name_start = p;
+ char* proc_name_end = p;
+ if (!find_char('[', &p, end)) break;
+ char* process_name_start = proc_name_start;
+ char* process_name_end = p;
+ char* pid_start = p+1;
+ char* pp = process_name_start;
+ if (find_char('(', &pp, p)) {
+ process_name_end = pp;
+ }
+ if (!find_char(']', &p, end)) break;
+ p++;
+ if (*p != ' ') break;
+ proc_name_end = p;
+ p++;
+
+ int proc_matched = 0;
+ if (num_pid_filters > 0) {
+ char* endp = NULL;
+ int pid_value = (int)strtol(pid_start, &endp, 10);
+ if (endp && (*endp == ']')) {
+ int found = proc_filter_excluding;
+ int i = 0;
+ for (i = 0; i < num_pid_filters; i++) {
+ if (pid_value == pid_filters[i]) {
+ found = !proc_filter_excluding;
+ break;
+ }
+ }
+ if (found) {
+ proc_matched = 1;
+ }
+ }
+ }
+ if (num_proc_filters > 0 && !proc_matched) {
+ int found = proc_filter_excluding;
+ int i = 0;
+ for (i = 0; i < num_proc_filters; i++) {
+ if (!proc_filters[i]) continue;
+ if (strncmp(proc_filters[i], process_name_start, process_name_end-process_name_start) == 0) {
+ found = !proc_filter_excluding;
+ break;
+ }
+ }
+ if (found) {
+ proc_matched = 1;
+ }
+ }
+ if (proc_matched) {
+ shall_print = 1;
+ } else {
+ if (num_pid_filters > 0 || num_proc_filters > 0) {
+ shall_print = 0;
+ break;
+ }
+ }
+
+ /* log level */
+ char* level_start = p;
+ char* level_end = p;
+ const char* level_color = NULL;
+ if (!strncmp(p, "<Notice>:", 9)) {
+ level_end += 9;
+ level_color = FG_GREEN;
+ } else if (!strncmp(p, "<Error>:", 8)) {
+ level_end += 8;
+ level_color = FG_RED;
+ } else if (!strncmp(p, "<Warning>:", 10)) {
+ level_end += 10;
+ level_color = FG_YELLOW;
+ } else if (!strncmp(p, "<Debug>:", 8)) {
+ level_end += 8;
+ level_color = FG_MAGENTA;
+ } else {
+ level_color = FG_WHITE;
+ }
+
+ /* write date and time */
+ cprintf(FG_LIGHT_GRAY);
+ fwrite(line, 1, 16, stdout);
+
+ if (show_device_name) {
+ /* write device name */
+ cprintf(FG_DARK_YELLOW);
+ fwrite(device_name_start, 1, device_name_end-device_name_start+1, stdout);
+ cprintf(COLOR_RESET);
+ }
+
+ /* write process name */
+ cprintf(FG_BRIGHT_CYAN);
+ fwrite(process_name_start, 1, process_name_end-process_name_start, stdout);
+ cprintf(FG_CYAN);
+ fwrite(process_name_end, 1, proc_name_end-process_name_end+1, stdout);
+
+ /* write log level */
+ cprintf(level_color);
+ if (level_end > level_start) {
+ fwrite(level_start, 1, level_end-level_start, stdout);
+ p = level_end;
+ }
+
+ lp -= p - linep;
+ linep = p;
+
+ cprintf(FG_WHITE);
+
+ } else {
+ shall_print = 1;
+ 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);
+ cprintf(COLOR_RESET);
+ fflush(stdout);
+ if (trigger_off) {
+ triggered = 0;
+ }
+ }
+ line[0] = '\0';
+ lp = 0;
+ return;
}
}
static int start_logging(void)
{
- idevice_error_t ret = idevice_new(&device, udid);
+ 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, "idevicesyslog");
+ 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);
@@ -77,7 +367,7 @@ static int start_logging(void)
lerr = lockdownd_start_service(lockdown, SYSLOG_RELAY_SERVICE_NAME, &svc);
if (lerr == LOCKDOWN_E_PASSWORD_PROTECTED) {
fprintf(stderr, "*** Device is passcode protected, enter passcode on the device to continue ***\n");
- while (1) {
+ while (!quit_flag) {
lerr = lockdownd_start_service(lockdown, SYSLOG_RELAY_SERVICE_NAME, &svc);
if (lerr != LOCKDOWN_E_PASSWORD_PROTECTED) {
break;
@@ -105,7 +395,7 @@ static int start_logging(void)
}
/* start capturing syslog */
- serr = syslog_relay_start_capture(syslog, syslog_callback, NULL);
+ serr = syslog_relay_start_capture_raw(syslog, syslog_callback, NULL);
if (serr != SYSLOG_RELAY_E_SUCCESS) {
fprintf(stderr, "ERROR: Unable tot start capturing syslog.\n");
syslog_relay_client_free(syslog);
@@ -115,7 +405,7 @@ static int start_logging(void)
return -1;
}
- fprintf(stdout, "[connected]\n");
+ fprintf(stdout, "[connected:%s]\n", udid);
fflush(stdout);
return 0;
@@ -138,6 +428,12 @@ static void stop_logging(void)
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 (!syslog) {
if (!udid) {
@@ -152,7 +448,10 @@ static void device_event_cb(const idevice_event_t* event, void* userdata)
} else if (event->event == IDEVICE_DEVICE_REMOVE) {
if (syslog && (strcmp(udid, event->udid) == 0)) {
stop_logging();
- fprintf(stdout, "[disconnected]\n");
+ fprintf(stdout, "[disconnected:%s]\n", udid);
+ if (exit_on_disconnect) {
+ quit_flag++;
+ }
}
}
}
@@ -166,9 +465,75 @@ static void clean_exit(int sig)
quit_flag++;
}
+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"
+ "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"
+ );
+}
+
int main(int argc, char *argv[])
{
- int i;
+ 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' },
+ { "help", no_argument, NULL, 'h' },
+ { "udid", required_argument, NULL, 'u' },
+ { "network", no_argument, NULL, 'n' },
+ { "exit", no_argument, NULL, 'x' },
+ { "trigger", required_argument, NULL, 't' },
+ { "untrigger", required_argument, NULL, 'T' },
+ { "match", required_argument, NULL, 'm' },
+ { "process", required_argument, NULL, 'p' },
+ { "exclude", required_argument, NULL, 'e' },
+ { "quiet", no_argument, NULL, 'q' },
+ { "kernel", no_argument, NULL, 'k' },
+ { "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}
+ };
signal(SIGINT, clean_exit);
signal(SIGTERM, clean_exit);
@@ -177,70 +542,243 @@ int main(int argc, char *argv[])
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:nxt:T:m:e:p:qkKo:v", 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;
- }
- udid = strdup(argv[i]);
- continue;
- }
- else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
- print_usage(argc, argv);
+ 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 'n':
+ use_network = 1;
+ break;
+ case 'q':
+ exclude_filter++;
+ add_filter(QUIET_FILTER);
+ break;
+ case 'p':
+ case 'e':
+ if (c == 'p') {
+ include_filter++;
+ } else if (c == 'e') {
+ exclude_filter++;
+ }
+ if (!*optarg) {
+ fprintf(stderr, "ERROR: filter string must not be empty!\n");
+ print_usage(argc, argv, 1);
+ return 2;
+ }
+ add_filter(optarg);
+ break;
+ case 'm':
+ if (!*optarg) {
+ fprintf(stderr, "ERROR: message filter string must not be empty!\n");
+ print_usage(argc, argv, 1);
+ return 2;
+ } else {
+ char **new_msg_filters = realloc(msg_filters, sizeof(char*) * (num_msg_filters+1));
+ if (!new_msg_filters) {
+ fprintf(stderr, "ERROR: realloc() failed\n");
+ exit(EXIT_FAILURE);
+ }
+ msg_filters = new_msg_filters;
+ msg_filters[num_msg_filters] = strdup(optarg);
+ num_msg_filters++;
+ }
+ break;
+ case 't':
+ if (!*optarg) {
+ fprintf(stderr, "ERROR: trigger filter string must not be empty!\n");
+ print_usage(argc, argv, 1);
+ return 2;
+ } else {
+ char **new_trigger_filters = realloc(trigger_filters, sizeof(char*) * (num_trigger_filters+1));
+ if (!new_trigger_filters) {
+ fprintf(stderr, "ERROR: realloc() failed\n");
+ exit(EXIT_FAILURE);
+ }
+ trigger_filters = new_trigger_filters;
+ trigger_filters[num_trigger_filters] = strdup(optarg);
+ num_trigger_filters++;
+ }
+ break;
+ case 'T':
+ if (!*optarg) {
+ fprintf(stderr, "ERROR: untrigger filter string must not be empty!\n");
+ print_usage(argc, argv, 1);
+ return 2;
+ } else {
+ char **new_untrigger_filters = realloc(untrigger_filters, sizeof(char*) * (num_untrigger_filters+1));
+ if (!new_untrigger_filters) {
+ fprintf(stderr, "ERROR: realloc() failed\n");
+ exit(EXIT_FAILURE);
+ }
+ untrigger_filters = new_untrigger_filters;
+ untrigger_filters[num_untrigger_filters] = strdup(optarg);
+ num_untrigger_filters++;
+ }
+ break;
+ case 'k':
+ include_kernel++;
+ break;
+ case 'K':
+ exclude_kernel++;
+ break;
+ case 'x':
+ exit_on_disconnect = 1;
+ break;
+ case 'h':
+ print_usage(argc, argv, 0);
+ return 0;
+ case 1: {
+ printf("%s\n", QUIET_FILTER);
return 0;
}
- else {
- print_usage(argc, argv);
+ case 2:
+ 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);
return 0;
+ default:
+ print_usage(argc, argv, 1);
+ return 2;
}
}
+ 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);
+ return 2;
+ }
+
+ if (include_filter > 0 && exclude_filter > 0) {
+ fprintf(stderr, "ERROR: -p and -e/-q cannot be used together.\n");
+ print_usage(argc, argv, 1);
+ return 2;
+ }
+ 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;
+ }
+
+ if (exclude_filter > 0) {
+ proc_filter_excluding = 1;
+ if (include_kernel) {
+ int i = 0;
+ for (i = 0; i < num_proc_filters; i++) {
+ if (!strcmp(proc_filters[i], "kernel")) {
+ free(proc_filters[i]);
+ proc_filters[i] = NULL;
+ }
+ }
+ } else if (exclude_kernel) {
+ add_filter("kernel");
+ }
+ } else {
+ if (include_kernel) {
+ add_filter("kernel");
+ } else if (exclude_kernel) {
+ proc_filter_excluding = 1;
+ add_filter("kernel");
+ }
+ }
+
+ if (num_untrigger_filters > 0 && num_trigger_filters == 0) {
+ triggered = 1;
+ }
+
+ argc -= optind;
+ argv += optind;
+
int num = 0;
- char **devices = NULL;
- idevice_get_device_list(&devices, &num);
- idevice_device_list_free(devices);
+ 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);
}
+
+ fprintf(stderr, "Waiting for device with UDID %s to become available...\n", udid);
}
- idevice_event_subscribe(device_event_cb, NULL);
+ line_buffer_size = 1024;
+ line = malloc(line_buffer_size);
+
+ 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 (udid) {
- free(udid);
+ if (num_proc_filters > 0) {
+ int i;
+ for (i = 0; i < num_proc_filters; i++) {
+ free(proc_filters[i]);
+ }
+ free(proc_filters);
+ }
+ if (num_pid_filters > 0) {
+ free(pid_filters);
+ }
+ if (num_msg_filters > 0) {
+ int i;
+ for (i = 0; i < num_msg_filters; i++) {
+ free(msg_filters[i]);
+ }
+ free(msg_filters);
+ }
+ if (num_trigger_filters > 0) {
+ int i;
+ for (i = 0; i < num_trigger_filters; i++) {
+ free(trigger_filters[i]);
+ }
+ free(trigger_filters);
+ }
+ if (num_untrigger_filters > 0) {
+ int i;
+ for (i = 0; i < num_untrigger_filters; i++) {
+ free(untrigger_filters[i]);
+ }
+ free(untrigger_filters);
}
- return 0;
-}
+ free(line);
-void print_usage(int argc, char **argv)
-{
- char *name = NULL;
-
- name = strrchr(argv[0], '/');
- printf("Usage: %s [OPTIONS]\n", (name ? name + 1: argv[0]));
- printf("Relay syslog of a connected device.\n\n");
- printf(" -d, --debug\t\tenable communication debugging\n");
- printf(" -u, --udid UDID\ttarget specific device by UDID\n");
- printf(" -h, --help\t\tprints usage information\n");
- printf("\n");
- printf("Homepage: <" PACKAGE_URL ">\n");
-}
+ free(udid);
+ return 0;
+}