This is the port of OpenSSH to NaCl (which is then integrated into nassh).
Most people who want to hack on the Secure Shell app do not need to make changes here. Typically this will be built once and copied into the nassh tree. You can even just download an existing Secure Shell extension and copy the NaCl binaries out of that.
The chromium-hterm mailing list can be used to contact other users and developers for questions.
We currently use Chrome‘s Native Client NaCl project to compile C/C++ code in a way that the browser can execute directly. This is a restricted/secure runtime so that the native code can’t break out and attack other processes. More details can be found in the NaCl documentation.
We plan on migrating to WebAssembly (WASM) at some point, but requires more planning.
The build only supports building against newlib which means it only supports building using the PNaCl toolchain. Previously, the focus was on glibc & NaCl (because PNaCl didn‘t exist or wasn’t stable), but now the focus is on newlib & PNaCl. Since the glibc build wasn't used anywhere, we dropped support for it entirely.
Also, even though we build using PNaCl, we still translate the pexe (the PNaCl executable) into nexe‘s (NaCl executables) for release. There might be room for improvement here, but it’s a low priority atm as we haven't had any requests to support any arch other than x86/x86_64/arm.
You'll need some extra packages to compile. Adjust these for your distro.
$ sudo apt-get install \ gcc g++ libstdc++6:i386 libglib2.0-0:i386 git make cmake lbzip2 \ python python2.7 python3 pylint3 python3-requests python3-wcwidth \ wget curl zlib1g-dev zip unzip rsync pkg-config xz-utils patch
To compile, you just have to run ./build.sh
. It should take care of downloading the NaCl SDK and building all the required dependencies.
When it's finished, the output/
directory will hold all the compiled objects, and the output/plugin/
directory can be copied over to nassh.
If you're hacking on the source, here are the files you most likely care about:
output/
: All download & compiled objects are saved here.bin/
: Various helper tools used at build time.build/
: All subprojects get an individual build directory.distfiles/
: All downloaded archives are cached here.home/
: Scratch dir used as $HOME when building projects.plugin/
: The final output of the build process for nassh.sysroot/
: Headers & libs for building the plugin & ssh code.openssh-*/
: Code to download & build OpenSSH.Here are the rest of the files, but most likely you don't need to touch these:
The src/ layout contains all the glue layers that make OpenSSH work. This boils down to routing messages between the JS & NaCl worlds, and emulating the filesystem and network layers.
Here's the main module code:
open
or close
, they hit here first.Here's the core filesystem related logic:
FileSystem
module expects this from all its handlers.Here's the path-specific modules:
/dev/null
./dev/random
./dev/stdin
, /dev/stdout
, /dev/stderr
, and /dev/tty
. Also handles JS sockets (which are used with web relays)./.ssh/
paths.Here's the networking related logic:
SOCK_STREAM
(TCP) sockets used to listen for inbound connections.SOCK_STREAM
(TCP) sockets for outbound connections.SOCK_DGRAM
(UDP) sockets. UDP tends to only be used to make DNS requests.Some utility code:
The nassh code takes care of creating a new NaCl object. It waits for the JS side to tell to run, at which point it spawns a thread and to run OpenSSH. When OpenSSH needs data from the JS world (like reading from stdin), it blocks until the JS world posts data back to it (like when the user types something).
The ssh_plugin.cc SshPluginModule
class is the initial entry point when the NaCl process starts up. It creates a SshPluginInstance
object which routes incoming JS messages (HandleMessage
and Invoke
) and sends responses back from the NaCl code (InvokeJS
). The exact JS<->NaCl API is documented in the nassh project, so consult those documents.
The file_system.cc FileSystem
class is used to pass some high level info (like terminal sizes) from the JS side. Further, when OpenSSH needs to work with files or network, it goes through the entry points in syscalls.cc
which routes through the FileSystem
object which looks up the right object/path.
Sometimes the NaCl process needs some debugging work beyond printf-style logs. Here's an example of how to get it to work.
If you're seeing a lot of “optimized out” and missing symbols, make sure you built the extension using ./build.sh --debug
.
First, you‘ll want to launch Chrome by hand so you can point it to a unique profile so it doesn’t interfere with your main profile, and so we can enable command line flags that otherwise are dangerous to security. You'll also need to see stdout/stderr because debug builds of the plugin send their output there (instead of via JS messages).
$ /opt/google/chrome/google-chrome \ --user-data-dir="${HOME}/.config/google-chrome-ssh-client-debug" \ --enable-nacl \ --enable-nacl-debug \ --no-sandbox \ --disable-hang-monitor
Turn on NaCl debugging in chrome://flags/#enable-nacl-debug
.
Make sure Secure Shell isn't listed in chrome://flags/#nacl-debug-mask
. Set it to “Debug everything” to be safe.
Go into chrome://extensions
and make sure you've loaded this extension in this local build.
Restart Chrome.
Connect to a server like normal. It should halt at “Loading NaCl plugin...”. Now you want to connect gdb.
$ ./output/naclsdk/toolchain/linux_x86_glibc/bin/x86_64-nacl-gdb -q (gdb) file output/ssh_client_nl_x86_64.dbg.nexe (gdb) target remote localhost:4014 Remote debugging using localhost:4014 0x000000000fddbc60 in ?? () (gdb) nacl-manifest ssh_client.dbg.nmf (gdb) remote get irt output/irt (gdb) nacl-irt output/irt (gdb) b PepperFile::Open Breakpoint 1 at 0x2e780: file src/pepper_file.cc, line 221. (gdb) c Continuing. [New Thread 2] [New Thread 3] [New Thread 4] [New Thread 5] [New Thread 6] Breakpoint 1, PepperFile::Open (this=<optimized out>, result=<optimized out>, pathname=<optimized out>, pres=<optimized out>) at src/pepper_file.cc:221 221 FileSystem* sys = FileSystem::GetFileSystem(); (gdb)
Here's a random list of documents which would be useful to people.