inspec 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.rubocop.yml +65 -0
- data/.travis.yml +23 -0
- data/CHANGELOG.md +38 -0
- data/Gemfile +33 -0
- data/LICENSE +201 -0
- data/MAINTAINERS.md +28 -0
- data/MAINTAINERS.toml +42 -0
- data/README.md +257 -0
- data/Rakefile +47 -0
- data/bin/inspec +109 -0
- data/docs/ctl_inspec.rst +195 -0
- data/docs/dsl_inspec.rst +182 -0
- data/docs/readme.rst +100 -0
- data/docs/resources.rst +4319 -0
- data/docs/template.rst +51 -0
- data/examples/test-kitchen/.kitchen.yml +20 -0
- data/examples/test-kitchen/Berksfile +3 -0
- data/examples/test-kitchen/Gemfile +21 -0
- data/examples/test-kitchen/README.md +27 -0
- data/examples/test-kitchen/metadata.rb +7 -0
- data/examples/test-kitchen/recipes/default.rb +6 -0
- data/examples/test-kitchen/recipes/nginx.rb +30 -0
- data/examples/test-kitchen/test/integration/default/web_spec.rb +28 -0
- data/inspec.gemspec +30 -0
- data/lib/inspec.rb +20 -0
- data/lib/inspec/backend.rb +42 -0
- data/lib/inspec/dsl.rb +151 -0
- data/lib/inspec/log.rb +34 -0
- data/lib/inspec/metadata.rb +79 -0
- data/lib/inspec/plugins.rb +9 -0
- data/lib/inspec/plugins/resource.rb +62 -0
- data/lib/inspec/profile.rb +138 -0
- data/lib/inspec/profile_context.rb +170 -0
- data/lib/inspec/resource.rb +76 -0
- data/lib/inspec/rspec_json_formatter.rb +27 -0
- data/lib/inspec/rule.rb +170 -0
- data/lib/inspec/runner.rb +154 -0
- data/lib/inspec/shell.rb +66 -0
- data/lib/inspec/targets.rb +9 -0
- data/lib/inspec/targets/core.rb +27 -0
- data/lib/inspec/targets/dir.rb +67 -0
- data/lib/inspec/targets/file.rb +29 -0
- data/lib/inspec/targets/folder.rb +43 -0
- data/lib/inspec/targets/tar.rb +34 -0
- data/lib/inspec/targets/url.rb +39 -0
- data/lib/inspec/targets/zip.rb +47 -0
- data/lib/inspec/version.rb +7 -0
- data/lib/matchers/matchers.rb +221 -0
- data/lib/resources/apache.rb +29 -0
- data/lib/resources/apache_conf.rb +113 -0
- data/lib/resources/apt.rb +140 -0
- data/lib/resources/audit_policy.rb +63 -0
- data/lib/resources/auditd_conf.rb +56 -0
- data/lib/resources/auditd_rules.rb +53 -0
- data/lib/resources/bond.rb +65 -0
- data/lib/resources/bridge.rb +114 -0
- data/lib/resources/command.rb +57 -0
- data/lib/resources/csv.rb +32 -0
- data/lib/resources/directory.rb +15 -0
- data/lib/resources/etc_group.rb +150 -0
- data/lib/resources/file.rb +110 -0
- data/lib/resources/gem.rb +46 -0
- data/lib/resources/group.rb +132 -0
- data/lib/resources/host.rb +143 -0
- data/lib/resources/inetd_conf.rb +56 -0
- data/lib/resources/interface.rb +127 -0
- data/lib/resources/iptables.rb +65 -0
- data/lib/resources/json.rb +64 -0
- data/lib/resources/kernel_module.rb +40 -0
- data/lib/resources/kernel_parameter.rb +55 -0
- data/lib/resources/limits_conf.rb +55 -0
- data/lib/resources/login_def.rb +60 -0
- data/lib/resources/mysql.rb +81 -0
- data/lib/resources/mysql_conf.rb +116 -0
- data/lib/resources/mysql_session.rb +52 -0
- data/lib/resources/npm.rb +44 -0
- data/lib/resources/ntp_conf.rb +58 -0
- data/lib/resources/oneget.rb +63 -0
- data/lib/resources/os.rb +22 -0
- data/lib/resources/os_env.rb +34 -0
- data/lib/resources/package.rb +169 -0
- data/lib/resources/parse_config.rb +75 -0
- data/lib/resources/passwd.rb +93 -0
- data/lib/resources/pip.rb +75 -0
- data/lib/resources/port.rb +296 -0
- data/lib/resources/postgres.rb +37 -0
- data/lib/resources/postgres_conf.rb +87 -0
- data/lib/resources/postgres_session.rb +59 -0
- data/lib/resources/processes.rb +57 -0
- data/lib/resources/registry_key.rb +54 -0
- data/lib/resources/script.rb +34 -0
- data/lib/resources/security_policy.rb +73 -0
- data/lib/resources/service.rb +379 -0
- data/lib/resources/ssh_conf.rb +75 -0
- data/lib/resources/user.rb +374 -0
- data/lib/resources/windows_feature.rb +77 -0
- data/lib/resources/yaml.rb +23 -0
- data/lib/resources/yum.rb +154 -0
- data/lib/utils/convert.rb +12 -0
- data/lib/utils/detect.rb +15 -0
- data/lib/utils/find_files.rb +36 -0
- data/lib/utils/hash.rb +13 -0
- data/lib/utils/modulator.rb +12 -0
- data/lib/utils/parser.rb +61 -0
- data/lib/utils/simpleconfig.rb +115 -0
- data/tasks/maintainers.rb +213 -0
- data/test/docker_run.rb +156 -0
- data/test/docker_test.rb +51 -0
- data/test/helper.rb +200 -0
- data/test/integration/.kitchen.yml +42 -0
- data/test/integration/Berksfile +4 -0
- data/test/integration/cookbooks/os_prepare/metadata.rb +8 -0
- data/test/integration/cookbooks/os_prepare/recipes/apt.rb +20 -0
- data/test/integration/cookbooks/os_prepare/recipes/default.rb +9 -0
- data/test/integration/cookbooks/os_prepare/recipes/file.rb +21 -0
- data/test/integration/cookbooks/os_prepare/recipes/package.rb +26 -0
- data/test/integration/default/_debug_spec.rb +1 -0
- data/test/integration/default/apt_spec.rb +42 -0
- data/test/integration/default/file_spec.rb +109 -0
- data/test/integration/default/group_spec.rb +32 -0
- data/test/integration/default/kernel_module_spec.rb +17 -0
- data/test/integration/default/kernel_parameter_spec.rb +56 -0
- data/test/integration/default/package_spec.rb +11 -0
- data/test/integration/default/service_spec.rb +28 -0
- data/test/integration/default/user_spec.rb +44 -0
- data/test/resource/command_test.rb +33 -0
- data/test/resource/dsl_test.rb +45 -0
- data/test/resource/file_test.rb +130 -0
- data/test/resource/ssh_config.rb +9 -0
- data/test/resource/sshd_config.rb +9 -0
- data/test/test-extra.yaml +11 -0
- data/test/test.yaml +11 -0
- data/test/unit/mock/cmd/Get-NetAdapter +24 -0
- data/test/unit/mock/cmd/GetUserAccount +33 -0
- data/test/unit/mock/cmd/GetWin32Group +23 -0
- data/test/unit/mock/cmd/PATH +1 -0
- data/test/unit/mock/cmd/Resolve-DnsName +26 -0
- data/test/unit/mock/cmd/Test-NetConnection +4 -0
- data/test/unit/mock/cmd/auditctl +7 -0
- data/test/unit/mock/cmd/auditpol +2 -0
- data/test/unit/mock/cmd/brew-info-jq +1 -0
- data/test/unit/mock/cmd/chage-l-root +7 -0
- data/test/unit/mock/cmd/dpkg-s-curl +21 -0
- data/test/unit/mock/cmd/dscl +5 -0
- data/test/unit/mock/cmd/etc-apt +7 -0
- data/test/unit/mock/cmd/find-etc-rc-d-name-S +12 -0
- data/test/unit/mock/cmd/find-net-interface +9 -0
- data/test/unit/mock/cmd/gem-list-local-a-q-rubocop +1 -0
- data/test/unit/mock/cmd/get-net-tcpconnection +24 -0
- data/test/unit/mock/cmd/get-netadapter-binding-bridge +4 -0
- data/test/unit/mock/cmd/get-package-firefox +30 -0
- data/test/unit/mock/cmd/get-package-ruby +18 -0
- data/test/unit/mock/cmd/get-service-dhcp +10 -0
- data/test/unit/mock/cmd/get-windows-feature +7 -0
- data/test/unit/mock/cmd/getent-hosts-example.com +1 -0
- data/test/unit/mock/cmd/getent-passwd-root +1 -0
- data/test/unit/mock/cmd/id-chartmann +1 -0
- data/test/unit/mock/cmd/id-root +1 -0
- data/test/unit/mock/cmd/initctl-show-config-ssh +3 -0
- data/test/unit/mock/cmd/initctl-status-ssh +1 -0
- data/test/unit/mock/cmd/iptables-s +6 -0
- data/test/unit/mock/cmd/launchctl-list +3 -0
- data/test/unit/mock/cmd/ls-1-etc-init.d +2 -0
- data/test/unit/mock/cmd/ls-sys-class-net-br +2 -0
- data/test/unit/mock/cmd/lsmod +2 -0
- data/test/unit/mock/cmd/lsof-np-itcp +4 -0
- data/test/unit/mock/cmd/netstat-tulpen +5 -0
- data/test/unit/mock/cmd/npm-ls-g--json-bower +9 -0
- data/test/unit/mock/cmd/pacman-qi-curl +21 -0
- data/test/unit/mock/cmd/ping-example.com +6 -0
- data/test/unit/mock/cmd/pip-show-jinja2 +11 -0
- data/test/unit/mock/cmd/ps-aux +3 -0
- data/test/unit/mock/cmd/pw-usershow-root-7 +1 -0
- data/test/unit/mock/cmd/reg_schedule +1 -0
- data/test/unit/mock/cmd/rpm-qia-curl +24 -0
- data/test/unit/mock/cmd/sbin_sysctl +1 -0
- data/test/unit/mock/cmd/secedit-export +7 -0
- data/test/unit/mock/cmd/service-e +2 -0
- data/test/unit/mock/cmd/service-sendmail-onestatus +3 -0
- data/test/unit/mock/cmd/service-sshd-status +1 -0
- data/test/unit/mock/cmd/sockstat +5 -0
- data/test/unit/mock/cmd/success +0 -0
- data/test/unit/mock/cmd/systemctl-show-all-sshd +6 -0
- data/test/unit/mock/cmd/win32_product +8 -0
- data/test/unit/mock/cmd/yum-repolist-all +52 -0
- data/test/unit/mock/files/auditd.conf +4 -0
- data/test/unit/mock/files/bond0 +37 -0
- data/test/unit/mock/files/etcgroup +3 -0
- data/test/unit/mock/files/example.csv +6 -0
- data/test/unit/mock/files/inetd.conf +2 -0
- data/test/unit/mock/files/kitchen.yml +7 -0
- data/test/unit/mock/files/limits.conf +5 -0
- data/test/unit/mock/files/login.defs +5 -0
- data/test/unit/mock/files/mysql.conf +8 -0
- data/test/unit/mock/files/mysql2.conf +2 -0
- data/test/unit/mock/files/ntp.conf +5 -0
- data/test/unit/mock/files/passwd +2 -0
- data/test/unit/mock/files/policyfile.lock.json +12 -0
- data/test/unit/mock/files/ssh_config +5 -0
- data/test/unit/mock/files/sshd_config +7 -0
- data/test/unit/mock/profiles/empty/metadata.rb +0 -0
- data/test/unit/mock/profiles/metadata/metadata.rb +1 -0
- data/test/unit/profile_context_test.rb +140 -0
- data/test/unit/profile_test.rb +49 -0
- data/test/unit/resources/apt_test.rb +46 -0
- data/test/unit/resources/audit_policy_test.rb +13 -0
- data/test/unit/resources/auditd_conf_test.rb +15 -0
- data/test/unit/resources/auditd_rules_test.rb +21 -0
- data/test/unit/resources/bond_test.rb +24 -0
- data/test/unit/resources/bridge_test.rb +56 -0
- data/test/unit/resources/csv_test.rb +35 -0
- data/test/unit/resources/etc_group_test.rb +37 -0
- data/test/unit/resources/gem_test.rb +20 -0
- data/test/unit/resources/group_test.rb +96 -0
- data/test/unit/resources/host_test.rb +38 -0
- data/test/unit/resources/inetd_conf_test.rb +15 -0
- data/test/unit/resources/interface_test.rb +54 -0
- data/test/unit/resources/iptables_test.rb +30 -0
- data/test/unit/resources/json_test.rb +36 -0
- data/test/unit/resources/kernel_module_test.rb +23 -0
- data/test/unit/resources/kernel_parameter_test.rb +13 -0
- data/test/unit/resources/limits_conf_test.rb +14 -0
- data/test/unit/resources/login_def_test.rb +16 -0
- data/test/unit/resources/mysql_conf_test.rb +14 -0
- data/test/unit/resources/npm_test.rb +20 -0
- data/test/unit/resources/ntp_conf_test.rb +16 -0
- data/test/unit/resources/oneget_test.rb +45 -0
- data/test/unit/resources/os_env_test.rb +13 -0
- data/test/unit/resources/package_test.rb +51 -0
- data/test/unit/resources/passwd_test.rb +24 -0
- data/test/unit/resources/pip_test.rb +15 -0
- data/test/unit/resources/port_test.rb +46 -0
- data/test/unit/resources/processes_test.rb +32 -0
- data/test/unit/resources/registry_key_test.rb +19 -0
- data/test/unit/resources/script_test.rb +19 -0
- data/test/unit/resources/security_policy_test.rb +16 -0
- data/test/unit/resources/service_test.rb +116 -0
- data/test/unit/resources/ssh_conf_test.rb +33 -0
- data/test/unit/resources/user_test.rb +93 -0
- data/test/unit/resources/windows_feature.rb +17 -0
- data/test/unit/resources/yaml_test.rb +34 -0
- data/test/unit/resources/yum_test.rb +68 -0
- data/test/unit/simpleconfig_test.rb +80 -0
- data/test/unit/utils/content_parser_test.rb +30 -0
- metadata +555 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# copyright: 2015, Vulcano Security GmbH
|
3
|
+
# author: Dominik Richter
|
4
|
+
# author: Christoph Hartmann
|
5
|
+
# license: All rights reserved
|
6
|
+
|
7
|
+
class Postgres < Inspec.resource(1)
|
8
|
+
name 'postgres'
|
9
|
+
|
10
|
+
attr_reader :service, :data_dir, :conf_dir, :conf_path
|
11
|
+
def initialize
|
12
|
+
case inspec.os[:family]
|
13
|
+
when 'ubuntu', 'debian'
|
14
|
+
@service = 'postgresql'
|
15
|
+
@data_dir = '/var/lib/postgresql'
|
16
|
+
@version = inspec.command('ls /etc/postgresql/').stdout.chomp
|
17
|
+
@conf_dir = "/etc/postgresql/#{@version}/main"
|
18
|
+
@conf_path = File.join @conf_dir, 'postgresql.conf'
|
19
|
+
|
20
|
+
when 'arch'
|
21
|
+
@service = 'postgresql'
|
22
|
+
@data_dir = '/var/lib/postgres/data'
|
23
|
+
@conf_dir = '/var/lib/postgres/data'
|
24
|
+
@conf_path = File.join @conf_dir, 'postgresql.conf'
|
25
|
+
|
26
|
+
else
|
27
|
+
@service = 'postgresql'
|
28
|
+
@data_dir = '/var/lib/postgresql'
|
29
|
+
@conf_dir = '/var/lib/pgsql/data'
|
30
|
+
@conf_path = File.join @conf_dir, 'postgresql.conf'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_s
|
35
|
+
'PostgreSQL'
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# copyright: 2015, Vulcano Security GmbH
|
3
|
+
# author: Dominik Richter
|
4
|
+
# author: Christoph Hartmann
|
5
|
+
# license: All rights reserved
|
6
|
+
|
7
|
+
require 'utils/simpleconfig'
|
8
|
+
require 'utils/find_files'
|
9
|
+
require 'resources/postgres'
|
10
|
+
|
11
|
+
class PostgresConf < Inspec.resource(1)
|
12
|
+
name 'postgres_conf'
|
13
|
+
|
14
|
+
include FindFiles
|
15
|
+
|
16
|
+
def initialize(conf_path = nil)
|
17
|
+
@conf_path = conf_path || inspec.postgres.conf_path
|
18
|
+
@conf_dir = File.expand_path(File.dirname @conf_path)
|
19
|
+
@files_contents = {}
|
20
|
+
@content = nil
|
21
|
+
@params = nil
|
22
|
+
read_content
|
23
|
+
end
|
24
|
+
|
25
|
+
def content
|
26
|
+
@content ||= read_content
|
27
|
+
end
|
28
|
+
|
29
|
+
def params(*opts)
|
30
|
+
@params || read_content
|
31
|
+
res = @params
|
32
|
+
opts.each do |opt|
|
33
|
+
res = res[opt] unless res.nil?
|
34
|
+
end
|
35
|
+
res
|
36
|
+
end
|
37
|
+
|
38
|
+
def read_content
|
39
|
+
@content = ''
|
40
|
+
@params = {}
|
41
|
+
|
42
|
+
# skip if the main configuration file doesn't exist
|
43
|
+
if !inspec.file(@conf_path).file?
|
44
|
+
return skip_resource "Can't find file \"#{@conf_path}\""
|
45
|
+
end
|
46
|
+
raw_conf = read_file(@conf_path)
|
47
|
+
if raw_conf.empty? && inspec.file(@conf_path).size > 0
|
48
|
+
return skip_resource("Can't read file \"#{@conf_path}\"")
|
49
|
+
end
|
50
|
+
|
51
|
+
to_read = [@conf_path]
|
52
|
+
until to_read.empty?
|
53
|
+
raw_conf = read_file(to_read[0])
|
54
|
+
@content += raw_conf
|
55
|
+
|
56
|
+
params = SimpleConfig.new(raw_conf).params
|
57
|
+
@params.merge!(params)
|
58
|
+
|
59
|
+
to_read = to_read.drop(1)
|
60
|
+
# see if there is more config files to include
|
61
|
+
|
62
|
+
to_read += include_files(params).find_all do |fp|
|
63
|
+
not @files_contents.key? fp
|
64
|
+
end
|
65
|
+
end
|
66
|
+
@content
|
67
|
+
end
|
68
|
+
|
69
|
+
def include_files(params)
|
70
|
+
include_files = params['include'] || []
|
71
|
+
include_files += params['include_if_exists'] || []
|
72
|
+
dirs = params['include_dir'] || []
|
73
|
+
dirs.each do |dir|
|
74
|
+
dir = File.join(@conf_dir, dir) if dir[0] != '/'
|
75
|
+
include_files += find_files(dir, depth: 1, type: 'file')
|
76
|
+
end
|
77
|
+
include_files
|
78
|
+
end
|
79
|
+
|
80
|
+
def read_file(path)
|
81
|
+
@files_contents[path] ||= inspec.file(path).content
|
82
|
+
end
|
83
|
+
|
84
|
+
def to_s
|
85
|
+
'PostgreSQL Configuration'
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# copyright: 2015, Vulcano Security GmbH
|
3
|
+
# author: Dominik Richter
|
4
|
+
# author: Christoph Hartmann
|
5
|
+
# license: All rights reserved
|
6
|
+
|
7
|
+
class Lines
|
8
|
+
def initialize(raw, desc)
|
9
|
+
@raw = raw
|
10
|
+
@desc = desc
|
11
|
+
end
|
12
|
+
|
13
|
+
def output
|
14
|
+
@raw
|
15
|
+
end
|
16
|
+
|
17
|
+
def lines
|
18
|
+
@raw.split("\n")
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
@desc
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class PostgresSession < Inspec.resource(1)
|
27
|
+
name 'postgres_session'
|
28
|
+
|
29
|
+
def initialize(user, pass)
|
30
|
+
@user = user || 'postgres'
|
31
|
+
@pass = pass
|
32
|
+
end
|
33
|
+
|
34
|
+
def query(query, db = [], &block)
|
35
|
+
dbs = db.map { |x| "-d #{x}" }.join(' ')
|
36
|
+
# TODO: simple escape, must be handled by a library
|
37
|
+
# that does this securely
|
38
|
+
escaped_query = query.gsub(/\\/, '\\\\').gsub(/"/, '\\"').gsub(/\$/, '\\$')
|
39
|
+
# run the query
|
40
|
+
cmd = inspec.command("PGPASSWORD='#{@pass}' psql -U #{@user} #{dbs} -c \"#{escaped_query}\"")
|
41
|
+
out = cmd.stdout + "\n" + cmd.stderr
|
42
|
+
if out =~ /could not connect to .*/ or
|
43
|
+
out.downcase =~ /^error/
|
44
|
+
# skip this test if the server can't run the query
|
45
|
+
RSpec.describe(cmd) do
|
46
|
+
it 'is skipped', skip: out do
|
47
|
+
end
|
48
|
+
end
|
49
|
+
else
|
50
|
+
# remove the whole header (i.e. up to the first ^-----+------+------$)
|
51
|
+
# remove the tail
|
52
|
+
lines = cmd.stdout
|
53
|
+
.sub(/(.*\n)+([-]+[+])*[-]+\n/, '')
|
54
|
+
.sub(/\n[^\n]*\n\n$/, '')
|
55
|
+
l = Lines.new(lines.strip, "PostgreSQL query: #{query}")
|
56
|
+
RSpec.__send__('describe', l, &block)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# copyright: 2015, Vulcano Security GmbH
|
3
|
+
# author: Dominik Richter
|
4
|
+
# author: Christoph Hartmann
|
5
|
+
# license: All rights reserved
|
6
|
+
|
7
|
+
class Processes < Inspec.resource(1)
|
8
|
+
name 'processes'
|
9
|
+
|
10
|
+
attr_reader :list
|
11
|
+
def initialize(grep)
|
12
|
+
# turn into a regexp if it isn't one yet
|
13
|
+
if grep.class == String
|
14
|
+
grep = '(/[^/]*)*'+grep if grep[0] != '/'
|
15
|
+
grep = Regexp.new('^' + grep + '(\s|$)')
|
16
|
+
end
|
17
|
+
|
18
|
+
all_cmds = ps_aux
|
19
|
+
@list = all_cmds.find_all do |hm|
|
20
|
+
hm[:command] =~ grep
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_s
|
25
|
+
'Processes'
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def ps_aux
|
31
|
+
# get all running processes
|
32
|
+
cmd = inspec.command('ps aux')
|
33
|
+
all = cmd.stdout.split("\n")[1..-1]
|
34
|
+
return [] if all.nil?
|
35
|
+
|
36
|
+
lines = all.map do |line|
|
37
|
+
# user 32296 0.0 0.0 42592 7972 pts/15 Ss+ Apr06 0:00 zsh
|
38
|
+
line.match(/^([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+(.*)$/)
|
39
|
+
end.compact
|
40
|
+
|
41
|
+
lines.map do |m|
|
42
|
+
{
|
43
|
+
user: m[1],
|
44
|
+
pid: m[2],
|
45
|
+
cpu: m[3],
|
46
|
+
mem: m[4],
|
47
|
+
vsz: m[5],
|
48
|
+
rss: m[6],
|
49
|
+
tty: m[7],
|
50
|
+
stat: m[8],
|
51
|
+
start: m[9],
|
52
|
+
time: m[10],
|
53
|
+
command: m[11],
|
54
|
+
}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# copyright: 2015, Vulcano Security GmbH
|
3
|
+
# author: Christoph Hartmann
|
4
|
+
# license: All rights reserved
|
5
|
+
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
# Usage:
|
9
|
+
# describe registry_key('Task Scheduler','HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Schedule') do
|
10
|
+
# its('Start') { should eq 2 }
|
11
|
+
# end
|
12
|
+
|
13
|
+
class RegistryKey < Inspec.resource(1)
|
14
|
+
name 'registry_key'
|
15
|
+
|
16
|
+
attr_accessor :reg_key
|
17
|
+
|
18
|
+
def initialize(name, reg_key = nil)
|
19
|
+
# if we have one parameter, we use it as name
|
20
|
+
reg_key ||= name
|
21
|
+
@name = name
|
22
|
+
@reg_key = reg_key
|
23
|
+
end
|
24
|
+
|
25
|
+
def registry_value(path, key)
|
26
|
+
cmd = "(Get-Item 'Registry::#{path}').GetValue('#{key}')"
|
27
|
+
command_result ||= inspec.command(cmd)
|
28
|
+
val = { exit_code: command_result.exit_status.to_i, data: command_result.stdout }
|
29
|
+
val
|
30
|
+
end
|
31
|
+
|
32
|
+
def convert_value(value)
|
33
|
+
val = value.strip
|
34
|
+
val = val.to_i if val.match(/^\d+$/)
|
35
|
+
val
|
36
|
+
end
|
37
|
+
|
38
|
+
# returns nil, if not existant or value
|
39
|
+
def method_missing(meth)
|
40
|
+
# get data
|
41
|
+
val = registry_value(@reg_key, meth)
|
42
|
+
|
43
|
+
# verify data
|
44
|
+
if (val[:exit_code] == 0)
|
45
|
+
return convert_value(val[:data])
|
46
|
+
else
|
47
|
+
return nil
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_s
|
52
|
+
"Registry Key #{@name}"
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# copyright: 2015, Vulcano Security GmbH
|
3
|
+
# author: Christoph Hartmann
|
4
|
+
# author: Dominik Richter
|
5
|
+
# license: All rights reserved
|
6
|
+
|
7
|
+
class Script < Cmd
|
8
|
+
name 'script'
|
9
|
+
attr_accessor :command
|
10
|
+
|
11
|
+
def initialize(script)
|
12
|
+
case inspec.os[:family]
|
13
|
+
when 'windows'
|
14
|
+
# encodes a script as base64 to run as powershell encodedCommand
|
15
|
+
# this comes with performance issues: @see https://gist.github.com/fnichol/7b20596b950e65fb96f9
|
16
|
+
require 'winrm'
|
17
|
+
script = WinRM::PowershellScript.new(script)
|
18
|
+
cmd = "powershell -encodedCommand #{script.encoded}"
|
19
|
+
else
|
20
|
+
return skip_resource 'The `script` resource is not supported on your OS yet.'
|
21
|
+
end
|
22
|
+
|
23
|
+
@command = cmd
|
24
|
+
end
|
25
|
+
|
26
|
+
# we cannot determine if a command exists, because that does not work for scripts
|
27
|
+
def exist?
|
28
|
+
nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s
|
32
|
+
'Script'
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# author: Christoph Hartmann
|
3
|
+
# author: Dominik Richter
|
4
|
+
#
|
5
|
+
# Security Configuration and Analysis
|
6
|
+
#
|
7
|
+
# Export local security policy:
|
8
|
+
# secedit /export /cfg secpol.cfg
|
9
|
+
#
|
10
|
+
# @link http://www.microsoft.com/en-us/download/details.aspx?id=25250
|
11
|
+
#
|
12
|
+
# In Windows, some security options are managed differently that the local GPO
|
13
|
+
# All local GPO parameters can be examined via Registry, but not all security
|
14
|
+
# parameters. Therefore we need a combination of Registry and secedit output
|
15
|
+
|
16
|
+
class SecurityPolicy < Inspec.resource(1)
|
17
|
+
name 'security_policy'
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
@loaded = false
|
21
|
+
@policy = nil
|
22
|
+
@exit_status = nil
|
23
|
+
end
|
24
|
+
|
25
|
+
# load security content
|
26
|
+
def load
|
27
|
+
# export the security policy
|
28
|
+
inspec.command('secedit /export /cfg win_secpol.cfg')
|
29
|
+
# store file content
|
30
|
+
command_result ||= inspec.command('type win_secpol.cfg')
|
31
|
+
# delete temp file
|
32
|
+
inspec.command('del win_secpol.cfg')
|
33
|
+
|
34
|
+
@exit_status = command_result.exit_status.to_i
|
35
|
+
@policy = command_result.stdout
|
36
|
+
@loaded = true
|
37
|
+
|
38
|
+
# returns self
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
def method_missing(method)
|
43
|
+
# load data if needed
|
44
|
+
if (@loaded == false)
|
45
|
+
load
|
46
|
+
end
|
47
|
+
|
48
|
+
# find line with key
|
49
|
+
key = Regexp.escape(method.to_s)
|
50
|
+
target = ''
|
51
|
+
@policy.each_line {|s|
|
52
|
+
target = s.strip if s.match(/^\s*#{key}\s*=\s*(.*)\b/)
|
53
|
+
}
|
54
|
+
|
55
|
+
# extract variable value
|
56
|
+
result = target.match(/[=]{1}\s*(?<value>.*)/)
|
57
|
+
|
58
|
+
if !result.nil?
|
59
|
+
val = result[:value]
|
60
|
+
val = val.to_i if val.match(/^\d+$/)
|
61
|
+
else
|
62
|
+
# TODO: we may need to return skip or failure if the
|
63
|
+
# requested value is not available
|
64
|
+
val = nil
|
65
|
+
end
|
66
|
+
|
67
|
+
val
|
68
|
+
end
|
69
|
+
|
70
|
+
def to_s
|
71
|
+
'Security Policy'
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,379 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# author: Christoph Hartmann
|
3
|
+
# author: Dominik Richter
|
4
|
+
# license: All rights reserved
|
5
|
+
|
6
|
+
# Usage:
|
7
|
+
# describe service('dhcp') do
|
8
|
+
# it { should be_enabled }
|
9
|
+
# it { should be_installed }
|
10
|
+
# it { should be_running }
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# We detect the init system for each operating system, based on the operating
|
14
|
+
# system.
|
15
|
+
#
|
16
|
+
# Fedora 15 : systemd
|
17
|
+
# RedHat 7 : systemd
|
18
|
+
# Ubuntu 15.04 : systemd
|
19
|
+
# Ubuntu < 15.04 : upstart
|
20
|
+
#
|
21
|
+
# TODO: extend the logic to detect the running init system, independently of OS
|
22
|
+
class Service < Inspec.resource(1)
|
23
|
+
name 'service'
|
24
|
+
|
25
|
+
def initialize(service_name)
|
26
|
+
@service_name = service_name
|
27
|
+
@service_mgmt = nil
|
28
|
+
@cache = nil
|
29
|
+
select_package_manager
|
30
|
+
end
|
31
|
+
|
32
|
+
def select_package_manager # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
33
|
+
family = inspec.os[:family]
|
34
|
+
|
35
|
+
case family
|
36
|
+
# Ubuntu
|
37
|
+
# @see: https://wiki.ubuntu.com/SystemdForUpstartUsers
|
38
|
+
# Ubuntu 15.04 : Systemd
|
39
|
+
# Systemd runs with PID 1 as /sbin/init.
|
40
|
+
# Upstart runs with PID 1 as /sbin/upstart.
|
41
|
+
# Ubuntu < 15.04 : Upstart
|
42
|
+
# Upstart runs with PID 1 as /sbin/init.
|
43
|
+
# Systemd runs with PID 1 as /lib/systemd/systemd.
|
44
|
+
when 'ubuntu'
|
45
|
+
version = inspec.os[:release].to_f
|
46
|
+
if version < 15.04
|
47
|
+
@service_mgmt = Upstart.new(inspec)
|
48
|
+
else
|
49
|
+
@service_mgmt = Systemd.new(inspec)
|
50
|
+
end
|
51
|
+
when 'debian'
|
52
|
+
version = inspec.os[:release].to_i
|
53
|
+
if version > 7
|
54
|
+
@service_mgmt = Systemd.new(inspec)
|
55
|
+
else
|
56
|
+
@service_mgmt = SysV.new(inspec)
|
57
|
+
end
|
58
|
+
when 'redhat', 'fedora', 'centos'
|
59
|
+
version = inspec.os[:release].to_i
|
60
|
+
if (%w{ redhat centos }.include?(family) && version >= 7) || (family == 'fedora' && version >= 15)
|
61
|
+
@service_mgmt = Systemd.new(inspec)
|
62
|
+
else
|
63
|
+
@service_mgmt = SysV.new(inspec)
|
64
|
+
end
|
65
|
+
when 'darwin'
|
66
|
+
@service_mgmt = LaunchCtl.new(inspec)
|
67
|
+
when 'windows'
|
68
|
+
@service_mgmt = WindowsSrv.new(inspec)
|
69
|
+
when 'freebsd'
|
70
|
+
@service_mgmt = BSDInit.new(inspec)
|
71
|
+
when 'arch', 'opensuse'
|
72
|
+
@service_mgmt = Systemd.new(inspec)
|
73
|
+
end
|
74
|
+
|
75
|
+
return skip_resource 'The `service` resource is not supported on your OS yet.' if @service_mgmt.nil?
|
76
|
+
end
|
77
|
+
|
78
|
+
def info
|
79
|
+
return @cache if !@cache.nil?
|
80
|
+
return nil if @service_mgmt.nil?
|
81
|
+
@cache = @service_mgmt.info(@service_name)
|
82
|
+
end
|
83
|
+
|
84
|
+
# verifies the service is enabled
|
85
|
+
def enabled?(_level = nil)
|
86
|
+
return false if info.nil?
|
87
|
+
info[:enabled]
|
88
|
+
end
|
89
|
+
|
90
|
+
# verifies the service is registered
|
91
|
+
def installed?(_name = nil, _version = nil)
|
92
|
+
return false if info.nil?
|
93
|
+
info[:installed]
|
94
|
+
end
|
95
|
+
|
96
|
+
# verifies the service is currently running
|
97
|
+
def running?(_under = nil)
|
98
|
+
return false if info.nil?
|
99
|
+
info[:running]
|
100
|
+
end
|
101
|
+
|
102
|
+
def to_s
|
103
|
+
"Service #{@service_name}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class ServiceManager
|
108
|
+
attr_reader :inspec
|
109
|
+
def initialize(inspec)
|
110
|
+
@inspec = inspec
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# @see: http://www.freedesktop.org/software/systemd/man/systemctl.html
|
115
|
+
# @see: http://www.freedesktop.org/software/systemd/man/systemd-system.conf.html
|
116
|
+
class Systemd < ServiceManager
|
117
|
+
def info(service_name)
|
118
|
+
cmd = inspec.command("systemctl show --all #{service_name}")
|
119
|
+
return nil if cmd.exit_status.to_i != 0
|
120
|
+
|
121
|
+
# parse data
|
122
|
+
params = SimpleConfig.new(
|
123
|
+
cmd.stdout.chomp,
|
124
|
+
assignment_re: /^\s*([^=]*?)\s*=\s*(.*?)\s*$/,
|
125
|
+
multiple_values: false,
|
126
|
+
).params
|
127
|
+
|
128
|
+
# LoadState values eg. loaded, not-found
|
129
|
+
params['LoadState'] == 'loaded' ? (installed = true) : (installed = false)
|
130
|
+
# test via 'systemctl is-active service'
|
131
|
+
# SubState values running
|
132
|
+
params['SubState'] == 'running' ? (running = true) : (running = false)
|
133
|
+
# test via systemctl --quiet is-enabled
|
134
|
+
# ActiveState values eg.g inactive, active
|
135
|
+
params['ActiveState'] == 'active' ? (enabled = true) : (enabled = false)
|
136
|
+
|
137
|
+
{
|
138
|
+
name: params['Id'],
|
139
|
+
description: params['Description'],
|
140
|
+
installed: installed,
|
141
|
+
running: running,
|
142
|
+
enabled: enabled,
|
143
|
+
type: 'systemd',
|
144
|
+
}
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# @see: http://upstart.ubuntu.com
|
149
|
+
class Upstart < ServiceManager
|
150
|
+
def info(service_name)
|
151
|
+
# get the status of upstart service
|
152
|
+
cmd = inspec.command("initctl status #{service_name}")
|
153
|
+
return nil if cmd.exit_status != 0
|
154
|
+
|
155
|
+
# @see: http://upstart.ubuntu.com/cookbook/#job-states
|
156
|
+
# grep for running to indicate the service is there
|
157
|
+
match_running = /running/.match(cmd.stdout)
|
158
|
+
!match_running.nil? ? (running = true) : (running = false)
|
159
|
+
|
160
|
+
# check if a service is enabled
|
161
|
+
# http://upstart.ubuntu.com/cookbook/#determine-if-a-job-is-disabled
|
162
|
+
# $ initctl show-config $job | grep -q "^ start on" && echo enabled || echo disabled
|
163
|
+
# Ubuntu 10.04 show-config is not supported
|
164
|
+
# @see http://manpages.ubuntu.com/manpages/maverick/man8/initctl.8.html
|
165
|
+
config = inspec.command("initctl show-config #{service_name}")
|
166
|
+
match_enabled = /^\s*start on/.match(config.stdout)
|
167
|
+
!match_enabled.nil? ? (enabled = true) : (enabled = false)
|
168
|
+
|
169
|
+
# implement fallback for Ubuntu 10.04
|
170
|
+
if inspec.os[:family] == 'ubuntu' &&
|
171
|
+
inspec.os[:release].to_f >= 10.04 &&
|
172
|
+
inspec.os[:release].to_f < 12.04 &&
|
173
|
+
cmd.exit_status == 0
|
174
|
+
enabled = true
|
175
|
+
end
|
176
|
+
|
177
|
+
{
|
178
|
+
name: service_name,
|
179
|
+
description: nil,
|
180
|
+
installed: true,
|
181
|
+
running: running,
|
182
|
+
enabled: enabled,
|
183
|
+
type: 'upstart',
|
184
|
+
}
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
class SysV < ServiceManager
|
189
|
+
def info(service_name)
|
190
|
+
# check if service is installed
|
191
|
+
# read all available services via ls /etc/init.d/
|
192
|
+
srvlist = inspec.command('ls -1 /etc/init.d/')
|
193
|
+
return nil if srvlist.exit_status != 0
|
194
|
+
|
195
|
+
# check if the service is in list
|
196
|
+
service = srvlist.stdout.split("\n").select { |srv| srv == service_name }
|
197
|
+
|
198
|
+
# abort if we could not find any service
|
199
|
+
return nil if service.empty?
|
200
|
+
|
201
|
+
# read all enabled services from runlevel
|
202
|
+
# on rhel via: 'chkconfig --list', is not installed by default
|
203
|
+
# bash: for i in `find /etc/rc*.d -name S*`; do basename $i | sed -r 's/^S[0-9]+//'; done | sort | uniq
|
204
|
+
enabled_services_cmd = inspec.command('find /etc/rc*.d -name S*')
|
205
|
+
enabled_services = enabled_services_cmd.stdout.split("\n").select { |line|
|
206
|
+
/(^.*#{service_name}.*)/.match(line)
|
207
|
+
}
|
208
|
+
enabled_services.empty? ? enabled = false : enabled = true
|
209
|
+
|
210
|
+
# check if service is really running
|
211
|
+
# service throws an exit code if the service is not installed or
|
212
|
+
# not enabled
|
213
|
+
|
214
|
+
# on debian service is located /usr/sbin/service, on centos it is located here /sbin/service
|
215
|
+
service_cmd = 'service'
|
216
|
+
service_cmd = '/usr/sbin/service' if inspec.os[:family] == 'debian'
|
217
|
+
service_cmd = '/sbin/service' if inspec.os[:family] == 'centos'
|
218
|
+
|
219
|
+
cmd = inspec.command("#{service_cmd} #{service_name} status")
|
220
|
+
cmd.exit_status == 0 ? (running = true) : (running = false)
|
221
|
+
{
|
222
|
+
name: service_name,
|
223
|
+
description: nil,
|
224
|
+
installed: true,
|
225
|
+
running: running,
|
226
|
+
enabled: enabled,
|
227
|
+
type: 'sysv',
|
228
|
+
}
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
# @see: https://www.freebsd.org/doc/en/articles/linux-users/startup.html
|
233
|
+
# @see: https://www.freebsd.org/cgi/man.cgi?query=rc.conf&sektion=5
|
234
|
+
class BSDInit < ServiceManager
|
235
|
+
def info(service_name)
|
236
|
+
# check if service is enabled
|
237
|
+
# services are enabled in /etc/rc.conf and /etc/defaults/rc.conf
|
238
|
+
# via #{service_name}_enable="YES"
|
239
|
+
# service SERVICE status returns the following result if not activated:
|
240
|
+
# Cannot 'status' sshd. Set sshd_enable to YES in /etc/rc.conf or use 'onestatus' instead of 'status'.
|
241
|
+
# gather all enabled services
|
242
|
+
cmd = inspec.command('service -e')
|
243
|
+
return nil if cmd.exit_status != 0
|
244
|
+
|
245
|
+
# search for the service
|
246
|
+
srv = /(^.*#{service_name}$)/.match(cmd.stdout)
|
247
|
+
return nil if srv.nil? || srv[0].nil?
|
248
|
+
enabled = true
|
249
|
+
|
250
|
+
# check if the service is running
|
251
|
+
# if the service is not available or not running, we always get an error code
|
252
|
+
cmd = inspec.command("service #{service_name} onestatus")
|
253
|
+
cmd.exit_status == 0 ? (running = true) : (running = false)
|
254
|
+
|
255
|
+
{
|
256
|
+
name: service_name,
|
257
|
+
description: nil,
|
258
|
+
installed: true,
|
259
|
+
running: running,
|
260
|
+
enabled: enabled,
|
261
|
+
type: 'bsd-init',
|
262
|
+
}
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
# MacOS / Darwin
|
267
|
+
# new launctl on macos 10.10
|
268
|
+
class LaunchCtl < ServiceManager
|
269
|
+
def info(service_name)
|
270
|
+
# get the status of upstart service
|
271
|
+
cmd = inspec.command('launchctl list')
|
272
|
+
return nil if cmd.exit_status != 0
|
273
|
+
|
274
|
+
# search for the service
|
275
|
+
srv = /(^.*#{service_name}.*)/.match(cmd.stdout)
|
276
|
+
return nil if srv.nil? || srv[0].nil?
|
277
|
+
|
278
|
+
# extract values from service
|
279
|
+
parsed_srv = /^([0-9]+)\s*(\w*)\s*(\S*)/.match(srv[0])
|
280
|
+
!parsed_srv.nil? ? (enabled = true) : (enabled = false)
|
281
|
+
|
282
|
+
# check if the service is running
|
283
|
+
pid = parsed_srv[0]
|
284
|
+
!pid.nil? ? (running = true) : (running = false)
|
285
|
+
|
286
|
+
# extract service label
|
287
|
+
srv = parsed_srv[3] || service_name
|
288
|
+
|
289
|
+
{
|
290
|
+
name: srv,
|
291
|
+
description: nil,
|
292
|
+
installed: true,
|
293
|
+
running: running,
|
294
|
+
enabled: enabled,
|
295
|
+
type: 'darwin',
|
296
|
+
}
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
# Determine the service state from Windows
|
301
|
+
# Uses Powershell to retrieve the information
|
302
|
+
class WindowsSrv < ServiceManager
|
303
|
+
# Determine service details
|
304
|
+
# PS: Get-Service -Name 'dhcp'| Select-Object -Property Name, DisplayName, Status | ConvertTo-Json
|
305
|
+
# {
|
306
|
+
# "Name": "dhcp",
|
307
|
+
# "DisplayName": "DHCP Client",
|
308
|
+
# "Status": 4
|
309
|
+
# }
|
310
|
+
#
|
311
|
+
# Until StartMode is not added to Get-Service, we need to do a workaround
|
312
|
+
# @see: https://connect.microsoft.com/PowerShell/feedback/details/424948/i-would-like-to-see-the-property-starttype-added-to-get-services
|
313
|
+
# Use the following powershell to determine the start mode
|
314
|
+
# PS: Get-WmiObject -Class Win32_Service | Where-Object {$_.Name -eq $name -or $_.DisplayName -eq $name} | Select-Object -Prop
|
315
|
+
# erty Name, StartMode, State, Status | ConvertTo-Json
|
316
|
+
# {
|
317
|
+
# "Name": "Dhcp",
|
318
|
+
# "StartMode": "Auto",
|
319
|
+
# "State": "Running",
|
320
|
+
# "Status": "OK"
|
321
|
+
# }
|
322
|
+
#
|
323
|
+
# Windows Services have the following status code:
|
324
|
+
# @see: https://msdn.microsoft.com/en-us/library/windows/desktop/ms685996(v=vs.85).aspx
|
325
|
+
# - 1: Stopped
|
326
|
+
# - 2: Starting
|
327
|
+
# - 3: Stopping
|
328
|
+
# - 4: Running
|
329
|
+
# - 5: Continue Pending
|
330
|
+
# - 6: Pause Pending
|
331
|
+
# - 7: Paused
|
332
|
+
def info(service_name)
|
333
|
+
cmd = inspec.command("New-Object -Type PSObject | Add-Member -MemberType NoteProperty -Name Service -Value (Get-Service -Name #{service_name}| Select-Object -Property Name, DisplayName, Status) -PassThru | Add-Member -MemberType NoteProperty -Name WMI -Value (Get-WmiObject -Class Win32_Service | Where-Object {$_.Name -eq '#{service_name}' -or $_.DisplayName -eq '#{service_name}'} | Select-Object -Property StartMode) -PassThru | ConvertTo-Json")
|
334
|
+
|
335
|
+
# cannot rely on exit code for now, successful command returns exit code 1
|
336
|
+
# return nil if cmd.exit_status != 0
|
337
|
+
# try to parse json
|
338
|
+
begin
|
339
|
+
service = JSON.parse(cmd.stdout)
|
340
|
+
rescue JSON::ParserError => _e
|
341
|
+
return nil
|
342
|
+
end
|
343
|
+
|
344
|
+
# check that we got a response
|
345
|
+
return nil if service.nil? || service['Service'].nil?
|
346
|
+
|
347
|
+
{
|
348
|
+
name: service['Service']['Name'],
|
349
|
+
description: service['Service']['DisplayName'],
|
350
|
+
installed: true,
|
351
|
+
running: service_running?(service),
|
352
|
+
enabled: service_enabled?(service),
|
353
|
+
type: 'windows',
|
354
|
+
}
|
355
|
+
end
|
356
|
+
|
357
|
+
private
|
358
|
+
|
359
|
+
# detect if service is enabled
|
360
|
+
def service_enabled?(service)
|
361
|
+
if !service['WMI'].nil? &&
|
362
|
+
!service['WMI']['StartMode'].nil? &&
|
363
|
+
service['WMI']['StartMode'] == 'Auto'
|
364
|
+
true
|
365
|
+
else
|
366
|
+
false
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
# detect if service is running
|
371
|
+
def service_running?(service)
|
372
|
+
if !service['Service']['Status'].nil? &&
|
373
|
+
service['Service']['Status'] == 4
|
374
|
+
true
|
375
|
+
else
|
376
|
+
false
|
377
|
+
end
|
378
|
+
end
|
379
|
+
end
|