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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
#
# 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
@original_username = username
@original_password = password
@original_domain = domain
@token = FFI::Buffer.new(:pointer)
@session_opened = false
@impersonating = false
end
def open
if session_opened
raise "Attempted to open a logon session that was already open."
end
username = wstring(original_username)
password = wstring(original_password)
domain = wstring(original_domain)
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)
if !status
last_error = FFI::LastError.error
raise Chef::Exceptions::Win32APIError, "Logon for user `#{original_username}` failed with Win32 status #{last_error}."
end
@session_opened = true
end
def close
puts "UserContext DEBUG: in close"
validate_session_open!
if impersonating
puts "UserContext DEBUG: impersonating, calling restore_user_context"
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 "Attempted to set the user context before opening a session."
end
if impersonating
raise "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
last_error = FFI::LastError.error
raise Chef::Exceptions::Win32APIError, "Attempt to impersonate user `#{original_username}` failed with Win32 status #{last_error}."
end
@impersonating = true
end
def restore_user_context
puts "UserContext DEBUG: calling restore_user_context"
validate_session_open!
if impersonating
puts "UserContext DEBUG: impersonating, calling RevertToSelf"
status = Chef::ReservedNames::Win32::API::Security.RevertToSelf
puts "UserContext DEBUG: RevertToSelf return: '#{status}'"
if !status
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
attr_reader :original_username
attr_reader :original_password
attr_reader :original_domain
attr_reader :token
attr_reader :session_opened
attr_reader :impersonating
def validate_session_open!
if ! session_opened
raise "Attempted to set the user context before opening a session."
end
end
end
end
end
end
|