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

Extended by:
FFI::Windows::Functions, String
Includes:
FFI::Windows::Structs
Defined in:
lib/puppet/util/windows/process.rb

Constant Summary collapse

WAIT_TIMEOUT =
0x102
WAIT_INTERVAL =
200
CREATE_NO_WINDOW =
0x08000000
PROCESS_QUERY_INFORMATION =
0x0400
MAX_PATH_LENGTH =
32_767
TOKEN_ALL_ACCESS =
0xF01FF
ERROR_NO_SUCH_PRIVILEGE =
1313
TOKEN_QUERY =
0x0008

Constants included from FFI::Windows::Functions

FFI::Windows::Functions::SC_ENUM_TYPE, FFI::Windows::Functions::SC_STATUS_TYPE

Constants included from FFI::Windows::Constants

FFI::Windows::Constants::ABOVE_NORMAL_PRIORITY_CLASS, FFI::Windows::Constants::ALL_SERVICE_TYPES, FFI::Windows::Constants::BELOW_NORMAL_PRIORITY_CLASS, FFI::Windows::Constants::CREATE_BREAKAWAY_FROM_JOB, FFI::Windows::Constants::CREATE_DEFAULT_ERROR_MODE, FFI::Windows::Constants::CREATE_NEW_CONSOLE, FFI::Windows::Constants::CREATE_NEW_PROCESS_GROUP, FFI::Windows::Constants::CREATE_PRESERVE_CODE_AUTHZ_LEVEL, FFI::Windows::Constants::CREATE_PROTECTED_PROCESS, FFI::Windows::Constants::CREATE_SEPARATE_WOW_VDM, FFI::Windows::Constants::CREATE_SHARED_WOW_VDM, FFI::Windows::Constants::CREATE_SUSPENDED, FFI::Windows::Constants::CREATE_UNICODE_ENVIRONMENT, FFI::Windows::Constants::DEBUG_ONLY_THIS_PROCESS, FFI::Windows::Constants::DEBUG_PROCESS, FFI::Windows::Constants::DELETE, FFI::Windows::Constants::DETACHED_PROCESS, FFI::Windows::Constants::ERROR_ALREADY_EXISTS, FFI::Windows::Constants::ERROR_FILE_NOT_FOUND, FFI::Windows::Constants::ERROR_PATH_NOT_FOUND, FFI::Windows::Constants::ERROR_SERVICE_DOES_NOT_EXIST, FFI::Windows::Constants::FILE_ALL_ACCESS, FFI::Windows::Constants::FILE_APPEND_DATA, FFI::Windows::Constants::FILE_ATTRIBUTE_DIRECTORY, FFI::Windows::Constants::FILE_ATTRIBUTE_READONLY, FFI::Windows::Constants::FILE_ATTRIBUTE_REPARSE_POINT, FFI::Windows::Constants::FILE_DELETE_CHILD, FFI::Windows::Constants::FILE_DEVICE_FILE_SYSTEM, FFI::Windows::Constants::FILE_EXECUTE, FFI::Windows::Constants::FILE_FLAG_BACKUP_SEMANTICS, FFI::Windows::Constants::FILE_FLAG_OPEN_REPARSE_POINT, FFI::Windows::Constants::FILE_GENERIC_EXECUTE, FFI::Windows::Constants::FILE_GENERIC_READ, FFI::Windows::Constants::FILE_GENERIC_WRITE, FFI::Windows::Constants::FILE_READ_ATTRIBUTES, FFI::Windows::Constants::FILE_READ_DATA, FFI::Windows::Constants::FILE_READ_EA, FFI::Windows::Constants::FILE_SHARE_READ, FFI::Windows::Constants::FILE_SHARE_WRITE, FFI::Windows::Constants::FILE_WRITE_ATTRIBUTES, FFI::Windows::Constants::FILE_WRITE_DATA, FFI::Windows::Constants::FILE_WRITE_EA, FFI::Windows::Constants::FINAL_STATES, FFI::Windows::Constants::FSCTL_GET_REPARSE_POINT, FFI::Windows::Constants::GENERIC_ALL, FFI::Windows::Constants::GENERIC_EXECUTE, FFI::Windows::Constants::GENERIC_READ, FFI::Windows::Constants::GENERIC_WRITE, FFI::Windows::Constants::HANDLE_FLAG_INHERIT, FFI::Windows::Constants::HIGH_PRIORITY_CLASS, FFI::Windows::Constants::IDLE_PRIORITY_CLASS, FFI::Windows::Constants::INHERIT_PARENT_AFFINITY, FFI::Windows::Constants::INVALID_FILE_ATTRIBUTES, FFI::Windows::Constants::INVALID_HANDLE_VALUE, FFI::Windows::Constants::IO_REPARSE_TAG_CSV, FFI::Windows::Constants::IO_REPARSE_TAG_DEDUP, FFI::Windows::Constants::IO_REPARSE_TAG_DFS, FFI::Windows::Constants::IO_REPARSE_TAG_DFSR, FFI::Windows::Constants::IO_REPARSE_TAG_HSM, FFI::Windows::Constants::IO_REPARSE_TAG_HSM2, FFI::Windows::Constants::IO_REPARSE_TAG_MOUNT_POINT, FFI::Windows::Constants::IO_REPARSE_TAG_NFS, FFI::Windows::Constants::IO_REPARSE_TAG_SIS, FFI::Windows::Constants::IO_REPARSE_TAG_SYMLINK, FFI::Windows::Constants::IO_REPARSE_TAG_WIM, FFI::Windows::Constants::LOGON_WITH_PROFILE, FFI::Windows::Constants::MAXIMUM_REPARSE_DATA_BUFFER_SIZE, FFI::Windows::Constants::METHOD_BUFFERED, FFI::Windows::Constants::NORMAL_PRIORITY_CLASS, FFI::Windows::Constants::OPEN_EXISTING, FFI::Windows::Constants::PROCESS_ALL_ACCESS, FFI::Windows::Constants::PROCESS_SET_INFORMATION, FFI::Windows::Constants::PROCESS_TERMINATE, FFI::Windows::Constants::PROCESS_VM_READ, FFI::Windows::Constants::REALTIME_PRIORITY_CLASS, FFI::Windows::Constants::REPLACEFILE_IGNORE_ACL_ERRORS, FFI::Windows::Constants::REPLACEFILE_IGNORE_MERGE_ERRORS, FFI::Windows::Constants::REPLACEFILE_WRITE_THROUGH, FFI::Windows::Constants::SC_MANAGER_ALL_ACCESS, FFI::Windows::Constants::SC_MANAGER_CONNECT, FFI::Windows::Constants::SC_MANAGER_CREATE_SERVICE, FFI::Windows::Constants::SC_MANAGER_ENUMERATE_SERVICE, FFI::Windows::Constants::SC_MANAGER_LOCK, FFI::Windows::Constants::SC_MANAGER_MODIFY_BOOT_CONFIG, FFI::Windows::Constants::SC_MANAGER_QUERY_LOCK_STATUS, FFI::Windows::Constants::SEM_FAILCRITICALERRORS, FFI::Windows::Constants::SEM_NOGPFAULTERRORBOX, FFI::Windows::Constants::SERVICENAME_MAX, FFI::Windows::Constants::SERVICE_ACCEPT_HARDWAREPROFILECHANGE, FFI::Windows::Constants::SERVICE_ACCEPT_NETBINDCHANGE, FFI::Windows::Constants::SERVICE_ACCEPT_PARAMCHANGE, FFI::Windows::Constants::SERVICE_ACCEPT_PAUSE_CONTINUE, FFI::Windows::Constants::SERVICE_ACCEPT_POWEREVENT, FFI::Windows::Constants::SERVICE_ACCEPT_PRESHUTDOWN, FFI::Windows::Constants::SERVICE_ACCEPT_SESSIONCHANGE, FFI::Windows::Constants::SERVICE_ACCEPT_SHUTDOWN, FFI::Windows::Constants::SERVICE_ACCEPT_STOP, FFI::Windows::Constants::SERVICE_ACCEPT_TIMECHANGE, FFI::Windows::Constants::SERVICE_ACCEPT_TRIGGEREVENT, FFI::Windows::Constants::SERVICE_ACCEPT_USER_LOGOFF, FFI::Windows::Constants::SERVICE_ACTIVE, FFI::Windows::Constants::SERVICE_ALL_ACCESS, FFI::Windows::Constants::SERVICE_AUTO_START, FFI::Windows::Constants::SERVICE_BOOT_START, FFI::Windows::Constants::SERVICE_CHANGE_CONFIG, FFI::Windows::Constants::SERVICE_CONFIG_DELAYED_AUTO_START_INFO, FFI::Windows::Constants::SERVICE_CONFIG_DESCRIPTION, FFI::Windows::Constants::SERVICE_CONFIG_FAILURE_ACTIONS, FFI::Windows::Constants::SERVICE_CONFIG_FAILURE_ACTIONS_FLAG, FFI::Windows::Constants::SERVICE_CONFIG_LAUNCH_PROTECTED, FFI::Windows::Constants::SERVICE_CONFIG_PREFERRED_NODE, FFI::Windows::Constants::SERVICE_CONFIG_PRESHUTDOWN_INFO, FFI::Windows::Constants::SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO, FFI::Windows::Constants::SERVICE_CONFIG_SERVICE_SID_INFO, FFI::Windows::Constants::SERVICE_CONFIG_TRIGGER_INFO, FFI::Windows::Constants::SERVICE_CONFIG_TYPES, FFI::Windows::Constants::SERVICE_CONTINUE_PENDING, FFI::Windows::Constants::SERVICE_CONTROL_CONTINUE, FFI::Windows::Constants::SERVICE_CONTROL_DEVICEEVENT, FFI::Windows::Constants::SERVICE_CONTROL_HARDWAREPROFILECHANGE, FFI::Windows::Constants::SERVICE_CONTROL_INTERROGATE, FFI::Windows::Constants::SERVICE_CONTROL_NETBINDADD, FFI::Windows::Constants::SERVICE_CONTROL_NETBINDDISABLE, FFI::Windows::Constants::SERVICE_CONTROL_NETBINDENABLE, FFI::Windows::Constants::SERVICE_CONTROL_NETBINDREMOVE, FFI::Windows::Constants::SERVICE_CONTROL_PARAMCHANGE, FFI::Windows::Constants::SERVICE_CONTROL_PAUSE, FFI::Windows::Constants::SERVICE_CONTROL_POWEREVENT, FFI::Windows::Constants::SERVICE_CONTROL_PRESHUTDOWN, FFI::Windows::Constants::SERVICE_CONTROL_SESSIONCHANGE, FFI::Windows::Constants::SERVICE_CONTROL_SHUTDOWN, FFI::Windows::Constants::SERVICE_CONTROL_SIGNALS, FFI::Windows::Constants::SERVICE_CONTROL_STOP, FFI::Windows::Constants::SERVICE_CONTROL_TIMECHANGE, FFI::Windows::Constants::SERVICE_CONTROL_TRIGGEREVENT, FFI::Windows::Constants::SERVICE_DEMAND_START, FFI::Windows::Constants::SERVICE_DISABLED, FFI::Windows::Constants::SERVICE_ENUMERATE_DEPENDENTS, FFI::Windows::Constants::SERVICE_FILE_SYSTEM_DRIVER, FFI::Windows::Constants::SERVICE_INACTIVE, FFI::Windows::Constants::SERVICE_INTERACTIVE_PROCESS, FFI::Windows::Constants::SERVICE_INTERROGATE, FFI::Windows::Constants::SERVICE_KERNEL_DRIVER, FFI::Windows::Constants::SERVICE_NO_CHANGE, FFI::Windows::Constants::SERVICE_PAUSED, FFI::Windows::Constants::SERVICE_PAUSE_CONTINUE, FFI::Windows::Constants::SERVICE_PAUSE_PENDING, FFI::Windows::Constants::SERVICE_QUERY_CONFIG, FFI::Windows::Constants::SERVICE_QUERY_STATUS, FFI::Windows::Constants::SERVICE_RUNNING, FFI::Windows::Constants::SERVICE_START, FFI::Windows::Constants::SERVICE_START_PENDING, FFI::Windows::Constants::SERVICE_START_TYPES, FFI::Windows::Constants::SERVICE_STATES, FFI::Windows::Constants::SERVICE_STATE_ALL, FFI::Windows::Constants::SERVICE_STOP, FFI::Windows::Constants::SERVICE_STOPPED, FFI::Windows::Constants::SERVICE_STOP_PENDING, FFI::Windows::Constants::SERVICE_SYSTEM_START, FFI::Windows::Constants::SERVICE_USER_DEFINED_CONTROL, FFI::Windows::Constants::SERVICE_USER_OWN_PROCESS, FFI::Windows::Constants::SERVICE_USER_SHARE_PROCESS, FFI::Windows::Constants::SERVICE_WIN32_OWN_PROCESS, FFI::Windows::Constants::SERVICE_WIN32_SHARE_PROCESS, FFI::Windows::Constants::SHGFI_DISPLAYNAME, FFI::Windows::Constants::SHGFI_PIDL, FFI::Windows::Constants::SPECIFIC_RIGHTS_ALL, FFI::Windows::Constants::STANDARD_RIGHTS_ALL, FFI::Windows::Constants::STANDARD_RIGHTS_EXECUTE, FFI::Windows::Constants::STANDARD_RIGHTS_READ, FFI::Windows::Constants::STANDARD_RIGHTS_REQUIRED, FFI::Windows::Constants::STANDARD_RIGHTS_WRITE, FFI::Windows::Constants::STARTF_USESTDHANDLES, FFI::Windows::Constants::SYNCHRONIZE, FFI::Windows::Constants::TOKEN_INFORMATION_CLASS, FFI::Windows::Constants::UNSAFE_PENDING_STATES, FFI::Windows::Constants::WRITE_DAC, FFI::Windows::Constants::WRITE_OWNER

