Author Archives: patters

Cross-compiling FFmpeg for Serviio 1.8 with shared libraries on Synology NAS (for 7 CPU architectures)

This method will build FFmpeg 3.2.2 for Synology DSM 6.0 with the shared libraries linked with relative paths, required for Serviio DLNA media server, using a Ubuntu/Xubuntu Desktop 14.04 virtual machine. The same method probably works with many other Linux distributions. The target CPU architectures are ARMv5, ARMv7 hard float ABI, ARM hard float ABI with NEON, Intel i686, Intel i686 Evansport, Intel x86-64, and PowerPC e500v2.

The >10MB size of the static executable is kind of getting out of hand especially on embedded systems with very limited RAM. Using shared libs means many concurrent instances of FFmpeg can use broadly the same memory footprint, and package distribution binaries can be smaller – our target systems already have libmp3lame, libm, libz, libbz2, liblzma, libpng16, librt, libgmp, libgnutls, libhogweed, libnettle, libfreetype, libfontconfig, libexpat, and libpthread which add up to several megabytes. I’m also guessing that the OS will decide when to unload them from RAM which could help when FFmpeg is being launched repeatedly in a short period of time (e.g. during library scanning).

The notes below also detail how to compile the Synology fork of FFmpeg 2.7.1 with Intel Evansport SMD (Streaming Media Drivers) hardware transcoding support. This source is itself based upon a fork by Intel which seems to form part of the Evansport SDK. Synology took a very long time (over a year) to partly comply with the GNU Public License and release this source code, despite numerous support requests, forum posts, and reports to the GPL Violations team. Their first DSM 6.0 beta was released in October 2015, and the DSM 6.0 sources were only published in late November 2016, but these remain incomplete since the kernel sources are not included.

Although the unmodified FFmpeg source code will compile successfully for PowerPC CPUs, the FFmpeg binary will core dump when running any command on a video file. I contacted Synology Support for help with this issue back in October 2012 and was given a patch to use at that time which changes the use of a CPU register in the DSP assembly code. The FFmpeg source code has changed a bit recently meaning the patch was no longer valid, but I was able to discover the appropriate location in the code and create a new working patch (code was moved from dsputil_ppc.c to blockdsp.c):

diff -rupN ffmpeg/libavcodec/ppc/blockdsp.c ffmpeg-patched/libavcodec/ppc/blockdsp.c
--- ffmpeg/libavcodec/ppc/blockdsp.c    2015-06-19 21:44:40.000000000 +0100
+++ ffmpeg-patched/libavcodec/ppc/blockdsp.c    2015-07-11 04:06:27.326911100 +0100
@@ -115,8 +115,9 @@ static long check_dcbzl_effect(void)
     memset(fakedata, 0xFF, 1024);
 
     /* Below the constraint "b" seems to mean "address base register"
-     * in gcc-3.3 / RS/6000 speaks. Seems to avoid using r0, so.... */
-    __asm__ volatile ("dcbzl %0, %1" :: "b" (fakedata_middle), "r" (zero));
+     * in gcc-3.3 / RS/6000 speaks. Seems to avoid using r0, so.... 
+    __asm__ volatile ("dcbzl %0, %1" :: "b" (fakedata_middle), "r" (zero)); */
+    __asm__ volatile ("dcbz %0, %1" :: "r" (fakedata_middle), "r" (zero));
 
     for (i = 0; i < 1024; i++)
         if (fakedata[i] == (char) 0)
 
#-----set up Synology toolchain
cd ~/Downloads
export DL_PATH="https://sourceforge.net/projects/dsgpl/files/DSM%206.0.2%20Tool%20Chains"
#-----add 32bit binary compatibility to Ubuntu 14.04 LTS (Syno toolchains are 32bit)
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386
sudo apt-get install git
sudo apt-get install chrpath
#----------------------------------------------------
#-----NOW PASTE ONE OF THE FOLLOWING SIX BLOCKS TO THE TERMINAL, DEPENDING ON YOUR TARGET CPU TYPE
#-----Marvell Kirkwood mv6281/mv6282 (ARMv5te)
#-----Marvell Armada 370/375/XP (ARMv7l FPU)
#-----Mindspeed Comcerto 2000/Marvell Armada 375 (ARM Cortex-A9 NEON)
#-----Freescale PowerQUICC III MPC8533E/QorIQ P1022 (PPC e500v2 FPU)
#-----Intel Atom/Bromolow/Cedarview (i686 SSSE3)
#-----Intel Evansport (i686 SSSE3 various HW decoders, HW H.264 encoder)




#-----Marvell Kirkwood mv6281/mv6282 CPU is based on the ARMv5TE core which has DSP and Thumb instruction support
#-----However using Thumb on ARMv5 results in worse performance
#-----http://www.arm.com/products/processors/technologies/dsp-simd.php
#-----http://www.marvell.com/embedded-processors/kirkwood/assets/88f6282-3_pb.pdf
wget "${DL_PATH}/Marvell%2088F628x%20Linux%202.6.32/6281-gcc464_glibc215_88f6281-GPL.txz"
tar xvJf 6281-gcc464_glibc215_88f6281-GPL.txz
wget "https://sourceforge.net/projects/dsgpl/files/toolkit/DSM6.0/ds.6281-6.0.dev.txz"
export DEV_DL="ds.6281-6.0.dev.txz"
export DEV_DL_ROOT="libc"
export CROSS_PREFIX=arm-marvell-linux-gnueabi
export TOOLCHAIN=/usr/local/${CROSS_PREFIX}
export TARGET=arm-marvell-linux-gnueabi
export MARCH="-march=armv5te -mtune=marvell-f -mtune=xscale"
#-----libx264:
#-----http://forum.doom9.org/showthread.php?t=160584
#-----https://mailman.videolan.org/pipermail/x264-devel/2010-December/008093.html
#-----x264 builds with NEON by default because x264 is so slow without NEON (and on any non-NEON chip) as to be useless.
#-----You can of course compile with --disable-asm on such chips, but we don't do it by default because
#-----we don't feel it's necessary to actively support chips on which x264 would be basically useless
export X264_CONFIG="./configure --prefix=${TOOLCHAIN} --host=${TARGET} --cross-prefix=${TOOLCHAIN}/bin/${CROSS_PREFIX}- --enable-shared --disable-asm --enable-pic --enable-strip --disable-opencl"
#-----FFmpeg:
#-----ARMv5TE CPU-specific options (based on inspecting 'configure' script https://github.com/FFmpeg/FFmpeg/blob/master/configure)
#-----pkg-config needs to be defined because with cross-prefix it assumes ${CROSS_PREFIX}-pkg-config which doesn't exist, and then librtmp won't be detected
#-----something changed in the FFmpeg configure script and now vfp and neon optimizations have to be explicitly disabled for ARMv5TE, which doesn't have those features in any case
export FF_CONFIG="./configure --arch=arm --cpu=armv5te --enable-cross-compile --cross-prefix=${TOOLCHAIN}/bin/${CROSS_PREFIX}- --target-os=linux --prefix=${TOOLCHAIN} --enable-shared --disable-static --enable-pic --disable-ffplay --disable-ffserver --disable-neon --disable-vfp --disable-armv6 --disable-armv6t2 --disable-debug --enable-pthreads --enable-libshine --enable-librtmp --enable-libass --enable-libspeex --enable-libvorbis --enable-gpl --enable-libx264 --enable-gnutls --pkg-config=pkg-config --extra-version=compiled_by_patters_for_Serviio"
#export FF_CONFIG="./configure --arch=arm --cpu=armv5te --enable-cross-compile --cross-prefix=${TOOLCHAIN}/bin/${CROSS_PREFIX}- --target-os=linux --prefix=${TOOLCHAIN} --enable-shared --disable-static --enable-pic --disable-ffplay --disable-ffserver --disable-neon --disable-vfp --disable-armv6 --disable-armv6t2 --disable-debug --enable-pthreads --enable-libshine --enable-librtmp --enable-libass --enable-libspeex --enable-libvorbis --enable-gpl --enable-libx264 --enable-gnutls --enable-nonfree --enable-libfdk_aac --pkg-config=pkg-config --extra-version=compiled_by_patters_for_Serviio"
#-----these next two packages are needed to build libshine
sudo apt-get install automake
sudo apt-get install libtool
wget https://github.com/savonet/shine/zipball/master
unzip master
cd toots-shine-*
./bootstrap
cd ..
#-----fetch libfdk-aac fixed point math AAC encoder, binaries linked to it cannot be redistributed under GPL
#-----so it is excluded from the FFmpeg binary I built for the Serviio package
wget http://sourceforge.net/projects/opencore-amr/files/fdk-aac/fdk-aac-0.1.4.tar.gz
tar xvzf fdk-aac-0.1.4.tar.gz
cd fdk-aac-0.1.4
./configure --prefix=${TOOLCHAIN} --host=${TARGET} --build=x86_64-linux-gnu --enable-shared --disable-static
make
make install
cd ..
 



#-----Marvell Armada 370/XP CPU is based on a dual issue ARMv7 core with Thumb-2, VFPv3-16, but no NEON vector unit
#-----http://www.marvell.com/embedded-processors/armada-300/assets/Marvell_ARMADA_370_SoC.pdf
#-----http://www.arm.com/products/processors/technologies/vector-floating-point.php
#-----since DSM 6.0 hard float ABI is used
wget "${DL_PATH}/Marvell%20Armada%20370%20Linux%203.2.40/armada370-gcc493_glibc220_hard-GPL.txz"
tar xvJf armada370-gcc493_glibc220_hard-GPL.txz
wget "https://sourceforge.net/projects/dsgpl/files/toolkit/DSM6.0/ds.armada370-6.0.dev.txz"
export DEV_DL="ds.armada370-6.0.dev.txz"
export DEV_DL_ROOT="sysroot"
export CROSS_PREFIX=arm-unknown-linux-gnueabi
export TARGET=arm-unknown-linux-gnueabi
export TOOLCHAIN=/usr/local/${CROSS_PREFIX}
#-----Tune for Marvell PJ4 dual issue core (two instructions per clock)
#-----Thumb-2 can be used on ARMv6 or newer with no performance drop
export MARCH="-march=armv7-a -mcpu=marvell-pj4 -mtune=marvell-pj4 -mhard-float -mfpu=vfpv3-d16 -mthumb"
#-----libx264:
#-----http://forum.doom9.org/showthread.php?t=160584
#-----https://mailman.videolan.org/pipermail/x264-devel/2010-December/008093.html
#-----x264 builds with NEON by default because x264 is so slow without NEON (and on any non-NEON chip) as to be useless.
#-----You can of course compile with --disable-asm on such chips, but we don't do it by default because
#-----we don't feel it's necessary to actively support chips on which x264 would be basically useless
#-----http://lists.busybox.net/pipermail/buildroot/2014-October/107797.html
export X264_CONFIG="./configure --prefix=${TOOLCHAIN} --host=${TARGET} --cross-prefix=${TOOLCHAIN}/bin/${CROSS_PREFIX}- --enable-shared --disable-asm --enable-pic --enable-strip --disable-opencl"
#-----FFmpeg:
#-----ARMv7 CPU-specific options (based on inspecting 'configure' script https://github.com/FFmpeg/FFmpeg/blob/master/configure)
#-----pkg-config needs to be defined because with cross-prefix it assumes ${CROSS_PREFIX}-pkg-config which doesn't exist, and then librtmp won't be detected
export FF_CONFIG="./configure --arch=arm --cpu=armv7-a --enable-thumb --enable-cross-compile --cross-prefix=${TOOLCHAIN}/bin/${CROSS_PREFIX}- --target-os=linux --prefix=${TOOLCHAIN} --enable-shared --disable-static --enable-pic --disable-ffplay --disable-ffserver --disable-neon --disable-debug --enable-pthreads --enable-libmp3lame --enable-librtmp --enable-libass --enable-libspeex --enable-libvorbis --enable-gpl --enable-libx264 --enable-gnutls --pkg-config=pkg-config --extra-version=compiled_by_patters_for_Serviio"




