chef 13.3.42-universal-mingw32 → 13.4.19-universal-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/VERSION +1 -1
- data/lib/.DS_Store +0 -0
- data/lib/chef/.DS_Store +0 -0
- data/lib/chef/knife/core/ui.rb +1 -1
- data/lib/chef/mash.rb +6 -0
- data/lib/chef/mixin/deep_merge.rb +1 -1
- data/lib/chef/mixin/user_context.rb +52 -0
- data/lib/chef/node/attribute.rb +80 -14
- data/lib/chef/node/immutable_collections.rb +16 -19
- data/lib/chef/provider/apt_repository.rb +12 -10
- data/lib/chef/provider/git.rb +20 -3
- data/lib/chef/provider/ifconfig/redhat.rb +4 -0
- data/lib/chef/provider/launchd.rb +20 -0
- data/lib/chef/provider/package/dnf.rb +3 -1
- data/lib/chef/provider/remote_file.rb +19 -0
- data/lib/chef/provider/remote_file/fetcher.rb +3 -0
- data/lib/chef/provider/remote_file/network_file.rb +18 -5
- data/lib/chef/provider/service/macosx.rb +4 -3
- data/lib/chef/provider/windows_path.rb +62 -0
- data/lib/chef/provider/zypper_repository.rb +1 -1
- data/lib/chef/providers.rb +1 -0
- data/lib/chef/resource.rb +5 -1
- data/lib/chef/resource/apt_repository.rb +1 -1
- data/lib/chef/resource/ifconfig.rb +36 -0
- data/lib/chef/resource/remote_file.rb +60 -0
- data/lib/chef/resource/windows_path.rb +41 -0
- data/lib/chef/resource/zypper_repository.rb +1 -0
- data/lib/chef/resources.rb +1 -0
- data/lib/chef/shell.rb +1 -0
- data/lib/chef/shell/shell_session.rb +4 -4
- data/lib/chef/util/windows/logon_session.rb +126 -0
- data/lib/chef/version.rb +4 -3
- data/lib/chef/win32/api/security.rb +2 -0
- data/spec/.DS_Store +0 -0
- data/spec/data/nodes/Timothys-MacBook-Pro.local.json +3 -0
- data/spec/functional/.DS_Store +0 -0
- data/spec/functional/mixin/user_context_spec.rb +117 -0
- data/spec/functional/resource/remote_file_spec.rb +171 -0
- data/spec/functional/resource/windows_path_spec.rb +64 -0
- data/spec/support/.DS_Store +0 -0
- data/spec/unit/.DS_Store +0 -0
- data/spec/unit/knife/client_delete_spec.rb +1 -1
- data/spec/unit/mixin/user_context_spec.rb +109 -0
- data/spec/unit/node/immutable_collections_spec.rb +12 -4
- data/spec/unit/node_spec.rb +7 -0
- data/spec/unit/provider/git_spec.rb +55 -0
- data/spec/unit/provider/ifconfig/redhat_spec.rb +8 -0
- data/spec/unit/provider/remote_file/fetcher_spec.rb +1 -0
- data/spec/unit/provider/remote_file/network_file_spec.rb +7 -2
- data/spec/unit/provider/service/macosx_spec.rb +4 -1
- data/spec/unit/provider/windows_path_spec.rb +65 -0
- data/spec/unit/resource/windows_path_spec.rb +38 -0
- data/spec/unit/resource_spec.rb +8 -0
- data/spec/unit/shell/shell_session_spec.rb +82 -58
- data/spec/unit/util/windows/logon_session_spec.rb +284 -0
- data/tasks/maintainers.rb +3 -3
- metadata +22 -5
@@ -35,10 +35,12 @@ class Chef
|
|
35
35
|
use_multipackage_api
|
36
36
|
use_package_name_for_source
|
37
37
|
|
38
|
-
provides :package, platform_family: %w{
|
38
|
+
provides :package, platform_family: %w{fedora amazon} do
|
39
39
|
which("dnf") && shell_out("rpm -q dnf").stdout =~ /^dnf-[1-9]/
|
40
40
|
end
|
41
41
|
|
42
|
+
provides :package, platform_family: %w{rhel}, platform_version: ">= 8"
|
43
|
+
|
42
44
|
provides :dnf_package, os: "linux"
|
43
45
|
|
44
46
|
#
|
@@ -29,6 +29,25 @@ class Chef
|
|
29
29
|
super
|
30
30
|
end
|
31
31
|
|
32
|
+
def define_resource_requirements
|
33
|
+
[ new_resource.remote_user, new_resource.remote_domain,
|
34
|
+
new_resource.remote_password ].each do |prop|
|
35
|
+
requirements.assert(:all_actions) do |a|
|
36
|
+
a.assertion do
|
37
|
+
if prop
|
38
|
+
node[:platform_family] == "windows"
|
39
|
+
else
|
40
|
+
true
|
41
|
+
end
|
42
|
+
end
|
43
|
+
a.failure_message Chef::Exceptions::UnsupportedPlatform, "'remote_user', 'remote_domain' and 'remote_password' properties are supported only for Windows platform"
|
44
|
+
a.whyrun("Assuming that the platform is Windows while passing 'remote_user', 'remote_domain' and 'remote_password' properties")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
super
|
49
|
+
end
|
50
|
+
|
32
51
|
def load_current_resource
|
33
52
|
@current_resource = Chef::Resource::RemoteFile.new(new_resource.name)
|
34
53
|
super
|
@@ -24,6 +24,9 @@ class Chef
|
|
24
24
|
|
25
25
|
def self.for_resource(uri, new_resource, current_resource)
|
26
26
|
if network_share?(uri)
|
27
|
+
if !Chef::Platform.windows?
|
28
|
+
raise Exceptions::UnsupportedPlatform, "Fetching the file on a network share is supported only on the Windows platform. Please change your source: #{uri}"
|
29
|
+
end
|
27
30
|
Chef::Provider::RemoteFile::NetworkFile.new(uri, new_resource, current_resource)
|
28
31
|
else
|
29
32
|
case uri.scheme
|
@@ -19,14 +19,18 @@
|
|
19
19
|
require "uri"
|
20
20
|
require "tempfile"
|
21
21
|
require "chef/provider/remote_file"
|
22
|
+
require "chef/mixin/user_context"
|
22
23
|
|
23
24
|
class Chef
|
24
25
|
class Provider
|
25
26
|
class RemoteFile
|
26
27
|
class NetworkFile
|
28
|
+
include Chef::Mixin::UserContext
|
27
29
|
|
28
30
|
attr_reader :new_resource
|
29
31
|
|
32
|
+
TRANSFER_CHUNK_SIZE = 1048576
|
33
|
+
|
30
34
|
def initialize(source, new_resource, current_resource)
|
31
35
|
@new_resource = new_resource
|
32
36
|
@source = source
|
@@ -35,13 +39,22 @@ class Chef
|
|
35
39
|
# Fetches the file on a network share, returning a Tempfile-like File handle
|
36
40
|
# windows only
|
37
41
|
def fetch
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
+
begin
|
43
|
+
tempfile = Chef::FileContentManagement::Tempfile.new(new_resource).tempfile
|
44
|
+
Chef::Log.debug("#{new_resource} staging #{@source} to #{tempfile.path}")
|
45
|
+
|
46
|
+
with_user_context(new_resource.remote_user, new_resource.remote_password, new_resource.remote_domain) do
|
47
|
+
::File.open(@source, "rb") do |remote_file|
|
48
|
+
while data = remote_file.read(TRANSFER_CHUNK_SIZE)
|
49
|
+
tempfile.write(data)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
ensure
|
54
|
+
tempfile.close if tempfile
|
55
|
+
end
|
42
56
|
tempfile
|
43
57
|
end
|
44
|
-
|
45
58
|
end
|
46
59
|
end
|
47
60
|
end
|
@@ -52,17 +52,18 @@ class Chef
|
|
52
52
|
@plist_size = 0
|
53
53
|
@plist = @new_resource.plist ? @new_resource.plist : find_service_plist
|
54
54
|
@service_label = find_service_label
|
55
|
-
#
|
55
|
+
# LaunchAgents should be loaded as the console user.
|
56
56
|
@console_user = @plist ? @plist.include?("LaunchAgents") : false
|
57
57
|
@session_type = @new_resource.session_type
|
58
58
|
|
59
59
|
if @console_user
|
60
|
-
@console_user = Etc.
|
60
|
+
@console_user = Etc.getpwuid(::File.stat("/dev/console").uid).name
|
61
61
|
Chef::Log.debug("#{new_resource} console_user: '#{@console_user}'")
|
62
62
|
cmd = "su "
|
63
63
|
param = this_version_or_newer?("10.10") ? "" : "-l "
|
64
|
+
param = "-l " if this_version_or_newer?("10.12")
|
64
65
|
@base_user_cmd = cmd + param + "#{@console_user} -c"
|
65
|
-
# Default
|
66
|
+
# Default LaunchAgent session should be Aqua
|
66
67
|
@session_type = "Aqua" if @session_type.nil?
|
67
68
|
end
|
68
69
|
|
@@ -0,0 +1,62 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Nimisha Sharad (<nimisha.sharad@msystechnologies.com>)
|
3
|
+
# Copyright:: Copyright 2008-2017, Chef Software Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require "chef/mixin/windows_env_helper" if Chef::Platform.windows?
|
20
|
+
require "chef/mixin/wide_string"
|
21
|
+
require "chef/exceptions"
|
22
|
+
|
23
|
+
class Chef
|
24
|
+
class Provider
|
25
|
+
class WindowsPath < Chef::Provider
|
26
|
+
|
27
|
+
include Chef::Mixin::WindowsEnvHelper if Chef::Platform.windows?
|
28
|
+
|
29
|
+
def load_current_resource
|
30
|
+
@current_resource = Chef::Resource::WindowsPath.new(new_resource.name)
|
31
|
+
@current_resource.path(new_resource.path)
|
32
|
+
@current_resource
|
33
|
+
end
|
34
|
+
|
35
|
+
action :add do
|
36
|
+
# The windows Env provider does not correctly expand variables in
|
37
|
+
# the PATH environment variable. Ruby expects these to be expanded.
|
38
|
+
#
|
39
|
+
path = expand_path(new_resource.path)
|
40
|
+
converge_by "Adding #{new_resource.path} to path environment variable" do
|
41
|
+
declare_resource(:env, "path") do
|
42
|
+
action :modify
|
43
|
+
delim ::File::PATH_SEPARATOR
|
44
|
+
value path.tr("/", '\\')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
action :remove do
|
50
|
+
# The windows Env provider does not correctly expand variables in
|
51
|
+
# the PATH environment variable. Ruby expects these to be expanded.
|
52
|
+
#
|
53
|
+
path = expand_path(new_resource.path)
|
54
|
+
declare_resource(:env, "path") do
|
55
|
+
action :delete
|
56
|
+
delim ::File::PATH_SEPARATOR
|
57
|
+
value path.tr("/", '\\')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -57,7 +57,7 @@ class Chef
|
|
57
57
|
end
|
58
58
|
|
59
59
|
action :refresh do
|
60
|
-
declare_resource(:execute, "zypper refresh #{escaped_repo_name}") do
|
60
|
+
declare_resource(:execute, "zypper#{' --gpg-auto-import-keys' if new_resource.gpgautoimportkeys} refresh #{escaped_repo_name}") do
|
61
61
|
only_if "zypper lr #{escaped_repo_name}"
|
62
62
|
end
|
63
63
|
end
|
data/lib/chef/providers.rb
CHANGED
data/lib/chef/resource.rb
CHANGED
@@ -641,7 +641,11 @@ class Chef
|
|
641
641
|
|
642
642
|
all_props = {}
|
643
643
|
self.class.state_properties.map do |p|
|
644
|
-
|
644
|
+
begin
|
645
|
+
all_props[p.name.to_s] = p.sensitive? ? '"*sensitive value suppressed*"' : value_to_text(p.get(self))
|
646
|
+
rescue Chef::Exceptions::ValidationFailed
|
647
|
+
# This space left intentionally blank, the property was probably required or had an invalid default.
|
648
|
+
end
|
645
649
|
end
|
646
650
|
|
647
651
|
ivars = instance_variables.map { |ivar| ivar.to_sym } - HIDDEN_IVARS
|
@@ -33,7 +33,7 @@ class Chef
|
|
33
33
|
# whether or not to add the repository as a source repo, too
|
34
34
|
property :deb_src, [TrueClass, FalseClass], default: false
|
35
35
|
property :keyserver, [String, nil, false], default: "keyserver.ubuntu.com", nillable: true, coerce: proc { |x| x ? x : nil }
|
36
|
-
property :key, [String, nil, false], default:
|
36
|
+
property :key, [String, Array, nil, false], default: [], coerce: proc { |x| x ? Array(x) : nil }
|
37
37
|
property :key_proxy, [String, nil, false], default: nil, nillable: true, coerce: proc { |x| x ? x : nil }
|
38
38
|
|
39
39
|
property :cookbook, [String, nil, false], default: nil, desired_state: false, nillable: true, coerce: proc { |x| x ? x : nil }
|
@@ -44,6 +44,10 @@ class Chef
|
|
44
44
|
@network = nil
|
45
45
|
@bootproto = nil
|
46
46
|
@onparent = nil
|
47
|
+
@ethtool_opts = nil
|
48
|
+
@bonding_opts = nil
|
49
|
+
@master = nil
|
50
|
+
@slave = nil
|
47
51
|
end
|
48
52
|
|
49
53
|
def target(arg = nil)
|
@@ -141,6 +145,38 @@ class Chef
|
|
141
145
|
:kind_of => String
|
142
146
|
)
|
143
147
|
end
|
148
|
+
|
149
|
+
def ethtool_opts(arg = nil)
|
150
|
+
set_or_return(
|
151
|
+
:ethtool_opts,
|
152
|
+
arg,
|
153
|
+
:kind_of => String
|
154
|
+
)
|
155
|
+
end
|
156
|
+
|
157
|
+
def bonding_opts(arg = nil)
|
158
|
+
set_or_return(
|
159
|
+
:bonding_opts,
|
160
|
+
arg,
|
161
|
+
:kind_of => String
|
162
|
+
)
|
163
|
+
end
|
164
|
+
|
165
|
+
def master(arg = nil)
|
166
|
+
set_or_return(
|
167
|
+
:master,
|
168
|
+
arg,
|
169
|
+
:kind_of => String
|
170
|
+
)
|
171
|
+
end
|
172
|
+
|
173
|
+
def slave(arg = nil)
|
174
|
+
set_or_return(
|
175
|
+
:slave,
|
176
|
+
arg,
|
177
|
+
:kind_of => String
|
178
|
+
)
|
179
|
+
end
|
144
180
|
end
|
145
181
|
|
146
182
|
end
|
@@ -131,6 +131,66 @@ class Chef
|
|
131
131
|
)
|
132
132
|
end
|
133
133
|
|
134
|
+
property :remote_user, String
|
135
|
+
|
136
|
+
property :remote_domain, String
|
137
|
+
|
138
|
+
property :remote_password, String, sensitive: true
|
139
|
+
|
140
|
+
def after_created
|
141
|
+
validate_identity_platform(remote_user, remote_password, remote_domain)
|
142
|
+
identity = qualify_user(remote_user, remote_password, remote_domain)
|
143
|
+
remote_domain(identity[:domain])
|
144
|
+
remote_user(identity[:user])
|
145
|
+
end
|
146
|
+
|
147
|
+
def validate_identity_platform(specified_user, password = nil, specified_domain = nil)
|
148
|
+
if node[:platform_family] == "windows"
|
149
|
+
if specified_user && password.nil?
|
150
|
+
raise ArgumentError, "A value for `remote_password` must be specified when a value for `user` is specified on the Windows platform"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def qualify_user(specified_user, password = nil, specified_domain = nil)
|
156
|
+
domain = specified_domain
|
157
|
+
user = specified_user
|
158
|
+
|
159
|
+
if specified_user.nil? && ! specified_domain.nil?
|
160
|
+
raise ArgumentError, "The domain `#{specified_domain}` was specified, but no user name was given"
|
161
|
+
end
|
162
|
+
|
163
|
+
# if domain is provided in both username and domain
|
164
|
+
if specified_user && ((specified_user.include? '\\') || (specified_user.include? "@")) && specified_domain
|
165
|
+
raise ArgumentError, "The domain is provided twice. Username: `#{specified_user}`, Domain: `#{specified_domain}`. Please specify domain only once."
|
166
|
+
end
|
167
|
+
|
168
|
+
if ! specified_user.nil? && specified_domain.nil?
|
169
|
+
# Splitting username of format: Domain\Username
|
170
|
+
domain_and_user = user.split('\\')
|
171
|
+
|
172
|
+
if domain_and_user.length == 2
|
173
|
+
domain = domain_and_user[0]
|
174
|
+
user = domain_and_user[1]
|
175
|
+
elsif domain_and_user.length == 1
|
176
|
+
# Splitting username of format: Username@Domain
|
177
|
+
domain_and_user = user.split("@")
|
178
|
+
if domain_and_user.length == 2
|
179
|
+
domain = domain_and_user[1]
|
180
|
+
user = domain_and_user[0]
|
181
|
+
elsif domain_and_user.length != 1
|
182
|
+
raise ArgumentError, "The specified user name `#{user}` is not a syntactically valid user name"
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
if ( password || domain ) && user.nil?
|
188
|
+
raise ArgumentError, "A value for `password` or `domain` was specified without specification of a value for `user`"
|
189
|
+
end
|
190
|
+
|
191
|
+
{ domain: domain, user: user }
|
192
|
+
end
|
193
|
+
|
134
194
|
private
|
135
195
|
|
136
196
|
include Chef::Mixin::Uris
|
@@ -0,0 +1,41 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Nimisha Sharad (<nimisha.sharad@msystechnologies.com>)
|
3
|
+
# Copyright:: Copyright 2008-2017, Chef Software Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require "chef/resource"
|
20
|
+
|
21
|
+
class Chef
|
22
|
+
class Resource
|
23
|
+
class WindowsPath < Chef::Resource
|
24
|
+
|
25
|
+
provides :windows_path, os: "windows"
|
26
|
+
|
27
|
+
allowed_actions :add, :remove
|
28
|
+
default_action :add
|
29
|
+
|
30
|
+
def initialize(name, run_context = nil)
|
31
|
+
super
|
32
|
+
@resource_name = :windows_path
|
33
|
+
@path = name
|
34
|
+
@provider = Chef::Provider::WindowsPath
|
35
|
+
@action = :add
|
36
|
+
end
|
37
|
+
|
38
|
+
property :path, String, name_property: true
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -39,6 +39,7 @@ class Chef
|
|
39
39
|
property :mode, default: "0644"
|
40
40
|
property :refresh_cache, [true, false], default: true
|
41
41
|
property :source, String, regex: /.*/
|
42
|
+
property :gpgautoimportkeys, [true, false], default: true
|
42
43
|
|
43
44
|
default_action :create
|
44
45
|
allowed_actions :create, :remove, :add, :refresh
|
data/lib/chef/resources.rb
CHANGED
data/lib/chef/shell.rb
CHANGED
@@ -138,6 +138,7 @@ module Shell
|
|
138
138
|
def self.session
|
139
139
|
unless client_type.instance.node_built?
|
140
140
|
puts "Session type: #{client_type.session_type}"
|
141
|
+
client_type.instance.json_configuration = @json_attribs
|
141
142
|
client_type.instance.reset!
|
142
143
|
end
|
143
144
|
client_type.instance
|
@@ -38,7 +38,7 @@ module Shell
|
|
38
38
|
@session_type
|
39
39
|
end
|
40
40
|
|
41
|
-
attr_accessor :node, :compile, :recipe, :run_context
|
41
|
+
attr_accessor :node, :compile, :recipe, :run_context, :json_configuration
|
42
42
|
attr_reader :node_attributes, :client
|
43
43
|
def initialize
|
44
44
|
@node_built = false
|
@@ -151,7 +151,7 @@ module Shell
|
|
151
151
|
|
152
152
|
def rebuild_node
|
153
153
|
Chef::Config[:solo_legacy_mode] = true
|
154
|
-
@client = Chef::Client.new(
|
154
|
+
@client = Chef::Client.new(json_configuration, Chef::Config[:shell_config])
|
155
155
|
@client.run_ohai
|
156
156
|
@client.load_node
|
157
157
|
@client.build_node
|
@@ -183,7 +183,7 @@ module Shell
|
|
183
183
|
def rebuild_node
|
184
184
|
# Tell the client we're chef solo so it won't try to contact the server
|
185
185
|
Chef::Config[:solo_legacy_mode] = true
|
186
|
-
@client = Chef::Client.new(
|
186
|
+
@client = Chef::Client.new(json_configuration, Chef::Config[:shell_config])
|
187
187
|
@client.run_ohai
|
188
188
|
@client.load_node
|
189
189
|
@client.build_node
|
@@ -218,7 +218,7 @@ module Shell
|
|
218
218
|
def rebuild_node
|
219
219
|
# Make sure the client knows this is not chef solo
|
220
220
|
Chef::Config[:solo_legacy_mode] = false
|
221
|
-
@client = Chef::Client.new(
|
221
|
+
@client = Chef::Client.new(json_configuration, Chef::Config[:shell_config])
|
222
222
|
@client.run_ohai
|
223
223
|
@client.register
|
224
224
|
@client.load_node
|
@@ -0,0 +1,126 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Adam Edwards (<adamed@chef.io>)
|
3
|
+
#
|
4
|
+
# Copyright:: Copyright (c) 2015 Chef Software, Inc.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require "chef/win32/api/security" if Chef::Platform.windows?
|
20
|
+
require "chef/mixin/wide_string"
|
21
|
+
|
22
|
+
class Chef
|
23
|
+
class Util
|
24
|
+
class Windows
|
25
|
+
class LogonSession
|
26
|
+
include Chef::Mixin::WideString
|
27
|
+
|
28
|
+
def initialize(username, password, domain = nil)
|
29
|
+
if username.nil? || password.nil?
|
30
|
+
raise ArgumentError, "The logon session must be initialize with non-nil user name and password parameters"
|
31
|
+
end
|
32
|
+
|
33
|
+
@original_username = username
|
34
|
+
@original_password = password
|
35
|
+
@original_domain = domain
|
36
|
+
@token = FFI::Buffer.new(:pointer)
|
37
|
+
@session_opened = false
|
38
|
+
@impersonating = false
|
39
|
+
end
|
40
|
+
|
41
|
+
def open
|
42
|
+
if session_opened
|
43
|
+
raise "Attempted to open a logon session that was already open."
|
44
|
+
end
|
45
|
+
|
46
|
+
username = wstring(original_username)
|
47
|
+
password = wstring(original_password)
|
48
|
+
domain = wstring(original_domain)
|
49
|
+
|
50
|
+
status = Chef::ReservedNames::Win32::API::Security.LogonUserW(username, domain, password, Chef::ReservedNames::Win32::API::Security::LOGON32_LOGON_NEW_CREDENTIALS, Chef::ReservedNames::Win32::API::Security::LOGON32_PROVIDER_DEFAULT, token)
|
51
|
+
|
52
|
+
if !status
|
53
|
+
last_error = FFI::LastError.error
|
54
|
+
raise Chef::Exceptions::Win32APIError, "Logon for user `#{original_username}` failed with Win32 status #{last_error}."
|
55
|
+
end
|
56
|
+
|
57
|
+
@session_opened = true
|
58
|
+
end
|
59
|
+
|
60
|
+
def close
|
61
|
+
validate_session_open!
|
62
|
+
|
63
|
+
if impersonating
|
64
|
+
restore_user_context
|
65
|
+
end
|
66
|
+
|
67
|
+
Chef::ReservedNames::Win32::API::System.CloseHandle(token.read_ulong)
|
68
|
+
@token = nil
|
69
|
+
@session_opened = false
|
70
|
+
end
|
71
|
+
|
72
|
+
def set_user_context
|
73
|
+
validate_session_open!
|
74
|
+
|
75
|
+
if ! session_opened
|
76
|
+
raise "Attempted to set the user context before opening a session."
|
77
|
+
end
|
78
|
+
|
79
|
+
if impersonating
|
80
|
+
raise "Attempt to set the user context when the user context is already set."
|
81
|
+
end
|
82
|
+
|
83
|
+
status = Chef::ReservedNames::Win32::API::Security.ImpersonateLoggedOnUser(token.read_ulong)
|
84
|
+
|
85
|
+
if !status
|
86
|
+
last_error = FFI::LastError.error
|
87
|
+
raise Chef::Exceptions::Win32APIError, "Attempt to impersonate user `#{original_username}` failed with Win32 status #{last_error}."
|
88
|
+
end
|
89
|
+
|
90
|
+
@impersonating = true
|
91
|
+
end
|
92
|
+
|
93
|
+
def restore_user_context
|
94
|
+
validate_session_open!
|
95
|
+
|
96
|
+
if impersonating
|
97
|
+
status = Chef::ReservedNames::Win32::API::Security.RevertToSelf
|
98
|
+
|
99
|
+
if !status
|
100
|
+
last_error = FFI::LastError.error
|
101
|
+
raise Chef::Exceptions::Win32APIError, "Unable to restore user context with Win32 status #{last_error}."
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
@impersonating = false
|
106
|
+
end
|
107
|
+
|
108
|
+
protected
|
109
|
+
|
110
|
+
attr_reader :original_username
|
111
|
+
attr_reader :original_password
|
112
|
+
attr_reader :original_domain
|
113
|
+
|
114
|
+
attr_reader :token
|
115
|
+
attr_reader :session_opened
|
116
|
+
attr_reader :impersonating
|
117
|
+
|
118
|
+
def validate_session_open!
|
119
|
+
if ! session_opened
|
120
|
+
raise "Attempted to set the user context before opening a session."
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|