Constants included from FFI::Windows::Structs

FFI::Windows::Structs::MAXIMUM_REPARSE_DATA_BUFFER_SIZE

Class Method Summary collapse

Methods included from String

wide_string

Class Method Details

.elevated_security?Boolean

Returns whether or not the owner of the current process is running with elevated security privileges.

Only supported on Windows Vista or later.

Returns:

  • (Boolean)


249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/puppet/util/windows/process.rb', line 249

def elevated_security?
  # default / pre-Vista
  elevated = false
  handle = nil

  begin
    handle = get_current_process
    open_process_token(handle, TOKEN_QUERY) do |token_handle|
      get_token_information(token_handle, :TokenElevation) do |token_info|
        token_elevation = parse_token_information_as_token_elevation(token_info)
        # TokenIsElevated member of the TOKEN_ELEVATION struct
        elevated = token_elevation[:TokenIsElevated] != 0
      end
    end

    elevated
  rescue Puppet::Util::Windows::Error => e
    raise e if e.code != ERROR_NO_SUCH_PRIVILEGE
  ensure
    FFI::WIN32.CloseHandle(handle) if handle
  end
end

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



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/puppet/util/windows/process.rb', line 20

def execute(command, arguments, stdin, stdout, stderr)
  create_args = {
    :command_line => command,
    :startup_info => {
      :stdin => stdin,
      :stdout => stdout,
      :stderr => stderr
    },
    :close_handles => false,
  }
  if arguments[:suppress_window]
    create_args[:creation_flags] = CREATE_NO_WINDOW
  end
  if arguments[:cwd]
    create_args[:cwd] = arguments[:cwd]
  end
  Process.create(create_args)
