chef 18.1.0 → 18.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +0 -3
  3. data/chef-universal-mingw-ucrt.gemspec +2 -2
  4. data/chef.gemspec +1 -1
  5. data/lib/chef/application/base.rb +18 -2
  6. data/lib/chef/client.rb +23 -6
  7. data/lib/chef/http/authenticator.rb +117 -34
  8. data/lib/chef/platform/query_helpers.rb +4 -2
  9. data/lib/chef/resource/apt_repository.rb +20 -2
  10. data/lib/chef/resource/bash.rb +13 -0
  11. data/lib/chef/resource/dsc_script.rb +1 -1
  12. data/lib/chef/resource/launchd.rb +2 -2
  13. data/lib/chef/resource/macos_userdefaults.rb +9 -5
  14. data/lib/chef/resource/rhsm_register.rb +1 -1
  15. data/lib/chef/resource/selinux_fcontext.rb +1 -1
  16. data/lib/chef/resource/selinux_login.rb +129 -0
  17. data/lib/chef/resource/selinux_permissive.rb +1 -1
  18. data/lib/chef/resource/selinux_port.rb +1 -1
  19. data/lib/chef/resource/selinux_state.rb +1 -1
  20. data/lib/chef/resource/selinux_user.rb +137 -0
  21. data/lib/chef/resource/service.rb +1 -1
  22. data/lib/chef/resource/user.rb +2 -2
  23. data/lib/chef/resource/windows_user_privilege.rb +14 -10
  24. data/lib/chef/resources.rb +2 -0
  25. data/lib/chef/version.rb +1 -1
  26. data/spec/data/trusted_certs/intermediate.pem +38 -27
  27. data/spec/data/trusted_certs/opscode.pem +33 -54
  28. data/spec/functional/resource/macos_userdefaults_spec.rb +4 -4
  29. data/spec/integration/client/client_spec.rb +22 -16
  30. data/spec/spec_helper.rb +3 -3
  31. data/spec/unit/client_spec.rb +26 -2
  32. data/spec/unit/compliance/runner_spec.rb +8 -0
  33. data/spec/unit/http/authenticator_spec.rb +64 -11
  34. data/spec/unit/provider/apt_repository_spec.rb +26 -5
  35. data/spec/unit/resource/macos_user_defaults_spec.rb +4 -4
  36. data/spec/unit/resource/selinux_login_spec.rb +73 -0
  37. data/spec/unit/resource/selinux_user_spec.rb +92 -0
  38. metadata +17 -16
  39. data/lib/chef/powershell.rb +0 -81
  40. data/spec/data/chef_guid +0 -1
  41. data/spec/data/nodes/mcwfhpowell.json +0 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2116a9a16e93030ed9aa85235426085567d3ef63e0c603bffa3a5a1614bb439e
4
- data.tar.gz: cc9dcbc47ddcb72e3fe920f9da13a788a607b66d628331b23a03ea8dbad53c30
3
+ metadata.gz: ae48a568217d00b159123bf621bdaee21412909ef553f400719f251559c8a4d4
4
+ data.tar.gz: 553c80d44e9babb553588b0d01beac0a413aec6b0d21fdbaaf754cc1b3fa0928
5
5
  SHA512:
6
- metadata.gz: d14c879526c8da207c572690f7e5c0a066c8ff89d33412053f6eaf3635ae2231d1f0c2c3478b1ebae30219ac0cbf86ee8c2381239eda50b937f853c2b7a77028
7
- data.tar.gz: 1bfb25d57117e4cc93655ab55573cebcffd9854402a59606f79e5a6e05bc8660d18c2ccc85d2a09c007789509dd23abee90a1a3d26a07bc6d93ba8fff12d0b58
6
+ metadata.gz: 3b2df041625cd266ae86c1a899c69493190f09018714cf281486291958268a669d65103555b63f0104345b5e281248d9bf7a2157a2de3632d92f84b4ed72c99c
7
+ data.tar.gz: 54b4391ec722faa770d54b7d5c6650285ab3dfdb933eed86938d579fb92b1501ad4bf3848e3f17950316eb5c8d9bc2bc99e044368246940321b10f3ddaaa1e97
data/Gemfile CHANGED
@@ -37,9 +37,6 @@ group(:omnibus_package, :pry) do
37
37
  gem "pry-stack_explorer"
38
38
  end
39
39
 