#-----Marvell Armada 375, Armada 385, and Mindspeed Comcerto 2000 CPU are based on dual ARM Cortex-A9 cores with NEON vector unit
#-----http://www.marvell.com/embedded-processors/armada-300/assets/ARMADA_375_SoC-01_product_brief.pdf
#-----http://www.marvell.com/embedded-processors/armada-38x/assets/A38x-Functional-Spec-PU0A.pdf
#-----http://www.mindspeed.com/products/cpe-processors/comcertoreg-2000
#-----http://www.arm.com/products/processors/cortex-a/cortex-a9.php
#-----http://www.arm.com/products/processors/technologies/neon.php
#-----Since DSM 6.0 Armada 375 finally has hard float ABI and therefore gains NEON support
wget "${DL_PATH}/Marvell%20Armada%20375%20Linux%203.2.40/armada375-gcc493_glibc220_hard-GPL.txz"
tar xvJf armada375-gcc493_glibc220_hard-GPL.txz
#-----Marvell gave all the ARMv7 toolchains the same name so rename to allow concurrent installations
mv arm-unknown-linux-gnueabi/ arm-cortexa9-linux-gnueabi/
wget "https://sourceforge.net/projects/dsgpl/files/toolkit/DSM6.0/ds.armada375-6.0.dev.txz"
export DEV_DL="ds.armada375-6.0.dev.txz"
export DEV_DL_ROOT="sysroot"
export CROSS_PREFIX=arm-unknown-linux-gnueabi
export TARGET=arm-unknown-linux-gnueabi
export TOOLCHAIN=/usr/local/arm-cortexa9-linux-gnueabi
#-----it seems that in general neon should be used as the fpu when present unless there's a specific reason not to use it
export MARCH="-march=armv7-a -mcpu=cortex-a9 -mfpu=neon -mhard-float -mthumb"
#-----libx264:
export X264_CONFIG="./configure --prefix=${TOOLCHAIN} --host=${TARGET} --cross-prefix=${TOOLCHAIN}/bin/${CROSS_PREFIX}- --enable-shared --enable-pic --enable-strip --disable-opencl"
#-----FFmpeg:
#-----ARMv7 CPU-specific options (based on inspecting 'configure' script https://github.com/FFmpeg/FFmpeg/blob/master/configure)
#-----pkg-config needs to be defined because with cross-prefix it assumes ${CROSS_PREFIX}-pkg-config which doesn't exist, and then librtmp won't be detected
export FF_CONFIG="./configure --arch=arm --cpu=cortex-a9 --enable-thumb --enable-cross-compile --cross-prefix=${TOOLCHAIN}/bin/${CROSS_PREFIX}- --target-os=linux --prefix=${TOOLCHAIN} --enable-shared --disable-static --enable-pic --disable-ffplay --disable-ffserver --disable-debug --enable-pthreads --enable-libmp3lame --enable-librtmp --enable-libass --enable-libspeex --enable-libvorbis --enable-gpl --enable-libx264 --enable-gnutls --pkg-config=pkg-config --extra-version=compiled_by_patters_for_Serviio"




#-----Freescale PowerQUICC III MPC8533E/QorIQ P1022 CPUs use the PowerPC e500v2 core with Signal Processing Engine (SPE) which is not a classic FPU design, but have no AltiVec vector unit 
#-----Some QorIQ models have e500mc cores with true FPUs but these are not used in 2013 series Synology NAS
#-----http://en.wikipedia.org/wiki/QorIQ
#-----http://cache.freescale.com/files/32bit/doc/fact_sheet/QP1022FS.pdf?fpsp=1
wget "${DL_PATH}/PowerPC%20QorIQ%20Linux%202.6.32/qoriq-gcc493_glibc220_hard_qoriq-GPL.txz"
tar xvJf qoriq-gcc493_glibc220_hard_qoriq-GPL.txz
wget "https://sourceforge.net/projects/dsgpl/files/toolkit/DSM6.0/ds.qoriq-6.0.dev.txz"
export DEV_DL="ds.qoriq-6.0.dev.txz"
export DEV_DL_ROOT="sysroot"
export CROSS_PREFIX=powerpc-e500v2-linux-gnuspe
export TOOLCHAIN=/usr/local/${CROSS_PREFIX}
export TARGET=powerpc-e500v2-linux-gnuspe
export MARCH="-mcpu=8548 -mhard-float -mfloat-gprs=double"
#-----asm disabled since QorIQ has no AltiVec
export X264_CONFIG="./configure --prefix=${TOOLCHAIN} --host=${TARGET} --cross-prefix=${TOOLCHAIN}/bin/${CROSS_PREFIX}- --enable-shared --disable-asm --enable-pic --enable-strip --disable-opencl"
#-----FFmpeg:#-----PowerPC e500v2 CPU-specific options (based on inspecting 'configure' script https://github.com/FFmpeg/FFmpeg/blob/master/configure)
#-----pkg-config needs to be defined because with cross-prefix it assumes ${CROSS_PREFIX}-pkg-config which doesn't exist, and then librtmp won't be detected
export FF_CONFIG="./configure --arch=ppc --cpu=e500v2 --enable-cross-compile --cross-prefix=${TOOLCHAIN}/bin/${CROSS_PREFIX}- --target-os=linux --prefix=${TOOLCHAIN} --enable-shared --disable-static --enable-pic --disable-ffplay --disable-ffserver --disable-debug --enable-pthreads --enable-libmp3lame --enable-librtmp --enable-libass --enable-libspeex --enable-libvorbis --enable-gpl --enable-libx264 --enable-gnutls --pkg-config=pkg-config --extra-version=compiled_by_patters_for_Serviio"




#-----Intel Evansport with support for hardware decoding of VC-1, H.264, MPEG-4, MPEG2, AAC and hardware encoding of H.264
#-----http://www.anandtech.com/show/8020/synology-ds214play-intel-evansport-almost-done-right/9
#-----libx264 requires yasm 1.20
sudo apt-get install yasm
wget "${DL_PATH}/Intel%20x86%20Linux%203.2.40%20%28Evansport%29/evansport-gcc493_glibc220_linaro_i686-GPL.txz"
tar xvJf evansport-gcc493_glibc220_linaro_i686-GPL.txz
#-----Both Intel i686 toolchains the same name so rename to allow concurrent installations
mv i686-pc-linux-gnu evansport-pc-linux-gnu
wget "https://sourceforge.net/projects/dsgpl/files/toolkit/DSM6.0/ds.evansport-6.0.dev.txz"
export DEV_DL="ds.evansport-6.0.dev.txz"
export DEV_DL_ROOT="sys-root"
export CROSS_PREFIX=i686-pc-linux-gnu
export TARGET=i686-pc-linux-gnu
export MARCH="-march=atom"
export TOOLCHAIN=/usr/local/evansport-pc-linux-gnu
export X264_CONFIG="./configure --prefix=${TOOLCHAIN} --host=${TARGET} --cross-prefix=${TOOLCHAIN}/bin/${CROSS_PREFIX}- --enable-shared --enable-pic --enable-strip --disable-opencl"
#-----FFmpeg:
#-----Intel CPU-specific options (based on inspecting 'configure' script https://github.com/FFmpeg/FFmpeg/blob/master/configure)
#-----pkg-config needs to be defined because with cross-prefix it assumes ${CROSS_PREFIX}-pkg-config which doesn't exist, and then librtmp won't be detected
export FF_CONFIG="./configure.syno --arch=x86 --cpu=atom --enable-cross-compile --cross-prefix=${TOOLCHAIN}/bin/${CROSS_PREFIX}- --target-os=linux --prefix=${TOOLCHAIN} --enable-shared --disable-static --enable-pic --disable-ffplay --disable-ffserver --disable-debug --enable-pthreads --enable-libmp3lame --enable-librtmp --enable-libass --enable-libspeex --enable-libvorbis --enable-libx264 --enable-libh264_smd --enable-smd --enable-gpl --enable-gnutls --pkg-config=pkg-config --extra-version=SMD_enabled-compiled_by_patters_for_Serviio"
export FF_CONFIG_I686="./configure --arch=x86 --cpu=atom --enable-cross-compile --cross-prefix=${TOOLCHAIN}/bin/${CROSS_PREFIX}- --target-os=linux --prefix=${TOOLCHAIN} --enable-shared --disable-static --enable-pic --disable-ffplay --disable-ffserver --disable-debug --enable-pthreads --enable-libmp3lame --enable-librtmp --enable-libass --enable-libspeex --enable-libvorbis --enable-libx264 --enable-gpl --enable-gnutls --pkg-config=pkg-config --extra-version=compiled_by_patters_for_Serviio"
#-----http://trac.ffmpeg.org/ticket/1794
#-----first ffmpeg compilation error run "make V=1" then add " -lismd_core -lismd_viddec -ljson-c" to the command line
#-----second ffmpeg compilation error run "make V=1" then add " -ljson-c" to the command line




#-----With the exception of Evansport (i686), Intel CPUs used in Synology products are all 64bit and SSSE3 capable
#-----Since DSM 6.0 x86_64 toolchain is used
#-----libx264 requires yasm 1.20
sudo apt-get install yasm
#-----unlike the others this toolchain has an external dependency on libz
#sudo apt-get install libz1:i386
wget "${DL_PATH}/Intel%20x86%20Linux%203.10.77%20%28Pineview%29/x64-gcc493_glibc220_linaro_x86_64-GPL.txz"
tar xvJf x64-gcc493_glibc220_linaro_x86_64-GPL.txz
wget "https://sourceforge.net/projects/dsgpl/files/toolkit/DSM6.0/ds.cedarview-6.0.dev.txz"
export DEV_DL="ds.cedarview-6.0.dev.txz"
export DEV_DL_ROOT="sys-root"
export CROSS_PREFIX=x86_64-pc-linux-gnu
export TARGET=x86_64-pc-linux-gnu
export TOOLCHAIN=/usr/local/${CROSS_PREFIX}
#-----We don't really care how lame is built since ffmpeg will use the version in DSM.
#-----The DSM version is built without asm optimizations but these only make a 5% difference, and have been known to introduce instability
export LAME_CONFIG="./configure --prefix=${TOOLCHAIN} --host=${TARGET} --build=x86_64-linux-gnu --enable-shared --disable-static --disable-decoder"
export X264_CONFIG="./configure --prefix=${TOOLCHAIN} --host=${TARGET} --cross-prefix=${TOOLCHAIN}/bin/${CROSS_PREFIX}- --enable-shared --enable-pic --enable-strip"
#-----FFmpeg:
#-----Intel CPU-specific options (based on inspecting 'configure' script https://github.com/FFmpeg/FFmpeg/blob/master/configure)
#-----pkg-config needs to be defined because with cross-prefix it assumes ${CROSS_PREFIX}-pkg-config which doesn't exist, and then librtmp won't be detected
export FF_CONFIG="./configure --arch=x86 --enable-cross-compile --cross-prefix=${TOOLCHAIN}/bin/${CROSS_PREFIX}- --target-os=linux --prefix=${TOOLCHAIN} --enable-shared --disable-static --enable-pic --disable-ffplay --disable-ffserver --disable-debug --enable-pthreads --enable-libmp3lame --enable-librtmp --enable-libass --enable-libspeex --enable-libvorbis --enable-gpl --enable-libx264 --enable-gnutls --pkg-config=pkg-config --extra-version=compiled_by_patters_for_Serviio"




#----------------------------------------------------
#-----script continues
sudo mv `echo $TOOLCHAIN | sed -r "s%^.*/(.*$)%\1%"` /usr/local
#-----some of the toolchains have bad permissions
sudo chmod -R 0755 ${TOOLCHAIN}
export PATH=${TOOLCHAIN}/bin:$PATH
export AR=${TOOLCHAIN}/bin/${CROSS_PREFIX}-ar
export AS=${TOOLCHAIN}/bin/${CROSS_PREFIX}-as
export CC=${TOOLCHAIN}/bin/${CROSS_PREFIX}-gcc
export CXX=${TOOLCHAIN}/bin/${CROSS_PREFIX}-g++
export LD=${TOOLCHAIN}/bin/${CROSS_PREFIX}-ld
export LDSHARED="${TOOLCHAIN}/bin/${CROSS_PREFIX}-gcc -shared "
export RANLIB=${TOOLCHAIN}/bin/${CROSS_PREFIX}-ranlib
export CFLAGS="-I${TOOLCHAIN}/include -O3 ${MARCH}"
export LDFLAGS="-L${TOOLCHAIN}/lib"
export PKG_CONFIG_PATH="${TOOLCHAIN}/lib/pkgconfig"