end

.get_current_processObject



64
65
66
67
# File 'lib/puppet/util/windows/process.rb', line 64

def get_current_process
  # this pseudo-handle does not require closing per MSDN docs
  GetCurrentProcess()
end

.get_environment_stringsObject

Returns a hash of the current environment variables encoded as UTF-8 The memory block returned from GetEnvironmentStringsW is double-null terminated and the vars are paired as below; Var1=Value10 Var2=Value20 VarX=ValueX00 Note - Some env variable names start with ‘=’ and are excluded from the return value Note - The env_ptr MUST be freed using the FreeEnvironmentStringsW function Note - There is no technical limitation to the size of the environment block returned.

However a practical limit of 64K is used as no single environment variable can exceed 32KB


302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
# File 'lib/puppet/util/windows/process.rb', line 302

def get_environment_strings
  env_ptr = GetEnvironmentStringsW()

  # pass :invalid => :replace to the Ruby String#encode to use replacement characters
  pairs = env_ptr.read_arbitrary_wide_string_up_to(65_534, :double_null, { :invalid => :replace })
                 .split(?\x00)
                 .reject { |env_str| env_str.nil? || env_str.empty? || env_str[0] == '=' }
                 .reject do |env_str|
                   # reject any string containing the Unicode replacement character
                   if env_str.include?("\uFFFD")
                     Puppet.warning(_("Discarding environment variable %{string} which contains invalid bytes") % { string: env_str })
                     true
                   end
                 end
                 .map { |env_pair| env_pair.split('=', 2) }
  pairs.to_h