40
- # proxifier gem is busted on ruby 3.1 and seems abandoned so use git fork of gem
41
- gem "proxifier", git: "https://github.com/chef/ruby-proxifier", branch: "lcg/ruby-3"
42
-
43
40
  # Everything except AIX and Windows
44
41
  group(:ruby_shadow) do
45
42
  # if ruby-shadow does a release that supports ruby-3.0 this can be removed
@@ -15,9 +15,9 @@ gemspec.add_dependency "wmi-lite", "~> 1.0"
15
15
  gemspec.add_dependency "win32-taskscheduler", "~> 2.0"
16
16
  gemspec.add_dependency "iso8601", ">= 0.12.1", "< 0.14" # validate 0.14 when it comes out
17
17
  gemspec.add_dependency "win32-certstore", "~> 0.6.15" # 0.5+ required for specifying user vs. system store
18
- gemspec.add_dependency "chef-powershell", "~> 1.0.12" # The guts of the powershell_exec code have been moved to its own gem, chef-powershell. It's part of the chef-powershell-shim repo.
18
+ gemspec.add_dependency "chef-powershell", "~> 18.0.0" # The guts of the powershell_exec code have been moved to its own gem, chef-powershell. It's part of the chef-powershell-shim repo.
19
19
 
20
20
  gemspec.extensions << "ext/win32-eventlog/Rakefile"
21
21
  gemspec.files += Dir.glob("{distro,ext}/**/*")
22
22
 
23
- gemspec
23
+ gemspec
data/chef.gemspec CHANGED
@@ -61,7 +61,7 @@ Gem::Specification.new do |s|
61
61
  s.add_dependency "unf_ext", ">= 0.0.8.2" # This is ruby31 compatible ucrt gem version
62
62
  s.add_dependency "corefoundation", "~> 0.3.4" # macos_userdefaults resource
63
63
 
64
- s.add_dependency "proxifier", "~> 1.0"
64
+ s.add_dependency "proxifier2", "~> 1.1"
65
65
 
66
66
  s.add_dependency "aws-sdk-s3", "~> 1.91" # s3 recipe-url support
67
67
  s.add_dependency "aws-sdk-secretsmanager", "~> 1.46"
@@ -386,8 +386,10 @@ class Chef::Application::Base < Chef::Application
386
386
  elsif uri.scheme == "s3"
387
387
  require "aws-sdk-s3" unless defined?(Aws::S3)
388
388
 
389
- s3 = Aws::S3::Client.new
390
- object = s3.get_object(bucket: uri.hostname, key: uri.path[1..-1])
389
+ bucket_name = uri.hostname
390
+ s3 = Aws::S3::Client.new(region: s3_bucket_location(bucket_name))
391
+
392
+ object = s3.get_object(bucket: bucket_name, key: uri.path[1..-1])
391
393
  File.open(path, "wb") do |f|
392
394
  f.write(object.body.read)
393
395
  end
@@ -403,6 +405,20 @@ class Chef::Application::Base < Chef::Application
403
405
  end
404
406
  end
405
407
 
408
+ def s3_bucket_location(bucket_name)
409
+ s3 = Aws::S3::Client.new(region: aws_api_region)
410
+
411
+ resp = s3.get_bucket_location(bucket: bucket_name)
412
+ resp.location_constraint
413
+ rescue Aws::S3::Errors::AccessDenied => _e
414
+ Chef::Log.warn("Missing s3:GetBucketLocation privilege, trying currently configured region #{aws_api_region}")
415
+ aws_api_region
416
+ end
417
+
418
+ def aws_api_region
419
+ ENV["AWS_REGION"] || Aws.shared_config.region || Aws::EC2Metadata.new.get("/latest/meta-data/placement/region")
420
+ end
421
+
406
422
  def interval_run_chef_client
407
423
  if Chef::Config[:daemonize]
408
424
  Chef::Daemon.daemonize(ChefUtils::Dist::Infra::PRODUCT)
data/lib/chef/client.rb CHANGED
@@ -66,6 +66,15 @@ class Chef
66
66
  class Client
67
67
  CRYPT_EXPORTABLE = 0x00000001
68
68
 
