Skip to content

Commit

Permalink
Merge 71cbee8 into 17c8aa9
Browse files Browse the repository at this point in the history
  • Loading branch information
rico89 committed May 4, 2018
2 parents 17c8aa9 + 71cbee8 commit 3c781c1
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 37 deletions.
98 changes: 76 additions & 22 deletions lib/puppet/provider/gpo/lgpo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ def exists?
@property_hash[:ensure] == :present
end

def deleted?
@property_hash[:ensure] == :deleted
end

def create
set_value(resource[:value])
@property_hash[:ensure] = :present
Expand Down Expand Up @@ -51,14 +55,19 @@ def self.instances
['machine', 'user'].map do |scope|
pol_file = "C:\\Windows\\System32\\GroupPolicy\\#{scope.capitalize}\\Registry.pol"
next [] unless File.file?(pol_file)

resources = Hash.new

gpos = lgpo('/parse', '/q', "/#{scope[0]}", pol_file)
gpos.split("\n\n").reject { |l| l.start_with? ';' }.map do |g|
split_g = g.split("\n")
path = paths.get_by_key(scope, split_g[1].downcase, split_g[2].downcase)

if path.nil?
warn "Unkown path for gpo resource: '#{split_g[1]}/#{split_g[2]}'"
next
end

admx_file = path['admx_file'].downcase
policy_id = path['policy_id'].downcase
setting_valuename = path['setting_valuename'].downcase
Expand Down Expand Up @@ -92,10 +101,31 @@ def self.instances
:value => value,
}
end

end
resources.map{|k, v| new(v)}
end.flatten
end.flatten
end

def out_line(scope, key, value_name, value)
"#{scope}\n#{key}\n#{value_name}\n#{value}"
end

# Convert lgpo_import.txt to lgpo_import.pol with lgpo.exe
def convert_to_pol(file)
pol_file = file.sub(/\.txt$/,'.pol')
lgpo_args = ['/r', file, '/w', pol_file]
lgpo(*lgpo_args)
File.delete(file)
pol_file
end

# import lgpo_import.pol with lgpo.exe
def import_pol(file, scope, guid)
lgpo_args = ["/#{scope[0]}", file]
lgpo_args << '/e' << guid if guid
lgpo(*lgpo_args)
File.delete(file)
end

def set_value(val)
Expand All @@ -110,32 +140,56 @@ def set_value(val)
raise Puppet::Error, "Wrong path: '#{path}'"
end

out_scope = scope == 'machine' ? 'computer' : scope

delete_value = setting_valuetype == '[HASHTABLE]' ? 'DELETEALLVALUES' : 'DELETE'
out_scope = (scope == 'machine' ? 'computer' : scope).capitalize

real_val = val == 'DELETE' ? delete_value : "#{path['setting_valuetype'].gsub('REG_', '')}:#{val}"
setting_valuename = real_val == 'DELETEALLVALUES' ? '*' : path['setting_valuename']
out = Array.new
if setting_valuetype == '[HASHTABLE]'
if val == 'DELETE'
out << out_line(out_scope, path['setting_key'], '*', 'DELETEALLVALUES')
else
val.each do |k, v|
out << out_line(out_scope, path['setting_key'], k, "SZ:#{v}")
end
end
else
val = "#{path['setting_valuetype'].gsub('REG_', '')}:#{val}" unless val == 'DELETE'
out << out_line(out_scope, path['setting_key'], path['setting_valuename'], val)
end

out = "#{out_scope}\n#{path['setting_key']}\n#{setting_valuename}\n#{real_val}"
# If it is a hash table we need to delete the current values in the pol file so that they can be updated
remove_key(path['setting_key'], scope, path['policy_cse']) if setting_valuetype == '[HASHTABLE]'

out_file_path = File.join(Puppet[:vardir], 'lgpo_import.txt')
out_polfile_path = File.join(Puppet[:vardir], 'lgpo_import.pol')
File.open(out_file_path, 'w') do |out_file|
out_file.write(out)
out_file.write(out.join("\n\n"))
end

out_polfile_path = convert_to_pol(out_file_path)
import_pol(out_polfile_path, scope, path['policy_cse'])
end

