How to run SSH/SFTP server for multiple user logins with password authentication on Android?


Question

I want to run an SSH server on my Android phone so that my clients (varying between 10 to 20) can easily and securely share data with me when I'm on the go, without using any third party hosting services like email, file sharing etc. Every user should have it's own directory (enforced using SFTP's chroot) and he/she should be able to login using his/her own password (not key file) I provide them, optionally sharing credentials with other users if one needs to.



I didn't find any such flexible solution, specially FOSS. So I built sshd program from openssh source code, using gcc-linux-aarch64 cross compiler on Ubuntu. However when I execute it on my phone, it throws error:



~# sshd -d
Privilege Separation user sshd does not exist


How can I add sshd and other users on Android? My phone is rooted.



PS: I'm jotting down answer to my own question what limitations I faced and how I have been achieving this for past few years. Any other method - particularly a non-root solution through GUI for ease of a common user - would be appreciated.


Answer

Note:




  • Make sure your phone is accessible from internet as explained here.

  • You need a rooted device.



Android phones nowadays aren't those old low-end devices, they can run a full-featured SSH server happily. And it's an easy recipe:




  • Get fully static sshd binary for your phone's architecture. See details below.

  • Create /etc/passwd and /etc/shadow. To add a new user with password like we do on a Linux OS:



    ~# mount -o rw,remount /system; mount -o rw,remount /
    ~# touch /etc/passwd /etc/shadow
    ~# busybox adduser -D -H -h /dev/null -s /system/bin/false -u 900 sshd
    ~# busybox adduser -D -H -h /home/user1 -s /system/bin/sh -u 901 user1
    ~# toybox passwd user1
    ~# mkdir -p /data/home/user1/Documents /home /sdcard/home /etc/ssh
    ~# mount -o bind /data/home /home
    ~# mount -o bind /data/home /mnt/runtime/default/emulated/0/home
    ~# chmod 0750 /data/home/user1; chown 0.901 /data/home/user1


    First bind mount is required because otherwise SFTP's chroot won't work with /data's bad ownership. Second is to easily access shared files from /sdcard/home. To set non-root permissions on /sdcard/home, use bindfs instead.

    sshd user is for Privilege Separation. user1 is our first user that'll be able to login through SSH. In the same way more users can be added.


  • Add required configurations to /etc/ssh/sshd_config (defaults suffice in most cases):



    UsePAM no
    PasswordAuthentication yes
    Subsystem sftp internal-sftp
    Match User user1
    ChrootDirectory /home/user1

  • Run SSH server, may use logwrapper to get log in logcat:



    ~# ssh-keygen -A
     # generate host keys on first use
    ~# /system/bin/sshd -4 -E /sdcard/home/.sshd.log


    Now you can access server through SFTP / SSHFS. SSHD can also be run as an init service that's handled by Android's init. See this answer for explanation.







DETAILS:



SSH server lets you login remotely after proper authentication. Additionally it serves sharing of files and many other resource sharing securely. But there is no concept of Linux console login on Android (1) because it boots directly to GUI. However it makes use of Discretionary Access Control (DAC) of Linux kernel which is based on UIDs / GIDs and permission mode. Every installed app is considers as a *NIX user and is assigned a unique UID at install time. See this answer for more details on this.



HOW USER LOGIN AND AUTHENTICATION WORK:



Traditionally /etc/passwd contained username vs. UID/GID mapping, while supplementary GIDs were added to /etc/group. Password was also added to /etc/passwd which was later moved to /etc/shadow with the introduction of shadow password suite. Similarly /etc/gshadow contains Secure Group Account Information. These files are read by privilege granting programs such as login, su, sshd etc. and managed by administering programs such as passwd and useradd.



Most of these programs are part of shadow and util-linux package and their behavior is controlled by defining a number of configuration items in /etc/login.defs, for instance logging of different events, password expiry, environment variables etc. Also there are many files that are required or updated by these utilities, including nologin, default/useradd, adduser.conf, skel/, shells, subuid, subgid, limits files under /etc/, /var/log/faillog, /var/log/lastlog, /var/run/utmp, /var/run/wtmp and possibly others.



To centralize the functionality of these privilege granting and administering programs, a more sophisticated authentication mechanism PAM was introduced. Instead of directly handling the user login and authentication stuff, programs link to PAM libraries (called modules) which in turn respond accordingly depending on its configuration files mainly under /etc/pam.d and /etc/security.



Other than PAM, a complicated name resolution mechanism NSS also (a set of modules) exists on Linux distros which controls - among many other things - how passwd, group, and shadow databases are read depending on its configuration file /etc/nsswitch.conf. Both PAM and NSS can be configured to use remote database service like LDAP / NIS. And then there are centralized caching daemons like NSCD and SSSD. Working together, they complete the puzzle of user logins (identification and authentication) on Linux.



HOW TO SETUP LOGIN ENVIRONMENT ON ANDROID:



None of the above described configuration files and libraries exist on Android because user logins don't happen at all. But the programs built with Linux's standard libc APIs require all these files and services - including PAM - on Android too, which is near to impossible. PAM can be disabled for sshd by setting UsePAM no in sshd_config so that it directly reads files /etc/passwd, /etc/group and /etc/shadow.



PAM be gone, still we need to provide a minimal environment that meets the least requirements of login process. ssh binary for instance, needs /etc/passwd to exist necessarily because it sets $HOME from there to read known_hosts, config and id_* key. Also if host is a domain name and not an IP address, /etc/resolv.conf must exist with nameserver for DNS to work. It's a different story explained here.



So we need to create the relevant files on Android manually. Or use the non-PAM counterparts of shadow-utils such as useradd and passwd to update these files. We can get a minimal set of these utilities on Android, e.g. with busybox or toybox.



RUNNING LINUX PROGRAMS ON ANDROID:



Ideally you should write / modify the source code of a program in accordance with Android environment and then build dynamic binaries / libraries using Android's NDK and Bionic libc. But due to differences among Linux distros and Android such as in filesystem hierarchy, kernel configuration, implementation of libc and other libraries (2), code written for Linux distros need heavy modification on Android, otherwise don't mind failed attempts. In case of openssh, see the list of modification patches in AOSP and on Termux. Two of these patches are no password authentication (3) and no multiple users (4, 5). Former was worked around on Termux by introducing new APIs in termux-auth (6, 7), but the later can't be achieved without setting up login environment on Android.



Other options is to build fully static binary with Linux's libc such as glibc, musl or uClibc. While it's easy to statically build small libraries, libc itself links to many other libraries. In case of glibc, all of them can't be built statically, such as dynamically-loaded modules. I'm not sure how effective --enable-static-nss is, but, e.g. gconv can't be linked statically (8). So sshd binary must not be built with glibc, otherwise it won't work without NSS modules.

Also set Privilege Separation Path to some existing directory like /data/local/tmp and disable any other unnecessary features like utmp, wtmp, lastlog etc. Or you would need to create /var directory in rootfs.



FURTHER READING:




Topics


2D Engines   3D Engines   9-Patch   Action Bars   Activities   ADB   Advertisements   Analytics   Animations   ANR   AOP   API   APK   APT   Architecture   Audio   Autocomplete   Background Processing   Backward Compatibility   Badges   Bar Codes   Benchmarking   Bitmaps   Bluetooth   Blur Effects   Bread Crumbs   BRMS   Browser Extensions   Build Systems   Bundles   Buttons   Caching   Camera   Canvas   Cards   Carousels   Changelog   Checkboxes   Cloud Storages   Color Analysis   Color Pickers   Colors   Comet/Push   Compass Sensors   Conferences   Content Providers   Continuous Integration   Crash Reports   Credit Cards   Credits   CSV   Curl/Flip   Data Binding   Data Generators   Data Structures   Database   Database Browsers   Date &   Debugging   Decompilers   Deep Links   Dependency Injections   Design   Design Patterns   Dex   Dialogs   Distributed Computing   Distribution Platforms   Download Managers   Drawables   Emoji   Emulators   EPUB   Equalizers &   Event Buses   Exception Handling   Face Recognition   Feedback &   File System   File/Directory   Fingerprint   Floating Action   Fonts   Forms   Fragments   FRP   FSM   Functional Programming   Gamepads   Games   Geocaching   Gestures   GIF   Glow Pad   Gradle Plugins   Graphics   Grid Views   Highlighting   HTML   HTTP Mocking   Icons   IDE   IDE Plugins   Image Croppers   Image Loaders   Image Pickers   Image Processing   Image Views   Instrumentation   Intents   Job Schedulers   JSON   Keyboard   Kotlin   Layouts   Library Demos   List View   List Views   Localization   Location   Lock Patterns   Logcat   Logging   Mails   Maps   Markdown   Mathematics   Maven Plugins   MBaaS   Media   Menus   Messaging   MIME   Mobile Web   Native Image   Navigation   NDK   Networking   NFC   NoSQL   Number Pickers   OAuth   Object Mocking   OCR Engines   OpenGL   ORM   Other Pickers   Parallax List   Parcelables   Particle Systems   Password Inputs   PDF   Permissions   Physics Engines   Platforms   Plugin Frameworks   Preferences   Progress Indicators   ProGuard   Properties   Protocol Buffer   Pull To   Purchases   Push/Pull   QR Codes   Quick Return   Radio Buttons   Range Bars   Ratings   Recycler Views   Resources   REST   Ripple Effects   RSS   Screenshots   Scripting   Scroll Views   SDK   Search Inputs   Security   Sensors   Services   Showcase Views   Signatures   Sliding Panels   Snackbars   SOAP   Social Networks   Spannable   Spinners   Splash Screens   SSH   Static Analysis   Status Bars   Styling   SVG   System   Tags   Task Managers   TDD &   Template Engines   Testing   Testing Tools   Text Formatting   Text Views   Text Watchers   Text-to   Toasts   Toolkits For   Tools   Tooltips   Trainings   TV   Twitter   Updaters   USB   User Stories   Utils   Validation   Video   View Adapters   View Pagers   Views   Watch Face   Wearable Data   Wearables   Weather   Web Tools   Web Views   WebRTC   WebSockets   Wheel Widgets   Wi-Fi   Widgets   Windows   Wizards   XML   XMPP   YAML   ZIP Codes