summaryrefslogtreecommitdiffstats
path: root/lib/puppet/provider/ssh_authorized_key/parsed.rb
blob: a9738e761f605f2ba0cc4d57a661d233938f6726 (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
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
require 'puppet/provider/parsedfile'


            Puppet::Type.type(:ssh_authorized_key).provide(
                :parsed,
    :parent => Puppet::Provider::ParsedFile,
    :filetype => :flat,
        
    :default_target => ''
) do
    desc "Parse and generate authorized_keys files for SSH."

    text_line :comment, :match => /^#/
    text_line :blank, :match => /^\s+/

    record_line :parsed,
        :fields   => %w{options type key name},
        :optional => %w{options},
        :rts => /^\s+/,
        :match    => /^(?:(.+) )?(ssh-dss|ssh-rsa) ([^ ]+) ?(.*)$/,
        :post_parse => proc { |h|
            h[:name] = "" if h[:name] == :absent
            h[:options] ||= [:absent]
            h[:options] = Puppet::Type::Ssh_authorized_key::ProviderParsed.parse_options(h[:options]) if h[:options].is_a? String
        },
        :pre_gen => proc { |h|
            h[:options] = [] if h[:options].include?(:absent)
            h[:options] = h[:options].join(',')
        }

    record_line :key_v1,
        :fields   => %w{options bits exponent modulus name},
        :optional => %w{options},
        :rts      => /^\s+/,
        :match    => /^(?:(.+) )?(\d+) (\d+) (\d+)(?: (.+))?$/

    def dir_perm
        0700
    end

    def file_perm
        0600
    end

    def target
            @resource.should(:target) || File.expand_path("~#{@resource.should(:user)}/.ssh/authorized_keys")
    rescue
            raise Puppet::Error, "Target not defined and/or specified user does not exist yet"
    end

    def user
        uid = File.stat(target).uid
        Etc.getpwuid(uid).name
    end

    def flush
        raise Puppet::Error, "Cannot write SSH authorized keys without user"    unless @resource.should(:user)
        raise Puppet::Error, "User '#{@resource.should(:user)}' does not exist" unless uid = Puppet::Util.uid(@resource.should(:user))
        unless File.exist?(dir = File.dirname(target))
            Puppet.debug "Creating #{dir}"
            Dir.mkdir(dir, dir_perm)
            File.chown(uid, nil, dir)
        end
        Puppet::Util::SUIDManager.asuser(@resource.should(:user)) { super }
        File.chown(uid, nil, target)
        File.chmod(file_perm, target)
    end

    # parse sshv2 option strings, wich is a comma separated list of
    # either key="values" elements or bare-word elements
    def self.parse_options(options)
        result = []
        scanner = StringScanner.new(options)
        while !scanner.eos?
            scanner.skip(/[ \t]*/)
            # scan a long option
            if out = scanner.scan(/[-a-z0-9A-Z_]+=\".*?\"/) or out = scanner.scan(/[-a-z0-9A-Z_]+/)
                result << out
            else
                # found an unscannable token, let's abort
                break
            end
            # eat a comma
            scanner.skip(/[ \t]*,[ \t]*/)
        end
        result
    end
end