# Convert lgpo_import.txt to lgpo_import.pol with lgpo.exe
lgpo_args = ['/r', out_file_path, '/w', out_polfile_path]
lgpo(*lgpo_args)
File.delete(out_file_path)
def remove_key(key, scope, cse_guid)
# This function is removing content from the pol file so that hash values can be updated without carying over the old part
Puppet.debug "remove #{key} in scope #{scope}"

system_pol_file = "C:\\Windows\\System32\\GroupPolicy\\#{scope.capitalize}\\Registry.pol"
return unless File.file?(system_pol_file)

out_file = File.join(Puppet[:vardir], 'lgpo_import.txt')
gpos = lgpo('/parse', '/q', "/#{scope[0]}", system_pol_file)
# Parse file and remove key
new_gpos = gpos.split("\n\n").reject { |l| l.start_with? ';' }
.reject{ |l| l.split("\n")[1] == key }
File.write(out_file, new_gpos.join("\n\n"))

# convert txt file to pol file
pol_file = convert_to_pol(out_file)

# import lgpo_import.pol with lgpo.exe
lgpo_args = ["/#{scope[0]}", out_polfile_path]
if guid = path['policy_cse']
lgpo_args << '/e' << guid
end
lgpo(*lgpo_args)
File.delete(out_polfile_path)
# delete existing polfile
File.delete(system_pol_file)

# apply pol file to
import_pol(pol_file, scope, cse_guid)
end
end

5 changes: 5 additions & 0 deletions lib/puppet/type/gpo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
newvalue(:deleted) do
provider.delete
end

def insync?(is)
return true if should == :deleted and provider.deleted?
super
end
end

newparam(:name, :namevar => true) do
Expand Down
91 changes: 76 additions & 15 deletions spec/unit/puppet/provider/gpo/lgpo_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,45 @@ def stub_create(scope, content, cse)
expect(File).to receive(:delete).once.with(out_polfile).and_return(nil)
end

def stub_hash_delete(scope, content, cse)
# This is the initial write to the gpo_import_file which writes the deleteallvalues statement for a hashed instance
lgpo_import_file = StringIO.new
expect(File).to receive(:open).once.with(out_file, 'w').and_yield(lgpo_import_file)
expect(lgpo_import_file).to receive(:write).with(content)

# pol file should get read one time initiated by the lgpo.exe call
pol_file = "C:\\Windows\\System32\\GroupPolicy\\#{scope.capitalize}\\Registry.pol"
allow(File).to receive(:file?) # Catch all calls
expect(File).to receive(:file?).once.with(pol_file).and_return(true)

# the stub for the pol lgpo call needs to be added here in order to simulate output
if true
provider.class.expects(:lgpo).once.with('/parse', '/q', "/#{scope[0]}", pol_file)
.returns(File.read(File.join(
File.dirname(__FILE__),
"../../../../fixtures/unit/puppet/provider/gpo/lgpo/#{scope}/full.out")))
else
provider.class.expects(:lgpo).never
end

# This is the subsequent writes to the lgpo file with the filtered content from the parsing
expect(File).to receive(:open).once.with(out_file, 'a').and_yield(lgpo_import_file)
expect(lgpo_import_file).to receive(:write).at_least(:once)

args = ["/r", out_file]
args << '/w' << out_polfile
provider.class.expects(:lgpo).once.with(*args).returns(nil)
expect(File).to receive(:delete).once.with(out_file).and_return(nil)

# Polfile needs to be deleted so a fresh import can be done from the filtered lgpo file
expect(File).to receive(:delete).once.with(pol_file).and_return(nil)

args = ["/#{scope[0]}", out_polfile]
args << '/e' << cse unless cse.nil?
provider.class.expects(:lgpo).once.with(*args).returns(nil)
expect(File).to receive(:delete).once.with(out_polfile).and_return(nil)
end

context 'when listing instances' do
context 'when the gpo file exists' do
it 'should list instances' do
Expand Down Expand Up @@ -175,7 +214,7 @@ def stub_create(scope, content, cse)