#-----set up all our dependent libraries from the Synology dev environment
mkdir ${CROSS_PREFIX}-dev
cd ${CROSS_PREFIX}-dev
tar xfJv ../${DEV_DL}

mkdir $TOOLCHAIN/lib/pkgconfig/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/include/expat.h $TOOLCHAIN/include/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/include/expat_external.h $TOOLCHAIN/include/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/libexpat.* $TOOLCHAIN/lib/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/pkgconfig/expat.pc $TOOLCHAIN/lib/pkgconfig/
sed -i "s|^prefix=.*$|prefix=${TOOLCHAIN}|" $TOOLCHAIN/lib/pkgconfig/expat.pc

cp -R usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/include/fontconfig/ $TOOLCHAIN/include/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/libfontconfig.* $TOOLCHAIN/lib/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/pkgconfig/fontconfig.pc $TOOLCHAIN/lib/pkgconfig/
sed -i "s|^prefix=.*$|prefix=${TOOLCHAIN}|" $TOOLCHAIN/lib/pkgconfig/fontconfig.pc

cp -R usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/include/freetype2/ $TOOLCHAIN/include/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/libfreetype.* $TOOLCHAIN/lib/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/pkgconfig/freetype2.pc $TOOLCHAIN/lib/pkgconfig/
sed -i "s|^prefix=.*$|prefix=${TOOLCHAIN}|" $TOOLCHAIN/lib/pkgconfig/freetype2.pc
sed -i "s|^exec_prefix=.*$|exec_prefix=${TOOLCHAIN}|" $TOOLCHAIN/lib/pkgconfig/freetype2.pc
sed -i "s|^libdir=.*$|libdir=${TOOLCHAIN}/lib|" $TOOLCHAIN/lib/pkgconfig/freetype2.pc
sed -i "s|^includedir=.*$|includedir=${TOOLCHAIN}/include/freetype2|" $TOOLCHAIN/lib/pkgconfig/freetype2.pc

cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/include/gmp.h $TOOLCHAIN/include/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/libgmp.* $TOOLCHAIN/lib/

cp -R usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/include/gnutls/ $TOOLCHAIN/include/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/libgnutls.* $TOOLCHAIN/lib/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/pkgconfig/gnutls.pc $TOOLCHAIN/lib/pkgconfig/
sed -i "s|^prefix=.*$|prefix=${TOOLCHAIN}|" $TOOLCHAIN/lib/pkgconfig/gnutls.pc

cp -R usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/include/lame/ $TOOLCHAIN/include/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/libmp3lame.* $TOOLCHAIN/lib/

cp -R usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/include/nettle/ $TOOLCHAIN/include/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/libnettle.* $TOOLCHAIN/lib/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/libhogweed.* $TOOLCHAIN/lib/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/pkgconfig/nettle.pc $TOOLCHAIN/lib/pkgconfig/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/pkgconfig/hogweed.pc $TOOLCHAIN/lib/pkgconfig/
sed -i "s|^prefix=.*$|prefix=${TOOLCHAIN}|" $TOOLCHAIN/lib/pkgconfig/nettle.pc
sed -i "s|^prefix=.*$|prefix=${TOOLCHAIN}|" $TOOLCHAIN/lib/pkgconfig/hogweed.pc

cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/include/png.h $TOOLCHAIN/include/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/include/pngconf.h $TOOLCHAIN/include/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/include/pnglibconf.h $TOOLCHAIN/include/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/libpng.* $TOOLCHAIN/lib/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/pkgconfig/libpng.pc $TOOLCHAIN/lib/pkgconfig/
sed -i "s|^prefix=.*$|prefix=${TOOLCHAIN}|" $TOOLCHAIN/lib/pkgconfig/libpng.pc

cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/include/zlib.h $TOOLCHAIN/include/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/include/zconf.h $TOOLCHAIN/include/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/libz.* $TOOLCHAIN/lib/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/pkgconfig/zlib.pc $TOOLCHAIN/lib/pkgconfig/
sed -i "s|^prefix=.*$|prefix=${TOOLCHAIN}|" $TOOLCHAIN/lib/pkgconfig/zlib.pc

cp -R usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/include/json-c/ $TOOLCHAIN/include/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/libjson-c.* $TOOLCHAIN/lib/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/pkgconfig/json-c.pc $TOOLCHAIN/lib/pkgconfig/
sed -i "s|^prefix=.*$|prefix=${TOOLCHAIN}|" $TOOLCHAIN/lib/pkgconfig/json-c.pc

#-----libbz2 and libxml-2.0 are dependencies of fontconfig
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/include/bzlib.h $TOOLCHAIN/include/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/libbz2.* $TOOLCHAIN/lib/

cp -R usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/include/libxml2/ $TOOLCHAIN/include/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/libxml2.* $TOOLCHAIN/lib/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/pkgconfig/libxml-2.0.pc $TOOLCHAIN/lib/pkgconfig/
sed -i "s|^prefix=.*$|prefix=${TOOLCHAIN}|" $TOOLCHAIN/lib/pkgconfig/libxml-2.0.pc

#-----liblzma is a dependency of libass
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/include/lzma.h $TOOLCHAIN/include/
cp -R usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/include/lzma/ $TOOLCHAIN/include/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/liblzma.* $TOOLCHAIN/lib/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/pkgconfig/liblzma.pc $TOOLCHAIN/lib/pkgconfig/

#-----libpng16 is a dependency of freetype2
cp -R usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/include/libpng16/ $TOOLCHAIN/include/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/libpng16.* $TOOLCHAIN/lib/
cp usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/pkgconfig/libpng16.pc $TOOLCHAIN/lib/pkgconfig/

#-----End of syno devkit extraction
cd ..

#-----shine shared lib for ARMv5 only (no FPU)
[ "${TOOLCHAIN}" == "/usr/local/arm-none-linux-gnueabi" ] && cd toots-shine-*
[ "${TOOLCHAIN}" == "/usr/local/arm-none-linux-gnueabi" ] && ./configure --prefix=${TOOLCHAIN} --host=${TARGET} --build=x86_64-linux-gnu --enable-shared --disable-static
[ "${TOOLCHAIN}" == "/usr/local/arm-none-linux-gnueabi" ] && make
[ "${TOOLCHAIN}" == "/usr/local/arm-none-linux-gnueabi" ] && make install
[ "${TOOLCHAIN}" == "/usr/local/arm-none-linux-gnueabi" ] && cd ..

#-----fribidi shared lib
wget http://fribidi.org/download/fribidi-0.19.6.tar.bz2
tar xvjf fribidi-0.19.6.tar.bz2
cd fribidi-0.19.6
#-----patch fribidi source since it won't compile - some sort of page size function is no longer available
#-----error on Intel: fribidi-run.c:70: error: 'PAGE_SIZE' undeclared (first use in this function)
#-----http://armbedded.eu/node/56
#-----http://lists.debian.org/debian-glibc/2006/10/msg00169.html
#-----http://my.safaribooksonline.com/book/operating-systems-and-server-administration/linux/0596009585/advanced-file-i-o/mapping_files_into_memory
[ "${CROSS_PREFIX}" == "i686-pc-linux-gnu" ] && sed -i "s|include <asm/page.h>|include <unistd.h>\n#   define PAGE_SIZE sysconf(_SC_PAGESIZE)|" lib/common.h
./configure --prefix=${TOOLCHAIN} --host=${TARGET} --build=x86_64-linux-gnu --enable-shared --disable-static
make
make install
cd ..

#-----fontconfig shared lib
wget http://www.freedesktop.org/software/fontconfig/release/fontconfig-2.11.1.tar.gz
tar xvzf fontconfig-2.11.1.tar.gz
cd fontconfig-2.11.1
./configure --prefix=${TOOLCHAIN} --host=${TARGET} --build=x86_64-linux-gnu --enable-shared --disable-static
-----correct some non-standard library linking behaviour
sed -i "s/^hardcode_into_libs=yes/hardcode_into_libs=no/" libtool
make
make install
cd ..

#-----libass shared lib
wget https://github.com/libass/libass/releases/download/0.13.4/libass-0.13.4.tar.xz
tar xvJf libass-0.13.4.tar.xz
cd libass-0.13.4
LDFLAGS=-Wl,-L${TOOLCHAIN}/lib,-rpath,\'\$\$ORIGIN\' ./configure --prefix=${TOOLCHAIN} --host=${TARGET} --build=x86_64-linux-gnu --enable-shared --disable-static
#-----correct some non-standard library linking behaviour
sed -i "s/^hardcode_into_libs=yes/hardcode_into_libs=no/" libtool
make
make install
cd ..
#-----Although libass would link correctly to older FFmpeg versions, this mod is now necessary:
#-----http://ffmpeg.org/pipermail/ffmpeg-user/2012-November/010906.html
#-----no longer needed, note here in case of regression in future versions 
#sed -i -r "s/(^Libs: .*$)/\1 -lfontconfig -lfribidi -lfreetype -lexpat/" $TOOLCHAIN/lib/pkgconfig/libass.pc

#-----libx264 shared lib
wget https://download.videolan.org/x264/snapshots/last_stable_x264.tar.bz2
tar xvjf last_stable_x264.tar.bz2
cd x264-snapshot-*
#-----NEON ASM needs to be built by GCC assembler not AS
[ "${TOOLCHAIN}" == "/usr/local/arm-cortexa9-linux-gnueabi" ] && export AS=${TOOLCHAIN}/bin/${CROSS_PREFIX}-gcc
#-----Intel ASM needs to be built by yasm assembler
[ "${TOOLCHAIN}" == "/usr/local/evansport-pc-linux-gnu" ] && export AS=yasm
[ "${TOOLCHAIN}" == "/usr/local/i686-pc-linux-gnu" ] && export AS=yasm
[ "${TOOLCHAIN}" == "/usr/local/x86_64-pc-linux-gnu" ] && export AS=yasm
$X264_CONFIG
#-----back out assembler changes
AS=${TOOLCHAIN}/bin/${CROSS_PREFIX}-as
make
make install
cd ..

#-----libx265 shared lib
#wget https://bitbucket.org/multicoreware/x265/downloads/x265_2.1.tar.gz
#tar xvzf x265_2.1.tar.gz
#cd x265_2.1

#-----librtmp shared lib
git clone git://git.ffmpeg.org/rtmpdump
cd rtmpdump
make CROSS_COMPILE=${TOOLCHAIN}/bin/${CROSS_PREFIX}- SYS=posix prefix=${TOOLCHAIN} CRYPTO=GNUTLS INC=-I${TOOLCHAIN}/include XLDFLAGS=-Wl,-L${TOOLCHAIN}/lib,-rpath,\'\$\$ORIGIN\'
#------librtmp.pc will have the wrong lib dependencies defined unless GNUTLS is specified again here
make install prefix=${TOOLCHAIN} CRYPTO=GNUTLS
cd ..

#-----libspeex shared lib
wget http://downloads.xiph.org/releases/speex/speex-1.2rc2.tar.gz
tar xvzf speex-1.2rc2.tar.gz
cd speex-1.2rc2
./configure --prefix=${TOOLCHAIN} --host=${TARGET} --build=x86_64-linux-gnu --enable-shared --disable-static
sed -i "s/^hardcode_into_libs=yes/hardcode_into_libs=no/" libtool
make
make install
cd ..

#-----libogg shared lib
wget http://downloads.xiph.org/releases/ogg/libogg-1.3.2.tar.xz
tar xvJf libogg-1.3.2.tar.xz
cd libogg-1.3.2
./configure --prefix=${TOOLCHAIN} --host=${TARGET} --build=x86_64-linux-gnu --enable-shared --disable-static
sed -i "s/^hardcode_into_libs=yes/hardcode_into_libs=no/" libtool
make
make install
cd ..

#-----libvorbis shared lib
wget http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.5.tar.xz
tar xvJf libvorbis-1.3.5.tar.xz
cd libvorbis-1.3.5
./configure --prefix=${TOOLCHAIN} --host=${TARGET} --build=x86_64-linux-gnu --enable-shared --disable-static
sed -i "s/^hardcode_into_libs=yes/hardcode_into_libs=no/" libtool
make
make install
cd ..