69
+ # adding these
70
+ # certstore 65536 == 0x00010000 == CurrentUser
71
+ # certstore 131072 == 0x00020000 == LocalMachine
72
+ # Reference: https://github.com/chef/win32-certstore/blob/main/lib/win32/certstore/mixin/crypto.rb#L90
73
+ CERT_SYSTEM_STORE_LOCAL_MACHINE = 0x00020000
74
+ CERT_SYSTEM_STORE_CURRENT_USER = 0x00010000
75
+ CERT_SYSTEM_STORE_SERVICES = 0x00050000
76
+ CERT_SYSTEM_STORE_USERS = 0x00060000
77
+
69
78
  attr_reader :local_context
70
79
 
71
80
  extend Chef::Mixin::Deprecation
@@ -674,9 +683,15 @@ class Chef
674
683
 
675
684
  # In the brave new world of No Certs On Disk, we want to put the pem file into Keychain or the Certstore
676
685
  # But is it already there?
686
+ # We're solving the multi-user scenario where both a system/admin user can run on the box but also someone without
687
+ # admin rights can also run correctly locally.
677
688
  def check_certstore_for_key(cert_name)
678
689
  require "win32-certstore"
679
- win32certstore = ::Win32::Certstore.open("MY")
690
+ if Chef::Config[:auth_key_registry_type] == "user"
691
+ win32certstore = ::Win32::Certstore.open("MY", store_location: CERT_SYSTEM_STORE_CURRENT_USER)
692
+ else
693
+ win32certstore = ::Win32::Certstore.open("MY")
694
+ end
680
695
  win32certstore.search("#{cert_name}")
681
696
  end
682
697
 
@@ -783,8 +798,6 @@ class Chef
783
798
  require "time" unless defined?(Time)
784
799
  autoload :URI, "uri"
785
800
 
786
- # KeyMigration.instance.key_migrated = true
787
-
788
801
  node = Chef::Config[:node_name]
789
802
  d = Time.now
790
803
  if d.month == 10 || d.month == 11 || d.month == 12
@@ -818,9 +831,13 @@ class Chef
818
831
  require "win32-certstore"
819
832
  tempfile = Tempfile.new("#{Chef::Config[:node_name]}.pfx")
820
833
  File.open(tempfile, "wb") { |f| f.print new_pfx.to_der }
821
-
822
- store = ::Win32::Certstore.open("MY")
823
- store.add_pfx(tempfile, password, CRYPT_EXPORTABLE)
834
+ # Need to determine where to store the key
835
+ if Chef::Config[:auth_key_registry_type] == "user"
836
+ win32certstore = ::Win32::Certstore.open("MY", store_location: CERT_SYSTEM_STORE_CURRENT_USER)
837
+ else
838
+ win32certstore = ::Win32::Certstore.open("MY")
839
+ end
840
+ win32certstore.add_pfx(tempfile, password, CRYPT_EXPORTABLE)
824
841
  tempfile.unlink
825
842
  end
826
843
 
@@ -102,12 +102,12 @@ class Chef
102
102
  self.class.get_cert_password
103
103
  end
104
104
 
105
- def encrypt_pfx_pass
106
- self.class.encrypt_pfx_pass
105
+ def encrypt_pfx_pass_with_vector
106
+ self.class.encrypt_pfx_pass_with_vector
107
107
  end
108
108
 
109
- def decrypt_pfx_pass
110
- self.class.decrypt_pfx_pass
109
+ def decrypt_pfx_pass_with_vector
110
+ self.class.decrypt_pfx_pass_with_vector
111
111
  end
112
112
 
113
113
  # Detects if a private key exists in a certificate repository like Keychain (macOS) or Certificate Store (Windows)
@@ -123,9 +123,18 @@ class Chef
123
123
  end
124
124
  end
125
125
 
126
+ def self.get_cert_user
127
+ Chef::Config[:auth_key_registry_type] == "user" ? "CurrentUser" : "LocalMachine"
128
+ end
129
+
130
+ def self.get_registry_user
131
+ Chef::Config[:auth_key_registry_type] == "user" ? "HKEY_CURRENT_USER" : "HKEY_LOCAL_MACHINE"
132
+ end
133
+
126
134
  def self.check_certstore_for_key(client_name)
135
+ store = get_cert_user
127
136
  powershell_code = <<~CODE
128
- $cert = Get-ChildItem -path cert:\\LocalMachine\\My -Recurse -Force | Where-Object { $_.Subject -Match "chef-#{client_name}" } -ErrorAction Stop
137
+ $cert = Get-ChildItem -path cert:\\#{store}\\My -Recurse -Force | Where-Object { $_.Subject -Match "chef-#{client_name}" } -ErrorAction Stop
129
138
  if (($cert.HasPrivateKey -eq $true) -and ($cert.PrivateKey.Key.ExportPolicy -ne "NonExportable")) {
130
139
  return $true
131
140
  }
