puppet 5.5.6-universal-darwin → 5.5.7-universal-darwin
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puppet might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Gemfile +3 -1
- data/Gemfile.lock +12 -12
- data/Rakefile +9 -0
- data/lib/puppet/application.rb +5 -0
- data/lib/puppet/application/apply.rb +1 -0
- data/lib/puppet/application/master.rb +9 -7
- data/lib/puppet/application/script.rb +1 -1
- data/lib/puppet/defaults.rb +51 -31
- data/lib/puppet/etc.rb +20 -0
- data/lib/puppet/file_serving/fileset.rb +1 -1
- data/lib/puppet/functions.rb +123 -0
- data/lib/puppet/functions/new.rb +37 -53
- data/lib/puppet/functions/warning.rb +1 -1
- data/lib/puppet/loaders.rb +1 -0
- data/lib/puppet/parser/functions.rb +3 -1
- data/lib/puppet/parser/functions/sprintf.rb +12 -1
- data/lib/puppet/pops/evaluator/runtime3_converter.rb +16 -0
- data/lib/puppet/pops/evaluator/runtime3_support.rb +3 -4
- data/lib/puppet/pops/issues.rb +8 -0
- data/lib/puppet/pops/loader/loader.rb +2 -2
- data/lib/puppet/pops/loader/loader_paths.rb +3 -1
- data/lib/puppet/pops/loader/module_loaders.rb +1 -1
- data/lib/puppet/pops/loader/ruby_legacy_function_instantiator.rb +62 -0
- data/lib/puppet/pops/loaders.rb +5 -21
- data/lib/puppet/pops/parser/heredoc_support.rb +1 -2
- data/lib/puppet/pops/parser/lexer2.rb +1 -1
- data/lib/puppet/pops/validation/checker4_0.rb +31 -6
- data/lib/puppet/pops/validation/validator_factory_4_0.rb +1 -0
- data/lib/puppet/property/keyvalue.rb +70 -8
- data/lib/puppet/provider/aix_object.rb +483 -0
- data/lib/puppet/provider/exec.rb +54 -57
- data/lib/puppet/provider/group/aix.rb +40 -115
- data/lib/puppet/provider/group/pw.rb +4 -8
- data/lib/puppet/provider/group/windows_adsi.rb +7 -4
- data/lib/puppet/provider/nameservice.rb +1 -25
- data/lib/puppet/provider/nameservice/directoryservice.rb +5 -3
- data/lib/puppet/provider/package/portage.rb +2 -2
- data/lib/puppet/provider/package/windows.rb +2 -2
- data/lib/puppet/provider/package/windows/exe_package.rb +3 -10
- data/lib/puppet/provider/package/zypper.rb +1 -1
- data/lib/puppet/provider/service/launchd.rb +19 -3
- data/lib/puppet/provider/service/windows.rb +49 -40
- data/lib/puppet/provider/user/aix.rb +180 -246
- data/lib/puppet/provider/user/windows_adsi.rb +9 -1
- data/lib/puppet/resource/catalog.rb +1 -5
- data/lib/puppet/type/augeas.rb +1 -1
- data/lib/puppet/type/exec.rb +16 -14
- data/lib/puppet/type/file.rb +2 -2
- data/lib/puppet/type/file/source.rb +9 -5
- data/lib/puppet/type/group.rb +65 -23
- data/lib/puppet/type/k5login.rb +2 -2
- data/lib/puppet/type/notify.rb +1 -1
- data/lib/puppet/type/package.rb +3 -6
- data/lib/puppet/type/resources.rb +12 -2
- data/lib/puppet/type/schedule.rb +8 -1
- data/lib/puppet/type/selboolean.rb +2 -2
- data/lib/puppet/type/selmodule.rb +3 -4
- data/lib/puppet/type/service.rb +2 -5
- data/lib/puppet/type/tidy.rb +1 -1
- data/lib/puppet/type/user.rb +15 -20
- data/lib/puppet/type/yumrepo.rb +2 -2
- data/lib/puppet/type/zone.rb +2 -2
- data/lib/puppet/util.rb +7 -3
- data/lib/puppet/util/execution.rb +15 -1
- data/lib/puppet/util/posix.rb +15 -0
- data/lib/puppet/util/storage.rb +12 -0
- data/lib/puppet/util/windows.rb +4 -2
- data/lib/puppet/util/windows/adsi.rb +235 -205
- data/lib/puppet/util/windows/process.rb +23 -3
- data/lib/puppet/util/windows/security.rb +14 -0
- data/lib/puppet/util/windows/service.rb +977 -0
- data/lib/puppet/util/windows/user.rb +3 -5
- data/lib/puppet/version.rb +1 -1
- data/locales/ja/puppet.po +705 -374
- data/locales/puppet.pot +485 -261
- data/man/man5/puppet.conf.5 +36 -15
- data/man/man8/puppet-agent.8 +1 -1
- data/man/man8/puppet-apply.8 +1 -1
- data/man/man8/puppet-ca.8 +1 -1
- data/man/man8/puppet-catalog.8 +1 -1
- data/man/man8/puppet-cert.8 +1 -1
- data/man/man8/puppet-certificate.8 +1 -1
- data/man/man8/puppet-certificate_request.8 +1 -1
- data/man/man8/puppet-certificate_revocation_list.8 +1 -1
- data/man/man8/puppet-config.8 +1 -1
- data/man/man8/puppet-describe.8 +1 -1
- data/man/man8/puppet-device.8 +1 -1
- data/man/man8/puppet-doc.8 +1 -1
- data/man/man8/puppet-epp.8 +1 -1
- data/man/man8/puppet-facts.8 +1 -1
- data/man/man8/puppet-filebucket.8 +1 -1
- data/man/man8/puppet-generate.8 +1 -1
- data/man/man8/puppet-help.8 +1 -1
- data/man/man8/puppet-key.8 +1 -1
- data/man/man8/puppet-lookup.8 +1 -1
- data/man/man8/puppet-man.8 +1 -1
- data/man/man8/puppet-master.8 +1 -1
- data/man/man8/puppet-module.8 +1 -1
- data/man/man8/puppet-node.8 +1 -1
- data/man/man8/puppet-parser.8 +1 -1
- data/man/man8/puppet-plugin.8 +1 -1
- data/man/man8/puppet-report.8 +1 -1
- data/man/man8/puppet-resource.8 +1 -1
- data/man/man8/puppet-script.8 +1 -1
- data/man/man8/puppet-status.8 +1 -1
- data/man/man8/puppet.8 +2 -2
- data/spec/fixtures/unit/provider/aix_object/aix_colon_list_real_world_input.out +1 -0
- data/spec/fixtures/unit/provider/aix_object/aix_colon_list_real_world_output.out +1 -0
- data/spec/fixtures/unit/provider/user/aix/aix_passwd_file.out +32 -0
- data/spec/integration/parser/collection_spec.rb +4 -8
- data/spec/integration/provider/service/windows_spec.rb +5 -5
- data/spec/integration/type/file_spec.rb +6 -6
- data/spec/integration/util/windows/adsi_spec.rb +6 -5
- data/spec/integration/util/windows/security_spec.rb +10 -7
- data/spec/integration/util/windows/user_spec.rb +37 -17
- data/spec/spec_helper.rb +0 -1
- data/spec/unit/application/apply_spec.rb +41 -2
- data/spec/unit/application/master_spec.rb +7 -0
- data/spec/unit/application_spec.rb +21 -3
- data/spec/unit/defaults_spec.rb +20 -0
- data/spec/unit/etc_spec.rb +25 -0
- data/spec/unit/file_serving/fileset_spec.rb +11 -11
- data/spec/unit/gettext/config_spec.rb +1 -1
- data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +6 -6
- data/spec/unit/pops/loaders/loaders_spec.rb +40 -7
- data/spec/unit/pops/parser/parse_heredoc_spec.rb +16 -0
- data/spec/unit/pops/validator/validator_spec.rb +129 -10
- data/spec/unit/property/keyvalue_spec.rb +97 -6
- data/spec/unit/provider/aix_object_spec.rb +805 -0
- data/spec/unit/provider/group/aix_spec.rb +57 -0
- data/spec/unit/provider/group/pw_spec.rb +0 -6
- data/spec/unit/provider/group/windows_adsi_spec.rb +34 -35
- data/spec/unit/provider/nameservice/directoryservice_spec.rb +2 -2
- data/spec/unit/provider/package/windows/exe_package_spec.rb +3 -3
- data/spec/unit/provider/package/windows_spec.rb +4 -4
- data/spec/unit/provider/service/launchd_spec.rb +19 -0
- data/spec/unit/provider/service/windows_spec.rb +71 -78
- data/spec/unit/provider/user/aix_spec.rb +162 -116
- data/spec/unit/provider/user/windows_adsi_spec.rb +4 -4
- data/spec/unit/resource/catalog_spec.rb +2 -2
- data/spec/unit/ssl/certificate_authority_spec.rb +0 -1
- data/spec/unit/type/group_spec.rb +111 -13
- data/spec/unit/type/resources_spec.rb +18 -0
- data/spec/unit/util/execution_spec.rb +77 -0
- data/spec/unit/util/posix_spec.rb +28 -0
- data/spec/unit/util/storage_spec.rb +107 -0
- data/spec/unit/util/windows/adsi_spec.rb +108 -13
- data/spec/unit/util/windows/service_spec.rb +669 -0
- metadata +17 -5
- data/lib/puppet/provider/aixobject.rb +0 -392
- data/spec/unit/provider/aixobject_spec.rb +0 -101
data/lib/puppet/type/user.rb
CHANGED
@@ -392,9 +392,7 @@ module Puppet
|
|
392
392
|
that the user is a part of.
|
393
393
|
|
394
394
|
If `inclusive` is specified, Puppet will ensure that the user is a
|
395
|
-
member of **only** specified groups.
|
396
|
-
|
397
|
-
Defaults to `minimum`."
|
395
|
+
member of **only** specified groups."
|
398
396
|
|
399
397
|
newvalues(:inclusive, :minimum)
|
400
398
|
|
@@ -405,13 +403,13 @@ module Puppet
|
|
405
403
|
desc "Whether the user is a system user, according to the OS's criteria;
|
406
404
|
on most platforms, a UID less than or equal to 500 indicates a system
|
407
405
|
user. This parameter is only used when the resource is created and will
|
408
|
-
not affect the UID when the user is present.
|
406
|
+
not affect the UID when the user is present."
|
409
407
|
|
410
408
|
defaultto false
|
411
409
|
end
|
412
410
|
|
413
411
|
newparam(:allowdupe, :boolean => true, :parent => Puppet::Parameter::Boolean) do
|
414
|
-
desc "Whether to allow duplicate UIDs.
|
412
|
+
desc "Whether to allow duplicate UIDs."
|
415
413
|
|
416
414
|
defaultto false
|
417
415
|
end
|
@@ -419,13 +417,16 @@ module Puppet
|
|
419
417
|
newparam(:managehome, :boolean => true, :parent => Puppet::Parameter::Boolean) do
|
420
418
|
desc "Whether to manage the home directory when Puppet creates or removes the user.
|
421
419
|
This creates the home directory if Puppet also creates the user account, and deletes the
|
422
|
-
home directory if Puppet also removes the user account.
|
420
|
+
home directory if Puppet also removes the user account.
|
423
421
|
|
424
422
|
This parameter has no effect unless Puppet is also creating or removing the user in the
|
425
423
|
resource at the same time. For instance, Puppet creates a home directory for a managed
|
426
424
|
user if `ensure => present` and the user does not exist at the time of the Puppet run.
|
427
425
|
If the home directory is then deleted manually, Puppet will not recreate it on the next
|
428
|
-
run.
|
426
|
+
run.
|
427
|
+
|
428
|
+
Note that on Windows, this manages creation/deletion of the user profile instead of the
|
429
|
+
home directory. The user profile is stored in the `C:\Users\<username>` directory."
|
429
430
|
|
430
431
|
defaultto false
|
431
432
|
|
@@ -545,7 +546,7 @@ module Puppet
|
|
545
546
|
newparam(:role_membership) do
|
546
547
|
desc "Whether specified roles should be considered the **complete list**
|
547
548
|
(`inclusive`) or the **minimum list** (`minimum`) of roles the user
|
548
|
-
has.
|
549
|
+
has."
|
549
550
|
|
550
551
|
newvalues(:inclusive, :minimum)
|
551
552
|
|
@@ -571,7 +572,7 @@ module Puppet
|
|
571
572
|
newparam(:auth_membership) do
|
572
573
|
desc "Whether specified auths should be considered the **complete list**
|
573
574
|
(`inclusive`) or the **minimum list** (`minimum`) of auths the user
|
574
|
-
has.
|
575
|
+
has."
|
575
576
|
|
576
577
|
newvalues(:inclusive, :minimum)
|
577
578
|
|
@@ -597,7 +598,7 @@ module Puppet
|
|
597
598
|
newparam(:profile_membership) do
|
598
599
|
desc "Whether specified roles should be treated as the **complete list**
|
599
600
|
(`inclusive`) or the **minimum list** (`minimum`) of roles
|
600
|
-
of which the user is a member.
|
601
|
+
of which the user is a member."
|
601
602
|
|
602
603
|
newvalues(:inclusive, :minimum)
|
603
604
|
|
@@ -610,16 +611,12 @@ module Puppet
|
|
610
611
|
def membership
|
611
612
|
:key_membership
|
612
613
|
end
|
613
|
-
|
614
|
-
validate do |value|
|
615
|
-
raise ArgumentError, _("Key/value pairs must be separated by an =") unless value.include?("=")
|
616
|
-
end
|
617
614
|
end
|
618
615
|
|
619
616
|
newparam(:key_membership) do
|
620
617
|
desc "Whether specified key/value pairs should be considered the
|
621
618
|
**complete list** (`inclusive`) or the **minimum list** (`minimum`) of
|
622
|
-
the user's attributes.
|
619
|
+
the user's attributes."
|
623
620
|
|
624
621
|
newvalues(:inclusive, :minimum)
|
625
622
|
|
@@ -637,6 +634,8 @@ module Puppet
|
|
637
634
|
newproperty(:attributes, :parent => Puppet::Property::KeyValue, :required_features => :manages_aix_lam) do
|
638
635
|
desc "Specify AIX attributes for the user in an array of attribute = value pairs."
|
639
636
|
|
637
|
+
self.log_only_changed_or_new_keys = true
|
638
|
+
|
640
639
|
def membership
|
641
640
|
:attribute_membership
|
642
641
|
end
|
@@ -644,16 +643,12 @@ module Puppet
|
|
644
643
|
def delimiter
|
645
644
|
" "
|
646
645
|
end
|
647
|
-
|
648
|
-
validate do |value|
|
649
|
-
raise ArgumentError, _("Attributes value pairs must be separated by an =") unless value.include?("=")
|
650
|
-
end
|
651
646
|
end
|
652
647
|
|
653
648
|
newparam(:attribute_membership) do
|
654
649
|
desc "Whether specified attribute value pairs should be treated as the
|
655
650
|
**complete list** (`inclusive`) or the **minimum list** (`minimum`) of
|
656
|
-
attribute/value pairs for the user.
|
651
|
+
attribute/value pairs for the user."
|
657
652
|
|
658
653
|
newvalues(:inclusive, :minimum)
|
659
654
|
|
data/lib/puppet/type/yumrepo.rb
CHANGED
@@ -273,7 +273,7 @@ Puppet::Type.newtype(:yumrepo) do
|
|
273
273
|
desc "Enable bandwidth throttling for downloads. This option
|
274
274
|
can be expressed as a absolute data rate in bytes/sec or a
|
275
275
|
percentage `60%`. An SI prefix (k, M or G) may be appended
|
276
|
-
to the data rate values
|
276
|
+
to the data rate values.#{ABSENT_DOC}"
|
277
277
|
|
278
278
|
newvalues(/^\d+[kMG%]?$/, :absent)
|
279
279
|
end
|
@@ -283,7 +283,7 @@ Puppet::Type.newtype(:yumrepo) do
|
|
283
283
|
in bytes/second. Used with the `throttle` option. If `throttle`
|
284
284
|
is a percentage and `bandwidth` is `0` then bandwidth throttling
|
285
285
|
will be disabled. If `throttle` is expressed as a data rate then
|
286
|
-
this option is ignored
|
286
|
+
this option is ignored.#{ABSENT_DOC}"
|
287
287
|
|
288
288
|
newvalues(/^\d+[kMG]?$/, :absent)
|
289
289
|
end
|
data/lib/puppet/type/zone.rb
CHANGED
@@ -262,7 +262,7 @@ end
|
|
262
262
|
# Specify the sysidcfg file. This is pretty hackish, because it's
|
263
263
|
# only used to boot the zone the very first time.
|
264
264
|
newparam(:sysidcfg) do
|
265
|
-
desc
|
265
|
+
desc "The text to go into the `sysidcfg` file when the zone is first
|
266
266
|
booted. The best way is to use a template:
|
267
267
|
|
268
268
|
# $confdir/modules/site/templates/sysidcfg.erb
|
@@ -290,7 +290,7 @@ end
|
|
290
290
|
}
|
291
291
|
|
292
292
|
The `sysidcfg` only matters on the first booting of the zone,
|
293
|
-
so Puppet only checks for it at that time.
|
293
|
+
so Puppet only checks for it at that time."
|
294
294
|
end
|
295
295
|
|
296
296
|
newparam(:create_args) do
|
data/lib/puppet/util.rb
CHANGED
@@ -479,9 +479,13 @@ module Util
|
|
479
479
|
|
480
480
|
def safe_posix_fork(stdin=$stdin, stdout=$stdout, stderr=$stderr, &block)
|
481
481
|
child_pid = Kernel.fork do
|
482
|
-
|
483
|
-
|
484
|
-
|
482
|
+
STDIN.reopen(stdin)
|
483
|
+
STDOUT.reopen(stdout)
|
484
|
+
STDERR.reopen(stderr)
|
485
|
+
|
486
|
+
$stdin = STDIN
|
487
|
+
$stdout = STDOUT
|
488
|
+
$stderr = STDERR
|
485
489
|
|
486
490
|
begin
|
487
491
|
Dir.foreach('/proc/self/fd') do |f|
|
@@ -114,6 +114,9 @@ module Puppet::Util::Execution
|
|
114
114
|
# an Array the first element should be the executable and the rest of the
|
115
115
|
# elements should be the individual arguments to that executable.
|
116
116
|
# @param options [Hash] a Hash of options
|
117
|
+
# @option options [String] :cwd the directory from which to run the command. Raises an error if the directory does not exist.
|
118
|
+
# This option is only available on the agent. It cannot be used on the master, meaning it cannot be used in, for example,
|
119
|
+
# regular functions, hiera backends, or report processors.
|
117
120
|
# @option options [Boolean] :failonfail if this value is set to true, then this method will raise an error if the
|
118
121
|
# command is not executed successfully.
|
119
122
|
# @option options [Integer, String] :uid (nil) the user id of the user that the process should be run as. Will be ignored if the
|
@@ -154,6 +157,7 @@ module Puppet::Util::Execution
|
|
154
157
|
:override_locale => true,
|
155
158
|
:custom_environment => {},
|
156
159
|
:sensitive => false,
|
160
|
+
:suppress_window => false,
|
157
161
|
}
|
158
162
|
|
159
163
|
options = default_options.merge(options)
|
@@ -186,6 +190,11 @@ module Puppet::Util::Execution
|
|
186
190
|
|
187
191
|
null_file = Puppet.features.microsoft_windows? ? 'NUL' : '/dev/null'
|
188
192
|
|
193
|
+
cwd = options[:cwd]
|
194
|
+
if cwd && ! Puppet::FileSystem.directory?(cwd)
|
195
|
+
raise ArgumentError, _("Working directory %{cwd} does not exist!") % { cwd: cwd }
|
196
|
+
end
|
197
|
+
|
189
198
|
begin
|
190
199
|
stdin = Puppet::FileSystem.open(options[:stdinfile] || null_file, nil, 'r')
|
191
200
|
# On Windows, continue to use the file-based approach to avoid breaking people's existing
|
@@ -320,7 +329,6 @@ module Puppet::Util::Execution
|
|
320
329
|
#
|
321
330
|
def self.execute_posix(command, options, stdin, stdout, stderr)
|
322
331
|
child_pid = Puppet::Util.safe_posix_fork(stdin, stdout, stderr) do
|
323
|
-
|
324
332
|
# We can't just call Array(command), and rely on it returning
|
325
333
|
# things like ['foo'], when passed ['foo'], because
|
326
334
|
# Array(command) will call command.to_a internally, which when
|
@@ -329,6 +337,12 @@ module Puppet::Util::Execution
|
|
329
337
|
command = [command].flatten
|
330
338
|
Process.setsid
|
331
339
|
begin
|
340
|
+
# We need to chdir to our cwd before changing privileges as there's a
|
341
|
+
# chance that the user may not have permissions to access the cwd, which
|
342
|
+
# would cause execute_posix to fail.
|
343
|
+
cwd = options[:cwd]
|
344
|
+
Dir.chdir(cwd) if cwd
|
345
|
+
|
332
346
|
Puppet::Util::SUIDManager.change_privileges(options[:uid], options[:gid], true)
|
333
347
|
|
334
348
|
# if the caller has requested that we override locale environment variables,
|
data/lib/puppet/util/posix.rb
CHANGED
@@ -9,7 +9,22 @@ module Puppet::Util::POSIX
|
|
9
9
|
# environment for "exec" runs
|
10
10
|
USER_ENV_VARS = ['HOME', 'USER', 'LOGNAME']
|
11
11
|
|
12
|
+
class << self
|
13
|
+
# Returns an array of all the groups that the user's a member of.
|
14
|
+
def groups_of(user)
|
15
|
+
groups = []
|
16
|
+
Puppet::Etc.group do |group|
|
17
|
+
groups << group.name if group.mem.include?(user)
|
18
|
+
end
|
19
|
+
|
20
|
+
uniq_groups = groups.uniq
|
21
|
+
if uniq_groups != groups
|
22
|
+
Puppet.debug(_('Removing any duplicate group entries'))
|
23
|
+
end
|
12
24
|
|
25
|
+
uniq_groups
|
26
|
+
end
|
27
|
+
end
|
13
28
|
|
14
29
|
# Retrieve a field from a POSIX Etc object. The id can be either an integer
|
15
30
|
# or a name. This only works for users and groups. It's also broken on
|
data/lib/puppet/util/storage.rb
CHANGED
@@ -82,6 +82,18 @@ class Puppet::Util::Storage
|
|
82
82
|
|
83
83
|
Puppet.info _("Creating state file %{file}") % { file: Puppet[:statefile] } unless Puppet::FileSystem.exist?(Puppet[:statefile])
|
84
84
|
|
85
|
+
if Puppet[:statettl] == 0 || Puppet[:statettl] == Float::INFINITY
|
86
|
+
Puppet.debug "Not pruning old state cache entries"
|
87
|
+
else
|
88
|
+
Puppet::Util.benchmark(:debug, "Pruned old state cache entries in %{seconds} seconds") do
|
89
|
+
ttl_cutoff = Time.now - Puppet[:statettl]
|
90
|
+
|
91
|
+
@@state.reject! do |k,v|
|
92
|
+
@@state[k][:checked] && @@state[k][:checked] < ttl_cutoff
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
85
97
|
Puppet::Util.benchmark(:debug, "Stored state in %{seconds} seconds") do
|
86
98
|
Puppet::Util::Yaml.dump(@@state, Puppet[:statefile])
|
87
99
|
end
|
data/lib/puppet/util/windows.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
module Puppet::Util::Windows
|
2
2
|
module ADSI
|
3
|
-
class
|
3
|
+
class ADSIObject; end
|
4
|
+
class User < ADSIObject; end
|
4
5
|
class UserProfile; end
|
5
|
-
class Group; end
|
6
|
+
class Group < ADSIObject; end
|
6
7
|
end
|
7
8
|
module File; end
|
8
9
|
module Registry
|
@@ -31,5 +32,6 @@ module Puppet::Util::Windows
|
|
31
32
|
require 'puppet/util/windows/adsi'
|
32
33
|
require 'puppet/util/windows/registry'
|
33
34
|
require 'puppet/util/windows/eventlog'
|
35
|
+
require 'puppet/util/windows/service'
|
34
36
|
end
|
35
37
|
end
|
@@ -106,138 +106,201 @@ module Puppet::Util::Windows::ADSI
|
|
106
106
|
[:lpwstr, :lpdword], :win32_bool
|
107
107
|
end
|
108
108
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
# for instance VORDEFINIERT on German Windows
|
114
|
-
Puppet::Util::Windows::SID.sid_to_name('S-1-5-32').upcase,
|
115
|
-
# localized version of NT AUTHORITY (can't use S-1-5)
|
116
|
-
# for instance AUTORITE NT on French Windows
|
117
|
-
Puppet::Util::Windows::SID.name_to_principal('SYSTEM').domain.upcase
|
118
|
-
]
|
119
|
-
end
|
120
|
-
|
121
|
-
def uri(name, host = '.')
|
122
|
-
host = '.' if (localized_domains << Socket.gethostname.upcase).include?(host.upcase)
|
109
|
+
# Common base class shared by the User and Group
|
110
|
+
# classes below.
|
111
|
+
class ADSIObject
|
112
|
+
extend Enumerable
|
123
113
|
|
124
|
-
|
125
|
-
|
114
|
+
# Define some useful class-level methods
|
115
|
+
class << self
|
116
|
+
# Is either 'user' or 'group'
|
117
|
+
attr_reader :object_class
|
118
|
+
|
119
|
+
def localized_domains
|
120
|
+
@localized_domains ||= [
|
121
|
+
# localized version of BUILTIN
|
122
|
+
# for instance VORDEFINIERT on German Windows
|
123
|
+
Puppet::Util::Windows::SID.sid_to_name('S-1-5-32').upcase,
|
124
|
+
# localized version of NT AUTHORITY (can't use S-1-5)
|
125
|
+
# for instance AUTORITE NT on French Windows
|
126
|
+
Puppet::Util::Windows::SID.name_to_principal('SYSTEM').domain.upcase
|
127
|
+
]
|
128
|
+
end
|
129
|
+
|
130
|
+
def uri(name, host = '.')
|
131
|
+
host = '.' if (localized_domains << Socket.gethostname.upcase).include?(host.upcase)
|
132
|
+
Puppet::Util::Windows::ADSI.uri(name, @object_class, host)
|
133
|
+
end
|
134
|
+
|
135
|
+
def parse_name(name)
|
136
|
+
if name =~ /\//
|
137
|
+
raise Puppet::Error.new( _("Value must be in DOMAIN\\%{object_class} style syntax") % { object_class: @object_class } )
|
138
|
+
end
|
139
|
+
|
140
|
+
matches = name.scan(/((.*)\\)?(.*)/)
|
141
|
+
domain = matches[0][1] || '.'
|
142
|
+
account = matches[0][2]
|
143
|
+
|
144
|
+
return account, domain
|
145
|
+
end
|
146
|
+
|
147
|
+
# returns Puppet::Util::Windows::SID::Principal[]
|
148
|
+
# may contain objects that represent unresolvable SIDs
|
149
|
+
def get_sids(adsi_child_collection)
|
150
|
+
sids = []
|
151
|
+
adsi_child_collection.each do |m|
|
152
|
+
sids << Puppet::Util::Windows::SID.ads_to_principal(m)
|
153
|
+
end
|
154
|
+
|
155
|
+
sids
|
156
|
+
end
|
157
|
+
|
158
|
+
def name_sid_hash(names)
|
159
|
+
return {} if names.nil? || names.empty?
|
160
|
+
|
161
|
+
sids = names.map do |name|
|
162
|
+
sid = Puppet::Util::Windows::SID.name_to_principal(name)
|
163
|
+
raise Puppet::Error.new( _("Could not resolve name: %{name}") % { name: name } ) if !sid
|
164
|
+
[sid.sid, sid]
|
165
|
+
end
|
166
|
+
|
167
|
+
Hash[ sids ]
|
168
|
+
end
|
126
169
|
|
127
|
-
Puppet::Util::Windows::ADSI.uri(name, account_type, host)
|
128
|
-
end
|
129
170
|
|
130
|
-
|
131
|
-
|
132
|
-
raise Puppet::Error.new( _("Value must be in DOMAIN\\user style syntax") )
|
171
|
+
def delete(name)
|
172
|
+
Puppet::Util::Windows::ADSI.delete(name, @object_class)
|
133
173
|
end
|
134
174
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
175
|
+
def exists?(name_or_sid)
|
176
|
+
well_known = false
|
177
|
+
if (sid = Puppet::Util::Windows::SID.name_to_principal(name_or_sid))
|
178
|
+
# Examples of SidType include SidTypeUser, SidTypeGroup
|
179
|
+
return true if sid.account_type == "SidType#{@object_class.capitalize}".to_sym
|
180
|
+
|
181
|
+
# 'well known group' is special as it can be a group like Everyone OR a user like SYSTEM
|
182
|
+
# so try to resolve it
|
183
|
+
# https://msdn.microsoft.com/en-us/library/cc234477.aspx
|
184
|
+
well_known = sid.account_type == :SidTypeWellKnownGroup
|
185
|
+
return false if sid.account_type != :SidTypeAlias && !well_known
|
186
|
+
name_or_sid = "#{sid.domain}\\#{sid.account}"
|
187
|
+
end
|
141
188
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
189
|
+
object = Puppet::Util::Windows::ADSI.connect(uri(*parse_name(name_or_sid)))
|
190
|
+
object.Class.downcase == @object_class
|
191
|
+
rescue
|
192
|
+
# special accounts like SYSTEM or special groups like Authenticated Users cannot
|
193
|
+
# resolve via monikers like WinNT://./SYSTEM,user or WinNT://./Authenticated Users,group
|
194
|
+
# -- they'll fail to connect. thus, given a validly resolved SID, this failure is
|
195
|
+
# ambiguous as it may indicate either a group like Service or an account like SYSTEM
|
196
|
+
well_known
|
148
197
|
end
|
149
198
|
|
150
|
-
|
151
|
-
|
199
|
+
def list_all
|
200
|
+
raise NotImplementedError, _("Subclass must implement class-level method 'list_all'!")
|
201
|
+
end
|
152
202
|
|
153
|
-
|
154
|
-
|
203
|
+
def each(&block)
|
204
|
+
objects = []
|
205
|
+
list_all.each do |o|
|
206
|
+
# Setting WIN32OLE.codepage in the microsoft_windows feature ensures
|
207
|
+
# values are returned as UTF-8
|
208
|
+
objects << new(o.name)
|
209
|
+
end
|
155
210
|
|
156
|
-
|
157
|
-
sid = Puppet::Util::Windows::SID.name_to_principal(name)
|
158
|
-
raise Puppet::Error.new( _("Could not resolve name: %{name}") % { name: name } ) if !sid
|
159
|
-
[sid.sid, sid]
|
211
|
+
objects.each(&block)
|
160
212
|
end
|
161
|
-
|
162
|
-
Hash[ sids ]
|
163
213
|
end
|
164
|
-
end
|
165
214
|
|
166
|
-
|
167
|
-
|
168
|
-
extend Puppet::Util::Windows::ADSI::Shared
|
169
|
-
extend FFI::Library
|
170
|
-
|
171
|
-
# https://msdn.microsoft.com/en-us/library/aa746340.aspx
|
172
|
-
# IADsUser interface
|
173
|
-
|
174
|
-
require 'puppet/util/windows/sid'
|
175
|
-
|
176
|
-
attr_accessor :native_user
|
177
|
-
attr_reader :name, :sid
|
178
|
-
def initialize(name, native_user = nil)
|
215
|
+
attr_reader :name
|
216
|
+
def initialize(name, native_object = nil)
|
179
217
|
@name = name
|
180
|
-
@
|
181
|
-
end
|
182
|
-
|
183
|
-
def native_user
|
184
|
-
@native_user ||= Puppet::Util::Windows::ADSI.connect(self.class.uri(*self.class.parse_name(@name)))
|
218
|
+
@native_object = native_object
|
185
219
|
end
|
186
220
|
|
187
|
-
def
|
188
|
-
|
221
|
+
def object_class
|
222
|
+
self.class.object_class
|
189
223
|
end
|
190
224
|
|
191
225
|
def uri
|
192
226
|
self.class.uri(sid.account, sid.domain)
|
193
227
|
end
|
194
228
|
|
195
|
-
def
|
196
|
-
Puppet::Util::Windows::
|
229
|
+
def native_object
|
230
|
+
@native_object ||= Puppet::Util::Windows::ADSI.connect(self.class.uri(*self.class.parse_name(name)))
|
231
|
+
end
|
232
|
+
|
233
|
+
def sid
|
234
|
+
@sid ||= Puppet::Util::Windows::SID.octet_string_to_principal(native_object.objectSID)
|
197
235
|
end
|
198
236
|
|
199
237
|
def [](attribute)
|
200
238
|
# Setting WIN32OLE.codepage in the microsoft_windows feature ensures
|
201
239
|
# values are returned as UTF-8
|
202
|
-
|
240
|
+
native_object.Get(attribute)
|
203
241
|
end
|
204
242
|
|
205
243
|
def []=(attribute, value)
|
206
|
-
|
244
|
+
native_object.Put(attribute, value)
|
207
245
|
end
|
208
246
|
|
209
247
|
def commit
|
210
248
|
begin
|
211
|
-
|
249
|
+
native_object.SetInfo
|
212
250
|
rescue WIN32OLERuntimeError => e
|
213
251
|
# ERROR_BAD_USERNAME 2202L from winerror.h
|
214
252
|
if e.message =~ /8007089A/m
|
215
253
|
raise Puppet::Error.new(
|
216
|
-
|
217
|
-
e
|
254
|
+
_("Puppet is not able to create/delete domain %{object_class} objects with the %{object_class} resource.") % { object_class: object_class },
|
218
255
|
)
|
219
256
|
end
|
220
257
|
|
221
|
-
raise Puppet::Error.new( _("
|
258
|
+
raise Puppet::Error.new( _("%{object_class} update failed: %{error}") % { object_class: object_class.capitalize, error: e }, e )
|
222
259
|
end
|
223
260
|
self
|
224
261
|
end
|
262
|
+
end
|
263
|
+
|
264
|
+
class User < ADSIObject
|
265
|
+
extend FFI::Library
|
266
|
+
|
267
|
+
require 'puppet/util/windows/sid'
|
268
|
+
|
269
|
+
# https://msdn.microsoft.com/en-us/library/aa746340.aspx
|
270
|
+
# IADsUser interface
|
271
|
+
@object_class = 'user'
|
272
|
+
|
273
|
+
class << self
|
274
|
+
def list_all
|
275
|
+
Puppet::Util::Windows::ADSI.execquery('select name from win32_useraccount where localaccount = "TRUE"')
|
276
|
+
end
|
277
|
+
|
278
|
+
def logon(name, password)
|
279
|
+
Puppet::Util::Windows::User.password_is?(name, password)
|
280
|
+
end
|
281
|
+
|
282
|
+
def create(name)
|
283
|
+
# Windows error 1379: The specified local group already exists.
|
284
|
+
raise Puppet::Error.new(_("Cannot create user if group '%{name}' exists.") % { name: name }) if Puppet::Util::Windows::ADSI::Group.exists? name
|
285
|
+
new(name, Puppet::Util::Windows::ADSI.create(name, @object_class))
|
286
|
+
end
|
287
|
+
end
|
225
288
|
|
226
289
|
def password_is?(password)
|
227
290
|
self.class.logon(name, password)
|
228
291
|
end
|
229
292
|
|
230
293
|
def add_flag(flag_name, value)
|
231
|
-
flag =
|
294
|
+
flag = native_object.Get(flag_name) rescue 0
|
232
295
|
|
233
|
-
|
296
|
+
native_object.Put(flag_name, flag | value)
|
234
297
|
|
235
298
|
commit
|
236
299
|
end
|
237
300
|
|
238
301
|
def password=(password)
|
239
302
|
if !password.nil?
|
240
|
-
|
303
|
+
native_object.SetPassword(password)
|
241
304
|
commit
|
242
305
|
end
|
243
306
|
|
@@ -251,7 +314,7 @@ module Puppet::Util::Windows::ADSI
|
|
251
314
|
groups = []
|
252
315
|
# Setting WIN32OLE.codepage in the microsoft_windows feature ensures
|
253
316
|
# values are returned as UTF-8
|
254
|
-
|
317
|
+
native_object.Groups.each {|g| groups << g.Name} rescue nil
|
255
318
|
groups
|
256
319
|
end
|
257
320
|
|
@@ -281,9 +344,13 @@ module Puppet::Util::Windows::ADSI
|
|
281
344
|
end
|
282
345
|
|
283
346
|
def group_sids
|
284
|
-
self.class.get_sids(
|
347
|
+
self.class.get_sids(native_object.Groups)
|
285
348
|
end
|
286
349
|
|
350
|
+
# TODO: This code's pretty similar to set_members in the Group class. Would be nice
|
351
|
+
# to refactor them into the ADSIObject class at some point. This was not done originally
|
352
|
+
# because these use different methods to do stuff that are also aliased to other methods,
|
353
|
+
# so the shared code isn't exactly a 1:1 mapping.
|
287
354
|
def set_groups(desired_groups, minimum = true)
|
288
355
|
return if desired_groups.nil?
|
289
356
|
|
@@ -311,10 +378,82 @@ module Puppet::Util::Windows::ADSI
|
|
311
378
|
end
|
312
379
|
end
|
313
380
|
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
381
|
+
# Declare all of the available user flags on the system. Note that
|
382
|
+
# ADS_UF is read as ADS_UserFlag
|
383
|
+
# https://docs.microsoft.com/en-us/windows/desktop/api/iads/ne-iads-ads_user_flag
|
384
|
+
# and
|
385
|
+
# https://support.microsoft.com/en-us/help/305144/how-to-use-the-useraccountcontrol-flags-to-manipulate-user-account-pro
|
386
|
+
# for the flag values.
|
387
|
+
ADS_USERFLAGS = {
|
388
|
+
ADS_UF_SCRIPT: 0x0001,
|
389
|
+
ADS_UF_ACCOUNTDISABLE: 0x0002,
|
390
|
+
ADS_UF_HOMEDIR_REQUIRED: 0x0008,
|
391
|
+
ADS_UF_LOCKOUT: 0x0010,
|
392
|
+
ADS_UF_PASSWD_NOTREQD: 0x0020,
|
393
|
+
ADS_UF_PASSWD_CANT_CHANGE: 0x0040,
|
394
|
+
ADS_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED: 0x0080,
|
395
|
+
ADS_UF_TEMP_DUPLICATE_ACCOUNT: 0x0100,
|
396
|
+
ADS_UF_NORMAL_ACCOUNT: 0x0200,
|
397
|
+
ADS_UF_INTERDOMAIN_TRUST_ACCOUNT: 0x0800,
|
398
|
+
ADS_UF_WORKSTATION_TRUST_ACCOUNT: 0x1000,
|
399
|
+
ADS_UF_SERVER_TRUST_ACCOUNT: 0x2000,
|
400
|
+
ADS_UF_DONT_EXPIRE_PASSWD: 0x10000,
|
401
|
+
ADS_UF_MNS_LOGON_ACCOUNT: 0x20000,
|
402
|
+
ADS_UF_SMARTCARD_REQUIRED: 0x40000,
|
403
|
+
ADS_UF_TRUSTED_FOR_DELEGATION: 0x80000,
|
404
|
+
ADS_UF_NOT_DELEGATED: 0x100000,
|
405
|
+
ADS_UF_USE_DES_KEY_ONLY: 0x200000,
|
406
|
+
ADS_UF_DONT_REQUIRE_PREAUTH: 0x400000,
|
407
|
+
ADS_UF_PASSWORD_EXPIRED: 0x800000,
|
408
|
+
ADS_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION: 0x1000000
|
409
|
+
}
|
410
|
+
|
411
|
+
def userflag_set?(flag)
|
412
|
+
flag_value = ADS_USERFLAGS[flag] || 0
|
413
|
+
! (self['UserFlags'] & flag_value).zero?
|
414
|
+
end
|
415
|
+
|
416
|
+
# Common helper for set_userflags and unset_userflags.
|
417
|
+
#
|
418
|
+
# @api private
|
419
|
+
def op_userflags(*flags, &block)
|
420
|
+
# Avoid an unnecessary set + commit operation.
|
421
|
+
return if flags.empty?
|
422
|
+
|
423
|
+
unrecognized_flags = flags.reject { |flag| ADS_USERFLAGS.keys.include?(flag) }
|
424
|
+
unless unrecognized_flags.empty?
|
425
|
+
raise ArgumentError, _("Unrecognized ADS UserFlags: %{unrecognized_flags}") % { unrecognized_flags: unrecognized_flags.join(', ') }
|
426
|
+
end
|
427
|
+
|
428
|
+
self['UserFlags'] = flags.inject(self['UserFlags'], &block)
|
429
|
+
end
|
430
|
+
|
431
|
+
def set_userflags(*flags)
|
432
|
+
op_userflags(*flags) { |userflags, flag| userflags | ADS_USERFLAGS[flag] }
|
433
|
+
end
|
434
|
+
|
435
|
+
def unset_userflags(*flags)
|
436
|
+
op_userflags(*flags) { |userflags, flag| userflags & ~ADS_USERFLAGS[flag] }
|
437
|
+
end
|
438
|
+
|
439
|
+
def disabled?
|
440
|
+
userflag_set?(:ADS_UF_ACCOUNTDISABLE)
|
441
|
+
end
|
442
|
+
|
443
|
+
def locked_out?
|
444
|
+
# Note that the LOCKOUT flag is known to be inaccurate when using the
|
445
|
+
# LDAP IADsUser provider, but this class consistently uses the WinNT
|
446
|
+
# provider, which is expected to be accurate.
|
447
|
+
userflag_set?(:ADS_UF_LOCKOUT)
|
448
|
+
end
|
449
|
+
|
450
|
+
def expired?
|
451
|
+
expires = native_object.Get('AccountExpirationDate')
|
452
|
+
expires && expires < Time.now
|
453
|
+
rescue WIN32OLERuntimeError => e
|
454
|
+
# This OLE error code indicates the property can't be found in the cache
|
455
|
+
raise e unless e.message =~ /8000500D/m
|
456
|
+
false
|
318
457
|
end
|
319
458
|
|
320
459
|
# UNLEN from lmcons.h - https://stackoverflow.com/a/2155176
|
@@ -341,47 +480,6 @@ module Puppet::Util::Windows::ADSI
|
|
341
480
|
Puppet::Util::Windows::SID.name_to_principal(current_user_name)
|
342
481
|
end
|
343
482
|
|
344
|
-
def self.exists?(name_or_sid)
|
345
|
-
well_known = false
|
346
|
-
if (sid = Puppet::Util::Windows::SID.name_to_principal(name_or_sid))
|
347
|
-
return true if sid.account_type == :SidTypeUser
|
348
|
-
|
349
|
-
# 'well known group' is special as it can be a group like Everyone OR a user like SYSTEM
|
350
|
-
# so try to resolve it
|
351
|
-
# https://msdn.microsoft.com/en-us/library/cc234477.aspx
|
352
|
-
well_known = sid.account_type == :SidTypeWellKnownGroup
|
353
|
-
return false if sid.account_type != :SidTypeAlias && !well_known
|
354
|
-
name_or_sid = "#{sid.domain}\\#{sid.account}"
|
355
|
-
end
|
356
|
-
|
357
|
-
user = Puppet::Util::Windows::ADSI.connect(User.uri(*User.parse_name(name_or_sid)))
|
358
|
-
# otherwise, verify that the account is actually a User account
|
359
|
-
user.Class == 'User'
|
360
|
-
rescue
|
361
|
-
# special accounts like SYSTEM cannot resolve via moniker like WinNT://./SYSTEM,user
|
362
|
-
# and thus fail to connect - so given a validly resolved SID, this failure is ambiguous as it
|
363
|
-
# may indicate either a group like Service or an account like SYSTEM
|
364
|
-
well_known
|
365
|
-
end
|
366
|
-
|
367
|
-
|
368
|
-
def self.delete(name)
|
369
|
-
Puppet::Util::Windows::ADSI.delete(name, 'user')
|
370
|
-
end
|
371
|
-
|
372
|
-
def self.each(&block)
|
373
|
-
wql = Puppet::Util::Windows::ADSI.execquery('select name from win32_useraccount where localaccount = "TRUE"')
|
374
|
-
|
375
|
-
users = []
|
376
|
-
wql.each do |u|
|
377
|
-
# Setting WIN32OLE.codepage in the microsoft_windows feature ensures
|
378
|
-
# values are returned as UTF-8
|
379
|
-
users << new(u.name)
|
380
|
-
end
|
381
|
-
|
382
|
-
users.each(&block)
|
383
|
-
end
|
384
|
-
|
385
483
|
ffi_convention :stdcall
|
386
484
|
|
387
485
|
# https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx
|
@@ -410,58 +508,33 @@ module Puppet::Util::Windows::ADSI
|
|
410
508
|
end
|
411
509
|
end
|
412
510
|
|
413
|
-
class Group
|
414
|
-
extend Enumerable
|
415
|
-
extend Puppet::Util::Windows::ADSI::Shared
|
511
|
+
class Group < ADSIObject
|
416
512
|
|
417
513
|
# https://msdn.microsoft.com/en-us/library/aa706021.aspx
|
418
514
|
# IADsGroup interface
|
515
|
+
@object_class = 'group'
|
419
516
|
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
@native_group = native_group
|
425
|
-
end
|
426
|
-
|
427
|
-
def uri
|
428
|
-
self.class.uri(sid.account, sid.domain)
|
429
|
-
end
|
430
|
-
|
431
|
-
def native_group
|
432
|
-
@native_group ||= Puppet::Util::Windows::ADSI.connect(self.class.uri(*self.class.parse_name(name)))
|
433
|
-
end
|
434
|
-
|
435
|
-
def sid
|
436
|
-
@sid ||= Puppet::Util::Windows::SID.octet_string_to_principal(native_group.objectSID)
|
437
|
-
end
|
438
|
-
|
439
|
-
def commit
|
440
|
-
begin
|
441
|
-
native_group.SetInfo unless native_group.nil?
|
442
|
-
rescue WIN32OLERuntimeError => e
|
443
|
-
# ERROR_BAD_USERNAME 2202L from winerror.h
|
444
|
-
if e.message =~ /8007089A/m
|
445
|
-
raise Puppet::Error.new(
|
446
|
-
_("Puppet is not able to create/delete domain groups with the group resource."),
|
447
|
-
e
|
448
|
-
)
|
449
|
-
end
|
517
|
+
class << self
|
518
|
+
def list_all
|
519
|
+
Puppet::Util::Windows::ADSI.execquery('select name from win32_group where localaccount = "TRUE"')
|
520
|
+
end
|
450
521
|
|
451
|
-
|
522
|
+
def create(name)
|
523
|
+
# Windows error 2224: The account already exists.
|
524
|
+
raise Puppet::Error.new( _("Cannot create group if user '%{name}' exists.") % { name: name } ) if Puppet::Util::Windows::ADSI::User.exists?(name)
|
525
|
+
new(name, Puppet::Util::Windows::ADSI.create(name, @object_class))
|
452
526
|
end
|
453
|
-
self
|
454
527
|
end
|
455
528
|
|
456
529
|
def add_member_sids(*sids)
|
457
530
|
sids.each do |sid|
|
458
|
-
|
531
|
+
native_object.Add(Puppet::Util::Windows::ADSI.sid_uri(sid))
|
459
532
|
end
|
460
533
|
end
|
461
534
|
|
462
535
|
def remove_member_sids(*sids)
|
463
536
|
sids.each do |sid|
|
464
|
-
|
537
|
+
native_object.Remove(Puppet::Util::Windows::ADSI.sid_uri(sid))
|
465
538
|
end
|
466
539
|
end
|
467
540
|
|
@@ -469,13 +542,15 @@ module Puppet::Util::Windows::ADSI
|
|
469
542
|
# may contain objects that represent unresolvable SIDs
|
470
543
|
# qualified account names are returned by calling #domain_account
|
471
544
|
def members
|
472
|
-
self.class.get_sids(
|
545
|
+
self.class.get_sids(native_object.Members)
|
473
546
|
end
|
474
547
|
alias member_sids members
|
475
548
|
|
476
549
|
def set_members(desired_members, inclusive = true)
|
477
550
|
return if desired_members.nil?
|
478
551
|
|
552
|
+
desired_members = desired_members.split(',').map(&:strip)
|
553
|
+
|
479
554
|
current_hash = Hash[ self.member_sids.map { |sid| [sid.sid, sid] } ]
|
480
555
|
desired_hash = self.class.name_sid_hash(desired_members)
|
481
556
|
|
@@ -496,50 +571,5 @@ module Puppet::Util::Windows::ADSI
|
|
496
571
|
remove_member_sids(*members_to_remove)
|
497
572
|
end
|
498
573
|
end
|
499
|
-
|
500
|
-
def self.create(name)
|
501
|
-
# Windows error 2224: The account already exists.
|
502
|
-
raise Puppet::Error.new( _("Cannot create group if user '%{name}' exists.") % { name: name } ) if Puppet::Util::Windows::ADSI::User.exists? name
|
503
|
-
new(name, Puppet::Util::Windows::ADSI.create(name, 'group'))
|
504
|
-
end
|
505
|
-
|
506
|
-
def self.exists?(name_or_sid)
|
507
|
-
well_known = false
|
508
|
-
if (sid = Puppet::Util::Windows::SID.name_to_principal(name_or_sid))
|
509
|
-
return true if sid.account_type == :SidTypeGroup
|
510
|
-
|
511
|
-
# 'well known group' is special as it can be a group like Everyone OR a user like SYSTEM
|
512
|
-
# so try to resolve it
|
513
|
-
# https://msdn.microsoft.com/en-us/library/cc234477.aspx
|
514
|
-
well_known = sid.account_type == :SidTypeWellKnownGroup
|
515
|
-
return false if sid.account_type != :SidTypeAlias && !well_known
|
516
|
-
name_or_sid = "#{sid.domain}\\#{sid.account}"
|
517
|
-
end
|
518
|
-
|
519
|
-
user = Puppet::Util::Windows::ADSI.connect(Group.uri(*Group.parse_name(name_or_sid)))
|
520
|
-
user.Class == 'Group'
|
521
|
-
rescue
|
522
|
-
# special groups like Authenticated Users cannot resolve via moniker like WinNT://./Authenticated Users,group
|
523
|
-
# and thus fail to connect - so given a validly resolved SID, this failure is ambiguous as it
|
524
|
-
# may indicate either a group like Service or an account like SYSTEM
|
525
|
-
well_known
|
526
|
-
end
|
527
|
-
|
528
|
-
def self.delete(name)
|
529
|
-
Puppet::Util::Windows::ADSI.delete(name, 'group')
|
530
|
-
end
|
531
|
-
|
532
|
-
def self.each(&block)
|
533
|
-
wql = Puppet::Util::Windows::ADSI.execquery('select name from win32_group where localaccount = "TRUE"')
|
534
|
-
|
535
|
-
groups = []
|
536
|
-
wql.each do |g|
|
537
|
-
# Setting WIN32OLE.codepage in the microsoft_windows feature ensures
|
538
|
-
# values are returned as UTF-8
|
539
|
-
groups << new(g.name)
|
540
|
-
end
|
541
|
-
|
542
|
-
groups.each(&block)
|
543
|
-
end
|
544
574
|
end
|
545
575
|
end
|