Module: Puppet::Util::Windows::Process

Extended by:
Windows::Handle, Windows::Process, Windows::Synchronize
Defined in:
lib/puppet/util/windows/process.rb

Defined Under Namespace

Modules: API

Constant Summary collapse

TOKEN_ALL_ACCESS =
0xF01FF
ERROR_NO_SUCH_PRIVILEGE =
1313

Class Method Summary collapse

Class Method Details

.execute(command, arguments, stdin, stdout, stderr) ⇒ Object



122
123
124
# File 'lib/puppet/util/windows/process.rb', line 122

def execute(command, arguments, stdin, stdout, stderr)
  Process.create( :command_line => command, :startup_info => {:stdin => stdin, :stdout => stdout, :stderr => stderr}, :close_handles => false )
end

.get_current_processObject



148
149
150
151
# File 'lib/puppet/util/windows/process.rb', line 148

def get_current_process
  # this pseudo-handle does not require closing per MSDN docs
  API.get_current_process
end

.get_token_information(token_handle, token_information) ⇒ Object



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/puppet/util/windows/process.rb', line 184

def get_token_information(token_handle, token_information)
  # to determine buffer size
  return_length_ptr = FFI::MemoryPointer.new(:uint, 1)
  result = API.get_token_information(token_handle, token_information, nil, 0, return_length_ptr)
  return_length = return_length_ptr.read_uint

  if return_length <= 0
    raise Puppet::Util::Windows::Error.new(
      "GetTokenInformation(#{token_handle}, #{token_information}, nil, 0, #{return_length_ptr})")
  end

  # re-call API with properly sized buffer for all results
  token_information_buf = FFI::MemoryPointer.new(return_length)
  result = API.get_token_information(token_handle, token_information,
    token_information_buf, return_length, return_length_ptr)

  if !result
    raise Puppet::Util::Windows::Error.new(
      "GetTokenInformation(#{token_handle}, #{token_information}, #{token_information_buf}, " +
        "#{return_length}, #{return_length_ptr})")
  end

  raw_privileges = API::Token_Privileges.new(token_information_buf)
  privileges = { :count => raw_privileges[:privilege_count], :privileges => [] }

  offset = token_information_buf + API::Token_Privileges.offset_of(:privileges)
  privilege_ptr = FFI::Pointer.new(API::LUID_And_Attributes, offset)

  # extract each instance of LUID_And_Attributes
  0.upto(privileges[:count] - 1) do |i|
    privileges[:privileges] <<  API::LUID_And_Attributes.new(privilege_ptr[i])
  end

  privileges
end

.lookup_privilege_value(name, system_name = '') ⇒ Object



170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/puppet/util/windows/process.rb', line 170

def lookup_privilege_value(name, system_name = '')
  luid = FFI::MemoryPointer.new(API::LUID.size)
  result = API.lookup_privilege_value(
    system_name,
    name.to_s,
    luid
    )

  return API::LUID.new(luid) if result
  raise Puppet::Util::Windows::Error.new(
    "LookupPrivilegeValue(#{system_name}, #{name}, #{luid})")
end

.open_process_token(handle, desired_access) ⇒ Object



154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/puppet/util/windows/process.rb', line 154

def open_process_token(handle, desired_access)
  token_handle_ptr = FFI::MemoryPointer.new(:uint, 1)
  result = API.open_process_token(handle, desired_access, token_handle_ptr)
  if !result
    raise Puppet::Util::Windows::Error.new(
      "OpenProcessToken(#{handle}, #{desired_access.to_s(8)}, #{token_handle_ptr})")
  end

  begin
    yield token_handle = token_handle_ptr.read_uint
  ensure
    API.close_handle(token_handle)
  end
end

.process_privilege_symlink?Boolean

Returns:

  • (Boolean)


223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/puppet/util/windows/process.rb', line 223

def process_privilege_symlink?
  handle = get_current_process
  open_process_token(handle, TOKEN_ALL_ACCESS) do |token_handle|
    luid = lookup_privilege_value('SeCreateSymbolicLinkPrivilege')
    token_info = get_token_information(token_handle, :token_privileges)
    token_info[:privileges].any? { |p| p[:luid].values == luid.values }
  end
rescue Puppet::Util::Windows::Error => e
  if e.code == ERROR_NO_SUCH_PRIVILEGE
    false # pre-Vista
  else
    raise e
  end
end

.wait_process(handle) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/puppet/util/windows/process.rb', line 127

def wait_process(handle)
  while WaitForSingleObject(handle, 0) == Windows::Synchronize::WAIT_TIMEOUT
    sleep(1)
  end

  exit_status = [0].pack('L')
  unless GetExitCodeProcess(handle, exit_status)
    raise Puppet::Util::Windows::Error.new("Failed to get child process exit code")
  end
  exit_status = exit_status.unpack('L').first

  # $CHILD_STATUS is not set when calling win32/process Process.create
  # and since it's read-only, we can't set it. But we can execute a
  # a shell that simply returns the desired exit status, which has the
  # desired effect.
  %x{#{ENV['COMSPEC']} /c exit #{exit_status}}

  exit_status
end