summaryrefslogtreecommitdiff
path: root/lib/chef/util
diff options
context:
space:
mode:
authoradamedx <adamedx@gmail.com>2016-04-02 23:22:14 -0700
committerBryan McLellan <btm@loftninjas.org>2017-09-05 20:09:30 -0400
commitd8fa21b9851b2a6d3c1ee370c8d0cfee8be278b4 (patch)
treeef63f7b277c30c4d1d48d944c3be3e219c56a7ef /lib/chef/util
parent2e9c29b0658136f0536d423ca71899a825f3920d (diff)
downloadchef-d8fa21b9851b2a6d3c1ee370c8d0cfee8be278b4.tar.gz
Windows thread alternate user impersonation support
Diffstat (limited to 'lib/chef/util')
-rw-r--r--lib/chef/util/windows/logon_session.rb118
1 files changed, 118 insertions, 0 deletions
diff --git a/lib/chef/util/windows/logon_session.rb b/lib/chef/util/windows/logon_session.rb
new file mode 100644
index 0000000000..c557ce0ff1
--- /dev/null
+++ b/lib/chef/util/windows/logon_session.rb
@@ -0,0 +1,118 @@
+#
+# Author:: Adam Edwards (<adamed@chef.io>)
+#
+# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/win32/api/security" if Chef::Platform.windows?
+require "chef/mixin/wide_string"
+
+class Chef
+ class Util
+ class Windows
+ class LogonSession
+ include Chef::Mixin::WideString
+
+ def initialize(username, password, domain = nil)
+ if username.nil? || password.nil?
+ raise ArgumentError, "The logon session must be initialize with non-nil user name and password parameters"
+ end
+
+ @username = username
+ @password = password
+ @domain = domain
+ @token = FFI::Buffer.new(:pointer)
+ @session_opened = false
+ @impersonating = false
+ end
+
+ def open
+ if @session_opened
+ raise RuntimeError, "Attempted to open a logon session that was already open."
+ end
+
+ username = wstring(@username)
+ password = wstring(@password)
+ domain = wstring(@domain)
+
+ status = Chef::ReservedNames::Win32::API::Security.LogonUserW(username, domain, password, Chef::ReservedNames::Win32::API::Security::LOGON32_LOGON_NETWORK, Chef::ReservedNames::Win32::API::Security::LOGON32_PROVIDER_DEFAULT, @token)
+
+ if status == 0
+ last_error = FFI::LastError.error
+ raise Chef::Exceptions::Win32APIError, "Logon for user `#{@username}` failed with Win32 status #{last_error}."
+ end
+
+ @session_opened = true
+ end
+
+ def close
+ validate_session_open!
+
+ if @impersonating
+ restore_user_context
+ end
+
+ Chef::ReservedNames::Win32::API::System.CloseHandle(@token.read_ulong)
+ @token = nil
+ @session_opened = false
+ end
+
+ def set_user_context
+ validate_session_open!
+
+ if ! @session_opened
+ raise RuntimeError, "Attempted to set the user context before opening a session."
+ end
+
+ if @impersonating
+ raise RuntimeError, "Attempt to set the user context when the user context is already set."
+ end
+
+ status = Chef::ReservedNames::Win32::API::Security.ImpersonateLoggedOnUser(@token.read_ulong)
+
+ if status == 0
+ last_error = FFI::LastError.error
+ raise Chef::Exceptions::Win32APIError, "Attempt to impersonate user `#{@username}` failed with Win32 status #{last_error}."
+ end
+
+ @impersonating = true
+ end
+
+ def restore_user_context
+ validate_session_open!
+
+ if @impersonating
+ status = Chef::ReservedNames::Win32::API::Security.RevertToSelf
+
+ if status == 0
+ last_error = FFI::LastError.error
+ raise Chef::Exceptions::Win32APIError, "Unable to restore user context with Win32 status #{last_error}."
+ end
+ end
+
+ @impersonating = false
+ end
+
+ protected
+
+ def validate_session_open!
+ if ! @session_opened
+ raise RuntimeError, "Attempted to set the user context before opening a session."
+ end
+ end
+ end
+ end
+ end
+end