diff --git a/repos/gems/recipes/src/ssh_terminal/content.mk b/repos/gems/recipes/src/ssh_terminal/content.mk
deleted file mode 100644
index b52845e48d..0000000000
--- a/repos/gems/recipes/src/ssh_terminal/content.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-SRC_DIR := src/server/ssh_terminal
-include $(GENODE_DIR)/repos/base/recipes/src/content.inc
-
-content: $(MIRROR_FROM_LIBPORTS)
-
-$(MIRROR_FROM_LIBPORTS):
- mkdir -p $(dir $@)
- cp -r $(GENODE_DIR)/repos/libports/$@ $(dir $@)
diff --git a/repos/gems/recipes/src/ssh_terminal/hash b/repos/gems/recipes/src/ssh_terminal/hash
deleted file mode 100644
index ac60fc1176..0000000000
--- a/repos/gems/recipes/src/ssh_terminal/hash
+++ /dev/null
@@ -1 +0,0 @@
-2021-10-13 c49961ec747733def5b1d6c7f0a0fca302ecda8f
diff --git a/repos/gems/recipes/src/ssh_terminal/used_apis b/repos/gems/recipes/src/ssh_terminal/used_apis
deleted file mode 100644
index 5a72c98ae9..0000000000
--- a/repos/gems/recipes/src/ssh_terminal/used_apis
+++ /dev/null
@@ -1,10 +0,0 @@
-base
-gems
-libc
-libssh
-nic_session
-report_session
-os
-terminal_session
-timer_session
-vfs
diff --git a/repos/gems/run/ssh_exec_channel.run b/repos/gems/run/ssh_exec_channel.run
deleted file mode 100644
index 1206d00e49..0000000000
--- a/repos/gems/run/ssh_exec_channel.run
+++ /dev/null
@@ -1,328 +0,0 @@
-#
-# \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
-#
-
-
-source ${genode_dir}/repos/base/run/platform_drv.inc
-append_platform_drv_build_components
-
-lappend build_components test/exec_terminal
-
-build $build_components
-
-create_boot_directory
-
-import_from_depot [depot_user]/src/[base_src] \
- [depot_user]/src/bash \
- [depot_user]/src/coreutils-minimal \
- [depot_user]/src/exec_terminal \
- [depot_user]/src/init \
- [depot_user]/src/ipxe_nic_drv \
- [depot_user]/src/libc \
- [depot_user]/src/openssl \
- [depot_user]/src/libssh \
- [depot_user]/src/platform_drv \
- [depot_user]/src/posix \
- [depot_user]/src/fs_rom \
- [depot_user]/src/nic_router \
- [depot_user]/src/rtc_drv \
- [depot_user]/src/ssh_terminal \
- [depot_user]/src/vfs \
- [depot_user]/src/vfs_jitterentropy \
- [depot_user]/src/vfs_lxip \
- [depot_user]/src/vfs_pipe \
- [depot_user]/src/vim-minimal \
- [depot_user]/src/zlib
-
-#
-# Generate config
-#
-
-set config {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 2000-01-01 00:00
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-}
-
-append_platform_drv_config
-
-append 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 {
- ed25519_key
- exec_terminal
-}
-
-# platform-specific modules
-append_platform_drv_boot_modules
-
-build_boot_image $boot_modules
-
-#
-# Execute test
-#
-
-append qemu_args " -nographic "
-append_qemu_nic_args "hostfwd=tcp::5555-:22"
-
-set nic_router_match_string ".uplink. dynamic IP config. interface (\[0-9\]+\.\[0-9\]+\.\[0-9\]+\.\[0-9\]+).*\n"
-
-if {[get_cmd_switch --autopilot]} {
- run_genode_until $nic_router_match_string 60
- set serial_id [output_spawn_id]
-
- if {[have_include "power_on/qemu"]} {
- set host "localhost"
- set port "5555"
- } else {
- regexp $nic_router_match_string $output all host
- set port "22"
- }
- # wait for ssh_terminal to come up
- run_genode_until "--- SSH terminal started ---.*\n" 15 $serial_id
-
- for {set index 0} {$index < 3} {incr index} {
- puts "test interactive channel"
- spawn sshpass -p xuon ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -l noux $host -p $port
- set ssh_id $spawn_id
- run_genode_until {/bin/bash] Hello from Genode!.*\n} 15 $serial_id
- send -i $ssh_id "ls\r"
- run_genode_until "bin" 15 $ssh_id
- send -i $ssh_id "exit\r"
- run_genode_until "child \"init\" exited with exit value 0.*\n" 15 $serial_id
-
- puts "test exec channel echo"
- set echo_text "The quick brown fox jumps over the lazy dog"
- spawn sshpass -p xuon ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -l noux $host -p $port echo "$echo_text"
- set ssh_id $spawn_id
- run_genode_until ".*$echo_text.*\n" 15 $ssh_id
- run_genode_until "child \"init\" exited with exit value 0.*\n" 15 $serial_id
-
- puts "test exec channel ls"
- spawn sshpass -p xuon ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -l noux $host -p $port "ls"
- set ssh_id $spawn_id
- run_genode_until "bin" 15 $ssh_id
- run_genode_until "child \"init\" exited with exit value 0.*\n" 15 $serial_id
-
- puts "test exec channel with empty command will not hang"
- spawn sshpass -p xuon ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -l noux $host -p $port " "
- set ssh_id $spawn_id
- run_genode_until "child \"init\" exited with exit value.*\n" 15 $serial_id
- }
-
- puts ""
- puts ""
-} else {
- run_genode_until forever
-}
-
-exec rm bin/ed25519_key bin/ed25519_key.pub
-
-# vi: set ft=tcl :
diff --git a/repos/gems/run/ssh_terminal.run b/repos/gems/run/ssh_terminal.run
deleted file mode 100644
index b570dac8de..0000000000
--- a/repos/gems/run/ssh_terminal.run
+++ /dev/null
@@ -1,273 +0,0 @@
-#
-# \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 timer
- drivers/nic
- drivers/rtc
- server/ssh_terminal
- server/fs_rom
- server/vfs
- lib/vfs/jitterentropy
- lib/vfs/lxip
- lib/vfs/pipe
- test/libports/ncurses
- test/terminal_echo
- noux-pkg/bash
- server/nic_router
-}
-
-source ${genode_dir}/repos/base/run/platform_drv.inc
-append_platform_drv_build_components
-
-build $build_components
-
-create_boot_directory
-
-#
-# Generate config
-#
-
-set config {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- echo Welcome to Genode! > /dev/log
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-}
-
-append_platform_drv_config
-
-append 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 ipxe_nic_drv rtc_drv report_rom vfs fs_rom
- test-terminal_echo nic_router
-
- libc.lib.so libm.lib.so vfs.lib.so
- vfs_lxip.lib.so lxip.lib.so
- posix.lib.so libcrypto.lib.so libssh.lib.so zlib.lib.so ncurses.lib.so
- vfs_jitterentropy.lib.so vfs_pipe.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 " -nographic "
-append_qemu_nic_args "hostfwd=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 genode $host -p $port
- set ssh_id $spawn_id
- set spawn_id_list [list $ssh_id $serial_id]
- run_genode_until {.*\[init -> /bin/bash.*\] Welcome to Genode!.*\n} 15 $spawn_id_list
- puts ""
- puts ""
-} else {
- run_genode_until forever
-}
-
-exec rm bin/ed25519_key bin/ed25519_key.pub
-
-# vi: set ft=tcl :
diff --git a/repos/gems/src/server/ssh_terminal/README b/repos/gems/src/server/ssh_terminal/README
deleted file mode 100644
index 7797e36725..0000000000
--- a/repos/gems/src/server/ssh_terminal/README
+++ /dev/null
@@ -1,121 +0,0 @@
-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/gems/run/ssh_terminal_ or _repos/gems/run/ssh_exec_channel_.
-
-
-Configuration
-~~~~~~~~~~~~~
-
-Examplary configuration:
-
-!
-!
-!
-!
-!
-!
-!
-! 012345678
-!
-!
-!
-!
-!
-!
-
-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 '' 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 '' node. It first specifies 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 therefore
- 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 accommodate 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:
-
-!
-
-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. Once the
-Terminal session has been detached an 'exit' report is generated. Detaching a
-terminal client will lead to a disconnect for the corresponding SSH session If
-there are active SSH session after the Terminal in question has been detached, a
-new report will be generated.
-
-
-Notes
-~~~~~
-
-* A helper component is needed, in case an exec channel is required or when
- Terminal sessions need to be started *after* the SSH connection is
- established. An example can be found here: _repos/gems/src/test/exec_terminal/
-
-* The SSH connection MUST be forcefully cut at the client in case the Terminal
- session is established *before* the ssh channel is open. This can be done
- when using OpenSSH by entering '~.'.
-
-* 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).
-
-* Reports from concurrent logins will override each other and potentially lead
- to lost reports.
-
-* 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.
diff --git a/repos/gems/src/server/ssh_terminal/login.h b/repos/gems/src/server/ssh_terminal/login.h
deleted file mode 100644
index b2df1bebd6..0000000000
--- a/repos/gems/src/server/ssh_terminal/login.h
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * \brief Component providing a Terminal session via SSH
- * \author Josef Soentgen
- * \author Pirmin Duss
- * \date 2019-05-29
- */
-
-/*
- * Copyright (C) 2018 Genode Labs GmbH
- * Copyright (C) 2019 gapfruit AG
- *
- * This file is part of the Genode OS framework, which is distributed
- * under the terms of the GNU Affero General Public License version 3.
- */
-
-#ifndef _SSH_TERMINAL_LOGIN_H_
-#define _SSH_TERMINAL_LOGIN_H_
-
-/* Genode includes */
-#include
-#include
-#include
-
-/* libssh includes */
-#include
-
-/* local includes */
-#include "util.h"
-
-
-namespace Ssh {
-
- using namespace Genode;
- using namespace Util;
-
- using User = String<32>;
- using Password = String<64>;
- using Hash = String<65>;
-
- struct Login;
- struct Login_registry;
-}
-
-
-struct Ssh::Login : Genode::Registry::Element
-{
- Ssh::User user { };
- Ssh::Password password { };
- Ssh::Hash pub_key_hash { };
- ssh_key pub_key { nullptr };
- bool multi_login { false };
- bool request_terminal { false };
-
- /**
- * Constructor
- */
- Login(Genode::Registry ®,
- Ssh::User const &user,
- Ssh::Password const &pw,
- Filename const &pk_file,
- bool const multi_login,
- bool const request_terminal)
- :
- Element(reg, *this),
- user(user), password(pw), multi_login(multi_login),
- request_terminal(request_terminal)
- {
- Libc::with_libc([&] {
-
- if (pk_file.valid() &&
- ssh_pki_import_pubkey_file(pk_file.string(), &pub_key)) {
- Genode::error("could not import public key for user '",
- user, "'");
- }
-
- if (pub_key) {
- unsigned char *h = nullptr;
- size_t hlen = 0;
- /* pray and assume both calls never fail */
- ssh_get_publickey_hash(pub_key, SSH_PUBLICKEY_HASH_SHA256,
- &h, &hlen);
- char const *p = ssh_get_fingerprint_hash(SSH_PUBLICKEY_HASH_SHA256,
- h, hlen);
- if (p) {
- pub_key_hash = Ssh::Hash(p);
- }
-
- ssh_clean_pubkey_hash(&h);
-
- /* abuse function to free fingerprint */
- ssh_clean_pubkey_hash((unsigned char**)&p);
- }
- }); /* Libc::with_libc */
- }
-
- virtual ~Login() { ssh_key_free(pub_key); }
-
- bool auth_password() const { return password.valid(); }
- bool auth_publickey() const { return pub_key != nullptr; }
-
- void print(Genode::Output &out) const
- {
- Genode::print(out, "user ", user, ": ");
- if (auth_password()) { Genode::print(out, "password "); }
- if (auth_publickey()) { Genode::print(out, "public-key"); }
- }
-};
-
-
-struct Ssh::Login_registry : Genode::Registry
-{
- Genode::Allocator &_alloc;
- Util::Pthread_mutex _mutex { };
-
- /**
- * Import one login from node
- */
- bool _import_single(Genode::Xml_node const &node)
- {
- User user = node.attribute_value("user", User());
- Password pw = node.attribute_value("password", Password());
- Filename pub = node.attribute_value("pub_key", Filename());
- bool multi_login = node.attribute_value("multi_login", false);
- bool req_term = node.attribute_value("request_terminal", false);
-
- if (!user.valid() || (!pw.valid() && !pub.valid())) {
- Genode::warning("ignoring invalid policy");
- return false;
- }
-
- if (lookup(user.string())) {
- Genode::warning("ignoring already imported login ", user.string());
- return false;
- }
-
- try {
- new (&_alloc) Login(*this, user, pw, pub, multi_login, req_term);
- return true;
- } catch (...) { return false; }
- }
-
- void _remove_all()
- {
- for_each([&] (Login &login) {
- Genode::destroy(&_alloc, &login);
- });
- }
-
- /**
- * Constructor
- *
- * \param alloc allocator for registry elements
- */
- Login_registry(Genode::Allocator &alloc) : _alloc(alloc) { }
-
- /**
- * Return registry mutex
- */
- Util::Pthread_mutex &mutex() { return _mutex; }
-
- /**
- * Import all login information from config
- */
- void import(Genode::Xml_node const &node)
- {
- _remove_all();
-
- try {
- node.for_each_sub_node("policy",
- [&] (Genode::Xml_node const &node) {
- _import_single(node);
- });
- } catch (...) { }
- }
-
- /**
- * Look up login information by user name
- */
- Ssh::Login const *lookup(char const *user) const
- {
- Login const *p = nullptr;
- auto lookup_user = [&] (Login const &login) {
- if (login.user == user) { p = &login; }
- };
- for_each(lookup_user);
- return p;
- }
-};
-
-#endif /* _SSH_TERMINAL_LOGIN_H_ */
diff --git a/repos/gems/src/server/ssh_terminal/main.cc b/repos/gems/src/server/ssh_terminal/main.cc
deleted file mode 100644
index cc73dbbadf..0000000000
--- a/repos/gems/src/server/ssh_terminal/main.cc
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * \brief Component providing a Terminal session via SSH
- * \author Josef Soentgen
- * \date 2018-09-25
- *
- * On the local side this component provides Terminal sessions to its
- * configured clients while it also provides SSH sessions on the remote side.
- * The relation between both sides is establish via the policy settings that
- * determine which Terminal session may be accessed by a SSH login and the
- * other way around.
- *
- * When the component gets started it will create a read-only login database.
- * A login consists of a username and either a password or public-key or both.
- * The username is the unique primary key and is used to identify the right
- * Terminal session when a login is attempted. In return, it is also used to
- * attach a Terminal session to an (existing) SSH session. The SSH protocol
- * processing is done via libssh running in its own event thread while the
- * EP handles the Terminal session. Locking is done at the appropriate places
- * to synchronize both threads.
- */
-
-/*
- * Copyright (C) 2018 Genode Labs GmbH
- *
- * This file is part of the Genode OS framework, which is distributed
- * under the terms of the GNU Affero General Public License version 3.
- */
-
-/* Genode includes */
-#include
-#include
-
-/* local includes */
-#include "root_component.h"
-
-
-struct Main
-{
- Genode::Env &_env;
-
- Genode::Sliced_heap _sliced_heap { _env.ram(), _env.rm() };
- Terminal::Root_component _root { _env, _sliced_heap };
-
- Main(Genode::Env &env) : _env(env)
- {
- Genode::log("--- SSH terminal started ---");
- _env.parent().announce(env.ep().manage(_root));
- }
-};
-
-
-void Libc::Component::construct(Libc::Env &env) { static Main main(env); }
diff --git a/repos/gems/src/server/ssh_terminal/root_component.h b/repos/gems/src/server/ssh_terminal/root_component.h
deleted file mode 100644
index 2c19bd90da..0000000000
--- a/repos/gems/src/server/ssh_terminal/root_component.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * \brief Component providing a Terminal session via SSH
- * \author Josef Soentgen
- * \author Pirmin Duss
- * \date 2019-05-29
- */
-
-/*
- * Copyright (C) 2018 Genode Labs GmbH
- * Copyright (C) 2019 gapfruit AG
- *
- * This file is part of the Genode OS framework, which is distributed
- * under the terms of the GNU Affero General Public License version 3.
- */
-
-#ifndef _SSH_TERMINAL_ROOT_COMPONENT_H_
-#define _SSH_TERMINAL_ROOT_COMPONENT_H_
-
-/* Genode includes */
-#include
-#include
-
-/* local includes */
-#include "session_component.h"
-#include "server.h"
-
-
-namespace Terminal
-{
- using namespace Genode;
-
- class Root_component;
-}
-
-
-class Terminal::Root_component : public Genode::Root_component
-{
- private:
-
- Genode::Env &_env;
-
- Genode::Attached_rom_dataspace _config_rom { _env, "config" };
- Genode::Xml_node _config { _config_rom.xml() };
-
- Genode::Heap _logins_alloc { _env.ram(), _env.rm() };
- Ssh::Login_registry _logins { _logins_alloc };
-
- Ssh::Server _server { _env, _config, _logins };
-
- Genode::Signal_handler _config_sigh {
- _env.ep(), *this, &Terminal::Root_component::_handle_config_update };
-
- void _handle_config_update()
- {
- _config_rom.update();
- if (!_config_rom.valid()) { return; }
-
- Libc::with_libc([&] () {
- {
- Util::Pthread_mutex::Guard guard(_logins.mutex());
- _logins.import(_config_rom.xml());
- }
-
- _server.update_config(_config_rom.xml());
- });
- }
-
- protected:
-
- Session_component *_create_session(const char *args)
- {
- try {
- Session_label const label = label_from_args(args);
- Session_policy policy(label, _config);
-
- Ssh::User const user = policy.attribute_value("user", Ssh::User());
- if (!user.valid()) { throw -1; }
-
- Ssh::Login const *login = _logins.lookup(user.string());
- if (!login) { throw -1; }
-
- Session_component *s = nullptr;
- s = new (md_alloc()) Session_component(_env, 4096, login->user);
-
- try {
- Libc::with_libc([&] () { _server.attach_terminal(*s); });
- return s;
- } catch (...) {
- Genode::destroy(md_alloc(), s);
- throw;
- }
- } catch (...) { throw Service_denied(); }
- }
-
- void _destroy_session(Session_component *s)
- {
- Libc::with_libc([&] () { _server.detach_terminal(*s); });
- Genode::destroy(md_alloc(), s);
- }
-
- public:
-
- Root_component(Genode::Env &env,
- Genode::Allocator &md_alloc)
- :
- Genode::Root_component(&env.ep().rpc_ep(),
- &md_alloc),
- _env(env)
- {
- _config_rom.sigh(_config_sigh);
- _handle_config_update();
- }
-};
-
-#endif /* _SSH_TERMINAL_ROOT_COMPONENT_H_ */
diff --git a/repos/gems/src/server/ssh_terminal/server.cc b/repos/gems/src/server/ssh_terminal/server.cc
deleted file mode 100644
index 33d6e98fb7..0000000000
--- a/repos/gems/src/server/ssh_terminal/server.cc
+++ /dev/null
@@ -1,707 +0,0 @@
-/*
- * \brief Component providing a Terminal session via SSH
- * \author Josef Soentgen
- * \author Pirmin Duss
- * \author Sid Hussmann
- * \date 2019-05-29
- */
-
-/*
- * Copyright (C) 2018 Genode Labs GmbH
- * Copyright (C) 2019 gapfruit AG
- *
- * This file is part of the Genode OS framework, which is distributed
- * under the terms of the GNU Affero General Public License version 3.
- */
-
-
-/* local includes */
-#include "server.h"
-
-/*
- * Add the libssh callback forward declarations here so that we can use them
- * from within the classes and thereby document the ones currently implemented.
- */
-
-extern int channel_data_cb(ssh_session, ssh_channel, void *, uint32_t, int, void *);
-extern int channel_env_request_cb(ssh_session, ssh_channel, char const *, char const *, void *);
-extern int channel_pty_request_cb(ssh_session, ssh_channel, char const *, int, int, int, int, void *);
-extern int channel_pty_window_change_cb(ssh_session, ssh_channel, int, int, int, int, void *);
-extern int channel_shell_request_cb(ssh_session, ssh_channel, void *);
-extern int channel_exec_request_cb(ssh_session, ssh_channel, char const *, void *);
-
-extern void bind_incoming_connection(ssh_bind, void *);
-extern int session_service_request_cb(ssh_session, char const *, void *);
-extern int session_auth_password_cb(ssh_session, char const *, char const *, void *);
-extern int session_auth_pubkey_cb(ssh_session, char const *, struct ssh_key_struct *, char, void *);
-extern ssh_channel session_channel_open_request_cb(ssh_session, void *);
-
-/**
- * forward declaration of the write available callback.
- */
-static int write_avail_cb(socket_t fd, int revents, void *userdata);
-
-
-Ssh::Terminal_session::Terminal_session(Genode::Registry ®,
- Ssh::Terminal &conn,
- ssh_event event_loop)
-:
- Element(reg, *this), conn(conn), _event_loop(event_loop)
-{
- if (pipe(_fds)) {
- Genode::error("Failed to create wakeup pipe");
- throw -1;
- }
- conn.write_avail_fd = _fds[1];
-
- _state = PIPE_INITIALIZED;
-}
-
-void Ssh::Terminal_session::initialize_ssh_event_fds()
-{
- if (_state != PIPE_INITIALIZED ||
- ssh_event_add_fd(_event_loop,
- _fds[0],
- POLLIN,
- write_avail_cb,
- this) != SSH_OK) {
- Genode::error("Failed to initialize ssh event file descriptors");
- throw -1;
- }
-
- _state = SSH_INITIALIZED;
-}
-
-
-Ssh::Server::Server(Genode::Env &env,
- Genode::Xml_node const &config,
- Ssh::Login_registry &logins)
-:
- _env(env), _heap(env.ram(), env.rm()), _logins(logins)
-{
- Libc::with_libc([&] {
-
- _parse_config(config);
-
- if (ssh_init() < 0) {
- Genode::error("ssh_init failed.");
- throw Init_failed();
- }
-
- _ssh_bind = ssh_bind_new();
- if (!_ssh_bind) {
- Genode::error("ssh_bind failed.");
- throw Init_failed();
- }
-
- ssh_bind_options_set(_ssh_bind, SSH_BIND_OPTIONS_LOG_VERBOSITY, &_log_level);
- ssh_bind_options_set(_ssh_bind, SSH_BIND_OPTIONS_BINDPORT, &_port);
-
- _initialize_bind_callbacks();
- _initialize_session_callbacks();
- _initialize_channel_callbacks();
-
- /*
- * Always try to load all types of host key and error-out if
- * the file is set but could not be loaded.
- */
- try {
- _load_hostkey(_rsa_key);
- _load_hostkey(_ecdsa_key);
- _load_hostkey(_ed25519_key);
- } catch (...) {
- Genode::error("loading keys failed.");
- throw Init_failed();
- }
-
- _event_loop = ssh_event_new();
-
- if (ssh_bind_listen(_ssh_bind) < 0) {
- Genode::error("could not listen on port ", _port, ": ",
- ssh_get_error(_ssh_bind));
- throw Init_failed();
- }
-
- /* add AFTER(!) ssh_bind_listen call */
- if (ssh_event_add_bind(_event_loop, _ssh_bind) < 0) {
- Genode::error("unable to add server to event loop: ",
- ssh_get_error(_ssh_bind));
- throw Init_failed();
- }
-
- /* add pipe to wake up loop on late connecting terminal */
- if (pipe(_server_fds) ||
- ssh_event_add_fd(_event_loop,
- _server_fds[0],
- POLLIN,
- write_avail_cb,
- this) != SSH_OK ) {
- Genode::error("Failed to create wakeup pipe");
- throw -1;
- }
-
- if (pthread_create(&_event_thread, nullptr, _server_loop, this)) {
- Genode::error("could not create event thread");
- throw Init_failed();
- }
-
- Genode::log("Listen on port: ", _port);
- }); /* Libc::with_libc */
-}
-
-
-Ssh::Server::~Server()
-{
- close(_server_fds[0]);
- close(_server_fds[1]);
-}
-
-
-void Ssh::Server::_initialize_channel_callbacks()
-{
- Genode::memset(&_channel_cb, 0, sizeof(_channel_cb));
-
- _channel_cb.userdata = this;
- _channel_cb.channel_data_function = channel_data_cb;
- _channel_cb.channel_env_request_function = channel_env_request_cb;
- _channel_cb.channel_pty_request_function = channel_pty_request_cb;
- _channel_cb.channel_pty_window_change_function = channel_pty_window_change_cb;
- _channel_cb.channel_shell_request_function = channel_shell_request_cb;
- _channel_cb.channel_exec_request_function = channel_exec_request_cb;
-
- ssh_callbacks_init(&_channel_cb);
-}
-
-
-void Ssh::Server::_initialize_session_callbacks()
-{
- Genode::memset(&_session_cb, 0, sizeof(_session_cb));
-
- _session_cb.userdata = this;
- _session_cb.auth_password_function = session_auth_password_cb;
- _session_cb.auth_pubkey_function = session_auth_pubkey_cb;
- _session_cb.service_request_function = session_service_request_cb;
- _session_cb.channel_open_request_session_function = session_channel_open_request_cb;
-
- ssh_callbacks_init(&_session_cb);
-}
-
-
-void Ssh::Server::_initialize_bind_callbacks()
-{
- Genode::memset(&_bind_cb, 0, sizeof(_bind_cb));
- _bind_cb.incoming_connection = bind_incoming_connection;
- ssh_callbacks_init(&_bind_cb);
- ssh_bind_set_callbacks(_ssh_bind, &_bind_cb, this);
-}
-
-
-void Ssh::Server::_cleanup_session(Session &s)
-{
- if (s.auth_sucessful) {
- _log_logout(s);
- }
-
- ssh_channel_free(s.channel);
- s.channel = nullptr;
-
- ssh_blocking_flush(s.session, 5*1000);
- ssh_event_remove_session(_event_loop, s.session);
- ssh_disconnect(s.session);
- ssh_free(s.session);
- s.session = nullptr;
-
- if (s.terminal) {
- s.terminal->detach_channel();
- }
-
- try {
- _request_terminal_reporter.generate([&] (Xml_generator& xml) {
- xml.attribute("user", s.user());
- xml.attribute("exit", "now");
- });
- } catch (...) {
- Genode::warning("could not enable exit reporting");
- }
-
- Genode::destroy(&_heap, &s);
-}
-
-
-void Ssh::Server::_cleanup_sessions()
-{
- auto cleanup = [&] (Session &s) {
- if (!ssh_is_connected(s.session)) {
- _cleanup_session(s);
- }
- };
- _sessions.for_each(cleanup);
-}
-
-
-void Ssh::Server::_parse_config(Genode::Xml_node const &config)
-{
- using Util::Filename;
-
- _verbose = config.attribute_value("verbose", false);
- _log_level = config.attribute_value("debug", 0u);
- _log_logins = config.attribute_value("log_logins", true);
-
- {
- Util::Pthread_mutex::Guard guard(_logins.mutex());
- auto print = [&] (Login const &login) {
- Genode::log("Login configured: ", login);
- };
- _logins.for_each(print);
- }
-
- if (_config_once) { return; }
-
- _config_once = true;
-
- _port = config.attribute_value("port", 0u);
- if (!_port) {
- error("port invalid");
- throw Invalid_config();
- }
-
- _allow_password = config.attribute_value("allow_password", false);
- _allow_publickey = config.attribute_value("allow_publickey", false);
- if (!_allow_password && !_allow_publickey) {
- error("authentication methods missing");
- throw Invalid_config();
- }
-
- _rsa_key = config.attribute_value("rsa_key", Filename());
- _ecdsa_key = config.attribute_value("ecdsa_key", Filename());
- _ed25519_key = config.attribute_value("ed25519_key", Filename());
-
- Genode::log("Allowed auth methods: ",
- _allow_password ? "password " : "",
- _allow_publickey ? "public-key" : "");
-}
-
-
-void Ssh::Server::_load_hostkey(Util::Filename const &file)
-{
- if (file.valid() &&
- ssh_bind_options_set(_ssh_bind, SSH_BIND_OPTIONS_HOSTKEY,
- file.string()) < 0) {
- Genode::error("could not load hostkey '", file, "'");
- throw -1;
- }
-}
-
-
-void *Ssh::Server::_server_loop(void *arg)
-{
- Ssh::Server *server = reinterpret_cast(arg);
- server->loop();
- return nullptr;
-}
-
-
-bool Ssh::Server::_allow_multi_login(ssh_session s, Login const &login)
-{
- if (login.multi_login) { return true; }
-
- bool found = false;
- auto lookup = [&] (Session const &s) {
- if (s.user() == login.user) { found = true; }
- };
- _sessions.for_each(lookup);
- return !found;
-}
-
-
-void Ssh::Server::_log_failed(char const *user, Session const &s, bool pubkey)
-{
- if (!_log_logins) { return; }
-
- char const *date = Util::get_time();
- Genode::log(date, " failed user ", user, " (", s.id(), ") ",
- "with ", pubkey ? "public-key" : "password");
-}
-
-
-void Ssh::Server::_log_logout(Session const &s)
-{
- if (!_log_logins) { return; }
-
- char const *date = Util::get_time();
- Genode::log(date, " logout user ", s.user(), " (", s.id(), ")");
-}
-
-
-void Ssh::Server::_log_login(User const &user, Session const &s, bool pubkey)
-{
- if (!_log_logins) { return; }
-
- char const *date = Util::get_time();
- Genode::log(date, " login user ", user, " (", s.id(), ") ",
- "with ", pubkey ? "public-key" : "password");
-}
-
-
-void Ssh::Server::attach_terminal(Ssh::Terminal &conn)
-{
- Util::Pthread_mutex::Guard guard(_terminals.mutex());
-
- try {
- new (&_heap) Terminal_session(_terminals,
- conn, _event_loop);
- } catch (...) {
- Genode::error("could not attach Terminal for user ",
- conn.user());
- throw -1;
- }
-
- /* there might be sessions already waiting on the terminal */
- bool attached = false;
- auto lookup = [&] (Session &s) {
- if (s.user() == conn.user() && !s.terminal) {
- s.terminal = &conn;
- s.terminal->attach_channel();
- attached = true;
- }
- };
- _sessions.for_each(lookup);
-
- _wake_loop();
-}
-
-
-void Ssh::Server::detach_terminal(Ssh::Terminal &conn)
-{
- Util::Pthread_mutex::Guard guard(_terminals.mutex());
-
- Terminal_session *p = nullptr;
- auto lookup = [&] (Terminal_session &t) {
-
- if (&t.conn == &conn) {
- p = &t;
- }
- };
- _terminals.for_each(lookup);
-
- if (!p) {
- Genode::error("could not detach Terminal for user ", conn.user());
- return;
- }
-
- auto invalidate_terminal = [&] (Session &sess) {
- if (sess.terminal != &conn) { return; }
- sess.terminal_detached = true;
-
- /* flush before destroying the terminal */
- try { sess.terminal->send(sess.channel); }
- catch (...) { }
- };
- _sessions.for_each(invalidate_terminal);
-
- _wake_loop();
-}
-
-
-void Ssh::Server::update_config(Genode::Xml_node const &config)
-{
- Util::Pthread_mutex::Guard guard(_terminals.mutex());
-
- _parse_config(config);
- ssh_bind_options_set(_ssh_bind, SSH_BIND_OPTIONS_LOG_VERBOSITY, &_log_level);
-}
-
-
-Ssh::Terminal *Ssh::Server::lookup_terminal(Session &s)
-{
- Ssh::Terminal *p = nullptr;
- auto lookup = [&] (Terminal_session &t) {
- if (t.conn.user() == s.user()) { p = &t.conn; }
- };
- _terminals.for_each(lookup);
- return p;
-}
-
-
-Ssh::Session *Ssh::Server::lookup_session(ssh_session s)
-{
- Session *p = nullptr;
- auto lookup = [&] (Session &sess) {
- if (sess.session == s) { p = &sess; }
- };
- _sessions.for_each(lookup);
- return p;
-}
-
-
-bool Ssh::Server::request_terminal(Session &session,
- const char* command)
-{
- Util::Pthread_mutex::Guard guard(_logins.mutex());
- Login const *l = _logins.lookup(session.user().string());
- if (!l || !l->request_terminal) {
- return false;
- }
-
- try {
- _request_terminal_reporter.generate([&] (Xml_generator& xml) {
- xml.attribute("user", session.user());
- if (command) {
- xml.attribute("command", command);
- }
- });
- } catch (...) {
- Genode::warning("could not enable login reporting");
- return false;
- }
-
- if (_log_logins) {
- char const *date = Util::get_time();
- Genode::log(date, " request Terminal for user ", session.user(),
- " (", session.session, ")");
- }
-
- return true;
-}
-
-
-void Ssh::Server::incoming_connection(ssh_session s)
-{
- /*
- * In case we get bombarded by incoming connections, deny
- * all attempts when this arbritray level is reached.
- */
- enum { MEM_RESERVE = 128u * 1024, };
- if (_env.pd().avail_ram().value < (size_t)MEM_RESERVE) {
- error("Too many connections");
- throw -1;
- }
-
- /*
- * Queue up new ssh_session to be enabled later in pthread ssh loop.
- * We can't directly add the new Session object to the _session registry,
- * because this ssh callback may be invoked from within a
- * _session.for_each(...) invocation. The internal _session Genode::Mutex
- * is taken during _session.for_each(...) and during a 'new' here,
- * which would lead to a deadlock.
- */
- new (&_heap) Session(_new_sessions, s, &_channel_cb, ++_session_id);
-}
-
-
-bool Ssh::Server::auth_password(ssh_session s, char const *u, char const *pass)
-{
- Session *p = lookup_session(s);
- if (!p || p->session != s) {
- Genode::warning("session not found");
- return false;
- }
- Session &session = *p;
-
- /*
- * Even if there is no valid login for the user, let
- * the client try anyway and check multi login afterwards.
- */
- Util::Pthread_mutex::Guard guard(_logins.mutex());
- Login const *l = _logins.lookup(u);
- if (l && l->user == u && l->password == pass) {
- if (_allow_multi_login(s, *l)) {
- session.bad_auth_attempts = 0;
- session.auth_sucessful = true;
- session.adopt(l->user);
- _log_login(l->user, session, false);
- return true;
- } else {
- ssh_disconnect(session.session);
- _log_failed(u, session, false);
- return false;
- }
- }
-
- _log_failed(u, *p, false);
-
- int &i = session.bad_auth_attempts;
- if (++i >= _max_auth_attempts) {
- if (_log_logins) {
- char const *date = Util::get_time();
- Genode::log(date, " disconnect user ", u, " (", session.id(),
- ") after ", i, " failed authentication attempts"
- " with password");
- }
- ssh_disconnect(session.session);
- }
- return false;
-}
-
-
-bool Ssh::Server::auth_pubkey(ssh_session s, char const *u,
- struct ssh_key_struct *pubkey,
- char signature_state)
-{
- Session *p = lookup_session(s);
- if (!p || p->session != s) {
- Genode::warning("session not found");
- return false;
- }
- Session &session = *p;
-
- /*
- * In this first state the given pubkey is solely probed.
- * Ideally we would check here if the given pubkey is in fact to the
- * configured one, i.e., reading a 'authorized_keys' like file and
- * check its entries.
- *
- * For now we simple accept all keys and reject them in the later
- * state.
- */
- if (signature_state == SSH_PUBLICKEY_STATE_NONE) {
- return true;
- }
-
- /*
- * In this second state we check the provided pubkey and if it
- * matches allow authentication to proceed.
- */
- if (signature_state == SSH_PUBLICKEY_STATE_VALID) {
- Util::Pthread_mutex::Guard guard(_logins.mutex());
- Login const *l = _logins.lookup(u);
- if (l && !ssh_key_cmp(pubkey, l->pub_key,
- SSH_KEY_CMP_PUBLIC)) {
- if (_allow_multi_login(s, *l)) {
- session.auth_sucessful = true;
- session.adopt(l->user);
- _log_login(l->user, session, true);
- return true;
- }
- }
- }
-
- _log_failed(u, session, true);
- return false;
-}
-
-
-void Ssh::Server::loop()
-{
- while (true) {
-
- int const events = ssh_event_dopoll(_event_loop, -1);
- if (events == SSH_ERROR) {
- _cleanup_sessions();
- }
-
- {
- Util::Pthread_mutex::Guard guard(_terminals.mutex());
-
- /* finish pending initialization of terminal sessions */
- auto initialize = [&] (Terminal_session &t) {
- try {
- if (t._state == Terminal_session::PIPE_INITIALIZED) {
- t.initialize_ssh_event_fds();
- }
- } catch (...) {
- /* Not sure what to do here - terminal is "almost" attached.
- Previously service was denied in that case but as
- descriptor handling must be performed in ssh loop thread
- it is too late for that. */
- }
- };
- _terminals.for_each(initialize);
-
- /* remove all stale sessions */
- auto cleanup = [&] (Session &s) {
- if (s.terminal_detached) {
- Terminal_session *p = nullptr;
- auto lookup = [&] (Terminal_session &t) {
- if (&t.conn == s.terminal) {
- p = &t;
- s.terminal = nullptr;
- }
- };
- _terminals.for_each(lookup);
-
- if (p)
- Genode::destroy(&_heap, p);
- }
-
- if (!s.terminal_detached
- && ssh_is_connected(s.session)) { return ; }
- _cleanup_session(s);
- };
- _sessions.for_each(cleanup);
-
- /* second reset all active terminals */
- auto reset_pending = [&] (Terminal_session &t) {
- if (!t.conn.attached_channels()) { return; }
- t.conn.reset_pending();
- };
- _terminals.for_each(reset_pending);
-
- /*
- * third send data on all sessions being attached
- * to a terminal.
- */
- auto send = [&] (Session &s) {
- if (!s.terminal) { return; }
-
- try { s.terminal->send(s.channel); }
- catch (...) { _cleanup_session(s); }
- };
- _sessions.for_each(send);
- }
-
- /* enable all new sessions that got added by ssh callbacks */
- auto activate = [&] (Session &inactive_session) {
- /* re-queue session object */
- new (&_heap) Session(_sessions,
- inactive_session.session,
- inactive_session.channel_cb,
- inactive_session.id());
-
- ssh_session s = inactive_session.session;
-
- /* remove temporary object */
- Genode::destroy(&_heap, &inactive_session);
-
- /* activate session */
- ssh_set_server_callbacks(s, &_session_cb);
-
- int auth_methods = SSH_AUTH_METHOD_UNKNOWN;
- auth_methods += _allow_password ? SSH_AUTH_METHOD_PASSWORD : 0;
- auth_methods += _allow_publickey ? SSH_AUTH_METHOD_PUBLICKEY : 0;
- ssh_set_auth_methods(s, auth_methods);
-
- /*
- * Normally we would check the result of the key exchange
- * function but for better or worse using callbacks leads to
- * a false negative. So ignore any result and move on in hope
- * that the callsbacks will handle the situation.
- *
- * FIXME investigate why it somtimes fails in the first place.
- */
- int key_exchange_result = ssh_handle_key_exchange(s);
-
- if (SSH_OK != key_exchange_result) {
- Genode::warning("key exchange returned ", key_exchange_result);
- }
-
- ssh_event_add_session(_event_loop, s);
- };
- _new_sessions.for_each(activate);
- }
-}
-
-
-void Ssh::Server::_wake_loop()
-{
- /* wake the event loop up */
- char c = 1;
- ::write(_server_fds[1], &c, sizeof(c));
-}
-
-
-static int write_avail_cb(socket_t fd, int revents, void *userdata)
-{
- char c;
- return ::read(fd, &c, sizeof(char));
-}
diff --git a/repos/gems/src/server/ssh_terminal/server.h b/repos/gems/src/server/ssh_terminal/server.h
deleted file mode 100644
index 55d6b89bbf..0000000000
--- a/repos/gems/src/server/ssh_terminal/server.h
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * \brief Component providing a Terminal session via SSH
- * \author Josef Soentgen
- * \author Pirmin Duss
- * \date 2019-05-29
- */
-
-/*
- * Copyright (C) 2018 Genode Labs GmbH
- * Copyright (C) 2019 gapfruit AG
- *
- * This file is part of the Genode OS framework, which is distributed
- * under the terms of the GNU Affero General Public License version 3.
- */
-
-#ifndef _SSH_TERMINAL_SERVER_H_
-#define _SSH_TERMINAL_SERVER_H_
-
-/* Genode includes */
-#include
-#include
-#include
-
-/* libc includes */
-#include
-#include
-
-/* libssh includes */
-#include
-#include
-#include
-
-/* local includes */
-#include "login.h"
-#include "terminal.h"
-
-
-namespace Ssh {
-
- using namespace Genode;
-
- struct Server;
- struct Session;
- struct Terminal_session;
- struct Terminal_registry;
-}
-
-
-struct Ssh::Session : Genode::Registry::Element
-{
- User _user { };
- uint32_t _id { 0 };
-
- int bad_auth_attempts { 0 };
- bool auth_sucessful { false };
-
- ssh_session session { nullptr };
- ssh_channel channel { nullptr };
- ssh_channel_callbacks channel_cb { nullptr };
-
- Ssh::Terminal *terminal { nullptr };
- bool terminal_detached { false };
-
- Session(Genode::Registry ®,
- ssh_session s,
- ssh_channel_callbacks ccb,
- uint32_t id)
- : Element(reg, *this), _id(id), session(s), channel_cb(ccb) { }
-
- void adopt(User const &user) { _user = user; }
-
- User const &user() const { return _user; }
- uint32_t id() const { return _id; }
-
- void add_channel(ssh_channel c)
- {
- ssh_set_channel_callbacks(c, channel_cb);
- channel = c;
- }
-};
-
-
-struct Ssh::Terminal_session : Genode::Registry::Element
-{
- Ssh::Terminal &conn;
-
- ssh_event _event_loop;
-
- int _fds[2] { -1, -1 };
-
- enum State { UNINITIALIZED,
- PIPE_INITIALIZED,
- SSH_INITIALIZED } _state = UNINITIALIZED;
-
- Terminal_session(Genode::Registry ®,
- Ssh::Terminal &conn,
- ssh_event event_loop);
-
- ~Terminal_session()
- {
- switch (_state) {
- case SSH_INITIALIZED:
- ssh_event_remove_fd(_event_loop, _fds[0]);
- [[fallthrough]];
- case PIPE_INITIALIZED:
- close(_fds[0]);
- close(_fds[1]);
- [[fallthrough]];
- case UNINITIALIZED:
- break;
- }
- }
-
- void initialize_ssh_event_fds();
-};
-
-
-struct Ssh::Terminal_registry : Genode::Registry
-{
- Util::Pthread_mutex _mutex { };
- Util::Pthread_mutex &mutex() { return _mutex; }
-};
-
-
-class Ssh::Server
-{
- public:
-
- struct Init_failed : Genode::Exception { };
- struct Invalid_config : Genode::Exception { };
-
- private:
-
- using Session_registry = Genode::Registry;
-
- Genode::Env &_env;
- Genode::Heap _heap;
-
- bool _verbose { false };
- bool _allow_password { false };
- bool _allow_publickey { false };
- bool _log_logins { false };
- int _max_auth_attempts { 3 };
- unsigned _port { 0u };
- unsigned _log_level { 0u };
- int _server_fds[2] { -1, -1 };
-
- bool _config_once { false };
-
- ssh_bind _ssh_bind;
- ssh_event _event_loop;
-
- Util::Filename _rsa_key { };
- Util::Filename _ecdsa_key { };
- Util::Filename _ed25519_key { };
-
- Expanding_reporter _request_terminal_reporter { _env,
- "request_terminal",
- "request_terminal" };
-
- Terminal_registry _terminals { };
- Login_registry &_logins;
- pthread_t _event_thread;
-
- /*
- * Since we always pass ourself as userdata pointer, we may
- * safely use the same callback for all sessions and channels.
- */
- ssh_channel_callbacks_struct _channel_cb { };
- ssh_server_callbacks_struct _session_cb { };
- ssh_bind_callbacks_struct _bind_cb { };
-
- Session_registry _sessions { };
- Session_registry _new_sessions { };
- uint32_t _session_id { 0 };
-
- void _initialize_channel_callbacks();
- void _initialize_session_callbacks();
- void _initialize_bind_callbacks();
- void _cleanup_session(Session &s);
-
- void _cleanup_sessions();
- void _parse_config(Genode::Xml_node const &config);
- void _load_hostkey(Util::Filename const &file);
-
- /*
- * Event execution
- */
-
- static void *_server_loop(void *arg);
-
- bool _allow_multi_login(ssh_session s, Login const &login);
-
- /********************
- ** Login messages **
- ********************/
-
- void _log_failed(char const *user, Session const &s, bool pubkey);
- void _log_logout(Session const &s);
- void _log_login(User const &user, Session const &s, bool pubkey);
-
- void _wake_loop();
-
- public:
-
- Server(Genode::Env &env,
- Genode::Xml_node const &config,
- Ssh::Login_registry &logins);
-
- virtual ~Server();
-
- void loop();
-
- /***************************************************************
- ** Methods below are only used by Terminal session front end **
- ***************************************************************/
-
- /**
- * Attach Terminal session
- */
- void attach_terminal(Ssh::Terminal &conn);
-
- /**
- * Detach Terminal session
- */
- void detach_terminal(Ssh::Terminal &conn);
-
- /**
- * Update config
- */
- void update_config(Genode::Xml_node const &config);
-
- /*******************************************************
- ** Methods below are only used by callback back ends **
- *******************************************************/
-
- /**
- * Look up Terminal for session
- */
- Ssh::Terminal *lookup_terminal(Session &s);
-
- /**
- * Look up Session for SSH session
- */
- Session *lookup_session(ssh_session s);
-
- /**
- * Request Terminal
- */
- bool request_terminal(Session &session, const char* command = nullptr);
-
- /**
- * Handle new incoming connections
- */
- void incoming_connection(ssh_session s);
-
- /**
- * Handle password authentication
- */
- bool auth_password(ssh_session s, char const *u, char const *pass);
-
- /**
- * Handle public-key authentication
- */
- bool auth_pubkey(ssh_session s, char const *u,
- struct ssh_key_struct *pubkey,
- char signature_state);
-};
-
-#endif /* _SSH_TERMINAL_SERVER_H_ */
diff --git a/repos/gems/src/server/ssh_terminal/session_component.h b/repos/gems/src/server/ssh_terminal/session_component.h
deleted file mode 100644
index c3c91ad86c..0000000000
--- a/repos/gems/src/server/ssh_terminal/session_component.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * \brief Component providing a Terminal session via SSH
- * \author Josef Soentgen
- * \author Pirmin Duss
- * \date 2019-05-29
- */
-
-/*
- * Copyright (C) 2018 Genode Labs GmbH
- * Copyright (C) 2019 gapfruit AG
- *
- * This file is part of the Genode OS framework, which is distributed
- * under the terms of the GNU Affero General Public License version 3.
- */
-
-#ifndef _SSH_TERMINAL_SESSION_COMPONENT_H_
-#define _SSH_TERMINAL_SESSION_COMPONENT_H_
-
-/* Genode includes */
-#include
-#include
-
-/* local includes */
-#include "util.h"
-#include "terminal.h"
-
-
-namespace Terminal {
- class Session_component;
-};
-
-class Terminal::Session_component : public Genode::Rpc_object,
- public Ssh::Terminal
-{
- private:
-
- Genode::Attached_ram_dataspace _io_buffer;
-
- public:
-
- Session_component(Genode::Env &env,
- Genode::size_t io_buffer_size,
- Ssh::User const &user)
- :
- Ssh::Terminal(user),
- _io_buffer(env.ram(), env.rm(), io_buffer_size)
- { }
-
- virtual ~Session_component() = default;
-
- /********************************
- ** Terminal session interface **
- ********************************/
-
- Genode::size_t read(void *buf, Genode::size_t) override { return 0; }
- Genode::size_t write(void const *buf, Genode::size_t) override { return 0; }
-
- Size size() override { return Ssh::Terminal::size(); }
- bool avail() override { return !Ssh::Terminal::read_buffer_empty(); }
-
- void read_avail_sigh(Genode::Signal_context_capability sigh) override {
- Ssh::Terminal::read_avail_sigh(sigh);
- }
-
- void connected_sigh(Genode::Signal_context_capability sigh) override {
- Ssh::Terminal::connected_sigh(sigh);
- }
-
- void size_changed_sigh(Genode::Signal_context_capability sigh) override {
- Ssh::Terminal::size_changed_sigh(sigh);
- }
-
- Genode::Dataspace_capability _dataspace() { return _io_buffer.cap(); }
-
- Genode::size_t _read(Genode::size_t num)
- {
- Genode::size_t num_bytes = 0;
- Libc::with_libc([&] () {
- char *buf = _io_buffer.local_addr();
- num = Genode::min(_io_buffer.size(), num);
- num_bytes = Ssh::Terminal::read(buf, num);
- });
- return num_bytes;
- }
-
- Genode::size_t _write(Genode::size_t num)
- {
- ssize_t written = 0;
-
- char *buf = _io_buffer.local_addr();
- num = Genode::min(num, _io_buffer.size());
- written = Ssh::Terminal::write(buf, num);
-
- if (written < 0) {
- Genode::error("write error, dropping data");
- written = 0;
- }
-
- return written;
- }
-};
-
-#endif /* _SSH_TERMINAL_SESSION_COMPONENT_H_ */
diff --git a/repos/gems/src/server/ssh_terminal/ssh_callbacks.cc b/repos/gems/src/server/ssh_terminal/ssh_callbacks.cc
deleted file mode 100644
index e9bf6075b5..0000000000
--- a/repos/gems/src/server/ssh_terminal/ssh_callbacks.cc
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * \brief Component providing a Terminal session via SSH
- * \author Josef Soentgen
- * \author Pirmin Duss
- * \author Sid Hussmann
- * \date 2019-05-29
- */
-
-/*
- * Copyright (C) 2018 Genode Labs GmbH
- * Copyright (C) 2019 gapfruit AG
- *
- * This file is part of the Genode OS framework, which is distributed
- * under the terms of the GNU Affero General Public License version 3.
- */
-
-
-/* libssh includes */
-#include
-#include
-#include
-
-/* local includes */
-#include "server.h"
-
-
-/***********************
- ** Channel callbacks **
- ***********************/
-
-/**
- * Handle SSH channel data request
- */
-int channel_data_cb(ssh_session session, ssh_channel channel,
- void *data, uint32_t len, int is_stderr,
- void *userdata)
-{
- using Genode::error;
-
- if (len == 0) {
- return 0;
- }
-
- Ssh::Server &server = *reinterpret_cast(userdata);
- Ssh::Session *p = server.lookup_session(session);
- if (!p) {
- error("session not found");
- return SSH_ERROR;
- }
-
- if (p->channel != channel) {
- error("wrong channel");
- return SSH_ERROR;
- }
-
- if (!p->terminal) {
- error("no terminal");
- return SSH_ERROR;
- }
-
- Ssh::Terminal &conn { *p->terminal };
- Util::Pthread_mutex::Guard guard { conn.read_buf.mutex() };
- char const *src { reinterpret_cast(data) };
- size_t num_bytes { 0 };
-
- while ((conn.read_buf.write_avail() > 0) && (num_bytes < len)) {
-
- char c = src[num_bytes];
-
- /* replace ^? with ^H and let's hope we do not break anything */
- enum { DEL = 0x7f, BS = 0x08, };
- if (c == DEL) {
- conn.read_buf.append(BS);
- } else {
- conn.read_buf.append(c);
- }
-
- num_bytes++;
- }
- conn.notify_read_avail();
- return num_bytes;
-}
-
-
-/**
- * Handle SSH channel shell request
- *
- * For now we ignore this request because there is no way to change the
- * $ENV of the Terminal::Session client currently.
- */
-int channel_env_request_cb(ssh_session session, ssh_channel channel,
- char const *env_name, char const *env_value,
- void *userdata)
-{
- return SSH_OK;
-}
-
-
-/**
- * Handle SSH channel PTY request
- */
-int channel_pty_request_cb(ssh_session session, ssh_channel channel,
- char const *term,
- int cols, int rows, int py, int px,
- void *userdata)
-{
- using namespace Genode;
- Ssh::Server &server = *reinterpret_cast(userdata);
- Ssh::Session *p = server.lookup_session(session);
- if (!p || p->channel != channel) { return SSH_ERROR; }
-
- /*
- * Look up terminal and in case there is none, check
- * if we have to wait for another subsystem to come up.
- * In this case we return successfully to the client
- * and wait for a Terminal session to be established.
- */
- if (!p->terminal) {
- p->terminal = server.lookup_terminal(*p);
- if (!p->terminal) {
- return server.request_terminal(*p) ? SSH_OK
- : SSH_ERROR;
- }
- }
-
- p->terminal->attach_channel();
-
- Ssh::Terminal &conn = *p->terminal;
- conn.size(Terminal::Session::Size(cols, rows));
- conn.notify_size_changed();
-
- /* session handling already takes care of having a terminal attached */
- conn.notify_connected();
- return SSH_OK;
-}
-
-
-/**
- * Handle SSH channel PTY resize request
- */
-int channel_pty_window_change_cb(ssh_session session, ssh_channel channel,
- int width, int height, int pxwidth, int pwheight,
- void *userdata)
-{
- (void)pxwidth;
- (void)pwheight;
-
- using namespace Genode;
- Ssh::Server &server = *reinterpret_cast(userdata);
- Ssh::Session *p = server.lookup_session(session);
- if (!p || p->channel != channel || !p->terminal) { return SSH_ERROR; }
-
- Ssh::Terminal &conn = *p->terminal;
- conn.size(Terminal::Session::Size(width, height));
- conn.notify_size_changed();
- return SSH_OK;
-}
-
-
-/**
- * Handle SSH channel shell request
- *
- * For now we ignore this request as the shell is implicitly provided when
- * the PTY request is handled.
- */
-int channel_shell_request_cb(ssh_session session, ssh_channel channel,
- void *userdata)
-{
- return SSH_OK;
-}
-
-
-/**
- * Handle SSH channel exec request
- *
- * Exec requests provide a command that needs to be executed.
- * The command is provided while starting a new terminal using
- * request_terminal().
- */
-int channel_exec_request_cb(ssh_session session, ssh_channel channel,
- const char *command,
- void *userdata)
-{
- using namespace Genode;
-
- Ssh::Server &server = *reinterpret_cast(userdata);
- Ssh::Session *p = server.lookup_session(session);
- if (!p || p->channel != channel) { return SSH_ERROR; }
-
- /*
- * Look up terminal and in case there is none, check
- * if we have to wait for another subsystem to come up.
- * In this case we return successfully to the client
- * and wait for a Terminal session to be established.
- */
- if (!p->terminal) {
- p->terminal = server.lookup_terminal(*p);
- if (!p->terminal) {
- return server.request_terminal(*p, command) ? SSH_OK
- : SSH_ERROR;
- }
- }
- /* exec commands can only be done with newly started terminals */
- return SSH_ERROR;
-}
-
-
-/***********************
- ** Session callbacks **
- ***********************/
-
-/**
- * Handle SSH session service requests
- */
-int session_service_request_cb(ssh_session,
- char const *service, void*)
-{
- return Genode::strcmp(service, "ssh-userauth") == 0 ? 0 : -1;
-}
-
-
-/**
- * Handle SSH session password authentication requests
- */
-int session_auth_password_cb(ssh_session session,
- char const *user, char const *password,
- void *userdata)
-{
- Ssh::Server &server = *reinterpret_cast(userdata);
- return server.auth_password(session, user, password) ? SSH_AUTH_SUCCESS
- : SSH_AUTH_DENIED;
-}
-
-
-/**
- * Handle SSH session public-key authentication requests
- */
-int session_auth_pubkey_cb(ssh_session session, char const *user,
- struct ssh_key_struct *pubkey,
- char state, void *userdata)
-{
- Ssh::Server &server = *reinterpret_cast(userdata);
- return server.auth_pubkey(session, user, pubkey, state) ? SSH_AUTH_SUCCESS
- : SSH_AUTH_DENIED;
-
-}
-
-
-/**
- * Handle SSH session open channel requests
- */
-ssh_channel session_channel_open_request_cb(ssh_session session,
- void *userdata)
-{
- using namespace Genode;
-
- Ssh::Server &server = *reinterpret_cast(userdata);
- Ssh::Session *p = server.lookup_session(session);
- if (!p) {
- error("could not look up session");
- return nullptr;
- }
-
- /* for now only one channel */
- if (p->channel) {
- log("Only one channel per session supported");
- return nullptr;
- }
-
- ssh_channel channel = ssh_channel_new(p->session);
-
- if (!channel) {
- error("could not create new channel: '", ssh_get_error(p->session));
- return nullptr;
- }
-
- p->add_channel(channel);
- return channel;
-}
-
-
-/**
- * Handle new incoming SSH session requests
- */
-void bind_incoming_connection(ssh_bind sshbind, void *userdata)
-{
- using namespace Genode;
-
- ssh_session session = ssh_new();
- if (!session || ssh_bind_accept(sshbind, session)) {
- error("could not accept session: '", ssh_get_error(session), "'");
- ssh_free(session);
- return;
- }
-
- Ssh::Server &server = *reinterpret_cast(userdata);
- try {
- server.incoming_connection(session);
- }
- catch (...) {
- ssh_disconnect(session);
- ssh_free(session);
- }
-}
diff --git a/repos/gems/src/server/ssh_terminal/target.mk b/repos/gems/src/server/ssh_terminal/target.mk
deleted file mode 100644
index c3fb9d0e0c..0000000000
--- a/repos/gems/src/server/ssh_terminal/target.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-TARGET = ssh_terminal
-SRC_CC = main.cc
-SRC_CC += server.cc
-SRC_CC += ssh_callbacks.cc
-SRC_CC += util.cc
-LIBS = base libc libssh
-
-CC_CXX_WARN_STRICT =
diff --git a/repos/gems/src/server/ssh_terminal/terminal.h b/repos/gems/src/server/ssh_terminal/terminal.h
deleted file mode 100644
index 5b78629dd9..0000000000
--- a/repos/gems/src/server/ssh_terminal/terminal.h
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * \brief Component providing a Terminal session via SSH
- * \author Josef Soentgen
- * \author Pirmin Duss
- * \date 2019-05-29
- */
-
-/*
- * Copyright (C) 2018 Genode Labs GmbH
- * Copyright (C) 2019 gapfruit AG
- *
- * This file is part of the Genode OS framework, which is distributed
- * under the terms of the GNU Affero General Public License version 3.
- */
-
-#ifndef _SSH_TERMINAL_TERMINAL_H_
-#define _SSH_TERMINAL_TERMINAL_H_
-
-/* Genode includes */
-#include
-#include
-#include
-#include
-#include
-
-/* local includes */
-#include "login.h"
-
-
-namespace Ssh
-{
- using namespace Genode;
-
- class Terminal;
-}
-
-
-class Ssh::Terminal
-{
- private:
-
- typedef Util::Buffer<4096u> Buffer;
-
- Mutex _write_buf_swap { };
-
- Buffer _write_buf_a { };
- Buffer _write_buf_b { };
- Buffer *_write_buf_ep { &_write_buf_a };
- Buffer *_write_buf_pthread { &_write_buf_b };
-
- ::Terminal::Session::Size _size { 0, 0 };
-
- Signal_context_capability _size_changed_sigh;
- Signal_context_capability _connected_sigh;
- Signal_context_capability _read_avail_sigh;
-
- Ssh::User const _user { };
-
- unsigned _attached_channels { 0u };
- unsigned _pending_channels { 0u };
-
- public:
-
- Buffer read_buf { };
-
- int write_avail_fd { -1 };
-
- /**
- * Constructor
- */
- Terminal(Ssh::User const &user) : _user(user) { }
-
- virtual ~Terminal() = default;
-
- Ssh::User const &user() const { return _user; }
-
- unsigned attached_channels() const { return _attached_channels; }
-
- void attach_channel() { ++_attached_channels; }
- void detach_channel() { --_attached_channels; }
- void reset_pending() { _pending_channels = 0; }
-
- /*********************************
- ** Terminal::Session interface **
- *********************************/
-
- /**
- * Register signal handler to be notified once the size was changed
- */
- void size_changed_sigh(Signal_context_capability sigh) {
- _size_changed_sigh = sigh; }
-
- /**
- * Register signal handler to be notified once we accepted the TCP
- * connection
- */
- void connected_sigh(Signal_context_capability sigh)
- {
- _connected_sigh = sigh;
-
- if (_attached_channels > 0) {
- notify_connected();
- }
- }
-
- /**
- * Register signal handler to be notified when data is available for
- * reading
- */
- void read_avail_sigh(Signal_context_capability sigh)
- {
- _read_avail_sigh = sigh;
-
- /* if read data is available right now, deliver signal immediately */
- if (read_buffer_empty() && _read_avail_sigh.valid()) {
- Signal_transmitter(_read_avail_sigh).submit();
- }
- }
-
- /**
- * Inform client about the finished initialization of the SSH
- * session
- */
- void notify_connected()
- {
- if (!_connected_sigh.valid()) { return; }
- Signal_transmitter(_connected_sigh).submit();
- }
-
- /**
- * Inform client about avail data
- */
- void notify_read_avail()
- {
- if (!_read_avail_sigh.valid()) { return; }
- Signal_transmitter(_read_avail_sigh).submit();
- }
-
- /**
- * Inform client about the changed size of the remote terminal
- */
- void notify_size_changed()
- {
- if (!_size_changed_sigh.valid()) { return; }
- Signal_transmitter(_size_changed_sigh).submit();
- }
-
- /**
- * Set size of the Terminal session to match remote terminal
- */
- void size(::Terminal::Session::Size size) { _size = size; }
-
- /**
- * Return size of the Terminal session
- */
- ::Terminal::Session::Size size() const { return _size; }
-
- /*****************
- ** I/O methods **
- *****************/
-
- /**
- * Send internal write buffer content to SSH channel
- */
- void send(ssh_channel channel)
- {
- {
- /* swap write buffers if current is empty */
- Mutex::Guard guard(_write_buf_swap);
-
- if (!_write_buf_pthread->read_avail()) {
- auto buffer_tmp = _write_buf_ep;
- _write_buf_ep = _write_buf_pthread;
- _write_buf_pthread = buffer_tmp;
- }
- }
-
- /* write buffer for pthread is used w/o mutex, it's not used by EP */
- Buffer &write_buf = *_write_buf_pthread;
-
- if (!write_buf.read_avail()) { return; }
-
- /* ignore send request */
- if (!channel || !ssh_channel_is_open(channel)) { return; }
-
- char const *src = write_buf.content();
- size_t const len = write_buf.read_avail();
- /* XXX we do not handle partial writes */
- int const num_bytes = ssh_channel_write(channel, src, len);
-
- if (num_bytes && (size_t)num_bytes < len) {
- warning("send on channel was truncated");
- }
-
- if (++_pending_channels >= _attached_channels) {
- write_buf.reset();
- }
-
- /* at this point the client might have disconnected */
- if (num_bytes < 0) { throw -1; }
- }
-
- /******************************************
- ** Methods called by Terminal front end **
- ******************************************/
-
- /**
- * Read out internal read buffer and copy into destination buffer.
- */
- size_t read(char *dst, size_t dst_len)
- {
- Util::Pthread_mutex::Guard guard(read_buf.mutex());
-
- size_t const num_bytes = min(dst_len, read_buf.read_avail());
- Genode::memcpy(dst, read_buf.content(), num_bytes);
- read_buf.consume(num_bytes);
-
- /* notify client if there are still bytes available for reading */
- if (!read_buf.read_avail()) { read_buf.reset(); }
- else {
- if (_read_avail_sigh.valid()) {
- Signal_transmitter(_read_avail_sigh).submit();
- }
- }
-
- return num_bytes;
- }
-
- /**
- * Write into internal buffer and copy to underlying socket
- */
- size_t write(char const *src, Genode::size_t src_len)
- {
- size_t num_bytes = 0;
-
- {
- Mutex::Guard guard(_write_buf_swap);
-
- Buffer &write_buf = *_write_buf_ep;
-
- size_t i = 0;
-
- while (write_buf.write_avail() > 0 && i < src_len) {
-
- char c = src[i];
- if (c == '\n') {
- write_buf.append('\r');
- }
-
- write_buf.append(c);
- num_bytes++;
-
- i++;
- }
- }
-
- /* wake the event loop up */
- Libc::with_libc([&] {
- char c = 1;
- ::write(write_avail_fd, &c, sizeof(c));
- });
-
- return num_bytes;
- }
-
- /**
- * Return true if the internal read buffer is ready to receive data
- */
- bool read_buffer_empty()
- {
- bool empty = true;
-
- Libc::with_libc([&] {
- Util::Pthread_mutex::Guard guard(read_buf.mutex());
- empty = !read_buf.read_avail();
- });
-
- return empty;
- }
-};
-
-#endif /* _SSH_TERMINAL_TERMINAL_H_ */
diff --git a/repos/gems/src/server/ssh_terminal/util.cc b/repos/gems/src/server/ssh_terminal/util.cc
deleted file mode 100644
index 36ddfd059b..0000000000
--- a/repos/gems/src/server/ssh_terminal/util.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * \brief Component providing a Terminal session via SSH
- * \author Josef Soentgen
- * \author Pirmin Duss
- * \date 2019-05-29
- */
-
-/*
- * Copyright (C) 2018 Genode Labs GmbH
- * Copyright (C) 2019 gapfruit AG
- *
- * This file is part of the Genode OS framework, which is distributed
- * under the terms of the GNU Affero General Public License version 3.
- */
-
-/* local includes */
-#include "util.h"
-
-char const *Util::get_time()
-{
- static char buffer[32];
-
- char const *p = "";
- Libc::with_libc([&] {
- struct timespec ts;
- if (clock_gettime(0, &ts)) { return; }
-
- struct tm *tm = localtime((time_t*)&ts.tv_sec);
- if (!tm) { return; }
-
- size_t const n = strftime(buffer, sizeof(buffer), "%F %H:%M:%S", tm);
- if (n > 0 && n < sizeof(buffer)) { p = buffer; }
- }); /* Libc::with_libc */
-
- return p;
-}
diff --git a/repos/gems/src/server/ssh_terminal/util.h b/repos/gems/src/server/ssh_terminal/util.h
deleted file mode 100644
index 84be040f34..0000000000
--- a/repos/gems/src/server/ssh_terminal/util.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * \brief Component providing a Terminal session via SSH
- * \author Josef Soentgen
- * \author Pirmin Duss
- * \date 2019-05-29
- */
-
-/*
- * Copyright (C) 2018 Genode Labs GmbH
- * Copyright (C) 2019 gapfruit AG
- *
- * This file is part of the Genode OS framework, which is distributed
- * under the terms of the GNU Affero General Public License version 3.
- */
-
-#ifndef _SSH_TERMINAL_UTIL_H_
-#define _SSH_TERMINAL_UTIL_H_
-
-/* Genode includes */
-#include
-#include
-
-/* libc includes */
-#include
-#include
-#include
-
-
-namespace Util
-{
- using Filename = Genode::String<256>;
-
- template
- struct Buffer;
-
- /*
- * get the current time from the libc backend.
- */
- char const *get_time();
-
- struct Pthread_mutex;
-}
-
-
-struct Util::Pthread_mutex
-{
- public:
-
- class Guard
- {
- private:
-
- Pthread_mutex &_mutex;
-
- public:
-
- explicit Guard(Pthread_mutex &mutex) : _mutex(mutex) { _mutex.lock(); }
-
- ~Guard() { _mutex.unlock(); }
- };
-
- private:
-
- pthread_mutex_t _mutex;
-
- public:
-
- Pthread_mutex() { pthread_mutex_init(&_mutex, nullptr); }
-
- ~Pthread_mutex() { pthread_mutex_destroy(&_mutex); }
-
- void lock() { pthread_mutex_lock(&_mutex); }
- void unlock() { pthread_mutex_unlock(&_mutex); }
-};
-
-
-template
-struct Util::Buffer
-{
- Util::Pthread_mutex _mutex { };
- char _data[C] { };
- size_t _head { 0 };
- size_t _tail { 0 };
-
- size_t read_avail() const { return _head > _tail ? _head - _tail : 0; }
- size_t write_avail() const { return _head <= C ? C - _head : 0; }
- char const *content() const { return &_data[_tail]; }
-
- void append(char c) { _data[_head++] = c; }
- void consume(size_t n) { _tail += n; }
- void reset() { _head = _tail = 0; }
-
- Util::Pthread_mutex &mutex() { return _mutex; }
-};
-
-#endif /* _SSH_TERMINAL_UTIL_H_ */