#-----Evansport only - don't run these two lines until right before compiling FFmpeg since some of the includes will break other stuff
[ "${TOOLCHAIN}" == "/usr/local/evansport-pc-linux-gnu" ] && cp -R ${CROSS_PREFIX}-dev/usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/include/intelce-utilities $TOOLCHAIN/include
[ "${TOOLCHAIN}" == "/usr/local/evansport-pc-linux-gnu" ] && cp -R ${CROSS_PREFIX}-dev/usr/local/$TARGET/$TARGET/${DEV_DL_ROOT}/usr/lib/intelce-utilities $TOOLCHAIN/lib

#-----FFmpeg (Evansport uses a separate Synology-modified source bundle)
[ "${TOOLCHAIN}" == "/usr/local/evansport-pc-linux-gnu" ] || wget https://www.ffmpeg.org/releases/ffmpeg-3.2.2.tar.xz
[ "${TOOLCHAIN}" == "/usr/local/evansport-pc-linux-gnu" ] || tar xvJf ffmpeg-3.2.2.tar.xz
[ "${TOOLCHAIN}" == "/usr/local/evansport-pc-linux-gnu" ] || cd ffmpeg-3.2.2
[ "${TOOLCHAIN}" == "/usr/local/evansport-pc-linux-gnu" ] && wget https://sourceforge.net/projects/dsgpl/files/Synology%20NAS%20GPL%20Source/8451branch/evansport-source/ffmpeg-2.7.x.txz
[ "${TOOLCHAIN}" == "/usr/local/evansport-pc-linux-gnu" ] && tar xvJf ffmpeg-2.7.x.txz
[ "${TOOLCHAIN}" == "/usr/local/evansport-pc-linux-gnu" ] && cd ffmpeg-2.7.x

#-----PowerPC-specific fix originally provided by Synology Support in Oct 2012, adapted after code re-org by ffmpeg
[ "${CROSS_PREFIX}" == "powerpc-e500v2-linux-gnuspe" ] && wget http://dl.dropboxusercontent.com/u/1188556/ffmpeg-syno-ppc.patch
[ "${CROSS_PREFIX}" == "powerpc-e500v2-linux-gnuspe" ] && patch --verbose -p1 < ffmpeg-syno-ppc.patch

#-----Evansport SMD driver scheduler uses inline asm which breaks compilation without -fasm
#-----http://stackoverflow.com/questions/18574943/gcc-inline-assembler-implicit-function-declaration-on-powerpc-arch
#-----http://ffmpeg.org/pipermail/ffmpeg-devel/2008-October/056533.html
#-----http://www.tldp.org/HOWTO/Assembly-HOWTO/gcc.html
#-----we also need to add the intelce-utlities locations of the SMD libraries
#-----libx264 will fail to compile with this added to include path, so only add it just before compiling ffmpeg
[ "${TOOLCHAIN}" == "/usr/local/evansport-pc-linux-gnu" ] \
  && export CFLAGS="${CFLAGS} -fasm -I${TOOLCHAIN}/include/json-c -I${TOOLCHAIN}/include/intelce-utilities -I${TOOLCHAIN}/include/intelce-utilities/linux_user"

#-----Evansport SMD functionality is disabled by default
[ "${TOOLCHAIN}" == "/usr/local/evansport-pc-linux-gnu" ] && sed -i "1i#define SYNO_EVANSPORT_SMD" synoconfig.h
#-----Evansport ffmpeg will by default skip DTS audio tracks for transcoding and will refuse to encode AC3
[ "${TOOLCHAIN}" == "/usr/local/evansport-pc-linux-gnu" ] && wget https://dl.dropboxusercontent.com/u/1188556/ffmpeg-2.7.1-syno-dts-skip.patch
[ "${TOOLCHAIN}" == "/usr/local/evansport-pc-linux-gnu" ] && patch --verbose -p1 < ffmpeg-2.7.1-syno-dts-skip.patch

#-----set library linker to use relative library search path (../lib and .)
#-----tricky shell escaping of $ORIGIN is required http://itee.uq.edu.au/~daniel/using_origin/
#-----http://stackoverflow.com/questions/6562403/i-dont-understand-wl-rpath-wl
#-----however although FFmpeg gets a correct rpath, the downstream libraries get a value of "RIGIN/../lib:RIGIN"
#-----owing to some additional variable substitution happening - easier to build with XORIGIN and use chrpath later
[ "${TOOLCHAIN}" == "/usr/local/evansport-pc-linux-gnu" ] \
  || LDFLAGS=-Wl,-L${TOOLCHAIN}/lib,-rpath,XORIGIN/../lib:XORIGIN,-rpath-link,${TOOLCHAIN}/lib ${FF_CONFIG} \
  && LDFLAGS=-Wl,-L${TOOLCHAIN}/lib,-L${TOOLCHAIN}/lib/intelce-utilities,-rpath,XORIGIN/../lib:XORIGIN,-rpath-link,${TOOLCHAIN}/lib,-rpath-link,${TOOLCHAIN}/lib/intelce-utilities ${FF_CONFIG}

#-----external libs (librtmp, libass) don't seem to link to ffmpeg (check ffmpeg binary with objdump -x)
#-----this is in fact normal because LDFLAGS as defined in config.mak contains '--as-needed'
#-----https://wiki.gentoo.org/wiki/Project:Quality_Assurance/As-needed
#-----e.g. FFmpeg does not contain any symbols from librtmp, but libavformat does
#-----use ldd on the target system and the full dependency chain will be shown
make
make install

#-----remove intelce-utilities from include path
[ "${TOOLCHAIN}" == "/usr/local/evansport-pc-linux-gnu" ] && export CFLAGS="-I${TOOLCHAIN}/include -O3 ${MARCH}"
[ "${TOOLCHAIN}" == "/usr/local/evansport-pc-linux-gnu" ] && rm -rf ${TOOLCHAIN}/include/intelce-utilities
[ "${TOOLCHAIN}" == "/usr/local/evansport-pc-linux-gnu" ] && rm -rf ${TOOLCHAIN}/lib/intelce-utilities 

mkdir native-${CROSS_PREFIX}
cd native-${CROSS_PREFIX}

#-----evansport FFmpeg 2.7.1
#-----fix up rpath settings
sudo chrpath -r '$ORIGIN/../lib:$ORIGIN' ${TOOLCHAIN}/bin/ffmpeg
sudo chrpath -r '$ORIGIN' ${TOOLCHAIN}/lib/libavcodec.so.56
sudo chrpath -r '$ORIGIN' ${TOOLCHAIN}/lib/libavdevice.so.56
sudo chrpath -r '$ORIGIN' ${TOOLCHAIN}/lib/libavfilter.so.5
sudo chrpath -r '$ORIGIN' ${TOOLCHAIN}/lib/libavformat.so.56
sudo chrpath -r '$ORIGIN' ${TOOLCHAIN}/lib/libavutil.so.54
sudo chrpath -r '$ORIGIN' ${TOOLCHAIN}/lib/libpostproc.so.53
sudo chrpath -r '$ORIGIN' ${TOOLCHAIN}/lib/libswresample.so.1
sudo chrpath -r '$ORIGIN' ${TOOLCHAIN}/lib/libswscale.so.3
cp ${TOOLCHAIN}/lib/libavcodec.so.56 .
cp ${TOOLCHAIN}/lib/libavdevice.so.56 .
cp ${TOOLCHAIN}/lib/libavfilter.so.5 .
cp ${TOOLCHAIN}/lib/libavformat.so.56 .
cp ${TOOLCHAIN}/lib/libavutil.so.54 .
cp ${TOOLCHAIN}/lib/libpostproc.so.53 .
cp ${TOOLCHAIN}/lib/libswresample.so.1 .
cp ${TOOLCHAIN}/lib/libswscale.so.3 .
cp ${TOOLCHAIN}/bin/ffmpeg .
cp ${TOOLCHAIN}/bin/fc-cache .
cp ${TOOLCHAIN}/lib/libass.so.5 .
cp ${TOOLCHAIN}/lib/libfribidi.so.0 .
cp ${TOOLCHAIN}/lib/libogg.so.0 .
cp ${TOOLCHAIN}/lib/librtmp.so.1 .
cp ${TOOLCHAIN}/lib/libspeex.so.1 .
cp ${TOOLCHAIN}/lib/libvorbis.so.0 .
cp ${TOOLCHAIN}/lib/libvorbisenc.so.2 .
cp ${TOOLCHAIN}/lib/libx264.so.148 .


#-----FFmpeg 3.2.2
#-----fix up rpath settings
sudo chrpath -r '$ORIGIN/../lib:$ORIGIN' ${TOOLCHAIN}/bin/ffmpeg
sudo chrpath -r '$ORIGIN' ${TOOLCHAIN}/lib/libavcodec.so.57
sudo chrpath -r '$ORIGIN' ${TOOLCHAIN}/lib/libavdevice.so.57
sudo chrpath -r '$ORIGIN' ${TOOLCHAIN}/lib/libavfilter.so.6
sudo chrpath -r '$ORIGIN' ${TOOLCHAIN}/lib/libavformat.so.57
sudo chrpath -r '$ORIGIN' ${TOOLCHAIN}/lib/libavutil.so.55
sudo chrpath -r '$ORIGIN' ${TOOLCHAIN}/lib/libpostproc.so.54
sudo chrpath -r '$ORIGIN' ${TOOLCHAIN}/lib/libswresample.so.2
sudo chrpath -r '$ORIGIN' ${TOOLCHAIN}/lib/libswscale.so.4
cp ${TOOLCHAIN}/lib/libavcodec.so.57 .
cp ${TOOLCHAIN}/lib/libavdevice.so.57 .
cp ${TOOLCHAIN}/lib/libavfilter.so.6 .
cp ${TOOLCHAIN}/lib/libavformat.so.57 .
cp ${TOOLCHAIN}/lib/libavutil.so.55 .
cp ${TOOLCHAIN}/lib/libpostproc.so.54 .
cp ${TOOLCHAIN}/lib/libswresample.so.2 .
cp ${TOOLCHAIN}/lib/libswscale.so.4 .
cp ${TOOLCHAIN}/bin/ffmpeg .
cp ${TOOLCHAIN}/bin/fc-cache .
cp ${TOOLCHAIN}/lib/libass.so.5 .
cp ${TOOLCHAIN}/lib/libfribidi.so.0 .
cp ${TOOLCHAIN}/lib/libogg.so.0 .
cp ${TOOLCHAIN}/lib/librtmp.so.1 .
cp ${TOOLCHAIN}/lib/libspeex.so.1 .
cp ${TOOLCHAIN}/lib/libvorbis.so.0 .
cp ${TOOLCHAIN}/lib/libvorbisenc.so.2 .
cp ${TOOLCHAIN}/lib/libx264.so.148 .
[ ${TOOLCHAIN} == "/usr/local/arm-none-linux-gnueabi" ] && cp ${TOOLCHAIN}/lib/libshine.so.3 .
#cp ${TOOLCHAIN}/lib/libfdk-aac.so.1 .
sudo chmod +x *
sudo chown root:root *
XZ_OPT=-9 tar -cvJf ffmpeg-${CROSS_PREFIX}.tar.xz *
 

Here’s how the library dependencies look. There are no links to any libraries in /opt, and DSM-bundled libraries in /lib are linked to where possible. All the other new libraries are kept within the Serviio lib folder (../lib relative to the ffmpeg binary).

