summaryrefslogtreecommitdiff
path: root/lib/chessh/ssh/daemon.ex
blob: acb6bea05503a69d8fda81f4e2f514f1ae493b23 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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