chef 12.5.1 → 12.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +6 -1
- data/README.md +6 -4
- data/Rakefile +1 -4
- data/chef-windows.gemspec +21 -0
- data/chef.gemspec +58 -0
- data/lib/chef/api_client/registration.rb +9 -4
- data/lib/chef/application.rb +3 -84
- data/lib/chef/application/apply.rb +9 -2
- data/lib/chef/application/client.rb +8 -3
- data/lib/chef/application/solo.rb +7 -1
- data/lib/chef/application/windows_service.rb +21 -6
- data/lib/chef/application/windows_service_manager.rb +2 -3
- data/lib/chef/audit/runner.rb +1 -0
- data/lib/chef/chef_class.rb +1 -11
- data/lib/chef/chef_fs/chef_fs_data_store.rb +181 -2
- data/lib/chef/chef_fs/file_system/cookbook_subdir.rb +5 -0
- data/lib/chef/chef_fs/file_system/file_system_entry.rb +11 -7
- data/lib/chef/client.rb +28 -1
- data/lib/chef/cookbook/cookbook_collection.rb +14 -1
- data/lib/chef/cookbook/cookbook_version_loader.rb +1 -1
- data/lib/chef/cookbook/metadata.rb +115 -9
- data/lib/chef/cookbook/remote_file_vendor.rb +1 -1
- data/lib/chef/cookbook_version.rb +6 -2
- data/lib/chef/data_bag.rb +1 -1
- data/lib/chef/data_bag_item.rb +1 -1
- data/lib/chef/digester.rb +5 -1
- data/lib/chef/dsl/chef_provisioning.rb +57 -0
- data/lib/chef/dsl/cheffish.rb +64 -0
- data/lib/chef/dsl/declare_resource.rb +108 -0
- data/lib/chef/dsl/platform_introspection.rb +3 -3
- data/lib/chef/dsl/recipe.rb +3 -73
- data/lib/chef/dsl/resources.rb +27 -1
- data/lib/chef/event_dispatch/base.rb +3 -0
- data/lib/chef/event_dispatch/dispatcher.rb +5 -0
- data/lib/chef/event_dispatch/events_output_stream.rb +8 -0
- data/lib/chef/exceptions.rb +21 -1
- data/lib/chef/file_access_control/unix.rb +12 -12
- data/lib/chef/file_content_management/deploy/cp.rb +2 -2
- data/lib/chef/file_content_management/deploy/mv_unix.rb +4 -4
- data/lib/chef/file_content_management/deploy/mv_windows.rb +1 -1
- data/lib/chef/formatters/base.rb +7 -0
- data/lib/chef/formatters/error_inspectors/compile_error_inspector.rb +2 -2
- data/lib/chef/formatters/indentable_output_stream.rb +5 -0
- data/lib/chef/http.rb +19 -3
- data/lib/chef/http/decompressor.rb +2 -2
- data/lib/chef/json_compat.rb +1 -0
- data/lib/chef/knife.rb +16 -2
- data/lib/chef/knife/bootstrap.rb +55 -10
- data/lib/chef/knife/cookbook_site_install.rb +5 -1
- data/lib/chef/knife/core/bootstrap_context.rb +2 -1
- data/lib/chef/knife/core/node_presenter.rb +1 -1
- data/lib/chef/knife/ssh.rb +30 -16
- data/lib/chef/knife/ssl_check.rb +4 -2
- data/lib/chef/knife/ssl_fetch.rb +3 -2
- data/lib/chef/knife/status.rb +14 -1
- data/lib/chef/log.rb +14 -0
- data/lib/chef/mixin/get_source_from_package.rb +7 -2
- data/lib/chef/mixin/properties.rb +302 -0
- data/lib/chef/mixin/proxified_socket.rb +38 -0
- data/lib/chef/mixin/subclass_directive.rb +37 -0
- data/lib/chef/node.rb +13 -5
- data/lib/chef/platform/query_helpers.rb +14 -3
- data/lib/chef/platform/service_helpers.rb +20 -38
- data/lib/chef/policy_builder/expand_node_object.rb +3 -0
- data/lib/chef/policy_builder/policyfile.rb +1 -0
- data/lib/chef/property.rb +51 -12
- data/lib/chef/provider.rb +40 -35
- data/lib/chef/provider/deploy.rb +1 -1
- data/lib/chef/provider/dsc_resource.rb +54 -20
- data/lib/chef/provider/execute.rb +25 -4
- data/lib/chef/provider/group.rb +1 -1
- data/lib/chef/provider/lwrp_base.rb +1 -0
- data/lib/chef/provider/package.rb +76 -30
- data/lib/chef/provider/package/dpkg.rb +152 -69
- data/lib/chef/provider/package/openbsd.rb +6 -8
- data/lib/chef/provider/package/solaris.rb +2 -0
- data/lib/chef/provider/package/windows.rb +95 -14
- data/lib/chef/provider/package/windows/exe.rb +129 -0
- data/lib/chef/provider/package/windows/msi.rb +37 -13
- data/lib/chef/provider/package/windows/registry_uninstall_entry.rb +89 -0
- data/lib/chef/provider/package/yum.rb +13 -3
- data/lib/chef/provider/powershell_script.rb +3 -0
- data/lib/chef/provider/remote_file/cache_control_data.rb +37 -4
- data/lib/chef/provider/remote_file/http.rb +1 -1
- data/lib/chef/provider/script.rb +1 -0
- data/lib/chef/provider/service.rb +13 -10
- data/lib/chef/provider/service/solaris.rb +43 -17
- data/lib/chef/provider/service/upstart.rb +3 -3
- data/lib/chef/provider/user.rb +1 -1
- data/lib/chef/provider/user/dscl.rb +111 -100
- data/lib/chef/provider/user/windows.rb +5 -3
- data/lib/chef/recipe.rb +3 -5
- data/lib/chef/resource.rb +77 -320
- data/lib/chef/resource/action_class.rb +4 -0
- data/lib/chef/resource/dpkg_package.rb +4 -3
- data/lib/chef/resource/dsc_resource.rb +40 -2
- data/lib/chef/resource/execute.rb +9 -1
- data/lib/chef/resource/ksh.rb +32 -0
- data/lib/chef/resource/lwrp_base.rb +6 -10
- data/lib/chef/resource/package.rb +8 -9
- data/lib/chef/resource/registry_key.rb +1 -1
- data/lib/chef/resource/resource_notification.rb +14 -1
- data/lib/chef/resource/script.rb +1 -1
- data/lib/chef/resource/windows_package.rb +1 -1
- data/lib/chef/resource_builder.rb +14 -7
- data/lib/chef/resource_reporter.rb +6 -0
- data/lib/chef/resources.rb +1 -7
- data/lib/chef/rest.rb +1 -1
- data/lib/chef/run_context.rb +45 -2
- data/lib/chef/run_list/run_list_expansion.rb +47 -0
- data/lib/chef/runner.rb +25 -0
- data/lib/chef/search/query.rb +16 -2
- data/lib/chef/util/diff.rb +2 -2
- data/lib/chef/util/powershell/ps_credential.rb +2 -3
- data/lib/chef/version.rb +1 -1
- data/lib/chef/win32/api/file.rb +51 -1
- data/lib/chef/win32/file.rb +5 -0
- data/lib/chef/win32/file/version_info.rb +93 -0
- data/lib/chef/win32/mutex.rb +1 -1
- data/spec/data/apt/chef-integration-test2-1.0/debian/changelog +5 -0
- data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2.debhelper.log +45 -0
- data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2.substvars +1 -0
- data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/conffiles +1 -0
- data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/control +10 -0
- data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/md5sums +1 -0
- data/spec/data/apt/chef-integration-test2-1.0/debian/compat +1 -0
- data/spec/data/apt/chef-integration-test2-1.0/debian/conffiles +1 -0
- data/spec/data/apt/chef-integration-test2-1.0/debian/control +13 -0
- data/spec/data/apt/chef-integration-test2-1.0/debian/copyright +34 -0
- data/spec/data/apt/chef-integration-test2-1.0/debian/files +1 -0
- data/spec/data/apt/chef-integration-test2-1.0/debian/rules +13 -0
- data/spec/data/apt/chef-integration-test2-1.0/debian/source/format +1 -0
- data/spec/data/apt/chef-integration-test2_1.0-1.debian.tar.gz +0 -0
- data/spec/data/apt/chef-integration-test2_1.0-1.dsc +18 -0
- data/spec/data/apt/chef-integration-test2_1.0-1_amd64.build +91 -0
- data/spec/data/apt/chef-integration-test2_1.0-1_amd64.changes +31 -0
- data/spec/data/apt/chef-integration-test2_1.0-1_amd64.deb +0 -0
- data/spec/data/apt/chef-integration-test2_1.0.orig.tar.gz +0 -0
- data/spec/functional/application_spec.rb +1 -1
- data/spec/functional/audit/runner_spec.rb +4 -0
- data/spec/functional/knife/ssh_spec.rb +5 -5
- data/spec/functional/notifications_spec.rb +74 -4
- data/spec/functional/resource/aix_service_spec.rb +2 -2
- data/spec/functional/resource/dpkg_package_spec.rb +339 -0
- data/spec/functional/resource/ifconfig_spec.rb +3 -1
- data/spec/functional/resource/mount_spec.rb +5 -2
- data/spec/functional/resource/package_spec.rb +1 -1
- data/spec/functional/resource/user/windows_spec.rb +8 -0
- data/spec/functional/resource/windows_package_spec.rb +177 -0
- data/spec/functional/win32/version_info_spec.rb +50 -0
- data/spec/integration/client/client_spec.rb +80 -0
- data/spec/integration/knife/download_spec.rb +9 -0
- data/spec/integration/knife/upload_spec.rb +28 -1
- data/spec/integration/recipes/lwrp_inline_resources_spec.rb +93 -23
- data/spec/integration/recipes/resource_action_spec.rb +211 -116
- data/spec/integration/recipes/resource_converge_if_changed_spec.rb +72 -0
- data/spec/integration/solo/solo_spec.rb +34 -0
- data/spec/spec_helper.rb +11 -1
- data/spec/support/platform_helpers.rb +8 -0
- data/spec/support/shared/integration/integration_helper.rb +6 -0
- data/spec/support/shared/unit/execute_resource.rb +5 -0
- data/spec/support/shared/unit/platform_introspector.rb +7 -0
- data/spec/tiny_server.rb +6 -2
- data/spec/unit/api_client/registration_spec.rb +5 -4
- data/spec/unit/application_spec.rb +1 -181
- data/spec/unit/chef_fs/file_system/cookbook_subdir_spec.rb +34 -0
- data/spec/unit/cookbook/metadata_spec.rb +122 -2
- data/spec/unit/http_spec.rb +102 -0
- data/spec/unit/knife/bootstrap_spec.rb +55 -13
- data/spec/unit/knife/core/bootstrap_context_spec.rb +10 -3
- data/spec/unit/knife/ssl_check_spec.rb +7 -3
- data/spec/unit/knife/ssl_fetch_spec.rb +2 -2
- data/spec/unit/knife/status_spec.rb +13 -13
- data/spec/unit/knife_spec.rb +26 -2
- data/spec/unit/lwrp_spec.rb +1 -1
- data/spec/unit/mixin/properties_spec.rb +97 -0
- data/spec/unit/mixin/proxified_socket_spec.rb +94 -0
- data/spec/unit/mixin/subclass_directive_spec.rb +45 -0
- data/spec/unit/node_spec.rb +9 -1
- data/spec/unit/policy_builder/policyfile_spec.rb +2 -0
- data/spec/unit/property/validation_spec.rb +14 -12
- data/spec/unit/property_spec.rb +56 -0
- data/spec/unit/provider/deploy_spec.rb +1 -1
- data/spec/unit/provider/dsc_resource_spec.rb +63 -24
- data/spec/unit/provider/execute_spec.rb +95 -28
- data/spec/unit/provider/package/dpkg_spec.rb +185 -96
- data/spec/unit/provider/package/windows/exe_spec.rb +251 -0
- data/spec/unit/provider/package/windows/msi_spec.rb +94 -10
- data/spec/unit/provider/package/windows_spec.rb +227 -26
- data/spec/unit/provider/package/yum_spec.rb +6 -0
- data/spec/unit/provider/package_spec.rb +495 -366
- data/spec/unit/provider/remote_file/cache_control_data_spec.rb +62 -36
- data/spec/unit/provider/script_spec.rb +2 -2
- data/spec/unit/provider/service/solaris_smf_service_spec.rb +110 -39
- data/spec/unit/provider/service/upstart_service_spec.rb +19 -0
- data/spec/unit/provider/user/dscl_spec.rb +14 -0
- data/spec/unit/provider/user/windows_spec.rb +2 -2
- data/spec/unit/provider/user_spec.rb +9 -0
- data/spec/unit/provider_resolver_spec.rb +6 -30
- data/spec/unit/recipe_spec.rb +46 -20
- data/spec/unit/resource/chef_gem_spec.rb +1 -1
- data/spec/unit/resource/dsc_resource_spec.rb +14 -3
- data/spec/unit/resource/ksh_spec.rb +40 -0
- data/spec/unit/resource/registry_key_spec.rb +2 -2
- data/spec/unit/resource/resource_notification_spec.rb +44 -45
- data/spec/unit/resource_reporter_spec.rb +7 -0
- data/spec/unit/resource_spec.rb +268 -253
- data/spec/unit/rest_spec.rb +2 -2
- data/spec/unit/run_list/run_list_expansion_spec.rb +18 -3
- data/spec/unit/search/query_spec.rb +19 -1
- data/spec/unit/util/powershell/ps_credential_spec.rb +8 -1
- data/spec/unit/windows_service_spec.rb +83 -38
- data/tasks/external_tests.rb +19 -9
- data/tasks/rspec.rb +1 -1
- metadata +64 -15
- data/spec/support/pedant/Gemfile +0 -3
- data/spec/support/pedant/pedant_config.rb +0 -129
- data/spec/support/pedant/run_pedant.rb +0 -63
- data/spec/support/pedant/stickywicket.pem +0 -27
- data/spec/unit/provider/package_spec.rbe +0 -0
@@ -30,7 +30,7 @@ class Chef
|
|
30
30
|
Chef::Platform::ServiceHelpers.service_resource_providers.include?(:upstart)
|
31
31
|
end
|
32
32
|
|
33
|
-
UPSTART_STATE_FORMAT = /\
|
33
|
+
UPSTART_STATE_FORMAT = /\S+ \(?(start|stop)?\)? ?[\/ ](\w+)/
|
34
34
|
|
35
35
|
def self.supports?(resource, action)
|
36
36
|
Chef::Platform::ServiceHelpers.config_for_service(resource.service_name).include?(:upstart)
|
@@ -224,10 +224,10 @@ class Chef
|
|
224
224
|
command = "/sbin/status #{@job}"
|
225
225
|
status = popen4(command) do |pid, stdin, stdout, stderr|
|
226
226
|
stdout.each_line do |line|
|
227
|
-
# rsyslog stop/waiting
|
228
227
|
# service goal/state
|
229
228
|
# OR
|
230
|
-
#
|
229
|
+
# service (instance) goal/state
|
230
|
+
# OR
|
231
231
|
# service (goal) state
|
232
232
|
line =~ UPSTART_STATE_FORMAT
|
233
233
|
data = Regexp.last_match
|
data/lib/chef/provider/user.rb
CHANGED
@@ -89,7 +89,7 @@ class Chef
|
|
89
89
|
end
|
90
90
|
|
91
91
|
def define_resource_requirements
|
92
|
-
requirements.assert(:
|
92
|
+
requirements.assert(:create, :modify, :manage, :lock, :unlock) do |a|
|
93
93
|
a.assertion { @group_name_resolved }
|
94
94
|
a.failure_message Chef::Exceptions::User, "Couldn't lookup integer GID for group name #{@new_resource.gid}"
|
95
95
|
a.whyrun "group name #{@new_resource.gid} does not exist. This will cause group assignment to fail. Assuming this group will have been created previously."
|
@@ -44,6 +44,10 @@ class Chef
|
|
44
44
|
# This provider only supports Mac OSX versions 10.7 and above
|
45
45
|
class Dscl < Chef::Provider::User
|
46
46
|
|
47
|
+
attr_accessor :user_info
|
48
|
+
attr_accessor :authentication_authority
|
49
|
+
attr_accessor :password_shadow_conversion_algorithm
|
50
|
+
|
47
51
|
provides :user, os: "darwin"
|
48
52
|
|
49
53
|
def define_resource_requirements
|
@@ -56,19 +60,19 @@ class Chef
|
|
56
60
|
|
57
61
|
requirements.assert(:all_actions) do |a|
|
58
62
|
a.assertion { ::File.exists?("/usr/bin/dscl") }
|
59
|
-
a.failure_message(Chef::Exceptions::User, "Cannot find binary '/usr/bin/dscl' on the system for #{
|
63
|
+
a.failure_message(Chef::Exceptions::User, "Cannot find binary '/usr/bin/dscl' on the system for #{new_resource}!")
|
60
64
|
end
|
61
65
|
|
62
66
|
requirements.assert(:all_actions) do |a|
|
63
67
|
a.assertion { ::File.exists?("/usr/bin/plutil") }
|
64
|
-
a.failure_message(Chef::Exceptions::User, "Cannot find binary '/usr/bin/plutil' on the system for #{
|
68
|
+
a.failure_message(Chef::Exceptions::User, "Cannot find binary '/usr/bin/plutil' on the system for #{new_resource}!")
|
65
69
|
end
|
66
70
|
|
67
71
|
requirements.assert(:create, :modify, :manage) do |a|
|
68
72
|
a.assertion do
|
69
|
-
if
|
73
|
+
if new_resource.password && mac_osx_version_greater_than_10_7?
|
70
74
|
# SALTED-SHA512 password shadow hashes are not supported on 10.8 and above.
|
71
|
-
!salted_sha512?(
|
75
|
+
!salted_sha512?(new_resource.password)
|
72
76
|
else
|
73
77
|
true
|
74
78
|
end
|
@@ -80,10 +84,10 @@ in 'password', with the associated 'salt' and 'iterations'.")
|
|
80
84
|
|
81
85
|
requirements.assert(:create, :modify, :manage) do |a|
|
82
86
|
a.assertion do
|
83
|
-
if
|
87
|
+
if new_resource.password && mac_osx_version_greater_than_10_7? && salted_sha512_pbkdf2?(new_resource.password)
|
84
88
|
# salt and iterations should be specified when
|
85
89
|
# SALTED-SHA512-PBKDF2 password shadow hash is given
|
86
|
-
|
90
|
+
!new_resource.salt.nil? && !new_resource.iterations.nil?
|
87
91
|
else
|
88
92
|
true
|
89
93
|
end
|
@@ -94,9 +98,9 @@ in 'password', with the associated 'salt' and 'iterations'.")
|
|
94
98
|
|
95
99
|
requirements.assert(:create, :modify, :manage) do |a|
|
96
100
|
a.assertion do
|
97
|
-
if
|
101
|
+
if new_resource.password && !mac_osx_version_greater_than_10_7?
|
98
102
|
# On 10.7 SALTED-SHA512-PBKDF2 is not supported
|
99
|
-
!salted_sha512_pbkdf2?(
|
103
|
+
!salted_sha512_pbkdf2?(new_resource.password)
|
100
104
|
else
|
101
105
|
true
|
102
106
|
end
|
@@ -109,21 +113,21 @@ user password using shadow hash.")
|
|
109
113
|
end
|
110
114
|
|
111
115
|
def load_current_resource
|
112
|
-
@current_resource = Chef::Resource::User.new(
|
113
|
-
|
116
|
+
@current_resource = Chef::Resource::User.new(new_resource.username)
|
117
|
+
current_resource.username(new_resource.username)
|
114
118
|
|
115
119
|
@user_info = read_user_info
|
116
|
-
if
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
@authentication_authority = dscl_get(
|
123
|
-
|
124
|
-
if
|
120
|
+
if user_info
|
121
|
+
current_resource.uid(dscl_get(user_info, :uid))
|
122
|
+
current_resource.gid(dscl_get(user_info, :gid))
|
123
|
+
current_resource.home(dscl_get(user_info, :home))
|
124
|
+
current_resource.shell(dscl_get(user_info, :shell))
|
125
|
+
current_resource.comment(dscl_get(user_info, :comment))
|
126
|
+
@authentication_authority = dscl_get(user_info, :auth_authority)
|
127
|
+
|
128
|
+
if new_resource.password && dscl_get(user_info, :password) == "********"
|
125
129
|
# A password is set. Let's get the password information from shadow file
|
126
|
-
shadow_hash_binary = dscl_get(
|
130
|
+
shadow_hash_binary = dscl_get(user_info, :shadow_hash)
|
127
131
|
|
128
132
|
# Calling shell_out directly since we want to give an input stream
|
129
133
|
shadow_hash_xml = convert_binary_plist_to_xml(shadow_hash_binary.string)
|
@@ -132,26 +136,26 @@ user password using shadow hash.")
|
|
132
136
|
if shadow_hash["SALTED-SHA512"]
|
133
137
|
# Convert the shadow value from Base64 encoding to hex before consuming them
|
134
138
|
@password_shadow_conversion_algorithm = "SALTED-SHA512"
|
135
|
-
|
139
|
+
current_resource.password(shadow_hash["SALTED-SHA512"].string.unpack('H*').first)
|
136
140
|
elsif shadow_hash["SALTED-SHA512-PBKDF2"]
|
137
141
|
@password_shadow_conversion_algorithm = "SALTED-SHA512-PBKDF2"
|
138
142
|
# Convert the entropy from Base64 encoding to hex before consuming them
|
139
|
-
|
140
|
-
|
143
|
+
current_resource.password(shadow_hash["SALTED-SHA512-PBKDF2"]["entropy"].string.unpack('H*').first)
|
144
|
+
current_resource.iterations(shadow_hash["SALTED-SHA512-PBKDF2"]["iterations"])
|
141
145
|
# Convert the salt from Base64 encoding to hex before consuming them
|
142
|
-
|
146
|
+
current_resource.salt(shadow_hash["SALTED-SHA512-PBKDF2"]["salt"].string.unpack('H*').first)
|
143
147
|
else
|
144
148
|
raise(Chef::Exceptions::User,"Unknown shadow_hash format: #{shadow_hash.keys.join(' ')}")
|
145
149
|
end
|
146
150
|
end
|
147
151
|
|
148
|
-
convert_group_name if
|
152
|
+
convert_group_name if new_resource.gid
|
149
153
|
else
|
150
154
|
@user_exists = false
|
151
|
-
Chef::Log.debug("#{
|
155
|
+
Chef::Log.debug("#{new_resource} user does not exist")
|
152
156
|
end
|
153
157
|
|
154
|
-
|
158
|
+
current_resource
|
155
159
|
end
|
156
160
|
|
157
161
|
#
|
@@ -190,15 +194,16 @@ user password using shadow hash.")
|
|
190
194
|
# Create a user using dscl
|
191
195
|
#
|
192
196
|
def dscl_create_user
|
193
|
-
run_dscl("create /Users/#{
|
197
|
+
run_dscl("create /Users/#{new_resource.username}")
|
194
198
|
end
|
195
199
|
|
196
200
|
#
|
197
201
|
# Saves the specified Chef user `comment` into RealName attribute
|
198
|
-
# of Mac user.
|
202
|
+
# of Mac user. If `comment` is not specified, it takes `username` value.
|
199
203
|
#
|
200
204
|
def dscl_create_comment
|
201
|
-
|
205
|
+
comment = new_resource.comment || new_resource.username
|
206
|
+
run_dscl("create /Users/#{new_resource.username} RealName '#{comment}'")
|
202
207
|
end
|
203
208
|
|
204
209
|
#
|
@@ -207,13 +212,14 @@ user password using shadow hash.")
|
|
207
212
|
# from 200 if `system` is set, 500 otherwise.
|
208
213
|
#
|
209
214
|
def dscl_set_uid
|
210
|
-
|
215
|
+
# XXX: mutates the new resource
|
216
|
+
new_resource.uid(get_free_uid) if (new_resource.uid.nil? || new_resource.uid == '')
|
211
217
|
|
212
|
-
if uid_used?(
|
213
|
-
raise(Chef::Exceptions::RequestedUIDUnavailable, "uid #{
|
218
|
+
if uid_used?(new_resource.uid)
|
219
|
+
raise(Chef::Exceptions::RequestedUIDUnavailable, "uid #{new_resource.uid} is already in use")
|
214
220
|
end
|
215
221
|
|
216
|
-
run_dscl("create /Users/#{
|
222
|
+
run_dscl("create /Users/#{new_resource.username} UniqueID #{new_resource.uid}")
|
217
223
|
end
|
218
224
|
|
219
225
|
#
|
@@ -222,7 +228,7 @@ user password using shadow hash.")
|
|
222
228
|
#
|
223
229
|
def get_free_uid(search_limit=1000)
|
224
230
|
uid = nil
|
225
|
-
base_uid =
|
231
|
+
base_uid = new_resource.system ? 200 : 500
|
226
232
|
next_uid_guess = base_uid
|
227
233
|
users_uids = run_dscl("list /Users uid")
|
228
234
|
while(next_uid_guess < search_limit + base_uid)
|
@@ -248,7 +254,7 @@ user password using shadow hash.")
|
|
248
254
|
tmap
|
249
255
|
end
|
250
256
|
if uid_map[uid.to_s]
|
251
|
-
unless uid_map[uid.to_s] ==
|
257
|
+
unless uid_map[uid.to_s] == new_resource.username.to_s
|
252
258
|
return true
|
253
259
|
end
|
254
260
|
end
|
@@ -257,18 +263,23 @@ user password using shadow hash.")
|
|
257
263
|
|
258
264
|
#
|
259
265
|
# Sets the group id for the user using dscl. Fails if a group doesn't
|
260
|
-
# exist on the system with given group id.
|
266
|
+
# exist on the system with given group id. If `gid` is not specified, it
|
267
|
+
# sets a default Mac user group "staff", with id 20.
|
261
268
|
#
|
262
269
|
def dscl_set_gid
|
263
|
-
|
270
|
+
if new_resource.gid.nil?
|
271
|
+
# XXX: mutates the new resource
|
272
|
+
new_resource.gid(20)
|
273
|
+
elsif !new_resource.gid.to_s.match(/^\d+$/)
|
264
274
|
begin
|
265
|
-
possible_gid = run_dscl("read /Groups/#{
|
275
|
+
possible_gid = run_dscl("read /Groups/#{new_resource.gid} PrimaryGroupID").split(" ").last
|
266
276
|
rescue Chef::Exceptions::DsclCommandFailed => e
|
267
|
-
raise Chef::Exceptions::GroupIDNotFound.new("Group not found for #{
|
277
|
+
raise Chef::Exceptions::GroupIDNotFound.new("Group not found for #{new_resource.gid} when creating user #{new_resource.username}")
|
268
278
|
end
|
269
|
-
|
279
|
+
# XXX: mutates the new resource
|
280
|
+
new_resource.gid(possible_gid) if possible_gid && possible_gid.match(/^\d+$/)
|
270
281
|
end
|
271
|
-
run_dscl("create /Users/#{
|
282
|
+
run_dscl("create /Users/#{new_resource.username} PrimaryGroupID '#{new_resource.gid}'")
|
272
283
|
end
|
273
284
|
|
274
285
|
#
|
@@ -276,15 +287,15 @@ user password using shadow hash.")
|
|
276
287
|
# directory is managed (moved / created) for the user.
|
277
288
|
#
|
278
289
|
def dscl_set_home
|
279
|
-
if
|
280
|
-
run_dscl("delete /Users/#{
|
290
|
+
if new_resource.home.nil? || new_resource.home.empty?
|
291
|
+
run_dscl("delete /Users/#{new_resource.username} NFSHomeDirectory")
|
281
292
|
return
|
282
293
|
end
|
283
294
|
|
284
|
-
if
|
295
|
+
if new_resource.supports[:manage_home]
|
285
296
|
validate_home_dir_specification!
|
286
297
|
|
287
|
-
if (
|
298
|
+
if (current_resource.home == new_resource.home) && !new_home_exists?
|
288
299
|
ditto_home
|
289
300
|
elsif !current_home_exists? && !new_home_exists?
|
290
301
|
ditto_home
|
@@ -292,49 +303,49 @@ user password using shadow hash.")
|
|
292
303
|
move_home
|
293
304
|
end
|
294
305
|
end
|
295
|
-
run_dscl("create /Users/#{
|
306
|
+
run_dscl("create /Users/#{new_resource.username} NFSHomeDirectory '#{new_resource.home}'")
|
296
307
|
end
|
297
308
|
|
298
309
|
def validate_home_dir_specification!
|
299
|
-
unless
|
300
|
-
raise(Chef::Exceptions::InvalidHomeDirectory,"invalid path spec for User: '#{
|
310
|
+
unless new_resource.home =~ /^\//
|
311
|
+
raise(Chef::Exceptions::InvalidHomeDirectory,"invalid path spec for User: '#{new_resource.username}', home directory: '#{new_resource.home}'")
|
301
312
|
end
|
302
313
|
end
|
303
314
|
|
304
315
|
def current_home_exists?
|
305
|
-
::File.exist?("#{
|
316
|
+
::File.exist?("#{current_resource.home}")
|
306
317
|
end
|
307
318
|
|
308
319
|
def new_home_exists?
|
309
|
-
::File.exist?("#{
|
320
|
+
::File.exist?("#{new_resource.home}")
|
310
321
|
end
|
311
322
|
|
312
323
|
def ditto_home
|
313
324
|
skel = "/System/Library/User Template/English.lproj"
|
314
325
|
raise(Chef::Exceptions::User,"can't find skel at: #{skel}") unless ::File.exists?(skel)
|
315
|
-
shell_out! "ditto '#{skel}' '#{
|
316
|
-
::FileUtils.chown_R(
|
326
|
+
shell_out! "ditto '#{skel}' '#{new_resource.home}'"
|
327
|
+
::FileUtils.chown_R(new_resource.username,new_resource.gid.to_s,new_resource.home)
|
317
328
|
end
|
318
329
|
|
319
330
|
def move_home
|
320
|
-
Chef::Log.debug("#{
|
331
|
+
Chef::Log.debug("#{new_resource} moving #{self} home from #{current_resource.home} to #{new_resource.home}")
|
321
332
|
|
322
|
-
src =
|
323
|
-
FileUtils.mkdir_p(
|
333
|
+
src = current_resource.home
|
334
|
+
FileUtils.mkdir_p(new_resource.home)
|
324
335
|
files = ::Dir.glob("#{Chef::Util::PathHelper.escape_glob(src)}/*", ::File::FNM_DOTMATCH) - ["#{src}/.","#{src}/.."]
|
325
|
-
::FileUtils.mv(files
|
336
|
+
::FileUtils.mv(files,new_resource.home, :force => true)
|
326
337
|
::FileUtils.rmdir(src)
|
327
|
-
::FileUtils.chown_R(
|
338
|
+
::FileUtils.chown_R(new_resource.username,new_resource.gid.to_s,new_resource.home)
|
328
339
|
end
|
329
340
|
|
330
341
|
#
|
331
342
|
# Sets the shell for the user using dscl.
|
332
343
|
#
|
333
344
|
def dscl_set_shell
|
334
|
-
if
|
335
|
-
run_dscl("create /Users/#{
|
345
|
+
if new_resource.shell || ::File.exists?("#{new_resource.shell}")
|
346
|
+
run_dscl("create /Users/#{new_resource.username} UserShell '#{new_resource.shell}'")
|
336
347
|
else
|
337
|
-
run_dscl("create /Users/#{
|
348
|
+
run_dscl("create /Users/#{new_resource.username} UserShell '/usr/bin/false'")
|
338
349
|
end
|
339
350
|
end
|
340
351
|
|
@@ -345,7 +356,7 @@ user password using shadow hash.")
|
|
345
356
|
#
|
346
357
|
def set_password
|
347
358
|
# Return if there is no password to set
|
348
|
-
return if
|
359
|
+
return if new_resource.password.nil?
|
349
360
|
|
350
361
|
shadow_info = prepare_password_shadow_info
|
351
362
|
|
@@ -355,7 +366,7 @@ user password using shadow hash.")
|
|
355
366
|
:input => shadow_info.to_plist, :live_stream => shadow_info_binary)
|
356
367
|
command.run_command
|
357
368
|
|
358
|
-
if
|
369
|
+
if user_info.nil?
|
359
370
|
# User is just created. read_user_info() will read the fresh information
|
360
371
|
# for the user with a cache flush. However with experimentation we've seen
|
361
372
|
# that dscl cache is not immediately updated after the creation of the user
|
@@ -365,8 +376,8 @@ user password using shadow hash.")
|
|
365
376
|
end
|
366
377
|
|
367
378
|
# Replace the shadow info in user's plist
|
368
|
-
dscl_set(
|
369
|
-
save_user_info(
|
379
|
+
dscl_set(user_info, :shadow_hash, shadow_info_binary)
|
380
|
+
save_user_info(user_info)
|
370
381
|
end
|
371
382
|
|
372
383
|
#
|
@@ -379,12 +390,12 @@ user password using shadow hash.")
|
|
379
390
|
iterations = nil
|
380
391
|
|
381
392
|
if mac_osx_version_10_7?
|
382
|
-
hash_value = if salted_sha512?(
|
383
|
-
|
393
|
+
hash_value = if salted_sha512?(new_resource.password)
|
394
|
+
new_resource.password
|
384
395
|
else
|
385
396
|
# Create a random 4 byte salt
|
386
397
|
salt = OpenSSL::Random.random_bytes(4)
|
387
|
-
encoded_password = OpenSSL::Digest::SHA512.hexdigest(salt +
|
398
|
+
encoded_password = OpenSSL::Digest::SHA512.hexdigest(salt + new_resource.password)
|
388
399
|
hash_value = salt.unpack('H*').first + encoded_password
|
389
400
|
end
|
390
401
|
|
@@ -392,16 +403,16 @@ user password using shadow hash.")
|
|
392
403
|
shadow_info["SALTED-SHA512"].string = convert_to_binary(hash_value)
|
393
404
|
shadow_info
|
394
405
|
else
|
395
|
-
if salted_sha512_pbkdf2?(
|
396
|
-
entropy = convert_to_binary(
|
397
|
-
salt = convert_to_binary(
|
398
|
-
iterations =
|
406
|
+
if salted_sha512_pbkdf2?(new_resource.password)
|
407
|
+
entropy = convert_to_binary(new_resource.password)
|
408
|
+
salt = convert_to_binary(new_resource.salt)
|
409
|
+
iterations = new_resource.iterations
|
399
410
|
else
|
400
411
|
salt = OpenSSL::Random.random_bytes(32)
|
401
|
-
iterations =
|
412
|
+
iterations = new_resource.iterations # Use the default if not specified by the user
|
402
413
|
|
403
414
|
entropy = OpenSSL::PKCS5::pbkdf2_hmac(
|
404
|
-
|
415
|
+
new_resource.password,
|
405
416
|
salt,
|
406
417
|
iterations,
|
407
418
|
128,
|
@@ -427,43 +438,43 @@ user password using shadow hash.")
|
|
427
438
|
# and deleting home directory if needed.
|
428
439
|
#
|
429
440
|
def remove_user
|
430
|
-
if
|
441
|
+
if new_resource.supports[:manage_home]
|
431
442
|
# Remove home directory
|
432
|
-
FileUtils.rm_rf(
|
443
|
+
FileUtils.rm_rf(current_resource.home)
|
433
444
|
end
|
434
445
|
|
435
446
|
# Remove the user from its groups
|
436
447
|
run_dscl("list /Groups").each_line do |group|
|
437
448
|
if member_of_group?(group.chomp)
|
438
|
-
run_dscl("delete /Groups/#{group.chomp} GroupMembership '#{
|
449
|
+
run_dscl("delete /Groups/#{group.chomp} GroupMembership '#{new_resource.username}'")
|
439
450
|
end
|
440
451
|
end
|
441
452
|
|
442
453
|
# Remove user account
|
443
|
-
run_dscl("delete /Users/#{
|
454
|
+
run_dscl("delete /Users/#{new_resource.username}")
|
444
455
|
end
|
445
456
|
|
446
457
|
#
|
447
458
|
# Locks the user.
|
448
459
|
#
|
449
460
|
def lock_user
|
450
|
-
run_dscl("append /Users/#{
|
461
|
+
run_dscl("append /Users/#{new_resource.username} AuthenticationAuthority ';DisabledUser;'")
|
451
462
|
end
|
452
463
|
|
453
464
|
#
|
454
465
|
# Unlocks the user
|
455
466
|
#
|
456
467
|
def unlock_user
|
457
|
-
auth_string =
|
458
|
-
run_dscl("create /Users/#{
|
468
|
+
auth_string = authentication_authority.gsub(/AuthenticationAuthority: /,"").gsub(/;DisabledUser;/,"").strip
|
469
|
+
run_dscl("create /Users/#{new_resource.username} AuthenticationAuthority '#{auth_string}'")
|
459
470
|
end
|
460
471
|
|
461
472
|
#
|
462
473
|
# Returns true if the user is locked, false otherwise.
|
463
474
|
#
|
464
475
|
def locked?
|
465
|
-
if
|
466
|
-
!!(
|
476
|
+
if authentication_authority
|
477
|
+
!!(authentication_authority =~ /DisabledUser/ )
|
467
478
|
else
|
468
479
|
false
|
469
480
|
end
|
@@ -485,11 +496,11 @@ user password using shadow hash.")
|
|
485
496
|
# given attribute.
|
486
497
|
#
|
487
498
|
def diverged?(parameter)
|
488
|
-
parameter_updated?(parameter) && (not
|
499
|
+
parameter_updated?(parameter) && (not new_resource.send(parameter).nil?)
|
489
500
|
end
|
490
501
|
|
491
502
|
def parameter_updated?(parameter)
|
492
|
-
not (
|
503
|
+
not (new_resource.send(parameter) == current_resource.send(parameter))
|
493
504
|
end
|
494
505
|
|
495
506
|
#
|
@@ -500,11 +511,11 @@ user password using shadow hash.")
|
|
500
511
|
# type of the password specified.
|
501
512
|
#
|
502
513
|
def diverged_password?
|
503
|
-
return false if
|
514
|
+
return false if new_resource.password.nil?
|
504
515
|
|
505
516
|
# Dscl provider supports both plain text passwords and shadow hashes.
|
506
517
|
if mac_osx_version_10_7?
|
507
|
-
if salted_sha512?(
|
518
|
+
if salted_sha512?(new_resource.password)
|
508
519
|
diverged?(:password)
|
509
520
|
else
|
510
521
|
!salted_sha512_password_match?
|
@@ -514,14 +525,14 @@ user password using shadow hash.")
|
|
514
525
|
# will be updated when the user logs in. So it's possible that we will have
|
515
526
|
# SALTED-SHA512 password in the current_resource. In that case we will force
|
516
527
|
# password to be updated.
|
517
|
-
return true if salted_sha512?(
|
528
|
+
return true if salted_sha512?(current_resource.password)
|
518
529
|
|
519
530
|
# Some system users don't have salts; this can happen if the system is
|
520
531
|
# upgraded and the user hasn't logged in yet. In this case, we will force
|
521
532
|
# the password to be updated.
|
522
|
-
return true if
|
533
|
+
return true if current_resource.salt.nil?
|
523
534
|
|
524
|
-
if salted_sha512_pbkdf2?(
|
535
|
+
if salted_sha512_pbkdf2?(new_resource.password)
|
525
536
|
diverged?(:password) || diverged?(:salt) || diverged?(:iterations)
|
526
537
|
else
|
527
538
|
!salted_sha512_pbkdf2_password_match?
|
@@ -543,7 +554,7 @@ user password using shadow hash.")
|
|
543
554
|
# GroupMembership: root admin etc
|
544
555
|
members = membership_info.split(" ")
|
545
556
|
members.shift # Get rid of GroupMembership: string
|
546
|
-
members.include?(
|
557
|
+
members.include?(new_resource.username)
|
547
558
|
end
|
548
559
|
|
549
560
|
#
|
@@ -577,7 +588,7 @@ user password using shadow hash.")
|
|
577
588
|
shell_out("dscacheutil '-flushcache'")
|
578
589
|
|
579
590
|
begin
|
580
|
-
user_plist_file = "#{USER_PLIST_DIRECTORY}/#{
|
591
|
+
user_plist_file = "#{USER_PLIST_DIRECTORY}/#{new_resource.username}.plist"
|
581
592
|
user_plist_info = run_plutil("convert xml1 -o - #{user_plist_file}")
|
582
593
|
user_info = Plist::parse_xml(user_plist_info)
|
583
594
|
rescue Chef::Exceptions::PlistUtilCommandFailed
|
@@ -591,7 +602,7 @@ user password using shadow hash.")
|
|
591
602
|
# in DSCL_PROPERTY_MAP to the disk.
|
592
603
|
#
|
593
604
|
def save_user_info(user_info)
|
594
|
-
user_plist_file = "#{USER_PLIST_DIRECTORY}/#{
|
605
|
+
user_plist_file = "#{USER_PLIST_DIRECTORY}/#{new_resource.username}.plist"
|
595
606
|
Plist::Emit.save_plist(user_info, user_plist_file)
|
596
607
|
run_plutil("convert binary1 #{user_plist_file}")
|
597
608
|
end
|
@@ -673,9 +684,9 @@ user password using shadow hash.")
|
|
673
684
|
|
674
685
|
def salted_sha512_password_match?
|
675
686
|
# Salt is included in the first 4 bytes of shadow data
|
676
|
-
salt =
|
677
|
-
shadow = OpenSSL::Digest::SHA512.hexdigest(convert_to_binary(salt) +
|
678
|
-
|
687
|
+
salt = current_resource.password.slice(0,8)
|
688
|
+
shadow = OpenSSL::Digest::SHA512.hexdigest(convert_to_binary(salt) + new_resource.password)
|
689
|
+
current_resource.password == salt + shadow
|
679
690
|
end
|
680
691
|
|
681
692
|
def salted_sha512_pbkdf2?(string)
|
@@ -683,15 +694,15 @@ user password using shadow hash.")
|
|
683
694
|
end
|
684
695
|
|
685
696
|
def salted_sha512_pbkdf2_password_match?
|
686
|
-
salt = convert_to_binary(
|
697
|
+
salt = convert_to_binary(current_resource.salt)
|
687
698
|
|
688
699
|
OpenSSL::PKCS5::pbkdf2_hmac(
|
689
|
-
|
700
|
+
new_resource.password,
|
690
701
|
salt,
|
691
|
-
|
702
|
+
current_resource.iterations,
|
692
703
|
128,
|
693
704
|
OpenSSL::Digest::SHA512.new
|
694
|
-
).unpack('H*').first ==
|
705
|
+
).unpack('H*').first == current_resource.password
|
695
706
|
end
|
696
707
|
|
697
708
|
end
|