DS214> ldd /var/packages/Serviio/target/bin/ffmpeg
	linux-gate.so.1 (0xffffe000)
	libavdevice.so.57 => /volume1/@appstore/Serviio/bin/../lib/libavdevice.so.57 (0xb7708000)
	libavfilter.so.6 => /volume1/@appstore/Serviio/bin/../lib/libavfilter.so.6 (0xb74fd000)
	libavformat.so.57 => /volume1/@appstore/Serviio/bin/../lib/libavformat.so.57 (0xb72bd000)
	libavcodec.so.57 => /volume1/@appstore/Serviio/bin/../lib/libavcodec.so.57 (0xb5ee8000)
	libpostproc.so.54 => /volume1/@appstore/Serviio/bin/../lib/libpostproc.so.54 (0xb5ec1000)
	libswresample.so.2 => /volume1/@appstore/Serviio/bin/../lib/libswresample.so.2 (0xb5ea2000)
	libswscale.so.4 => /volume1/@appstore/Serviio/bin/../lib/libswscale.so.4 (0xb5e11000)
	libavutil.so.55 => /volume1/@appstore/Serviio/bin/../lib/libavutil.so.55 (0xb5d8b000)
	libm.so.6 => /lib/libm.so.6 (0xb5d42000)
	libpthread.so.0 => /lib/libpthread.so.0 (0xb5d25000)
	libc.so.6 => /lib/libc.so.6 (0xb5b77000)
	libass.so.5 => /volume1/@appstore/Serviio/bin/../lib/libass.so.5 (0xb5b33000)
	librtmp.so.1 => /volume1/@appstore/Serviio/bin/../lib/librtmp.so.1 (0xb5b14000)
	libz.so.1 => /lib/libz.so.1 (0xb5afb000)
	libgnutls.so.28 => /lib/libgnutls.so.28 (0xb59f0000)
	libbz2.so.1.0 => /lib/libbz2.so.1.0 (0xb59df000)
	libdl.so.2 => /lib/libdl.so.2 (0xb59da000)
	libx264.so.148 => /volume1/@appstore/Serviio/bin/../lib/libx264.so.148 (0xb583c000)
	libvorbisenc.so.2 => /volume1/@appstore/Serviio/bin/../lib/libvorbisenc.so.2 (0xb57aa000)
	libvorbis.so.0 => /volume1/@appstore/Serviio/bin/../lib/libvorbis.so.0 (0xb5770000)
	libspeex.so.1 => /volume1/@appstore/Serviio/bin/../lib/libspeex.so.1 (0xb5747000)
	libmp3lame.so.0 => /lib/libmp3lame.so.0 (0xb56cf000)
	liblzma.so.5 => /lib/liblzma.so.5 (0xb56a3000)
	/lib/ld-linux.so.2 (0xb7718000)
	libfribidi.so.0 => /volume1/@appstore/Serviio/bin/../lib/libfribidi.so.0 (0xb5688000)
	libfontconfig.so.1 => /lib/libfontconfig.so.1 (0xb5645000)
	libfreetype.so.6 => /lib/libfreetype.so.6 (0xb5586000)
	libhogweed.so.2 => /lib/libhogweed.so.2 (0xb5555000)
	libnettle.so.4 => /lib/libnettle.so.4 (0xb5521000)
	libgmp.so.10 => /lib/libgmp.so.10 (0xb54ac000)
	libogg.so.0 => /volume1/@appstore/Serviio/bin/../lib/libogg.so.0 (0xb54a2000)
	libxml2.so.2 => /lib/libxml2.so.2 (0xb5321000)
	libpng16.so.16 => /lib/libpng16.so.16 (0xb52e4000)
DS214>
 

Here’s how the even more complex Evansport build with hardware transcoding support looks:

DS214Play> ldd /var/packages/Serviio/target/bin/ffmpeg
	linux-gate.so.1 (0xffffe000)
	libavdevice.so.56 => /volume1/@appstore/Serviio/bin/../lib/libavdevice.so.56 (0xb77c0000)
	libavfilter.so.5 => /volume1/@appstore/Serviio/bin/../lib/libavfilter.so.5 (0xb7686000)
	libavformat.so.56 => /volume1/@appstore/Serviio/bin/../lib/libavformat.so.56 (0xb748d000)
	libavcodec.so.56 => /volume1/@appstore/Serviio/bin/../lib/libavcodec.so.56 (0xb630e000)
	libpostproc.so.53 => /volume1/@appstore/Serviio/bin/../lib/libpostproc.so.53 (0xb62e7000)
	libswresample.so.1 => /volume1/@appstore/Serviio/bin/../lib/libswresample.so.1 (0xb62cb000)
	libswscale.so.3 => /volume1/@appstore/Serviio/bin/../lib/libswscale.so.3 (0xb624a000)
	libavutil.so.54 => /volume1/@appstore/Serviio/bin/../lib/libavutil.so.54 (0xb61d4000)
	libffmpeg_plugin.so => /lib/libffmpeg_plugin.so (0xb61be000)
	libm.so.6 => /lib/libm.so.6 (0xb6175000)
	libismd_core.so => /lib/libismd_core.so (0xb6168000)
	libismd_viddec.so => /lib/libismd_viddec.so (0xb6160000)
	libjson-c.so.2 => /lib/libjson-c.so.2 (0xb6153000)
	libpthread.so.0 => /lib/libpthread.so.0 (0xb6137000)
	libc.so.6 => /lib/libc.so.6 (0xb5f88000)
	libass.so.5 => /volume1/@appstore/Serviio/bin/../lib/libass.so.5 (0xb5f44000)
	librtmp.so.1 => /volume1/@appstore/Serviio/bin/../lib/librtmp.so.1 (0xb5f25000)
	libz.so.1 => /lib/libz.so.1 (0xb5f0c000)
	libgnutls.so.28 => /lib/libgnutls.so.28 (0xb5e02000)
	libbz2.so.1.0 => /lib/libbz2.so.1.0 (0xb5df0000)
	libx264.so.148 => /volume1/@appstore/Serviio/bin/../lib/libx264.so.148 (0xb5c52000)
	libvorbisenc.so.2 => /volume1/@appstore/Serviio/bin/../lib/libvorbisenc.so.2 (0xb5bc0000)
	libvorbis.so.0 => /volume1/@appstore/Serviio/bin/../lib/libvorbis.so.0 (0xb5b87000)
	libspeex.so.1 => /volume1/@appstore/Serviio/bin/../lib/libspeex.so.1 (0xb5b5e000)
	libmp3lame.so.0 => /lib/libmp3lame.so.0 (0xb5ae5000)
	liblzma.so.5 => /lib/liblzma.so.5 (0xb5ab9000)
	libdl.so.2 => /lib/libdl.so.2 (0xb5ab4000)
	libxml2.so.2 => /lib/libxml2.so.2 (0xb5933000)
	libismd_demux.so => /lib/libismd_demux.so (0xb5928000)
	libismd_vidrend.so => /lib/libismd_vidrend.so (0xb591f000)
	libismd_clock.so => /lib/libismd_clock.so (0xb591d000)
	libismd_audio.so => /lib/libismd_audio.so (0xb590e000)
	libismd_videnc.so => /lib/libismd_videnc.so (0xb590a000)
	libismd_vidpproc.so => /lib/libismd_vidpproc.so (0xb5903000)
	libismdmessage.so => /lib/libismdmessage.so (0xb58ff000)
	libsven.so => /lib/libsven.so (0xb57b9000)
	libpal.so => /lib/libpal.so (0xb57b7000)
	libosal.so => /lib/libosal.so (0xb57ae000)
	libplatform_config.so => /lib/libplatform_config.so (0xb57ab000)
	libsystem_utils.so => /lib/libsystem_utils.so (0xb57a8000)
	libismd_clock_recovery.so => /lib/libismd_clock_recovery.so (0xb57a4000)
	/lib/ld-linux.so.2 (0xb77d0000)
	libfribidi.so.0 => /volume1/@appstore/Serviio/bin/../lib/libfribidi.so.0 (0xb5789000)
	libfontconfig.so.1 => /lib/libfontconfig.so.1 (0xb5747000)
	libfreetype.so.6 => /lib/libfreetype.so.6 (0xb5688000)
	libhogweed.so.2 => /lib/libhogweed.so.2 (0xb5657000)
	libnettle.so.4 => /lib/libnettle.so.4 (0xb5623000)
	libgmp.so.10 => /lib/libgmp.so.10 (0xb55ad000)
	libogg.so.0 => /volume1/@appstore/Serviio/bin/../lib/libogg.so.0 (0xb55a4000)
	libpng16.so.16 => /lib/libpng16.so.16 (0xb5567000)
DS214Play> 
 
 

SANE Backends network scanning package for Synology NAS

UPDATE – SANE version 1.0.28, new frontend AirSane package, and updated frontend software info below

SANE-package

Many scanners last considerably longer than they enjoy driver updates for. Manufacturers are seldom willing to update drivers for new operating systems. The transition to 64bit was a similar obstacle. Furthermore Microsoft dropped support for the TWAIN scanning API in favour of the WIA (Windows Image Acquisition) for 64bit versions of its OS, and Apple removed TWAIN in macOS 10.9 Mavericks, superseded by ICA (Image Capture Architecture). These conditions have resulted in a mountain of perfectly good hardware being thrown away unnecessarily. I recently found myself without any modern drivers for my own Canon CanoScan LiDE 20, so I decided to do something about the problem. Now you can use this package to share your obsolete scanner from your Synology NAS.

SANE is an open source scanning API which has a fantastic wealth of device support. SANE’s differentiator is that it separates the drivers (backend) from the presentation and the scanning (frontend). This is ideal for a headless device like a NAS, and it also frees the frontend to be quite generic rather than highly customized to each device.

 

Device Support

HP all-in-one models are not supported by the package since their backend hpaio is not part of a standard SANE build, and it requires significant additional dependencies. Scanner backends which require libieee1284 are not supported by the package (canon_pp, hpsj5s, and mustek_pp), neither is backend dell1600n_net which needed a TIFF library and in fact only supports one device. You can verify which backend is required for your model of scanner using the SANE Project search engine. Expand below for the full list of backends which this Synology package supports:

Backend support in Synology package as of version 1.0.28-003
------------------------------------------------------------

Note that some backends default to disabled in /var/packages/sane-backends/target/etc/sane.d/dll.conf
This can be because they may slow down detection routines
This is a default SANE config unrelated to the Synology pacakge
Detection is faster if unused backends are commented out in this file

abaton
agfafocus
apple
artec
artec_eplus48u
as6e
avision
bh
canon
canon630u
canon_dr
cardscan
coolscan
coolscan2
coolscan3
dc25
dc210
dc240
dmc
epjitsu
epson
epson2
epsonds
fujitsu
genesys (except on armv5tel which lacks C++11 toolchain support)
gt68xx
hp
hp3500
hp3900
hp4200
hp5400
hp5590
hpljm1005
hs2p
ibm
kodak
kodakaio
kvs1025
kvs20xx
kvs40xx
leo
lexmark
ma1509
magicolor
matsushita
microtek
microtek2
mustek
mustek_usb
mustek_usb2
nec
net
niash
p5
pie
pieusb
pixma
plustek
plustek_pp
qcam
ricoh
ricoh2
rts8891
s9036
sceptre
sharp
sm3600
sm3840
snapscan
sp15c
st400
stv680
tamarack
teco1
teco2
teco3
test
u12
umax
umax_pp
umax1220u
xerox_mfp
 

