File: known-hosts.rb

package info (click to toggle)
libnet-ssh-ruby 1.1.2-1
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 3,472 kB
  • ctags: 2,465
  • sloc: ruby: 10,848; makefile: 17
file content (96 lines) | stat: -rw-r--r-- 2,308 bytes parent folder | download | duplicates (2)
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
require 'strscan'
require 'net/ssh/transport/ossl/buffer'
require 'net/ssh/util/openssl'

module Net; module SSH
  class KnownHosts
    class <<self
      def canonize(location, port)
        value = location
        value = "[#{value}]:#{port}" if port && port != 22
        value
      end

      def search_for(host)
        search_in(hostfile_locations, host)
      end

      def add(host, key)
        hostfile_locations.each do |file|
          begin
            KnownHosts.new(file).add(host, key)
            return
          rescue SystemCallError
            # try the next hostfile
          end
        end
      end

      def search_in(files, host)
        files.map { |file| KnownHosts.new(file).keys_for(host) }.flatten
      end

      def hostfile_locations
        @hostfile_locations ||= [
          "#{home_directory}/.ssh/known_hosts",
          "#{home_directory}/.ssh/known_hosts2",
          "/etc/ssh/ssh_known_hosts",
          "/etc/ssh/ssh_known_hosts2"
        ]
      end

      def home_directory
        ENV['HOME'] ||
          (ENV['HOMEPATH'] && "#{ENV['HOMEDRIVE']}#{ENV['HOMEPATH']}") ||
          "/"
      end
    end


    attr_reader :source

    def initialize(source)
      @source = source
    end

    def keys_for(host)
      keys = []
      hosts = Array(host)

      File.open(source) do |file|
        scanner = StringScanner.new("")
        file.each_line do |line|
          scanner.string = line

          scanner.skip(/\s*/)
          next if scanner.match?(/$|#/)

          hostlist = scanner.scan(/\S+/)
          next if (hostlist.split(/,/) & hosts).empty?

          scanner.skip(/\s*/)
          type = scanner.scan(/\S+/)
          scanner.skip(/\s*/)
          blob = scanner.rest.unpack("m*").first
          keys << Net::SSH::Transport::OSSL::Buffer.new(blob).read_key
        end
      end

      keys
    rescue SystemCallError
      return []
    end

    def add(host, key)
      dir = File.dirname(source)
      Dir.mkdir(dir, 0700) if !File.exists?(dir)

      File.open(source, "a") do |file|
        buffer = Net::SSH::Transport::OSSL::Buffer.new
        buffer.write_key(key)
        blob = [buffer.to_s].pack("m*").gsub(/\s/, "")
        file.puts "#{Array(host).join(',')} #{key.ssh_type} #{blob}"
      end
    end
  end
end; end