diff options
author | Logan Hunt <loganhunt@simponic.xyz> | 2022-12-29 18:37:51 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-12-29 18:37:51 -0700 |
commit | c143bb549c53f2737c41cdfce6cc2598c5489bdc (patch) | |
tree | 33853e2a9c30ff7c670aa4ff5b73df005d6e6fec /lib/chessh/ssh | |
parent | f7c2ccbe26dc808e4a7eae9a378e6c382220961a (diff) | |
parent | 479ca815e3a1760c71e8977674434b15f94ae833 (diff) | |
download | chessh-c143bb549c53f2737c41cdfce6cc2598c5489bdc.tar.gz chessh-c143bb549c53f2737c41cdfce6cc2598c5489bdc.zip |
Merge pull request #1 from Simponic/erlang_ssh_server
Diffstat (limited to 'lib/chessh/ssh')
-rw-r--r-- | lib/chessh/ssh/daemon.ex | 77 | ||||
-rw-r--r-- | lib/chessh/ssh/server.ex | 0 | ||||
-rw-r--r-- | lib/chessh/ssh/server_key.ex | 12 |
3 files changed, 89 insertions, 0 deletions
diff --git a/lib/chessh/ssh/daemon.ex b/lib/chessh/ssh/daemon.ex new file mode 100644 index 0000000..9f17f75 --- /dev/null +++ b/lib/chessh/ssh/daemon.ex @@ -0,0 +1,77 @@ +defmodule Chessh.SSH.Daemon do + alias Chessh.Auth.PasswordAuthenticator + use GenServer + + def start_link(_) do + GenServer.start_link(__MODULE__, %{ + pid: nil + }) + end + + def init(state) do + GenServer.cast(self(), :start) + {:ok, state} + end + + def pwd_authenticate(username, password) do + # TODO - check concurrent sessions + PasswordAuthenticator.authenticate( + String.Chars.to_string(username), + String.Chars.to_string(password) + ) + end + + def pwd_authenticate(username, password, inet) do + [jail_timeout_ms, jail_attempt_threshold] = + Application.get_env(:chessh, RateLimits) + |> Keyword.take([:jail_timeout_ms, :jail_attempt_threshold]) + |> Keyword.values() + + {ip, _port} = inet + rateId = "failed_password_attempts:#{Enum.join(Tuple.to_list(ip), ".")}" + + if pwd_authenticate(username, password) do + true + else + case Hammer.check_rate_inc(rateId, jail_timeout_ms, jail_attempt_threshold, 1) do + {:allow, _count} -> + false + + {:deny, _limit} -> + :disconnect + end + end + end + + def pwd_authenticate(username, password, inet, _address), + do: pwd_authenticate(username, password, inet) + + def handle_cast(:start, state) do + port = Application.fetch_env!(:chessh, :port) + key_dir = String.to_charlist(Application.fetch_env!(:chessh, :key_dir)) + max_sessions = Application.fetch_env!(:chessh, :max_sessions) + + case :ssh.daemon( + port, + system_dir: key_dir, + pwdfun: &pwd_authenticate/4, + key_cb: Chessh.SSH.ServerKey, + # disconnectfun: + id_string: :random, + subsystems: [], + parallel_login: true, + max_sessions: max_sessions + ) do + {:ok, pid} -> + Process.link(pid) + {:noreply, %{state | pid: pid}, :hibernate} + + {:error, err} -> + raise inspect(err) + end + + {:noreply, state} + end + + def handle_info(_, state), do: {:noreply, state} +end diff --git a/lib/chessh/ssh/server.ex b/lib/chessh/ssh/server.ex deleted file mode 100644 index e69de29..0000000 --- a/lib/chessh/ssh/server.ex +++ /dev/null diff --git a/lib/chessh/ssh/server_key.ex b/lib/chessh/ssh/server_key.ex new file mode 100644 index 0000000..72a4fbb --- /dev/null +++ b/lib/chessh/ssh/server_key.ex @@ -0,0 +1,12 @@ +defmodule Chessh.SSH.ServerKey do + alias Chessh.Auth.KeyAuthenticator + @behaviour :ssh_server_key_api + + def is_auth_key(key, username, _daemon_options) do + KeyAuthenticator.authenticate(username, key) + end + + def host_key(algorithm, daemon_options) do + :ssh_file.host_key(algorithm, daemon_options) + end +end |