Synology Package Installation

  • In Synology DSM’s Package Center, click Settings and add my package repository:
    Add Package Repository
  • The repository will push its certificate automatically to the NAS, which is used to validate package integrity. Set the Trust Level to Synology Inc. and trusted publishers:
    Trust Level
  • Now browse the Community section in Package Center to install SANE Backends.
    Community-packages
    The repository only displays packages which are compatible with your specific model of NAS. If you don’t see SANE Backends in the list, then either your NAS model or your DSM version are not supported at this time. DSM 6.0 is the minimum supported version for this package.
  • When the package is started it will attempt to detect a scanner and output the results to the package log. If your scanner is listed in the log, that is all that is required at the backend.
  •  

    SANE Frontend for the Computer

    Since I have a variety of systems at home I spent some time investigating the various options. I list them in order of quality of experience below (updated in September 2019). You will need to manually specify the IP address of your NAS when setting up the scanner. Be aware that the scanner will need redefining on the computer if you change USB port later for instance. No credentials are needed for connection by default.

    • AirSane (macOS Mojave and earlier) – Hands down the most elegant SANE frontend solution, and one which I have now packaged separately for Synology. AirSane will autodetect any available SANE scanner and will advertise it via Bonjour to the macOS Image Capture application as a shared AirScan device. No configuration is required – it just works! Even if you don’t have a Mac it offers a simple WebUI for scanning.
      AirSane is in active development at the time of writing in September 2019, in fact its author SimulPiscator fixed a few issues I discovered while testing prior to packaging it.
    • WiaSane (Windows 10 and earlier) – Marc Hoersken has developed a SANE to WIA bridge which works very well, presenting the remote device to Windows Device Manager as if it is locally attached. Scanning using the Windows Fax and Scan application is seamless (preview, partial selections etc.), and other software with WIA support can be used, for instance NAPS2 (Not Another PDF Scanner 2) which offers OCR, and Paint.net, both of which are free. Although the latest version of WiaSane does now include a signed device driver which works in Windows 10, the device configuration wizard only seems to work at install time, and each time the scanner changes USB ID it has to be removed and reinstalled.
      WiaSane was last updated in February 2017
    • SwingSane As a Java application SwingSane will run on most operating systems. It is full-featured but it has some rough edges which caused me to think it was broken when I first evaluated it. This explanatory video by SwingSane’s author Roland Quast explains some of the non-obvious aspects.
      The most confusing thing is that the Settings tab was not offering me the appropriate settings for my scanner – for instance I could not set the resolution or the page size. Roland explains in the video that these main settings were specifically targeting Epson scanners, and that for all other models Custom Settings should be used, in particular he recommends to select Check Options which queries the backend driver for its parameters. The next problem is that with custom settings SwingSane will not select the whole bed of the scanner by default, only a small selection. If you export the settings and inspect the XML file you can discover the constraint values (maxima) for the br-x and br-y values in millimetres (bottom right of the selection rectangle), set those and save the settings. This is far too counter-intuitive when surely these values can be determined automatically by the software.
      One strength of SwingSane however, is that all the scans produced in the current session are stored in the preview tab and can be output to the same multi-page PDF (AirSane and Image Capture also permits this). Finally, the file requestor confused me on macOS (more so than on Windows). There is a dropdown for File Format which is blank (why show this?). I was expecting to specify the filename, but this is determined by the scan batch so really the file requestor is asking for a destination folder only. This should be stated in the window title. Furthermore on macOS you cannot save once you have browsed inside a folder – you have to navigate to the parent and select the destination folder without navigating to its contents! This is really not obvious and leads you to suspect the software is broken.
      SwingSane was last updated in April 2015.
    • SaneWinDS (Windows 10 and earlier) – This frontend does not hook into WIA so you will have to use it for the scan acquisition rather than acquiring from inside applications. It does a good job of presenting the available options, and will send the scans directly to the default application for the destination file type. There is no driver component – it’s just a software application so it works fine even on Windows 10.
      Author Alec Skelly last updated SaneWinDS in April 2015.
     

    Notes

    • The package can be stopped and started in Package Center but really this is to launch and provide the log output of sane-find-scanner and scanimage -L in the easiest way for non-technical users. saned uses the inetd super-server daemon so it is only loaded and invoked when a SANE frontend makes contact on port 6566. This means that really there is no performance nor memory penalty for leaving the package running all the time, even on very resource limited systems.
    • Unfortunately Synology decided to remove the ability to view package log files via the DSM 6.2 GUI and they’ve provided no information in the Developer Guide on how to integrate with the new Log Center apps. I lack the motivation to reverse engineer functionality the company significantly alters with each DSM release, so troubleshooting this package does now require some familiarity with SSH or SCP. The package log file is /var/packages/sane-backends/target/var/sane-find-scanner.log
    • Now that I have built the package with libusb 1.0 rather than using DSM’s version 0.1, it does automatically detect scanners that have been hot-plugged.
    • By default access is granted to SANE frontends originating from any IP address (0.0.0.0/0 and ::/0 for IPv6). This can be restricted by modifying /var/packages/sane-backends/target/etc/sane.d/saned.conf, or by configuring the DSM Firewall.
    • By default connections to the SANE backends do not require credentials. If you would like to secure devices, create the text file /var/packages/sane-backends/target/etc/sane.d/saned.users, specifying credentials in the format “user:password:backend”, e.g.:
      swingsane:fqkg3h328rge:plustek
    • The DSM 6.0 toolchains provide pre-built development libraries for certain components such as avahi and dbus which are complex to build. Although I did not build sane-backends with support for avahi (due to stability issues), these libraries are needed by the AirSane package hence the new requirement for DSM 6.0 at a minimum. Some much older macOS SANE frontends make the assumption that avahi will be used and so do not allow you to statically define a target IP address, so they cannot be used with this package.
    • Although most of the library search path behaviour can be controlled at compilation time, unfortunately the backend drivers are searched for using a static path, and sane-backends insists on saving its configuration in a static location. I am always careful that my packages do not damage the system they are installed on so I have kept all of this contained within /var/packages/sane-backends/target by cross-compiling in this same location on my development Linux VM. My build steps are documented on GitHub.
     

    Package scripts

    For information, here are the package scripts so you can see what it’s going to do. You can get more information about how packages work by reading the Synology 3rd Party Developer Guide.

    installer.sh

    #!/bin/sh
    
    #--------SANE Backends installer script
    #--------package maintained at pcloadletter.co.uk
    
    
    SYNO_CPU_ARCH="`uname -m`"
    [ "${SYNOPKG_DSM_ARCH}" == "comcerto2k" ] && SYNO_CPU_ARCH="armneon"
    [ "${SYNOPKG_DSM_ARCH}" == "armada375" ] && SYNO_CPU_ARCH="armneon"
    [ "${SYNOPKG_DSM_ARCH}" == "armada38x" ] && SYNO_CPU_ARCH="armneon"
    [ "${SYNOPKG_DSM_ARCH}" == "alpine" ] && SYNO_CPU_ARCH="armneon"
    [ "${SYNOPKG_DSM_ARCH}" == "alpine4k" ] && SYNO_CPU_ARCH="armneon"
    [ "${SYNOPKG_DSM_ARCH}" == "monaco" ] && SYNO_CPU_ARCH="armneon"
    NATIVE_BINS_URL="https://syno.pcloadletter.co.uk/bin/sane1.0.28-native-${SYNO_CPU_ARCH}.tar.xz"   
    NATIVE_BINS_FILE="`echo ${NATIVE_BINS_URL} | sed -r "s%^.*/(.*)%\1%"`"
    INSTALL_FILES="${NATIVE_BINS_URL}"
    COMMENT="# Synology SANE Backends Package"
    TEMP_FOLDER="`find / -maxdepth 2 -path '/volume?/@tmp' | head -n 1`"
    PUBLIC_FOLDER="`synoshare --get public | sed -r "/Path/!d;s/^.*\[(.*)\].*$/\1/"`"
    source /etc/profile
    
    
    preinst ()
    {
      cd ${TEMP_FOLDER}
      for WGET_URL in ${INSTALL_FILES}
      do
        WGET_FILENAME="`echo ${WGET_URL} | sed -r "s%^.*/(.*)%\1%"`"
        [ -f ${TEMP_FOLDER}/${WGET_FILENAME} ] && rm ${TEMP_FOLDER}/${WGET_FILENAME}
        wget ${WGET_URL}
        if [ $? != 0 ]; then
          if [ -d ${PUBLIC_FOLDER} ] && [ -f ${PUBLIC_FOLDER}/${WGET_FILENAME} ]; then
            cp ${PUBLIC_FOLDER}/${WGET_FILENAME} ${TEMP_FOLDER}
          else
            echo "There was a problem downloading ${WGET_FILENAME} from the official download link, " >> $SYNOPKG_TEMP_LOGFILE
            echo "which was \"${WGET_URL}\" " >> $SYNOPKG_TEMP_LOGFILE
            echo "Alternatively, you may download this file manually and place it in the 'public' shared folder. " >> $SYNOPKG_TEMP_LOGFILE
            exit 1
          fi
        fi
      done
    
      exit 0
    }
    
    
    postinst ()
    {
      #extract CPU-specific binaries
      cd ${SYNOPKG_PKGDEST}
      tar xJf ${TEMP_FOLDER}/${NATIVE_BINS_FILE} && rm ${TEMP_FOLDER}/${NATIVE_BINS_FILE}
    
      #allow access to saned by default (this can be restricted by IP/subnet)
      echo 0.0.0.0/0 >> /var/packages/${SYNOPKG_PKGNAME}/target/etc/sane.d/saned.conf
      echo ::/0 >> /var/packages/${SYNOPKG_PKGNAME}/target/etc/sane.d/saned.conf
    
      #add firewall config
      /usr/syno/bin/servicetool --install-configure-file --package /var/packages/${SYNOPKG_PKGNAME}/conf/${SYNOPKG_PKGNAME}.sc > /dev/null
    
      exit 0
    }
    
    
    preuninst ()
    {
      `dirname $0`/stop-start-status stop
    
      exit 0
    }
    
    
    postuninst ()
    {
      #remove system configuration changes
      sed -i "/${COMMENT}/d" /etc/services
      sed -i "/${COMMENT}/d" /etc/inetd.conf
    
      #remove firewall config
      if [ "${SYNOPKG_PKG_STATUS}" == "UNINSTALL" ]; then
        /usr/syno/bin/servicetool --remove-configure-file --package ${SYNOPKG_PKGNAME}.sc > /dev/null
      fi
    
      exit 0
    }
    
    
    preupgrade ()
    {
      `dirname $0`/stop-start-status stop
    
      exit 0
    }
    
    
    postupgrade ()
    {
      exit 0
    }
    
     

    start-stop-status.sh

    #!/bin/sh
    
    #--------SANE Backends start-stop-status script
    #--------package maintained at pcloadletter.co.uk
    
    PKG_FOLDER="/var/packages/sane-backends"
    DLOG="${PKG_FOLDER}/target/var/sane-find-scanner.log"
    COMMENT="# Synology SANE Backends Package"
    source /etc/profile
    source /root/.profile
    
    
    EnvCheck ()
    #updates to DSM will reset these changes so check them each startup
    {
      #/etc/services should contain 1 line added by this package tagged with trailing comments
      COUNT=`grep -c "${COMMENT}$" /etc/services`
      if [ $COUNT != 1 ]; then
    
        #remove any existing mods
        sed -i "/${COMMENT}/d" /etc/services
    
        #make the required changes
        echo "sane-port       6566/tcp                        ${COMMENT}" >> /etc/services
      fi
      #/etc/inetd.conf should contain 1 line added by this package tagged with trailing comments
      COUNT=`grep -c "${COMMENT}$" /etc/inetd.conf`
      if [ $COUNT != 1 ]; then
    
        #remove any existing mods
        sed -i "/${COMMENT}/d" /etc/inetd.conf
    
        #make the required changes      
        echo "sane-port stream tcp    nowait  root    ${PKG_FOLDER}/target/sbin/saned    saned  ${COMMENT}" >> /etc/inetd.conf
      fi
      #/usr/syno/etc/synoservice.d/pkgctl-sane-backends.cfg should contain an upstart entry for inetd
      COUNT=`grep -c "inetd" /usr/syno/etc/synoservice.d/pkgctl-sane-backends.cfg`
      if [ $COUNT != 1 ]; then
        sed -i -r "s/(\"pkgctl-sane-backends\")/\1,\"inetd\"/" /usr/syno/etc/synoservice.d/pkgctl-sane-backends.cfg
      fi
    }
    
    case $1 in
      start)
        EnvCheck
        reload inetd
        echo `date "+%F %R"` startup. `${PKG_FOLDER}/target/bin/sane-find-scanner -q` > ${PKG_FOLDER}/target/var/sane-find-scanner.log
        echo `date "+%F %R"` `${PKG_FOLDER}/target/bin/scanimage -L` >> ${PKG_FOLDER}/target/var/sane-find-scanner.log
        exit 0
      ;;
    
      stop)
        #remove any existing config changes
        sed -i "/${COMMENT}/d" /etc/services
        sed -i "/${COMMENT}/d" /etc/inetd.conf
        killall -q saned
        reload inetd
        exit 0
      ;;
    
      status)
        grep -q "${COMMENT}" /etc/inetd.conf && exit 0 || exit 1
      ;;
    
      log)
        echo "${DLOG}"
        exit 0
      ;;
    
    esac
    
     

    Changelog:

    • 0003 15/Sep/19 – Updated to SANE 1.0.28 and libusb 1.0.23 (DSM still uses libusb 0.1), fixed inetd start issue, allowed connections on IPv6 interfaces by default, added support for new Synology product models, added aarch64 build for 64bit ARM CPUs, published a separate package AirSane to automatically present SANE scanners to the macOS Image Capture application, updated the section on frontends in this page. Old package version available here for DSM 5.0 users.
    • 0002 20/Jul/16 – Added support for Marvell Armada 385 SoC
    • 0001 16/Dec/15 – Initial public release
     
     

Certificate Services operations fail with error 0x80070057