@@ -164,49 +173,86 @@ class Chef
164
173
  end
165
174
 
166
175
  def self.get_cert_password
176
+ store = get_registry_user
167
177
  @win32registry = Chef::Win32::Registry.new
168
- path = "HKEY_LOCAL_MACHINE\\Software\\Progress\\Authentication"
178
+ path = "#{store}\\Software\\Progress\\Authentication"
169
179
  # does the registry key even exist?
170
- present = @win32registry.get_values(path)
171
- if present.nil? || present.empty?
180
+ # password_blob should be an array of hashes
181
+ password_blob = @win32registry.get_values(path)
182
+ if password_blob.nil? || password_blob.empty?
172
183
  raise Chef::Exceptions::Win32RegKeyMissing
173
184
  end
174
185
 
175
- present.each do |secret|
176
- if secret[:name] == "PfxPass"
177
- password = decrypt_pfx_pass(secret[:data])
178
- return password
186
+ # Did someone have just the password stored in the registry?
187
+ raw_data = password_blob.map { |x| x[:data] }
188
+ vector = raw_data[2]
189
+ if !!vector
190
+ decrypted_password = decrypt_pfx_pass_with_vector(password_blob)
191
+ else
192
+ decrypted_password = decrypt_pfx_pass_with_password(password_blob)
193
+ if !!decrypted_password
194
+ migrate_pass_to_use_vector(decrypted_password)
195
+ else
196
+ Chef::Log.error("Failed to retrieve certificate password")
179
197
  end
180
198
  end
181
-
182
- raise Chef::Exceptions::Win32RegKeyMissing
183
-
199
+ decrypted_password
184
200
  rescue Chef::Exceptions::Win32RegKeyMissing
185
201
  # if we don't have a password, log that and generate one
186
- Chef::Log.warn "Authentication Hive and values not present in registry, creating them now"
187
- new_path = "HKEY_LOCAL_MACHINE\\Software\\Progress\\Authentication"
202
+ store = get_registry_user
203
+ new_path = "#{store}\\Software\\Progress\\Authentication"
188
204
  unless @win32registry.key_exists?(new_path)
189
205
  @win32registry.create_key(new_path, true)
190
206
  end
191
- require "securerandom" unless defined?(SecureRandom)
192
- size = 14
193
- password = SecureRandom.alphanumeric(size)
194
- encrypted_pass = encrypt_pfx_pass(password)
195
- values = { name: "PfxPass", type: :string, data: encrypted_pass }
196
- @win32registry.set_value(new_path, values)
197
- password
207
+ create_and_store_new_password
198
208
  end
199
209
 
200
- def self.encrypt_pfx_pass(password)
210
+ def self.encrypt_pfx_pass_with_vector(password)
201
211
  powershell_code = <<~CODE
202
- $encrypted_string = ConvertTo-SecureString "#{password}" -AsPlainText -Force
203
- $secure_string = ConvertFrom-SecureString $encrypted_string
204
- return $secure_string
212
+ $AES = [System.Security.Cryptography.Aes]::Create()
213
+ $key_temp = [System.Convert]::ToBase64String($AES.Key)
214
+ $iv_temp = [System.Convert]::ToBase64String($AES.IV)
215
+ $encryptor = $AES.CreateEncryptor()
216
+ [System.Byte[]]$Bytes = [System.Text.Encoding]::Unicode.GetBytes("#{password}")
217
+ $EncryptedBytes = $encryptor.TransformFinalBlock($Bytes,0,$Bytes.Length)
218
+ $EncryptedBase64String = [System.Convert]::ToBase64String($EncryptedBytes)
219
+ # create array of encrypted pass, key, iv
220
+ $password_blob = @($EncryptedBase64String, $key_temp, $iv_temp)
221
+ return $password_blob
205
222
  CODE
206
223
  powershell_exec!(powershell_code).result
207
224
  end
208
225
 