ensure
  if env_ptr && !env_ptr.null?
    if FreeEnvironmentStringsW(env_ptr) == FFI::WIN32_FALSE
      Puppet.debug "FreeEnvironmentStringsW memory leak"
    end
  end
end

.get_process_image_name_by_pid(pid) ⇒ Object



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

def get_process_image_name_by_pid(pid)
  image_name = ''.dup

  Puppet::Util::Windows::Security.with_privilege(Puppet::Util::Windows::Security::SE_DEBUG_NAME) do
    open_process(PROCESS_QUERY_INFORMATION, false, pid) do |phandle|
      FFI::MemoryPointer.new(:dword, 1) do |exe_name_length_ptr|
        # UTF is 2 bytes/char:
        max_chars = MAX_PATH_LENGTH + 1
        exe_name_length_ptr.write_dword(max_chars)
        FFI::MemoryPointer.new(:wchar, max_chars) do |exe_name_ptr|
          use_win32_path_format = 0
          result = QueryFullProcessImageNameW(phandle, use_win32_path_format, exe_name_ptr, exe_name_length_ptr)
          if result == FFI::WIN32_FALSE
            raise Puppet::Util::Windows::Error, "QueryFullProcessImageNameW(phandle, #{use_win32_path_format}, " \
                                                "exe_name_ptr, #{max_chars}"
          end
          image_name = exe_name_ptr.read_wide_string(exe_name_length_ptr.read_dword)
        end
      end
    end
  end

  image_name