While implementing a two-tier PKI I ran into the issue that certutil.exe -crl, and PowerShell cmdlets such as Get-CACrlDistributionPoint would fail on the Subordinate Domain CA with a generic error which made finding a solution very difficult:

PS C:\Windows\system32> Get-CACrlDistributionPoint
Get-CACrlDistributionPoint : CCertAdmin::GetConfigEntry: The parameter is incorrect. 0x80070057 (WIN32:
ERROR_INVALID_PARAMETER)
At line:1 char:1
+ Get-CACrlDistributionPoint
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-CACrlDistributionPoint], ArgumentException
+ FullyQualifiedErrorId : System.ArgumentException,Microsoft.CertificateServices.Administration.Comm
DistributionPointCommand

PS C:\Windows\system32> certutil -crl
CertUtil: -CRL command FAILED: 0x80070057 (WIN32: 87 ERROR_INVALID_PARAMETER)
CertUtil: The parameter is incorrect.
PS C:\Windows\system32>

I had started off by following this guide on Technet Blogs:
http://blogs.technet.com/b/yungchou/archive/2013/10/21/enterprise-pki-with-windows-server-2012-r2-active-directory-certificate-services-part-1-of-2.aspx

Not long after proceeding I realised that I needed to alter certain aspects of the way it was configured. I started again and continued to use the same CA server hostnames but with new CA names, this time preferring to follow this guide by Derek Seaman:
http://www.derekseaman.com/2014/01/windows-server-2012-r2-two-tier-pki-ca-pt-1.html

However I encountered the errors with the subordinate CA refusing to run the PowerShell cmdlets relating to the Certificate Authority. The errors were also encountered by commenter “Per” on Derek’s blog post, and similarly reported in the comments on the Windows Server 2012 R2 Active Directory Certificate Services Microsoft Test Lab page:
http://technet.microsoft.com/en-us/library/hh831348.aspx

There is a Microsoft KB referencing the same error at the time of creating the subordinate CA. The article implicates permissions, however this is a red herring.

It took a lot of trial and error, but eventually I did resolve this issue thanks to some pointers in a Microsoft Directory Services Team Blog post on troubleshooting Certificate Enrollment. I determined the root cause – several superfluous entries in Active Directory for an aborted CA installation. I needed to delete these with ADSIEdit, though I have subsequently discovered that you can also use the AD Sites and Services MMC snap-in to do this (at parent, View > Show Services Node). When I first attempted to set up the CAs I had been using the standard auto-generated names because I had thought that not doing so might invite trouble later on – so my subordinate domain CA had published itself to Active Directory at CN=Enrollment Services,CN=Public Key Services,CN=Services using the name domain-HOSTNAME-CA.

I had thought this entry was sane when I was looking back over the ADSIEdit output while investigating the problem – because I know it formats the cert request using this notation. Then I remembered that I had not used this CA name in my subsequent CA installation attempt. I removed this old name entry from Active Directory and it immediately fixed the issue. I guess because although it was for a different CA installation attempt, crucially it shared the same server hostname, hence the problem when PowerShell was invoking Certificate Services to query the Directory Service.

Following this, I then pruned similar superfluous records for the same abortive CA installation attempt which were located at:
CN=KRA,CN=Public Key Services,CN=Services
CN=AIA,CN=Public Key Services,CN=Services
CN=MY_CA_HOSTNAME,CN=CDP,CN=Public Key Services,CN=Services

Cross-compiling nano with UTF-8 support for Synology

export CROSS_PREFIX=i686-pc-linux-gnu
export TARGET=i686-pc-linux-gnu
export TOOLCHAIN=/usr/local/evansport-pc-linux-gnu
export AR=${TOOLCHAIN}/bin/${CROSS_PREFIX}-ar
export AS=${TOOLCHAIN}/bin/${CROSS_PREFIX}-as
export CC=${TOOLCHAIN}/bin/${CROSS_PREFIX}-gcc
export CXX=${TOOLCHAIN}/bin/${CROSS_PREFIX}-g++
export LD=${TOOLCHAIN}/bin/${CROSS_PREFIX}-ld
export LDSHARED="${TOOLCHAIN}/bin/${CROSS_PREFIX}-gcc -shared "
export RANLIB=${TOOLCHAIN}/bin/${CROSS_PREFIX}-ranlib
export CFLAGS="-I${TOOLCHAIN}/include -O3 ${MARCH}"
export LDFLAGS="-L${TOOLCHAIN}/lib"
export PKG_CONFIG_PATH="${TOOLCHAIN}/lib/pkgconfig"

#DSM 5.0 already includes libncursesw so we can link the nano binary to this
#fetch the source which was extracted from the Synology DSM 5.0 source tarball
wget https://dl.dropboxusercontent.com/u/1188556/ncurses-5.x.zip
unzip ncurses-5.x.zip
cd ncurses-5.x
./configure --prefix=${TOOLCHAIN} --host=${TARGET} --build=x86_64-linux-gnu --with-shared --without-normal --without-progs --without-debug --enable-widec
make
make install
cd ..
wget http://www.nano-editor.org/dist/v2.2/nano-2.2.6.tar.gz
tar xvzf nano-2.2.6.tar.gz
cd nano-2.2.6
#src/nano.h:92:20: fatal error: curses.h: No such file or directory
#http://blog.csdn.net/alienspy/article/details/24135761
wget http://dl.dropboxusercontent.com/u/1188556/nano.h.patch
patch nano.h < nano.h.patch
CFLAGS="${CFLAGS} -I${TOOLCHAIN}/include/ncurses" ./configure --prefix=${TOOLCHAIN} --host=${TARGET} --build=x86_64-linux-gnu --enable-utf8 --disable-nls --enable-color --enable-extra --enable-multibuffer --enable-nanorc
#sudo apt-get install texinfo
sed -i -e "s%^CPPFLAGS = -I/usr/include/ncursesw%CPPFLAGS = -I${TOOLCHAIN}/include/ncurses%" Makefile
sed -i -e "s%^CPPFLAGS = -I/usr/include/ncursesw%CPPFLAGS = -I${TOOLCHAIN}/include/ncurses%" src/Makefile
make
make install
#now install it to /usr/local/bin
 

nano.h.patch

--- src/nano.h.old      2014-09-17 12:16:15.006206100 +0100
+++ src/nano.h  2014-09-17 12:19:01.226206100 +0100
@@ -86,10 +86,10 @@
 #define KEY_IC SL_KEY_IC
 /* Ncurses support. */
 #elif defined(HAVE_NCURSES_H)
-#include <ncurses.h>
+#include <ncursesw/ncurses.h>
 #else
 /* Curses support. */
-#include <curses.h>
+#include <ncursesw/curses.h>
 #endif /* CURSES_H */

 #ifdef ENABLE_NLS
 

~/.nanorc