209
- def self.decrypt_pfx_pass(password)
226
+ def self.decrypt_pfx_pass_with_vector(password_blob)
227
+ raw_data = password_blob.map { |x| x[:data] }
228
+ password = raw_data[0]
229
+ key = raw_data[1]
230
+ vector = raw_data[2]
231
+
232
+ powershell_code = <<~CODE
233
+ $KeyBytes = [System.Convert]::FromBase64String("#{key}")
234
+ $IVBytes = [System.Convert]::FromBase64String("#{vector}")
235
+ $aes = [System.Security.Cryptography.Aes]::Create()
236
+ $aes.Key = $KeyBytes
237
+ $aes.IV = $IVBytes
238
+ $EncryptedBytes = [System.Convert]::FromBase64String("#{password}")
239
+ $Decryptor = $aes.CreateDecryptor()
240
+ $DecryptedBytes = $Decryptor.TransformFinalBlock($EncryptedBytes,0,$EncryptedBytes.Length)
241
+ $DecryptedString = [System.Text.Encoding]::Unicode.GetString($DecryptedBytes)
242
+ return $DecryptedString
243
+ CODE
244
+ results = powershell_exec!(powershell_code).result
245
+ end
246
+
247
+ def self.decrypt_pfx_pass_with_password(password_blob)
248
+ password = ""
249
+ password_blob.each do |secret|
250
+ if secret[:name] == "PfxPass"
251
+ password = secret[:data]
252
+ else
253
+ Chef::Log.error("Failed to retrieve a password for the private key")
254
+ end
255
+ end
210
256
  powershell_code = <<~CODE
211
257
  $secure_string = "#{password}" | ConvertTo-SecureString
212
258
  $string = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR((($secure_string))))
@@ -215,14 +261,49 @@ class Chef
215
261
  powershell_exec!(powershell_code).result
216
262
  end
217
263
 
218
- def self.retrieve_certificate_key(client_name)
219
- require "openssl" unless defined?(OpenSSL)
264
+ def self.migrate_pass_to_use_vector(password)
265
+ store = get_cert_user
266
+ corrected_store = (store == "CurrentUser" ? "HKCU" : "HKLM")
267
+ powershell_code = <<~CODE
268
+ Remove-ItemProperty -Path "#{corrected_store}:\\Software\\Progress\\Authentication" -Name "PfXPass"
269
+ CODE
270
+ powershell_exec!(powershell_code)
271
+ create_and_store_new_password(password)
272
+ end
220
273
 
274
+ # This method name is a bit of a misnomer. We call it to legit create a new password using the vector format.
275
+ # But we also call it with a password that needs to be migrated to use the vector format too.
276
+ def self.create_and_store_new_password(password = nil)
277
+ @win32registry = Chef::Win32::Registry.new
278
+ store = get_registry_user
279
+ path = "#{store}\\Software\\Progress\\Authentication"
280
+ if password.nil?
281
+ require "securerandom" unless defined?(SecureRandom)
282
+ size = 14
283
+ password = SecureRandom.alphanumeric(size)
284
+ end
285
+ encrypted_blob = encrypt_pfx_pass_with_vector(password)
286
+ encrypted_password = encrypted_blob[0]
287
+ key = encrypted_blob[1]
288
+ vector = encrypted_blob[2]
289
+ values = [
290
+ { name: "PfxPass", type: :string, data: encrypted_password },
291
+ { name: "PfxKey", type: :string, data: key },
292
+ { name: "PfxIV", type: :string, data: vector },
293
+ ]
294
+ values.each do |i|
295
+ @win32registry.set_value(path, i)
296
+ end
297
+ password
298
+ end
299
+
300
+ def self.retrieve_certificate_key(client_name)
221
301
  if ChefUtils.windows?
302
+ require "openssl" unless defined?(OpenSSL)
222
303
  password = get_cert_password
223
304
  return false unless password
224
305
 
225
- if check_certstore_for_key(client_name)
306
+ if !!check_certstore_for_key(client_name)
226
307
  ps_blob = powershell_exec!(get_the_key_ps(client_name, password)).result
227
308
  file_path = ps_blob["PSPath"].split("::")[1]
228
309
  pkcs = OpenSSL::PKCS12.new(File.binread(file_path), password)
@@ -252,10 +333,11 @@ class Chef
252
333
  end
253
334
 
254
335
  def self.get_the_key_ps(client_name, password)
336
+ store = get_cert_user
255
337
  powershell_code = <<~CODE
