gems: add interactive SSH Terminal component

This component allows access to Terminal sessions via interactive SSH
sessions. Please read _repos/gems/src/server/ssh_terminal/README_ for
more detailed information.

Fixes #3014.
This commit is contained in:
Josef Söntgen 2018-09-27 16:26:49 +02:00 committed by Christian Helmuth
parent 82fb76c142
commit 9557e64822
7 changed files with 1900 additions and 0 deletions

View File

@ -0,0 +1,12 @@
SRC_DIR := src/server/ssh_terminal
include $(GENODE_DIR)/repos/base/recipes/src/content.inc
MIRROR_FROM_LIBPORTS := lib/mk/libc_pipe.mk \
src/lib/libc_pipe \
include/libc-plugin
content: $(MIRROR_FROM_LIBPORTS)
$(MIRROR_FROM_LIBPORTS):
mkdir -p $(dir $@)
cp -r $(GENODE_DIR)/repos/libports/$@ $(dir $@)

View File

@ -0,0 +1 @@
2018-10-01 149f13d8d187bc35e8ce7875ac41b83a11682ba5

View File

@ -0,0 +1,10 @@
base
gems
libc
libssh
nic_session
report_session
os
terminal_session
timer_session
vfs

View File

@ -0,0 +1,197 @@
#
# \brief Test for the SSH terminal
#
assert_spec x86
if {[have_spec linux]} {
puts "Run script is not supported on this platform."
exit 0
}
# Build
#
set build_components {
core init
drivers/timer
drivers/nic
drivers/rtc
server/ssh_terminal
lib/libc_noux
lib/vfs/jitterentropy
lib/vfs/lxip
test/libports/ncurses
test/terminal_echo
noux
noux-pkg/bash
}
source ${genode_dir}/repos/base/run/platform_drv.inc
append_platform_drv_build_components
build $build_components
create_boot_directory
#
# Generate config
#
set config {
<config verbose="no">
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<default caps="100"/>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides> <service name="Timer"/> </provides>
</start>
<start name="report_rom">
<resource name="RAM" quantum="1M"/>
<provides> <service name="Report"/> <service name="ROM"/> </provides>
<config verbose="yes"/>
</start>
<start name="nic_drv">
<resource name="RAM" quantum="4M"/>
<provides> <service name="Nic"/> </provides>
</start>
<start name="rtc_drv">
<resource name="RAM" quantum="1M"/>
<provides> <service name="Rtc"/> </provides>
</start>
<start name="ssh_terminal" caps="250">
<resource name="RAM" quantum="32M"/>
<provides> <service name="Terminal"/> </provides>
<config port="22" allow_password="yes"
show_password="yes" ed25519_key="/etc/ssh/ed25519_key">
<policy label_prefix="noux" user="noux" password="xuon" multi_login="yes" request_terminal="yes"/>
<policy label_prefix="test-terminal_echo" user="charlie" password="echo"/>
<vfs>
<dir name="dev">
<log/>
<jitterentropy name="random"/>
<jitterentropy name="urandom"/>
<rtc/>
</dir>
<dir name="etc">
<dir name="ssh">
<rom name="ed25519_key"/>
</dir>
</dir>
<dir name="socket"> <lxip dhcp="yes"/> </dir>
</vfs>
<libc stdout="/dev/log" stderr="/dev/log" socket="/socket" rtc="/dev/rtc">
</libc>
</config>
<route>
<service name="Report"> <child name="report_rom"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
<start name="test-terminal_echo">
<resource name="RAM" quantum="1M"/>
</start>
<start name="noux" caps="500">
<resource name="RAM" quantum="64M"/>
<config verbose="yes">
<fstab>
<tar name="bash.tar" />
</fstab>
<start name="/bin/bash">
<env name="TERM" value="screen"/>
<env name="HOME" value="/"/>
<env name="IGNOREEOF" value="3"/>
</start>
</config>
</start>
}
append_platform_drv_config
append config {
</config>}
install_config $config
#
# Generate a new host key
#
if {![file exists bin/ed25519_key]} {
exec ssh-keygen -t ed25519 -f bin/ed25519_key -q -N ""
}
#
# Boot modules
#
# generic modules
set boot_modules {
core ld.lib.so init timer nic_drv rtc_drv report_rom
noux test-terminal_echo
libc.lib.so pthread.lib.so libm.lib.so vfs.lib.so
vfs_lxip.lib.so lxip.lib.so libc_pipe.lib.so libc_noux.lib.so
posix.lib.so libcrypto.lib.so libssh.lib.so zlib.lib.so ncurses.lib.so
vfs_jitterentropy.lib.so ssh_terminal
bash.tar ed25519_key
}
# platform-specific modules
append_platform_drv_boot_modules
build_boot_image $boot_modules
#
# Execute test
#
append qemu_args " -m 512 -nographic "
append_if [have_spec x86] qemu_args " -net nic,model=e1000 "
append qemu_args " -net user -redir tcp:5555::22 "
set lxip_match_string "ipaddr=(\[0-9\]+\.\[0-9\]+\.\[0-9\]+\.\[0-9\]+).*\n"
if {[get_cmd_switch --autopilot]} {
run_genode_until $lxip_match_string 60
set serial_id [output_spawn_id]
if {[have_include "power_on/qemu"]} {
set host "localhost"
set port "5555"
} else {
regexp $lxip_match_string $output all host
puts ""
set port "22"
}
# wait for ssh_terminal to come up
sleep 5
spawn sshpass -p xuon ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -l noux $host -p $port
set ssh_id $spawn_id
set spawn_id_list [list $ssh_id $serial_id]
run_genode_until "--- noux started ---" 15 $spawn_id_list
puts ""
puts ""
} else {
run_genode_until forever
}
exec rm bin/ed25519_key bin/ed25519_key.pub
# vi: set ft=tcl :

