ee008dd3e6ac3ec14ff3aa8214cb69f04762be5c
[mirror/dsa-puppet.git] / 3rdparty / modules / stdlib / lib / puppet / parser / functions / pw_hash.rb
1 #  Please note: This function is an implementation of a Ruby class and as such may not be entirely UTF8 compatible.
2 #  To ensure compatibility please use this function with Ruby 2.4.0 or greater - https://bugs.ruby-lang.org/issues/10085.
3 #
4 Puppet::Parser::Functions.newfunction(
5   :pw_hash,
6   :type => :rvalue,
7   :arity => 3,
8   :doc => <<-DOC
9   @summary
10     Hashes a password using the crypt function. Provides a hash usable
11     on most POSIX systems.
12
13   The first argument to this function is the password to hash. If it is
14   undef or an empty string, this function returns undef.
15
16   The second argument to this function is which type of hash to use. It
17   will be converted into the appropriate crypt(3) hash specifier. Valid
18   hash types are:
19
20   |Hash type            |Specifier|
21   |---------------------|---------|
22   |MD5                  |1        |
23   |SHA-256              |5        |
24   |SHA-512 (recommended)|6        |
25
26   The third argument to this function is the salt to use.
27
28   @return [Hash]
29     Provides a hash usable on most POSIX systems.
30
31   > *Note:*: this uses the Puppet Master's implementation of crypt(3). If your
32     environment contains several different operating systems, ensure that they
33     are compatible before using this function.
34   DOC
35 ) do |args|
36   raise ArgumentError, "pw_hash(): wrong number of arguments (#{args.size} for 3)" if args.size != 3
37   args.map! do |arg|
38     if (defined? Puppet::Pops::Types::PSensitiveType::Sensitive) && (arg.is_a? Puppet::Pops::Types::PSensitiveType::Sensitive)
39       arg.unwrap
40     else
41       arg
42     end
43   end
44   raise ArgumentError, 'pw_hash(): first argument must be a string' unless args[0].is_a?(String) || args[0].nil?
45   raise ArgumentError, 'pw_hash(): second argument must be a string' unless args[1].is_a? String
46   hashes = { 'md5'     => '1',
47              'sha-256' => '5',
48              'sha-512' => '6' }
49   hash_type = hashes[args[1].downcase]
50   raise ArgumentError, "pw_hash(): #{args[1]} is not a valid hash type" if hash_type.nil?
51   raise ArgumentError, 'pw_hash(): third argument must be a string' unless args[2].is_a? String
52   raise ArgumentError, 'pw_hash(): third argument must not be empty' if args[2].empty?
53   raise ArgumentError, 'pw_hash(): characters in salt must be in the set [a-zA-Z0-9./]' unless args[2] =~ %r{\A[a-zA-Z0-9./]+\z}
54
55   password = args[0]
56   return nil if password.nil? || password.empty?
57
58   salt = "$#{hash_type}$#{args[2]}"
59
60   # handle weak implementations of String#crypt
61   if 'test'.crypt('$1$1') != '$1$1$Bp8CU9Oujr9SSEw53WV6G.'
62     # JRuby < 1.7.17
63     # MS Windows and other systems that don't support enhanced salts
64     raise Puppet::ParseError, 'system does not support enhanced salts' unless RUBY_PLATFORM == 'java'
65     # puppetserver bundles Apache Commons Codec
66     org.apache.commons.codec.digest.Crypt.crypt(password.to_java_bytes, salt)
67   else
68     password.crypt(salt)
69   end
70 end