256
338
  Try {
257
339
  $my_pwd = ConvertTo-SecureString -String "#{password}" -Force -AsPlainText;
258
- $cert = Get-ChildItem -path cert:\\LocalMachine\\My -Recurse | Where-Object { $_.Subject -match "chef-#{client_name}$" } -ErrorAction Stop;
340
+ $cert = Get-ChildItem -path cert:\\#{store}\\My -Recurse | Where-Object { $_.Subject -match "chef-#{client_name}$" } -ErrorAction Stop;
259
341
  $tempfile = [System.IO.Path]::GetTempPath() + "export_pfx.pfx";
260
342
  Export-PfxCertificate -Cert $cert -Password $my_pwd -FilePath $tempfile;
261
343
  }
@@ -266,8 +348,9 @@ class Chef
266
348
  end
267
349
 
268
350
  def self.delete_old_key_ps(client_name)
351
+ store = get_cert_user
269
352
  powershell_code = <<~CODE
270
- Get-ChildItem -path cert:\\LocalMachine\\My -Recurse | Where-Object { $_.Subject -match "chef-#{client_name}$" } | Remove-Item -ErrorAction Stop;
353
+ Get-ChildItem -path cert:\\#{store}\\My -Recurse | Where-Object { $_.Subject -match "chef-#{client_name}$" } | Remove-Item -ErrorAction Stop;
271
354
  CODE
272
355
  end
273
356
 
@@ -17,11 +17,14 @@
17
17
  #
18
18
 
19
19
  require "chef-utils" unless defined?(ChefUtils::CANARY)
20
+ require_relative "../mixin/powershell_exec"
20
21
 
21
22
  class Chef
22
23
  class Platform
23
24
 
24
25
  class << self
26
+ include Chef::Mixin::PowershellExec
27
+
25
28
  def windows?
26
29
  ChefUtils.windows?
27
30
  end
@@ -58,8 +61,7 @@ class Chef
58
61
  end
59
62
 
60
63
  def dsc_refresh_mode_disabled?(node)
61
- require_relative "../powershell"
62
- exec = Chef::PowerShell.new("Get-DscLocalConfigurationManager")
64
+ exec = powershell_exec!("Get-DscLocalConfigurationManager")
63
65
  exec.error!
64
66
  exec.result["RefreshMode"] == "Disabled"
65
67
  end
@@ -187,6 +187,24 @@ class Chef
187
187
  end.compact
188
188
  end
189
189
 
190
+ # run the specified command and extract the public key ids
191
+ # accepts the command so it can be used to extract both the current keys
192
+ # and the new keys
193
+ # @param [Array<String>] cmd the command to run
194
+ #
195
+ # @return [Array] an array of key ids
196
+ def extract_public_keys_from_cmd(*cmd)
197
+ so = shell_out(*cmd)
198
+ # Sample output
199
+ # pub:-:4096:1:D94AA3F0EFE21092:1336774248:::-:::scSC::::::23::0:
200
+ so.stdout.split(/\n/).map do |t|
201
+ if t.match(/^pub:/)
202
+ f = t.split(":")
203
+ f.slice(0, 6).join(":")
204
+ end
205
+ end.compact
206
+ end
207
+
190
208
  # validate the key against the apt keystore to see if that version is expired
191
209
  # @param [String] key
192
210
  #
@@ -222,8 +240,8 @@ class Chef
222
240
  def no_new_keys?(file)
223
241
  # Now we are using the option --with-colons that works across old os versions
224
242
  # as well as the latest (16.10). This for both `apt-key` and `gpg` commands
225
- installed_keys = extract_fingerprints_from_cmd(*LIST_APT_KEY_FINGERPRINTS)
226
- proposed_keys = extract_fingerprints_from_cmd("gpg", "--with-fingerprint", "--with-colons", file)
243
+ installed_keys = extract_public_keys_from_cmd(*LIST_APT_KEY_FINGERPRINTS)
244
+ proposed_keys = extract_public_keys_from_cmd("gpg", "--with-fingerprint", "--with-colons", file)
227
245
  (installed_keys & proposed_keys).sort == proposed_keys.sort
228
246
  end
229
247
 
@@ -43,6 +43,19 @@ class Chef
43
43
  end