View File

@ -0,0 +1,114 @@
This directory contains an minimal SSH Terminal server. It provides
concurrent access to multiple Terminal sessions via interactive SSH sessions.
Before using the component, please consult the _Notes_ section to learn
about the current subtleties.
For an example on how to use the server please look at the run script
provided by _repos/gem/run/ssh_terminal_.
Configuration
~~~~~~~~~~~~~
Examplary configuration:
! <config port="2022" ed25519_key="/etc/ed25519_host_key
! allow_password="yes" allow_publickey="yes"/>
! <vfs>
! <policy label="noux-system" user="root" password="toor"/>
! <policy label="noux-user" user="user" pub_key="/etc/user.pub"/>
!
! <dir name="dev">
! <log/> <rtc/>
! <inline name="random">012345678</inline>
! </dir>
! <dir name="socket"> <lxip dhcp="yes"/> </dir>
! <dir name="etc"> <fs/> </dir>
! </vfs>
! <libc stdout="/dev/log" stderr="/dev/log" rtc="/dev/rtc" socket="/socket"/>
! </config>
The above config snippet shows a configuration where two Noux clients may
connect to the Terminal server and SSH connections with either a password or a
public are processed on port 2022. All SSH logins for the user 'root' are
linked to the 'noux-system' session, while all 'user' logins are forwarded
to the 'noux-user' session.
The '<config>' node has several mandatory attributes:
* 'port' specfies the TCP port the SSH server attempts to listen on.
* 'ecdsa_key', 'ed25519_key' and 'rsa_key' set the respective
path to the host key. At least one of them must be specified.
* 'allow_password' enables password logins while 'allow_publickey'
enables public-key logins. At least one of them must be specified.
Those Authentication methods are set for all logins even if they
are not useable by one or the other.
Aside from the mandatory attributes there are optional ones:
* 'log_logins' enables logging of login attempts. These attempts will
be printed to the LOG session. The default is 'yes'.
The relation between a Terminal session and a SSH session is established
by a '<policy>' node. It first specifes which Terminal client may access
the server. Second and more importantly it specifies which SSH session has
access to which Terminal session. The non policy-label specific attributes
of the node form a login that is used to authenticate access via the SSH
session:
* 'user' sets the name of a login and is used throughout the component
to establish the relation between Terminal and SSH session and is therefor
mandatory.
* 'password' sets the password of the login, which is used to authenticate
a login attempt.
* 'pub_key' sets the path to the public-key file, which is used to authenticate
a login attempt.
* 'multi_login' allows one Terminal session to be used by mutliple SSH
sessions concurrently, the default is false.
Either one of the 'password' or 'pub_key' attributes must be set in order for
the login to be valid.
Normally, all Terminal sessions are expected to be established before an SSH
connection is made. To accommdate the use-case where the Terminal client is
made available in a dynamic fashion, the 'request_terminal' attribute can by
set to 'yes'. In this case the SSH Terminal server will generate a report,
which then can be inspected and reacted upon by a management component,
whenever a SSH connection for a detached Terminal session is made. Data coming
from the SSH session will be ignored as long as the Terminal client is not
attached to the server. This mechanism is useful in cases where the attached
Terminal might terminate itself, e.g. a shell when receiving EOF, but a
subsequent login attempt expects the Terminal client to be still attached.
The following snippet shows such a report:
! <request_terminal user="baron"/>
The component will generate the report only once when the first login
via SSH is made and the corresponding Terminal session is not available.
All subsequent logins have to wait until the session is provided. If
there are active SSH session after the Terminal in question has been detached,
a new report will be generated.
Notes
~~~~~
* The SSH connection MUST be forcefully cut at the client, e.g. when
using OpenSSH by entering '~.'.
* Using tools that require an exec channel, e.g. scp(1) and rsync(1), is not
supported.
* Host keys can be generated by using ssh-keygen(1) on your host system
(e.g., 'ssh-keygen -t ed25519_key -f ed25519_key' without a passphrase and
then use the 'ed25519_key' file).
* Although concurrent access to one Terminal session via multiple SSH sessions
at the same time is possible, it should better be avoided as there are no
safety measures in place.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,5 @@
TARGET = ssh_terminal
SRC_CC = main.cc
LIBS = base libc pthread libssh libc_pipe
CC_CXX_WARN_STRICT =