# BASIC
syntax "BAS" "\.(bas|BAS|bas.txt)$"
color red "^ +[0-9]* "
color red "\b(GO TO|GO SUB) ([0-9]+)\b"
color yellow "\b(AND|NOT|OR)\b"
color yellow "(|=|<|>|<=|>=|<>)"
color magenta "\b(FOR [a-z]|NEXT [a-z]|GO TO|GO SUB|RETURN)\b"
color brightwhite "\b(IF|THEN)\b"
color green ""(\\.|[^\"])*""
color brightcyan "\bREM .*$"

##############################################################################
#
# Syntax highlighting for XML files
#
# Author:  Josef 'Jupp' Schugt, jupp(a)rubyforge.org
# License: GPL 2  or later
#
# Version: 2004-02-25
#
##############################################################################
syntax "ml" ".*\.([jrs]?html?|xml|sgml?)$"
color white "^.+$"
color green  start="<" end=">"
color cyan   "<[^> ]+"
color cyan   ">"
color yellow start="<!DOCTYPE" end="[/]?>"
color yellow start="<!--" end="-->"
color red    "&[^;]*;"

##############################################################################
#
# Syntax highlighting for HTTP codes
#
# Author:  Josef 'Jupp' Schugt, jupp(a)rubyforge.org
# License: GPL 2  or later
#
# Version: 2004-02-25
#
##############################################################################
syntax "urls"
color brightmagenta   "^.*$"
color cyan      "^(1[0-9][0-9]|20[256]|30[45]).*$"
color green      "^20[03].*$"
color brightyellow   "^(201|30[0-37]).*$"
color brightred      "^(204|[45][0-9][0-9]|666).*$"

##############################################################################
#
# Syntax highlighting for CSS files
#
# Author:  Simon Rupf, simon.rupf(a)int-ag.ch
# License: GPL 2  or later
#
# Version: 2005-02-14
#
##############################################################################
syntax "css" "\.css$"
color brightred     "."
color brightyellow  start="\{" end="\}"
color brightwhite           start=":" end="[;^\{]"
color brightblue    ":active|:focus|:hover|:link|:visited|:link|:after|:before|$"
color brightblue    start="\/\*" end="\\*/"
color green         ";|:|\{|\}"

syntax "sh" "\.sh$"
#icolor brightgreen "^[0-9A-Z_]+\(\)"
#color green "\b(case|do|done|elif|else|esac|exit|fi|for|function|if|in|local|read|return|select|shift|then|time|until|while)\b"
#color green "(\{|\}|\(|\)|\;|\]|\[|`|\\|\$|<|>|!|=|&|\|)"
#color green "-[Ldefgruwx]\b"
#color green "-(eq|ne|gt|lt|ge|le|s|n|z)\b"
#color brightblue "\b(cat|cd|chmod|chown|cp|echo|env|export|grep|install|let|ln|make|mkdir|mv|rm|sed|set|tar|touch|umask|unset)\b"
icolor brightwhite "\$\{?[0-9A-Z_!@#$*?-]+\}?"
color brightcyan "(^|[[:space:]])#.*$"
#color brightyellow ""(\\.|[^"])*"" "'(\\.|[^'])*'"
#color cyan ""(\\.|[^"])*"" "'(\\.|[^'])*'"
#color ,green "[[:space:]]+$"

Securing access to Microsoft Exchange 2013 EAC

The coexistence of the Exchange 2013 Administration Console (EAC) with the other Exchange website virtual directories represents a considerable security vulnerability for any organization that installs it using the out-of-box defaults. Since most organizations need Outlook Anywhere and EWS to be Web-facing, and usually OWA too, the EAC will also end up being publicly accessible – inadvisable security practice in itself, even more so for another important reason that I will explain. The EAC uses the IIS Virtual Directory /ecp which has other non-admin functions for normal email users, so it is not really desirable to try to limit access to it. Besides, an Exchange Service Pack or Cumulative Update is quite likely to reset the Virtual Directory settings and permissions later anyway. Now that the Exchange Management Console application has been retired, it is not practical to completely disable EAC unless you especially enjoy PowerShell, so we need to find a way to harden the server.

The problem is that the Domain’s built-in Administrator account does not have the Active Directory account lockout policy applied to it, so the EAC can simply be brute-force attacked if this account has access to the EAC or indeed OWA. One mitigation against this vulnerability is to make sure that the domain’s built-in Administrator account has all Exchange remote access disabled, and that a separate user account is used for day-to-day management. It is probably best to also disable the mailbox entirely to reduce the chance of someone accidentally re-enabling any of this in the EAC later.

Set-CASMailbox Administrator -OWAEnabled $false -ECPEnabled $false -ActiveSyncEnabled $false -OWAforDevicesEnabled $false -EwsEnabled $false -ImapEnabled $false -PopEnabled $false

Disable-Mailbox Administrator

Note that merely disabling the Administrator mailbox (without the first step of amending the access) offers no protection – the ECP can still be accessed and you won’t be able to use the Set-CASMailbox cmdlet, since no mailbox object exists.

There is still a big security problem though. Since the authentication is being handled by IIS the usernames are not being screened, and so a user encounters an HTTP 403 error when they are barred from using ECP but have been authenticated successfully (even if you remove the Administrator account from the ‘Organization Management’ Exchange Security Group), so the brute-force attacker can saturate the server with logon requests and precisely determine when they have cracked the Domain Admin credentials. Although these credentials cannot be used remotely if the above mitigation steps have been taken, the attacker can still use them later to fully penetrate the organization via other means: social engineering, physically entering the building etc.

Microsoft’s recommended solution is to use Powershell to designate a whole CAS server’s ECP Virtual Directory for Internal use only (keeping ECP disabled on the public facing CAS servers). This is totally unworkable for most small-to-medium enterprises though.

The only valid mitigation therefore is to restrict access to the ECP virtual directory to local subnets – something that we had wanted to avoid, and which on first sight looks impossible (since it’s a Virtual Directory, not a Website that we can re-bind to a new IP address and firewall more restrictively). In order to do this you will need to install the IIS Security Feature ‘IP and Domain Restrictions’:

Install-Feature-IIS-IP-Domain-Security

For the Default Web Site’s /ecp Virtual Directory (which is the public one), configure IP Address and Domain Restrictions:

IIS-IP-Domain-Security-Settings

In there, click Edit Feature Settings… (in the right-hand pane) and set ‘Access for unspecified clients’ to Deny. Then use Add Allow Entry to define your permitted IP ranges.

As I mentioned in the opening paragraph though this will need to be checked after Service Packs and Cumulative Updates are applied to the Exchange Server, in case this configuration is lost.

In fact the same precautions against brute force attack of the Administrator account would also apply to earlier versions of Exchange, and for VPN connectivity – i.e. when AD accounts are being used for any public facing authentication, the built-in Administrator should never be granted remote access.

PowerShell for EAP-PEAP secured SSTP VPN on Windows 8.1

Simple VPN configurations can be deployed by Group Policy but EAP authentication settings cannot be configured like this, even using Windows 8.1 and Windows Server 2012 R2. Microsoft added some new PowerShell cmdlets to Windows 8.1 for configuring VPNs, but the worked examples do not appear to function for all the settings for PEAP connections, and they do not show a worked example of how you go about exporting and re-importing a connection’s XMLStream.

Defining the XML as a block within the script itself, even assigning it as data type XML does not seem to work. Not being particularly accustomed to PowerShell, the following script took a while to get right. I assigned it as a laptop startup script by GPO. If I need to modify the connection in future I can increment the version number since the script checks the local machine Registry for that, and will not install if the desired version marker is already present.

 
# VPN Connection EAP-PEAP VPN provisioning 
# patters 2013

# This script is loosely based on the EAP-TTLS one published by Microsoft at http://technet.microsoft.com/en-us/library/jj613766.aspx
# The worked examples on that page and at http://technet.microsoft.com/en-us/library/jj554822.aspx
# are rudimentary, and in some details for PEAP, incorrect. To set advanced options like the TrustedRootCAs and the
# the server identity checking warning, you *must* export a GUI-authored config as XML. Configuring XML attributes alone
# will not work because some of them are missing when creating a new connection, and adding them results in errors.


# Check for marker in the Registry, and quit if found
# Desired version is 1
$version = 1
$test = Get-ItemProperty "HKLM:\Software\MyCompany" "MyCompany VPN" -ErrorAction SilentlyContinue
If ($test -eq $null) {
       $test = 0
} else {
       $test = $test."MyCompany VPN"
}
If ($test -ge $version) {exit} 

# VPN Connection look-up to remove any previous installations
$isTestVpn = $false
$vpnConnections = Get-VpnConnection -AllUserConnection
If($vpnConnections.Name -eq "MyCompany VPN") {Remove-VpnConnection -Name "MyCompany VPN" -AllUserConnection -Confirm:$false -Force}
$vpnConnections = Get-VpnConnection
If($vpnConnections.Name -eq "MyCompany VPN") {Remove-VpnConnection -Name "MyCompany VPN" -Confirm:$false -Force}

Try
{
       #-------------------------------------------------
       #The following section documents the attempts to get this working manually before I got importing/exporting of XML working

       # http://technet.microsoft.com/en-us/library/jj554822.aspx says to use "New-EapConfiguration -Peap" here, but is wrong      
       #$a = New-EapConfiguration

       # Generate configuration XML for PEAP authentication method with EAP-MSCHAPv2 as its inner method
       #$b = New-EapConfiguration -Peap -VerifyServerIdentity -FastReconnect $true -TunnledEapAuthMethod $a.EapConfigXmlStream

       # Edit properties within the generated configuration XML
       #$c = $b.EapConfigXmlStream
       #$c.EapHostConfig.Config.Eap.EapType.ServerValidation.ServerNames = "vpn.mycompany.com"

       # Specify AddTrust Root CA for Comodo - This attribute is missing unless you create the connection using the GUI
       # The following appears to generate the XML correctly, but it won't be accepted by the Add-VpnConnection cmdlet
       #$c.EapHostConfig.Config.Eap.EapType.ServerValidation.SetAttribute("TrustedRootCA","02 fa f3 e2 91 43 54 68 60 78 57 69 4d f5 e4 5b 68 85 18 68")   

       # PeapExtensions settings are nested XML objects so setting them as string datatype will fail
       # see http://www.vistax64.com/powershell/173859-xml-property-text.html
       #$c.EapHostConfig.Config.Eap.EapType.PeapExtensions.PerformServerValidation."#text" = "true"
       #$c.EapHostConfig.Config.Eap.EapType.PeapExtensions.AcceptServerName."#text" = "true"
       # Once again this attribute is missing unless the connection is created using the GUI. Adding it does not work
       #$c.EapHostConfig.Config.Eap.EapType.PeapExtensions.PeapExtensionsV2.AllowPromptingWhenServerCANotFound."#text" = "true"      

       # Create the VPN connection ‘MyCompany VPN’ with the EAP configuration XML generated above
       #Add-VpnConnection -Name "MyCompany VPN" -ServerAddress "vpn.mycompany.com" -TunnelType Sstp -EncryptionLevel Maximum -AuthenticationMethod Eap -EapConfigXmlStream $c -AllUserConnection
       #-------------------------------------------------



       # FORTUNATELY THERE IS AN EASIER WAY (once you figure out PowerShell XML – why couldn’t MS have shown a worked example in the docs)...



       # Create your VPN configuration entry manually then export its XML like so:
       #$exportXML = (Get-VpnConnection -Name "My_VPN_Final" -AllUserConnection).EapConfigXmlStream
       #$exportXML.Save("${env:temp}\My_VPN_config.xml")

       $importXML = New-Object XML
       $importXML.Load("\\mycompany.com\data\Software\MyCompany VPN\MyCompany VPN.xml")
       Add-VpnConnection -Name "MyCompany VPN" -ServerAddress "vpn.mycompany.com" -TunnelType Sstp -EncryptionLevel Maximum -AuthenticationMethod Eap -EapConfigXmlStream $importXML -AllUserConnection
       
       # Leave a marker in the Registry
       If (-Not (Test-Path "HKLM:\Software\MyCompany")) {New-Item -Path "HKLM:\Software\MyCompany"}
       if (Get-ItemProperty "HKLM:\Software\MyCompany" "MyCompany VPN" -ErrorAction SilentlyContinue) {
              Set-ItemProperty -Path "HKLM:\Software\MyCompany" -Name "MyCompany VPN" -Value $version
       } else {
              New-ItemProperty -Path "HKLM:\Software\MyCompany" -Name "MyCompany VPN" -Value $version
       }

}
Catch
{
       Write-Host "Error in connection setup!"
       Write-Host $_.Exception.Message
       Throw
}

Deploying vCenter Server Appliance 5.1 with AD auth

In theory using the vCenter Server Appliance (hereafter vCSA) offers a number of big advantages over using vCenter. Firstly you don’t need to commit a Windows Server OS licence, secondly to manage your VMs you can use a Flash-enabled browser on any operating system (including on Surface RT!), and thirdly it should be a lot quicker to deploy.

On that last point, a number of configuration steps in the setup of the vCSA are counter-intuitive and can waste a substantial amount of time. This is because the vCSA defaults to a hostname of localhost.yourdomain.com. The various web services that the appliance runs (SSO, Lookup Service, Inventory Service, vSphere Web Client) interact with each other using SSL sessions and, although there’s a built-in method to make vCSA regenerate its self-signed certificates at boot time, at the time of writing this does not work once these web services have been configured.

If you do not edit the hostname, you will not be able to enable AD authentication, and will likely encounter “Failed to connect to VMware Lookup Service https://yourhostname:7444/lookupservice/sdk – SSL certificate verification failed” when attempting to use the vSphere Web Client. However if after completing the initial setup wizard you configure the hostname to something meaningful and try to regenerate the SSL certificates, the vCSA will hang at boot time, displaying:

Waiting for network to come up (attempt 1 of 10)...
Appliance Name - VMware_vCenter_Server_Appliance
Configuration for eth0 found
The network for interface eth0 is managed internally, network properties ignored
DNS : x.x.x.x
Hostname or IP has changed. Regenerating the self-signed certificates.
Starting VMware vPostgres: ok
Waiting for the embedded database to start up: .[OK]

Furthermore, most of the potentially useful VMware KB articles assume a dedicated vCenter, rather than a vCSA. There seems to be no way out of this boot hang, and you will have to start deploying the vCSA all over again. The trick is to cancel out of the Setup wizard and change the hostname at the very start, before the various web services have been initialized at all.

I have outlined the successful setup process here as a reminder for future deployments:

  • When downloading the vCSA, download the .ova file. Ignore the other .vmdk and .ovf downloads, the .ova one will allow you to set up the IP address details at the time of deployment rather than having to change them later.
  • It is recommended to use Thick Provisioning for the disk, despite 120GB being overkill for typical small deployments.
  • Enter the chosen static IP address, network and DNS settings. Sadly they left out a hostname field here which would have saved a lot of grief.
  • Do not start the VM on completion of the wizard, then reduce the vCSA virtual machine RAM from 8GB down to 4GB – the supported minimum configuration for small deployments of less than 10 hosts.
  • As per the instructions displayed on the vCSA VM console, connect a web browser to port 5480 (the default credentials are root and vmware), and accept the EULA.
  • At this point quit the Setup wizard. Failure to do this will cause SSL certificate issues later.
  • In the Network tab change the hostname, in the Admin tab change the root password and enable SSL certificate regeneration, and finally in the System tab set the correct time zone then reboot.
  • Create a DNS A record for your vCSA.
  • After the reboot when you connect back to the admin console, the hostname in the certificate will remain as localhost.yourdomain.com – this is apparently normal.
  • Disable SSL certificate regeneration.
  • Start the Setup wizard again from the main vCenter Server tab Summary screen.
  • Select “Configure with default settings”.
  • Enable AD authentication (an Active Directory Computer account object will be created for your vCSA).
  • Despite having enabled Active Directory authentication, this will not work until the AD domain SSO Identity Source has been configured – you’ll see the error “A general system error occurred: Authorize Exception”. The VMware documentation mentions using the SSO Admin account to do this (admin@System-Domain) but this password is not defined by the user when deploying a vCSA. By default the root account is also an SSO admin, so log in to vSphere Web Client on port 9443 as root. Navigate to Administration > Sign-On and Discovery > Configuration > Add Identity Source:
    vCSA - Add SSO Identity Source
  • Enter the server URLs in the format ldap://dc1.mydomain.com
  • The DNs will probably both be cn=Users,dc=yourdomain,dc=com since you are only likely to need the Domain Admin user or Domain Admins group.
  • You need to set the Domain Alias to the NETBIOS domain name or else the vSphere Web Client plugin’s “use windows credentials” option will not work.
  • Set Authentication Type to Password and use a basic AD user account that you might use for photocopier scan-to-email directory lookups. Test the settings and save once working ok.
  • vCSA does not implicitly trust Domain Admins like a standard vCenter installation would, and the permissions are somewhat difficult to find in the vSphere Web Client. Navigate Home > vCenter > vCenter Servers > your vCSA > Manage tab > Permissions:
    vCSA edit vCenter permissions
  • Add your required AD groups to the role Administrator.
  • I had a further issue after all this, where connecting using vSphere Client with the “use windows credentials” option would result in the error “A General System error occured: Cannot get user info”. This is due to an omission in the vCSA which has been fixed in the latest download version (currently 5.1.0.10100-1123965). You can get around this by editing a config file on the vCSA.
  • One final reboot of the appliance is necessary to avoid permissions errors from the Inventory Service when logging into the vSphere Web Client with Windows session authentication. Be aware that the port 9443 web service can take several minutes to start, even after the console of the appliance has apparently finished booting.
  • In environments where you can’t afford the 120GB of disk space for the vCSA, you could use VMware Converter to V2V the appliance, resizing to say 40GB in the process.