How to run SSH/SFTP server for multiple user logins with password authentication on Android? 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.
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:


Basic explanation on NSS , LDAP and PAM
How To Add Linux User on Android?
Linux vs. Android
How to connect two phones via SSH?