context 'when there is no cse' do
it 'should create a resource without /e' do
stub_create('machine', "computer\nSoftware\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU\nAllowMUUpdateService\nDWORD:1", nil)
stub_create('machine', "Computer\nSoftware\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU\nAllowMUUpdateService\nDWORD:1", nil)

provider.create
end
Expand All @@ -191,8 +230,25 @@ def stub_create(scope, content, cse)
end

it 'should create a resource with /e' do
stub_create('machine', "computer\nSoftware\\Policies\\Microsoft Services\\AdmPwd\nAdmPwdEnabled\nDWORD:1", '{D76B9641-3288-4f75-942D-087DE603E3EA}')
stub_create('machine', "Computer\nSoftware\\Policies\\Microsoft Services\\AdmPwd\nAdmPwdEnabled\nDWORD:1", '{D76B9641-3288-4f75-942D-087DE603E3EA}')

provider.create
end
end

context 'when resource contain a hash value' do
let(:params) do
{
:title => 'windowsdefender::exclusions_processes::exclusions_processeslist',
:value => {'c:\windows\process0.exe' => '0', 'c:\windows\process1.exe' => '0',},
:provider => 'lgpo',
}
end

it 'should create two entries in LGPO import file' do
stub_create('machine', "Computer\nSoftware\\Policies\\Microsoft\\Windows Defender\\Exclusions\\Processes\nc:\\windows\\process0.exe\nSZ:0\n\nComputer\nSoftware\\Policies\\Microsoft\\Windows Defender\\Exclusions\\Processes\nc:\\windows\\process1.exe\nSZ:0", nil)
pol_file = "C:\\Windows\\System32\\GroupPolicy\\Machine\\Registry.pol"
expect(File).to receive(:delete).once.with(pol_file).and_return(nil)
provider.create
end
end
Expand All @@ -205,38 +261,43 @@ def stub_create(scope, content, cse)

context 'when there is no cse' do
it 'should create a resource without /e' do
stub_create('machine', "computer\nSoftware\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU\nAllowMUUpdateService\nDELETE", nil)
stub_create('machine', "Computer\nSoftware\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU\nAllowMUUpdateService\nDELETE", nil)

provider.delete
end
end

context 'when we need to delete a HASHTABLE instance' do
context 'when there is a cse' do
let(:params) do
{
:title => 'machine::windowsdefender::exclusions_processes::exclusions_processeslist',
:ensure => :deleted,
:title => 'admpwd::pol_admpwd_enabled::admpwdenabled',
:value => '1',
:provider => 'lgpo',
}
end
it 'should create a resource without /e' do
stub_create('machine', "computer\nSoftware\\Policies\\Microsoft\\Windows Defender\\Exclusions\\Processes\n*\nDELETEALLVALUES", nil)

it 'should create a resource with /e' do
stub_create('machine', "Computer\nSoftware\\Policies\\Microsoft Services\\AdmPwd\nAdmPwdEnabled\nDELETE", '{D76B9641-3288-4f75-942D-087DE603E3EA}')

provider.delete
end
end

context 'when there is a cse' do
end
context 'when deleting a hash resource' do
before :each do
expect(Puppet).to receive(:[]).exactly(3).times.with(:vardir).and_return('C:\ProgramData\PuppetLabs\Puppet\var')
end

context 'when we need to delete a HASHTABLE instance' do
let(:params) do
{
:title => 'admpwd::pol_admpwd_enabled::admpwdenabled',
:value => '1',
:title => 'machine::windowsdefender::exclusions_processes::exclusions_processeslist',
:ensure => :deleted,
:provider => 'lgpo',
}
end

it 'should create a resource with /e' do
stub_create('machine', "computer\nSoftware\\Policies\\Microsoft Services\\AdmPwd\nAdmPwdEnabled\nDELETE", '{D76B9641-3288-4f75-942D-087DE603E3EA}')
it 'should create a resource without /e' do
stub_hash_delete('machine', "Computer\nSoftware\\Policies\\Microsoft\\Windows Defender\\Exclusions\\Processes\n*\nDELETEALLVALUES", nil)

provider.delete
end
Expand Down

0 comments on commit 3c781c1

Please sign in to comment.