Cross compile smbclient for Dafang Hacks

Dafang Hacks is a 3rd party firmware for Ingenic T20 based IP cameras (i.e., Xiaomi Dafang/Wyzecam V2, etc.) The smbclient comes with the firmware is a very old version (2.2.7) which is incompatible with modern Samba protocols (SMB2/SMB3), but only LANMAN1/LANMAN2, which have serious security issues.

Samba supports SMB2 and durable handles from version 4.0, however, smbclient does not support SMB2 until 4.1. From version 4.0, Samba uses waf for build system but still keeps autoconf, but since version 4.1 autoconf is removed and waf became the only choice, which makes cross-compiling rather challenging.

I have tested several versions of Samba from 4.0 to 4.9 (versions above 4.9 requires gnutls, which is not compatible with mips uClibc that Dafang rootfs uses, according to here). It appears that Samba 4.7.12 can build a single binary of smbclient so we don’t need to copy over a bunch of libraries and mess with LD_LIBRARY_PATH. Yet, Samba 4.7.12 still needs some tweaks and patches to make it cross-compile using the Ingenic T20 toolchain.

I did the cross compilation with WSL2 and Void Linux, although other distros should work as well.

Assuming basic development tools are installed, the first thing is to grab Ingenic T20 toolchain:

git clone https://github.com/Dafang-Hacks/mips-gcc472-glibc216-64bit

which will provide the compilers we need for Dafang.

Before compiling Samba, several other packages needs to be installed. I’m using Void so package names may vary.

sudo xbps-install -S qemu qemu-user-static libtirpc-devel

We need qemu-mipsel-static for --cross-execute of Samba according to the doc, and libtirpc-devel is still needed for host arch since we will need to compile asn1_compile and compile_et for host. Also, we need source code of libtirpc so we can build it for target as well.

After grabbing source of libtirpc from https://sourceforge.net/projects/libtirpc/, we can write a script to do cross compiling of that:

#!/bin/bash

TOOLCHAIN=~/mips-gcc472-glibc216-64bit/bin
INSTALLPATH=$(pwd)/../_install

CROSS_COMPILE=$TOOLCHAIN/mips-linux-gnu-
export CC=${CROSS_COMPILE}gcc
export CPP=${CROSS_COMPILE}cpp
export CXX=${CROSS_COMPILE}g++
export AR=${CROSS_COMPILE}ar
export RANLIB=${CROSS_COMPILE}ranlib
export READELF=${CROSS_COMPILE}readelf

export LDFLAGS="-muclibc -O3 -L${TOOLCHAIN}/../mips-linux-gnu/libc/uclibc/lib"
export CFLAGS="-muclibc -O3 -I${TOOLCHAIN}/../mips-linux-gnu/libc/uclibc/usr/include"
export CPPFLAGS="-muclibc -O3 -I${TOOLCHAIN}/../mips-linux-gnu/libc/uclibc/usr/include"

./configure --host=mips-linux-gnu --prefix=${INSTALLPATH} \
        --disable-gssapi --disable-ipv6 \
        && make -j16 && make install

assuming toolchain was cloned to home folder.

Then we can build Samba on host to get binaries of asn1_compile and compile_et, and save it somewhere else (in my case samba-4.7.12/hostbin).

./buildtools/bin/waf configure --prefix=/system/sdcard \
        --without-gettext --disable-tdb-mutex-locking --disable-gnutls --disable-python \
        --without-gpgme --without-winbind --without-ads --without-ldap --disable-cups \
        --disable-iprint --without-pam --without-quotas --disable-avahi --without-iconv --without-acl-support \
        --without-dnsupdate --without-syslog --without-automount --without-dmapi --without-fam --without-libarchive \
        --without-regedit --without-fake-kaserver --disable-glusterfs --disable-cephfs --disable-fault-handling \
        --without-systemd --without-lttng --accel-aes=none --disable-pthreadpool --without-ad-dc --nopyc --nopyo \
        --without-ntvfs-fileserver --disable-rpath --disable-rpath-install --disable-rpath-private-install

./buildtools/bin/waf build --targets=asn1_compile,compile_et

mkdir -p hostbin
mv bin/default/source4/heimdal_build/asn1_compile ./hostbin/asn1_compile_host
mv bin/default/source4/heimdal_build/compile_et ./hostbin/compile_et_host
make distclean

The GCC in toolchain is old (gcc 4.7.2), and it will run into issues when compiling Samba with errors like:

mips-linux-gnu-gcc: error: void: No such file or directory

It’s because gcc in toolchain does not take macro definitions with whitespace in it, namely, anything like -DSTRING="abc def" will result in mips-linux-gnu-gcc: error: def: No such file or directory. To solve this, we need to patch samba-deps.py to escape all whitespaces into \x20:

