inspec 0.9.0
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.
- 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
|