44
44
  ```
45
45
 
46
+ **Using escape characters in a string of code**
47
+
48
+ In the following example, the `find` command uses an escape character (`\`). Use a second escape character (`\\`) to preserve the escape character in the code string:
49
+
50
+ ```ruby
51
+ bash 'delete some archives ' do
52
+ code <<-EOH
53
+ find ./ -name "*.tar.Z" -mtime +180 -exec rm -f {} \\;
54
+ EOH
55
+ ignore_failure true
56
+ end
57
+ ```
58
+
46
59
  **Install a file from a remote location**
47
60
 
48
61
  The following is an example of how to install the foo123 module for Nginx. This module adds shell-style functionality to an Nginx configuration file and does the following:
@@ -34,7 +34,7 @@ class Chef
34
34
  resource in #{ChefUtils::Dist::Infra::PRODUCT}, such as the Archive resource, a custom DSC resource, an existing DSC script that performs an important
35
35
  task, and so on. Use the dsc_script resource to embed the code that defines a DSC configuration directly within a #{ChefUtils::Dist::Infra::PRODUCT} recipe.
36
36
 
37
- Warning: The **dsc_script** resource may not be used with the 32 bit Chef Infra client. It must be executed from a 64 bit Chef Infra client.
37
+ Warning: The **dsc_script** resource is only available on 64-bit Chef Infra Client.
38
38
  DESC
39
39
 
40
40
  default_action :run
@@ -21,7 +21,7 @@ require_relative "../resource"
21
21
  class Chef
22
22
  class Resource
23
23
  class Launchd < Chef::Resource
24
- provides :launchd
24
+ provides :launchd, os: "darwin"
25
25
 
26
26
  description "Use the **launchd** resource to manage system-wide services (daemons) and per-user services (agents) on the macOS platform."
27
27
  introduced "12.8"
@@ -129,7 +129,7 @@ class Chef
129
129
  property :abandon_process_group, [ TrueClass, FalseClass ],
130
130
  description: "If a job dies, all remaining processes with the same process ID may be kept running. Set to true to kill all remaining processes."
131
131
 
132
- property :associated_bundle_identifiers, Hash,
132
+ property :associated_bundle_identifiers, Array,
133
133
  description: "This optional key indicates which bundles the Login Items Added by Apps panel associates with the helper executable."
134
134
 
135
135
  property :debug, [ TrueClass, FalseClass ],
@@ -50,15 +50,17 @@ class Chef
50
50
  end
51
51
  ```
52
52
 
53
- **Specifying the type of a key to skip automatic type detection**
53
+ **Setting a value for specific user and hosts**
54
54
 
55
55
  ```ruby
56
- macos_userdefaults 'Finder expanded save dialogs' do
57
- key 'NSNavPanelExpandedStateForSaveMode'
58
- value 'TRUE'
59
- type 'bool'
56
+ macos_userdefaults 'Enable macOS firewall' do
57
+ key 'globalstate'
58
+ value 1
59
+ user 'jane'
60
+ host :current
60
61
  end
61
62
  ```
63
+
62
64
  DOC
63
65
 
64
66
  property :domain, String,
@@ -79,6 +81,7 @@ class Chef
79
81
 
80
82
  property :host, [String, Symbol],
81
83
  description: "Set either :current, :all or a hostname to set the user default at the host level.",
84
+ default: :all,
82
85
  desired_state: false,
83
86
  introduced: "16.3"
84
87
 
@@ -94,6 +97,7 @@ class Chef
94
97
 
95
98
  property :user, [String, Symbol],
96
99
  description: "The system user that the default will be applied to. Set :current for current user, :all for all users or pass a valid username",
100
+ default: :current,
97
101
  desired_state: false
98
102
 
99
103
  property :sudo, [TrueClass, FalseClass],
@@ -92,7 +92,7 @@ class Chef
92
92
 
93
93
  property :release,
94
94
  [Float, String],
95
- description: "Sets the operating system minor release to use for subscriptions for the system. Products and updates are limited to the specified minor release version. This is used with the `auto_attach` option, it may also be used with activation keys. For example, `release '6.4'` will append `--release=6.4` to the register command.",
95
+ description: "Sets the operating system minor release to use for subscriptions for the system. Products and updates are limited to the specified minor release version. This is used with the `auto_attach` or `activation_key` options. For example, `release '6.4'` will append `--release=6.4` to the register command.",
96
96
  introduced: "17.8"
97
97
 
98
98
  action :register, description: "Register the node with RHSM." do
@@ -22,7 +22,7 @@ class Chef
22
22
 
23
23
  provides :selinux_fcontext
24
24
 
25
- description "Use **selinux_fcontext** resource to set the SELinux context of files with semanage fcontext."
25
+ description "Use the **selinux_fcontext** resource to set the SELinux context of files using the `semanage fcontext` command."
26
26
  introduced "18.0"
