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