end

.get_system_default_ui_languageObject



346
347
348
# File 'lib/puppet/util/windows/process.rb', line 346

def get_system_default_ui_language
  GetSystemDefaultUILanguage()
end

.get_token_information(token_handle, token_information, &block) ⇒ Object



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/puppet/util/windows/process.rb', line 169

def get_token_information(token_handle, token_information, &block)
  # to determine buffer size
  FFI::MemoryPointer.new(:dword, 1) do |return_length_ptr|
    result = GetTokenInformation(token_handle, token_information, nil, 0, return_length_ptr)
    return_length = return_length_ptr.read_dword

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

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

      if result == FFI::WIN32_FALSE
        raise Puppet::Util::Windows::Error, "GetTokenInformation(#{token_handle}, #{token_information}, #{token_information_buf}, " \
                                            "#{return_length}, #{return_length_ptr})"
      end

      yield token_information_buf
    end
  end

  # GetTokenInformation buffer has been cleaned up by this point, nothing to return
  nil
end

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



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

def lookup_privilege_value(name, system_name = '', &block)
  FFI::MemoryPointer.new(LUID.size) do |luid_ptr|
    result = LookupPrivilegeValueW(
      wide_string(system_name),
      wide_string(name.to_s),
      luid_ptr
    )

    if result == FFI::WIN32_FALSE
      raise Puppet::Util::Windows::Error, "LookupPrivilegeValue(#{system_name}, #{name}, #{luid_ptr})"
    end

    yield LUID.new(luid_ptr)
  end

  # the underlying MemoryPointer for LUID is cleaned up by this point
  nil
end

.open_process(desired_access, inherit_handle, process_id, &block) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/puppet/util/windows/process.rb', line 70

def open_process(desired_access, inherit_handle, process_id, &block)
  phandle = nil
  inherit = inherit_handle ? FFI::WIN32_TRUE : FFI::WIN32_FALSE
  begin
    phandle = OpenProcess(desired_access, inherit, process_id)
    if phandle == FFI::Pointer::NULL_HANDLE
      raise Puppet::Util::Windows::Error, "OpenProcess(#{desired_access.to_s(8)}, #{inherit}, #{process_id})"
    end

    yield phandle
  ensure
    FFI::WIN32.CloseHandle(phandle) if phandle
  end

  # phandle has had CloseHandle called against it, so nothing to return
  nil
end

.open_process_token(handle, desired_access, &block) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/puppet/util/windows/process.rb', line 89

def open_process_token(handle, desired_access, &block)
  token_handle = nil
  begin
    FFI::MemoryPointer.new(:handle, 1) do |token_handle_ptr|
      result = OpenProcessToken(handle, desired_access, token_handle_ptr)
      if result == FFI::WIN32_FALSE
        raise Puppet::Util::Windows::Error, "OpenProcessToken(#{handle}, #{desired_access.to_s(8)}, #{token_handle_ptr})"
      end

      yield token_handle = token_handle_ptr.read_handle
    end

    token_handle
  ensure
    FFI::WIN32.CloseHandle(token_handle) if token_handle
  end

  # token_handle has had CloseHandle called against it, so nothing to return
  nil
end

.parse_token_information_as_token_elevation(token_information_buf) ⇒ Object



214
215
216
# File 'lib/puppet/util/windows/process.rb', line 214