27
27
  examples <<~DOC
28
28
  **Allow http servers (e.g. nginx/apache) to modify moodle files**:
@@ -0,0 +1,129 @@
1
+ #
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+
14
+ require_relative "../resource"
15
+ require_relative "selinux/common_helpers"
16
+
17
+ class Chef
18
+ class Resource
19
+ class SelinuxLogin < Chef::Resource
20
+ unified_mode true
21
+
22
+ provides :selinux_login
23
+
24
+ description "Use the **selinux_login** resource to add, update, or remove SELinux user to OS login mappings."
25
+ introduced "18.1"
26
+ examples <<~DOC
27
+ **Manage test OS user mapping with a range of s0 and associated SELinux user test_u**:
28
+
29
+ ```ruby
30
+ selinux_login 'test' do
31
+ user 'test_u'
32
+ range 's0'
33
+ end
34
+ ```
35
+ DOC
36
+
37
+ property :login, String,
38
+ name_property: true,
39
+ description: "An optional property to set the OS user login value if it differs from the resource block's name."
40
+
41
+ property :user, String,
42
+ description: "SELinux user to be mapped."
43
+
44
+ property :range, String,
45
+ description: "MLS/MCS security range for the SELinux user."
46
+
47
+ load_current_value do |new_resource|
48
+ logins = shell_out!("semanage login -l").stdout.split("\n")
49
+
50
+ current_login = logins.grep(/^#{Regexp.escape(new_resource.login)}\s+/) do |l|
51
+ l.match(/^(?<login>[^\s]+)\s+(?<user>[^\s]+)\s+(?<range>[^\s]+)/)
52
+ # match returns [<Match 'data'>] or [], shift converts that to <Match 'data'> or nil
53
+ end.shift
54
+
55
+ current_value_does_not_exist! unless current_login
56
+
57
+ # Existing resources should maintain their current configuration unless otherwise specified
58
+ new_resource.user ||= current_login[:user]
59
+ new_resource.range ||= current_login[:range]
60
+
61
+ user current_login[:user]
62
+ range current_login[:range]
63
+ end
64
+
65
+ action_class do
66
+ include Chef::SELinux::CommonHelpers
67
+
68
+ def semanage_login_args
69
+ # Generate arguments for semanage login -a or -m
70
+ args = ""
71
+
72
+ args += " -s #{new_resource.user}" if new_resource.user
73
+ args += " -r #{new_resource.range}" if new_resource.range
74
+
75
+ args
76
+ end
77
+ end
78
+
79
+ action :manage, description: "Sets the SELinux login mapping to the desired settings regardless of previous state." do
80
+ run_action(:add)
81
+ run_action(:modify)
82
+ end
83
+
84
+ # Create if doesn't exist, do not touch if user already exists
85
+ action :add, description: "Creates the SELinux login mapping if not previously created." do
86
+ raise "The user property must be populated to create a new SELinux login" if new_resource.user.to_s.empty?
87
+
88
+ if selinux_disabled?
89
+ Chef::Log.warn("Unable to add SELinux login #{new_resource.login} as SELinux is disabled")
90
+ return
91
+ end
92
+
93
+ unless current_resource
94
+ converge_if_changed do
95
+ shell_out!("semanage login -a#{semanage_login_args} #{new_resource.login}")
96
+ end
97
+ end
98
+ end
99
+
100
+ # Only modify port if it exists & doesn't have the correct context already
101
+ action :modify, description: "Updates the SELinux login mapping if previously created." do
102
+ if selinux_disabled?
103
+ Chef::Log.warn("Unable to modify SELinux login #{new_resource.login} as SELinux is disabled")
104
+ return
105
+ end
106
+
107
+ if current_resource
108
+ converge_if_changed do
109
+ shell_out!("semanage login -m#{semanage_login_args} #{new_resource.login}")
110
+ end
111
+ end
112
+ end
113
+
114
+ # Delete if exists
115
+ action :delete, description: "Removes the SELinux login mapping if previously created." do
116
+ if selinux_disabled?
117
+ Chef::Log.warn("Unable to delete SELinux login #{new_resource.login} as SELinux is disabled")
118
+ return
119
+ end
120
+
121
+ if current_resource
122
+ converge_by "deleting SELinux login #{new_resource.login}" do
123
+ shell_out!("semanage login -d #{new_resource.login}")
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end