From 10bc34245e8e1e3ba63fb0720d3bcfb1119db921 Mon Sep 17 00:00:00 2001 From: Simponic Date: Tue, 27 Dec 2022 23:50:22 -0700 Subject: Initial erlang stuff --- lib/chessh/application.ex | 2 +- lib/chessh/auth/password.ex | 3 +-- lib/chessh/schema/key.ex | 3 +-- lib/chessh/ssh/daemon.ex | 60 ++++++++++++++++++++++++++++++++++++++++++++ lib/chessh/ssh/server.ex | 0 lib/chessh/ssh/server_key.ex | 11 ++++++++ 6 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 lib/chessh/ssh/daemon.ex delete mode 100644 lib/chessh/ssh/server.ex create mode 100644 lib/chessh/ssh/server_key.ex (limited to 'lib') diff --git a/lib/chessh/application.ex b/lib/chessh/application.ex index c760532..847dd98 100644 --- a/lib/chessh/application.ex +++ b/lib/chessh/application.ex @@ -2,7 +2,7 @@ defmodule Chessh.Application do use Application def start(_, _) do - children = [Chessh.Repo] + children = [Chessh.Repo, Chessh.SSH.Daemon] opts = [strategy: :one_for_one, name: Chessh.Supervisor] Supervisor.start_link(children, opts) end diff --git a/lib/chessh/auth/password.ex b/lib/chessh/auth/password.ex index 8a6c683..c3b03f5 100644 --- a/lib/chessh/auth/password.ex +++ b/lib/chessh/auth/password.ex @@ -1,6 +1,5 @@ defmodule Chessh.Auth.PasswordAuthenticator do - alias Chessh.Player - alias Chessh.Repo + alias Chessh.{Player, Repo} def authenticate(username, password) do case Repo.get_by(Player, username: String.Chars.to_string(username)) do diff --git a/lib/chessh/schema/key.ex b/lib/chessh/schema/key.ex index 765c83b..adf018d 100644 --- a/lib/chessh/schema/key.ex +++ b/lib/chessh/schema/key.ex @@ -16,7 +16,7 @@ defmodule Chessh.Key do |> cast(update_encode_key(attrs, :key), [:key]) |> cast(attrs, [:name]) |> validate_required([:key, :name]) - |> validate_format(:key, ~r/[\-\w\d]+ [^ ]+$/, message: "invalid ssh key") + |> validate_format(:key, ~r/[\-\w\d]+ [^ ]+$/, message: "invalid public ssh key") |> validate_format(:key, ~r/^(?!ssh-dss).+/, message: "DSA keys are not supported") end @@ -41,7 +41,6 @@ defmodule Chessh.Key do end # Remove comment at end of key |> String.replace(~r/ [^ ]+\@[^ ]+$/, "") - # Remove potential spaces / newline |> String.trim() end end diff --git a/lib/chessh/ssh/daemon.ex b/lib/chessh/ssh/daemon.ex new file mode 100644 index 0000000..acb6bea --- /dev/null +++ b/lib/chessh/ssh/daemon.ex @@ -0,0 +1,60 @@ +defmodule Chessh.SSH.Daemon do + 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, _address, attempts) do + if Chessh.Auth.PasswordAuthenticator.authenticate(username, password) do + true + else + newAttempts = + case attempts do + :undefined -> 0 + _ -> attempts + end + + if Application.fetch_env!(:chessh, :max_password_attempts) <= newAttempts do + :disconnect + else + {false, newAttempts + 1} + end + end + end + + 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, + 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 diff --git a/lib/chessh/ssh/server_key.ex b/lib/chessh/ssh/server_key.ex new file mode 100644 index 0000000..1096e09 --- /dev/null +++ b/lib/chessh/ssh/server_key.ex @@ -0,0 +1,11 @@ +defmodule Chessh.SSH.ServerKey do + @behaviour :ssh_server_key_api + + def is_auth_key(key, username, _daemon_options) do + Chessh.Auth.KeyAuthenticator.authenticate(username, key) + end + + def host_key(algorithm, daemon_options) do + :ssh_file.host_key(algorithm, daemon_options) + end +end -- cgit v1.2.3-70-g09d2