def parse_token_information_as_token_elevation(token_information_buf)
  TOKEN_ELEVATION.new(token_information_buf)
end

.parse_token_information_as_token_privileges(token_information_buf) ⇒ Object



198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/puppet/util/windows/process.rb', line 198

def parse_token_information_as_token_privileges(token_information_buf)
  raw_privileges = TOKEN_PRIVILEGES.new(token_information_buf)
  privileges = { :count => raw_privileges[:PrivilegeCount], :privileges => [] }

  offset = token_information_buf + TOKEN_PRIVILEGES.offset_of(:Privileges)
  privilege_ptr = FFI::Pointer.new(LUID_AND_ATTRIBUTES, offset)

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

  privileges
end

.process_privilege_symlink?Boolean

Returns:

  • (Boolean)


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

def process_privilege_symlink?
  privilege_symlink = false
  handle = get_current_process
  open_process_token(handle, TOKEN_ALL_ACCESS) do |token_handle|
    lookup_privilege_value('SeCreateSymbolicLinkPrivilege') do |luid|
      get_token_information(token_handle, :TokenPrivileges) do |token_info|
        token_privileges = parse_token_information_as_token_privileges(token_info)
        privilege_symlink = token_privileges[:privileges].any? { |p| p[:Luid].values == luid.values }
      end
    end
  end

  privilege_symlink
rescue Puppet::Util::Windows::Error => e
  if e.code == ERROR_NO_SUCH_PRIVILEGE
    false # pre-Vista
  else
    raise e
  end
end

.set_environment_variable(name, val) ⇒ Object



327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
# File 'lib/puppet/util/windows/process.rb', line 327

def set_environment_variable(name, val)
  raise Puppet::Util::Windows::Error(_('environment variable name must not be nil or empty')) if !name || name.empty?

  FFI::MemoryPointer.from_string_to_wide_string(name) do |name_ptr|
    if val.nil?
      if SetEnvironmentVariableW(name_ptr, FFI::MemoryPointer::NULL) == FFI::WIN32_FALSE
        raise Puppet::Util::Windows::Error, _("Failed to remove environment variable: %{name}") % { name: name }
      end
    else
      FFI::MemoryPointer.from_string_to_wide_string(val) do |val_ptr|
        if SetEnvironmentVariableW(name_ptr, val_ptr) == FFI::WIN32_FALSE
          raise Puppet::Util::Windows::Error, _("Failed to set environment variable: %{name}") % { name: name }
        end
      end
    end
  end
end

.supports_elevated_security?Boolean

Returns whether or not the OS has the ability to set elevated token information.

Returns true on Windows Vista or later, otherwise false

Returns:

  • (Boolean)


356
357
358
# File 'lib/puppet/util/windows/process.rb', line 356

def supports_elevated_security?
  windows_major_version >= 6
end

.wait_process(handle) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/puppet/util/windows/process.rb', line 40

def wait_process(handle)
  while WaitForSingleObject(handle, WAIT_INTERVAL) == WAIT_TIMEOUT
    sleep(0)
  end

  exit_status = -1
  FFI::MemoryPointer.new(:dword, 1) do |exit_status_ptr|
    if GetExitCodeProcess(handle, exit_status_ptr) == FFI::WIN32_FALSE
      raise Puppet::Util::Windows::Error, _("Failed to get child process exit code")
    end

    exit_status = exit_status_ptr.read_dword

    # $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.fetch('COMSPEC', nil)} /c exit #{exit_status})
  end

  exit_status
end

.windows_major_versionObject



273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
# File 'lib/puppet/util/windows/process.rb', line 273

def windows_major_version
  ver = 0

  FFI::MemoryPointer.new(OSVERSIONINFO.size) do |os_version_ptr|
    os_version = OSVERSIONINFO.new(os_version_ptr)
    os_version[:dwOSVersionInfoSize] = OSVERSIONINFO.size

    result = GetVersionExW(os_version_ptr)

    if result == FFI::WIN32_FALSE
      raise Puppet::Util::Windows::Error, _("GetVersionEx failed")
    end

    ver = os_version[:dwMajorVersion]
  end

  ver
end

.with_process_token(access, &block) ⇒ Object

Execute a block with the current process token



112
113
114
115
116
117
118
119
120
# File 'lib/puppet/util/windows/process.rb', line 112

def with_process_token(access, &block)
  handle = get_current_process
  open_process_token(handle, access) do |token_handle|
    yield token_handle
  end

  # all handles have been closed, so nothing to safely return
  nil
end