--- a/buildtools/wafsamba/samba_deps.py      2017-07-04 06:05:25.000000000 -0400
+++ b/buildtools/wafsamba/samba_deps.py      2021-03-14 18:01:22.730000000 -0400
@@ -235,3 +235,3 @@
         if sentinel == 'NULL':
-            proto = "extern void __%s_dummy_module_proto(void)" % (sname)
+            proto = "\'\"extern\\x20void\\x20__%s_dummy_module_proto(void)\"\'" % (sname)
             cflags.append('-DSTATIC_%s_MODULES_PROTO=%s' % (sname, proto))
@@ -250,3 +250,3 @@
             if sentinel == 'NULL':
-                proto = "extern void __%s_dummy_module_proto(void)" % (m)
+                proto = "\'\"extern\\x20void\\x20__%s_dummy_module_proto(void)\"\'" % (m)
                 cflags.append('-DSTATIC_%s_MODULES_PROTO=%s' % (m, proto))
@@ -257,3 +257,3 @@
                 proto += '_MODULE_PROTO(%s)' % f
-            proto += "extern void __%s_dummy_module_proto(void)" % (m)
+            proto += "\'\"extern\\x20void\\x20__%s_dummy_module_proto(void)\"\'" % (m)
             cflags.append('-DSTATIC_%s_MODULES_PROTO=%s' % (m, proto))

Assuming libtirpc was installed into _install folder at the same level as Samba source, we can use the cross compile script to build Samba:

#!/bin/bash

TOOLCHAIN=~/mips-gcc472-glibc216-64bit/bin
INSTALLPATH=$(pwd)/../_install

CROSS_COMPILE=$TOOLCHAIN/mips-linux-uclibc-gnu-
export CC=${CROSS_COMPILE}gcc
export CPP=${CROSS_COMPILE}cpp
export CXX=${CROSS_COMPILE}g++
export AR=${CROSS_COMPILE}ar
export RANLIB=${CROSS_COMPILE}ranlib
export READELF=${CROSS_COMPILE}readelf
export LD=${CROSS_COMPILE}ld
export STRIP=${CROSS_COMPILE}strip

export LDFLAGS="-muclibc -O3 -L${TOOLCHAIN}/../mips-linux-gnu/libc/uclibc/lib -L${INSTALLPATH}/lib"
export CFLAGS="-muclibc -O3 -I${TOOLCHAIN}/../mips-linux-gnu/libc/uclibc/usr/include -I${INSTALLPATH}/include -I${INSTALLPATH}/include/tirpc"
export CPPFLAGS="-muclibc -O3 -I${TOOLCHAIN}/../mips-linux-gnu/libc/uclibc/usr/include -I${INSTALLPATH}/include -I${INSTALLPATH}/include/tirpc"

export USING_SYSTEM_ASN1_COMPILE=1
export ASN1_COMPILE=$(pwd)/hostbin/asn1_compile_host
export USING_SYSTEM_COMPILE_ET=1
export COMPILE_ET=$(pwd)/hostbin/compile_et_host

./buildtools/bin/waf configure --prefix=/system/sdcard \
        --without-gettext --disable-tdb-mutex-locking --disable-gnutls --disable-python \
        --without-gpgme --without-winbind --without-ads --without-ldap --disable-cups \
        --disable-iprint --without-pam --without-quotas --disable-avahi --without-iconv --without-acl-support \
        --without-dnsupdate --without-syslog --without-automount --without-dmapi --without-fam --without-libarchive \
        --without-regedit --without-fake-kaserver --disable-glusterfs --disable-cephfs --disable-fault-handling \
        --without-systemd --without-lttng --accel-aes=none --disable-pthreadpool --without-ad-dc --nopyc --nopyo \
        --without-ntvfs-fileserver --disable-rpath --disable-rpath-install --disable-rpath-private-install \
        --bundled-libraries=!asn1_compile,!compile_et --nonshared-binary=client/smbclient \
        --without-utmp \
        --cross-compile --cross-execute 'qemu-mipsel-static -L /home/username/mips-gcc472-glibc216-64bit/mips-linux-gnu/libc/uclibc'

./buildtools/bin/waf --targets=client/smbclient && ${STRIP} -s bin/smbclient

Note that the library path for qemu-mispel-static must be absolute.

Copy the compiled binary (~15M) to Dafang’s /system/sdcard/bin, create a simple config file at /system/sdcard/etc/smb.conf with content:

[global]
max protocol = SMB3

and smbclient --version should show Version 4.7.12. To connect to SMB3 share, use

/system/sdcard/bin/smbclient -m SMB3 "//path/to/your/share" -U username -D "dir"

To verify the connection is using SMB3, use smbstatus from server, it should say something like

...
pid    dafang       users        dafang.ip.addr (ipv4:dafang.ip.addr:port)  SMB3_11           -                    partial(AES-128-CMAC)
...

You can use SMB2 instead if you wish.