inspec 0.9.5 → 0.9.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +58 -8
  3. data/README.md +8 -39
  4. data/Rakefile +74 -9
  5. data/bin/inspec +66 -10
  6. data/docs/ctl_inspec.rst +7 -1
  7. data/docs/inspec_and_friends.rst +1 -1
  8. data/docs/resources.rst +51 -45
  9. data/examples/README.md +7 -0
  10. data/examples/kitchen-ansible/.kitchen.yml +25 -0
  11. data/examples/kitchen-ansible/Gemfile +20 -0
  12. data/examples/kitchen-ansible/README.md +53 -0
  13. data/examples/kitchen-ansible/files/nginx.repo +6 -0
  14. data/examples/kitchen-ansible/tasks/main.yml +16 -0
  15. data/examples/kitchen-ansible/test/integration/default/default.yml +5 -0
  16. data/examples/{test-kitchen → kitchen-ansible}/test/integration/default/web_spec.rb +0 -0
  17. data/examples/{test-kitchen → kitchen-chef}/.kitchen.yml +1 -1
  18. data/examples/{test-kitchen → kitchen-chef}/Berksfile +0 -0
  19. data/examples/{test-kitchen → kitchen-chef}/Gemfile +1 -2
  20. data/examples/{test-kitchen → kitchen-chef}/README.md +1 -1
  21. data/examples/{test-kitchen → kitchen-chef}/metadata.rb +0 -0
  22. data/examples/{test-kitchen → kitchen-chef}/recipes/default.rb +0 -0
  23. data/examples/{test-kitchen → kitchen-chef}/recipes/nginx.rb +0 -0
  24. data/examples/kitchen-chef/test/integration/default/web_spec.rb +28 -0
  25. data/examples/kitchen-puppet/.kitchen.yml +22 -0
  26. data/examples/kitchen-puppet/Gemfile +21 -0
  27. data/examples/kitchen-puppet/Puppetfile +25 -0
  28. data/examples/kitchen-puppet/README.md +53 -0
  29. data/examples/kitchen-puppet/manifests/site.pp +33 -0
  30. data/examples/kitchen-puppet/metadata.json +11 -0
  31. data/examples/kitchen-puppet/test/integration/default/web_spec.rb +28 -0
  32. data/inspec.gemspec +2 -0
  33. data/lib/inspec/plugins/resource.rb +21 -0
  34. data/lib/inspec/shell.rb +73 -11
  35. data/lib/inspec/version.rb +1 -1
  36. data/lib/matchers/matchers.rb +43 -0
  37. data/lib/resources/apache_conf.rb +12 -9
  38. data/lib/resources/apt.rb +7 -0
  39. data/lib/resources/audit_policy.rb +6 -6
  40. data/lib/resources/auditd_conf.rb +6 -7
  41. data/lib/resources/auditd_rules.rb +9 -8
  42. data/lib/resources/bond.rb +6 -6
  43. data/lib/resources/bridge.rb +7 -0
  44. data/lib/resources/command.rb +10 -8
  45. data/lib/resources/csv.rb +6 -5
  46. data/lib/resources/directory.rb +6 -0
  47. data/lib/resources/etc_group.rb +9 -1
  48. data/lib/resources/file.rb +72 -61
  49. data/lib/resources/gem.rb +6 -4
  50. data/lib/resources/group.rb +7 -0
  51. data/lib/resources/host.rb +6 -0
  52. data/lib/resources/inetd_conf.rb +8 -8
  53. data/lib/resources/ini.rb +6 -6
  54. data/lib/resources/interface.rb +8 -8
  55. data/lib/resources/iptables.rb +6 -0
  56. data/lib/resources/json.rb +6 -5
  57. data/lib/resources/kernel_module.rb +6 -5
  58. data/lib/resources/kernel_parameter.rb +6 -4
  59. data/lib/resources/limits_conf.rb +6 -6
  60. data/lib/resources/login_def.rb +6 -0
  61. data/lib/resources/mysql_conf.rb +6 -0
  62. data/lib/resources/mysql_session.rb +7 -0
  63. data/lib/resources/npm.rb +6 -4
  64. data/lib/resources/ntp_conf.rb +7 -7
  65. data/lib/resources/oneget.rb +6 -0
  66. data/lib/resources/os.rb +8 -0
  67. data/lib/resources/os_env.rb +6 -0
  68. data/lib/resources/package.rb +8 -1
  69. data/lib/resources/parse_config.rb +14 -0
  70. data/lib/resources/passwd.rb +7 -0
  71. data/lib/resources/pip.rb +6 -0
  72. data/lib/resources/port.rb +22 -11
  73. data/lib/resources/postgres_conf.rb +6 -0
  74. data/lib/resources/postgres_session.rb +8 -0
  75. data/lib/resources/processes.rb +17 -1
  76. data/lib/resources/registry_key.rb +7 -0
  77. data/lib/resources/script.rb +11 -0
  78. data/lib/resources/security_policy.rb +6 -1
  79. data/lib/resources/service.rb +10 -0
  80. data/lib/resources/ssh_conf.rb +6 -0
  81. data/lib/resources/user.rb +9 -2
  82. data/lib/resources/windows_feature.rb +6 -0
  83. data/lib/resources/yaml.rb +6 -0
  84. data/lib/resources/yum.rb +7 -0
  85. data/lib/utils/find_files.rb +15 -7
  86. data/test/helper.rb +9 -0
  87. data/test/integration/.kitchen.yml +3 -0
  88. data/test/integration/test/integration/default/compare_matcher_spec.rb +19 -0
  89. data/test/integration/test/integration/default/etc_group.rb +13 -0
  90. data/test/integration/test/integration/default/os_spec.rb +13 -0
  91. data/test/integration/test/integration/default/port_spec.rb +1 -1
  92. data/test/unit/mock/cmd/find-apache2-conf-enabled +1 -0
  93. data/test/unit/mock/cmd/find-apache2-ports-conf +1 -0
  94. data/test/unit/mock/cmd/ps-aux +2 -0
  95. data/test/unit/mock/files/apache2.conf +14 -0
  96. data/test/unit/mock/files/ports.conf +6 -0
  97. data/test/unit/mock/files/serve-cgi-bin.conf +20 -0
  98. data/test/unit/resources/apache_conf_test.rb +31 -0
  99. data/test/unit/resources/file_test.rb +181 -0
  100. data/test/unit/resources/package_test.rb +9 -0
  101. data/test/unit/resources/port_test.rb +33 -13
  102. data/test/unit/resources/processes_test.rb +6 -0
  103. data/test/unit/resources/service_test.rb +10 -0
  104. data/test/unit/resources/user_test.rb +12 -0
  105. data/test/unit/utils/find_files_test.rb +23 -0
  106. metadata +61 -16
  107. data/bin/inspec.orig +0 -115
  108. data/lib/resources/.service.rb.swp +0 -0
  109. data/test/unit/mock/profiles/rules/metadata.rb +0 -2
  110. data/test/unit/mock/profiles/rules/test/test.rb +0 -6
@@ -10,6 +10,12 @@ require 'resources/postgres'
10
10
 
11
11
  class PostgresConf < Inspec.resource(1)
12
12
  name 'postgres_conf'
13
+ desc 'Use the postgres_conf InSpec audit resource to test the contents of the configuration file for PostgreSQL, typically located at /etc/postgresql/<version>/main/postgresql.conf or /var/lib/postgres/data/postgresql.conf, depending on the platform.'
14
+ example "
15
+ describe postgres_conf do
16
+ its('max_connections') { should eq '5' }
17
+ end
18
+ "
13
19
 
14
20
  include FindFiles
15
21
 
@@ -25,6 +25,14 @@ end
25
25
 
26
26
  class PostgresSession < Inspec.resource(1)
27
27
  name 'postgres_session'
28
+ desc 'Use the postgres_session InSpec audit resource to test SQL commands run against a PostgreSQL database.'
29
+ example "
30
+ sql = postgres_session('username', 'password')
31
+
32
+ describe sql.query('SELECT * FROM pg_shadow WHERE passwd IS NULL;') do
33
+ its('output') { should eq('') }
34
+ end
35
+ "
28
36
 
29
37
  def initialize(user, pass)
30
38
  @user = user || 'postgres'
@@ -6,8 +6,19 @@
6
6
 
7
7
  class Processes < Inspec.resource(1)
8
8
  name 'processes'
9
+ desc 'Use the processes InSpec audit resource to test properties for programs that are running on the system.'
10
+ example "
11
+ describe processes('mysqld') do
12
+ its('list.length') { should eq 1 }
13
+ its('users') { should eq ['mysql'] }
14
+ its('states') { should include 'S' }
15
+ end
16
+ "
17
+
18
+ attr_reader :list,
19
+ :users,
20
+ :states
9
21
 
10
- attr_reader :list
11
22
  def initialize(grep)
12
23
  # turn into a regexp if it isn't one yet
13
24
  if grep.class == String
@@ -19,6 +30,11 @@ class Processes < Inspec.resource(1)
19
30
  @list = all_cmds.find_all do |hm|
20
31
  hm[:command] =~ grep
21
32
  end
33
+
34
+ { users: :user,
35
+ states: :stat }.each do |var, key|
36
+ instance_variable_set("@#{var}", @list.map { |l| l[key] }.uniq)
37
+ end
22
38
  end
23
39
 
24
40
  def to_s
@@ -12,6 +12,12 @@ require 'json'
12
12
 
13
13
  class RegistryKey < Inspec.resource(1)
14
14
  name 'registry_key'
15
+ desc 'Use the registry_key InSpec audit resource to test key values in the Microsoft Windows registry.'
16
+ example "
17
+ describe registry_key('path\to\key') do
18
+ its('name') { should eq 'value' }
19
+ end
20
+ "
15
21
 
16
22
  attr_accessor :reg_key
17
23
 
@@ -20,6 +26,7 @@ class RegistryKey < Inspec.resource(1)
20
26
  reg_key ||= name
21
27
  @name = name
22
28
  @reg_key = reg_key
29
+ skip_resource 'The `registry_key` resource is not supported on your OS yet.'
23
30
  end
24
31
 
25
32
  def exists?
@@ -6,6 +6,16 @@
6
6
 
7
7
  class Script < Cmd
8
8
  name 'script'
9
+ desc 'Use the script InSpec audit resource to test a Windows PowerShell script on the Microsoft Windows platform.'
10
+ example "
11
+ script = <<-EOH
12
+ # you powershell script
13
+ EOH
14
+
15
+ describe script(script) do
16
+ its('matcher') { should eq 'output' }
17
+ end
18
+ "
9
19
 
10
20
  def initialize(script)
11
21
  case inspec.os[:family]
@@ -16,6 +26,7 @@ class Script < Cmd
16
26
  script = WinRM::PowershellScript.new(script)
17
27
  cmd = "powershell -encodedCommand #{script.encoded}"
18
28
  else
29
+ cmd = ''
19
30
  return skip_resource 'The `script` resource is not supported on your OS yet.'
20
31
  end
21
32
  super(cmd)
@@ -15,7 +15,12 @@
15
15
 
16
16
  class SecurityPolicy < Inspec.resource(1)
17
17
  name 'security_policy'
18
-
18
+ desc 'Use the security_policy InSpec audit resource to test security policies on the Microsoft Windows platform.'
19
+ example "
20
+ describe security_policy do
21
+ its('SeNetworkLogonRight') { should eq '*S-1-5-11' }
22
+ end
23
+ "
19
24
  def initialize
20
25
  @loaded = false
21
26
  @policy = nil
@@ -21,6 +21,14 @@
21
21
  # TODO: extend the logic to detect the running init system, independently of OS
22
22
  class Service < Inspec.resource(1)
23
23
  name 'service'
24
+ desc 'Use the service InSpec audit resource to test if the named service is installed, running and/or enabled.'
25
+ example "
26
+ describe service('service_name') do
27
+ it { should be_installed }
28
+ it { should be_enabled }
29
+ it { should be_running }
30
+ end
31
+ "
24
32
 
25
33
  def initialize(service_name)
26
34
  @service_name = service_name
@@ -62,6 +70,8 @@ class Service < Inspec.resource(1)
62
70
  else
63
71
  @service_mgmt = SysV.new(inspec)
64
72
  end
73
+ when 'wrlinux'
74
+ @service_mgmt = SysV.new(inspec)
65
75
  when 'darwin'
66
76
  @service_mgmt = LaunchCtl.new(inspec)
67
77
  when 'windows'
@@ -8,6 +8,12 @@ require 'utils/simpleconfig'
8
8
 
9
9
  class SshConf < Inspec.resource(1)
10
10
  name 'ssh_config'
11
+ desc 'Use the sshd_config InSpec audit resource to test configuration data for the Open SSH daemon located at /etc/ssh/sshd_config on Linux and UNIX platforms. sshd---the Open SSH daemon---listens on dedicated ports, starts a daemon for each incoming connection, and then handles encryption, authentication, key exchanges, command executation, and data exchanges.'
12
+ example "
13
+ describe sshd_config do
14
+ its('Protocol') { should eq '2' }
15
+ end
16
+ "
11
17
 
12
18
  def initialize(conf_path = nil, type = nil)
13
19
  @conf_path = conf_path || '/etc/ssh/ssh_config'
@@ -40,14 +40,21 @@ require 'utils/convert'
40
40
 
41
41
  class User < Inspec.resource(1)
42
42
  name 'user'
43
-
43
+ desc 'Use the user InSpec audit resource to test user profiles, including the groups to which they belong, the frequency of required password changes, the directory paths to home and shell.'
44
+ example "
45
+ describe user('root') do
46
+ it { should exist }
47
+ its('uid') { should eq 1234 }
48
+ its('gid') { should eq 1234 }
49
+ end
50
+ "
44
51
  def initialize(user)
45
52
  @user = user
46
53
 
47
54
  # select package manager
48
55
  @user_provider = nil
49
56
  case inspec.os[:family]
50
- when 'ubuntu', 'debian', 'redhat', 'fedora', 'centos', 'arch', 'opensuse'
57
+ when 'ubuntu', 'debian', 'redhat', 'fedora', 'centos', 'arch', 'opensuse', 'wrlinux'
51
58
  @user_provider = LinuxUser.new(inspec)
52
59
  when 'windows'
53
60
  @user_provider = WindowsUser.new(inspec)
@@ -29,6 +29,12 @@
29
29
  # }
30
30
  class WindowsFeature < Inspec.resource(1)
31
31
  name 'windows_feature'
32
+ desc 'Use the windows_feature InSpec audit resource to test features on Microsoft Windows.'
33
+ example "
34
+ describe windows_feature('dhcp') do
35
+ it { should be_installed }
36
+ end
37
+ "
32
38
 
33
39
  def initialize(feature)
34
40
  @feature = feature
@@ -11,6 +11,12 @@ require 'yaml'
11
11
  # end
12
12
  class YamlConfig < JsonConfig
13
13
  name 'yaml'
14
+ desc 'Use the yaml InSpec audit resource to test configuration data in a YAML file.'
15
+ example "
16
+ describe yaml do
17
+ its('name') { should eq 'foo' }
18
+ end
19
+ "
14
20
 
15
21
  # override file load and parse hash from yaml
16
22
  def parse(content)
@@ -32,6 +32,13 @@ require 'resources/file'
32
32
 
33
33
  class Yum < Inspec.resource(1)
34
34
  name 'yum'
35
+ desc 'Use the yum InSpec audit resource to test packages in the Yum repository.'
36
+ example "
37
+ describe yum.repo('name') do
38
+ it { should exist }
39
+ it { should be_enabled }
40
+ end
41
+ "
35
42
 
36
43
  # returns all repositories
37
44
  # works as following:
@@ -16,21 +16,29 @@ module FindFiles
16
16
  door: 'D',
17
17
  }
18
18
 
19
+ # ignores errors
19
20
  def find_files(path, opts = {})
21
+ find_files_or_error(path, opts) || []
22
+ end
23
+
24
+ def find_files_or_error(path, opts = {})
20
25
  depth = opts[:depth]
21
- type = TYPES[opts[:type].to_sym]
26
+ type = TYPES[opts[:type].to_sym] if opts[:type]
22
27
 
23
28
  cmd = "find #{path}"
24
29
  cmd += " -maxdepth #{depth.to_i}" if depth.to_i > 0
25
30
  cmd += " -type #{type}" unless type.nil?
26
31
 
27
- result = inspec.run_command(cmd)
32
+ result = inspec.command(cmd)
28
33
  exit_status = result.exit_status
29
34
 
30
- return [nil, exit_status] unless exit_status == 0
31
- files = result.stdout.split("\n")
32
- .map(&:strip)
33
- .find_all { |x| !x.empty? }
34
- [files, exit_status]
35
+ unless exit_status == 0
36
+ warn "find_files(): exit #{exit_status} from `#{find}`"
37
+ return nil
38
+ end
39
+
40
+ result.stdout.split("\n")
41
+ .map(&:strip)
42
+ .find_all { |x| !x.empty? }
35
43
  end
36
44
  end
@@ -4,6 +4,7 @@
4
4
 
5
5
  require 'minitest/autorun'
6
6
  require 'minitest/spec'
7
+ require 'mocha/setup'
7
8
 
8
9
  require 'simplecov'
9
10
  SimpleCov.start do
@@ -36,6 +37,7 @@ class MockLoader
36
37
  ubuntu1404: { family: 'ubuntu', release: '14.04', arch: 'x86_64' },
37
38
  ubuntu1504: { family: 'ubuntu', release: '15.04', arch: 'x86_64' },
38
39
  windows: { family: 'windows', release: nil, arch: nil },
40
+ wrlinux: { family: 'wrlinux', release: '7.0(3)I2(2)', arch: 'x86_64' },
39
41
  undefined: { family: nil, release: nil, arch: nil },
40
42
  }
41
43
 
@@ -92,6 +94,9 @@ class MockLoader
92
94
  'policyfile.lock.json' => mockfile.call('policyfile.lock.json'),
93
95
  '/sys/class/net/br0/bridge' => mockdir.call(true),
94
96
  'rootwrap.conf' => mockfile.call('rootwrap.conf'),
97
+ '/etc/apache2/apache2.conf' => mockfile.call('apache2.conf'),
98
+ '/etc/apache2/ports.conf' => mockfile.call('ports.conf'),
99
+ '/etc/apache2/conf-enabled/serve-cgi-bin.conf' => mockfile.call('serve-cgi-bin.conf'),
95
100
  }
96
101
 
97
102
  # create all mock commands
@@ -188,6 +193,10 @@ class MockLoader
188
193
  "find /etc/apt/ -name *.list -exec sh -c 'cat {} || echo -n' \\;" => cmd.call('etc-apt'),
189
194
  # iptables
190
195
  'iptables -S' => cmd.call('iptables-s'),
196
+ # apache_conf
197
+ 'find /etc/apache2/ports.conf -maxdepth 1 -type f' => cmd.call('find-apache2-ports-conf'),
198
+ 'find /etc/apache2/conf-enabled/*.conf -maxdepth 1 -type f' => cmd.call('find-apache2-conf-enabled'),
199
+
191
200
  }
192
201
 
193
202
  @backend
@@ -34,6 +34,9 @@ platforms:
34
34
  - name: ubuntu-12.04-i386
35
35
  - name: ubuntu-10.04
36
36
  - name: ubuntu-10.04-i386
37
+ - name: mint-17.2-cinnamon
38
+ driver_config:
39
+ box: artem-sidorenko/mint-17.2-cinnamon
37
40
 
38
41
  suites:
39
42
  - name: default
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ # uses the `cmp` matcher instead of the eq matcher
4
+ describe sshd_config do
5
+ its('Port') { should eq '22' }
6
+ its('Port') { should_not eq 22 }
7
+
8
+ its('Port') { should cmp '22' }
9
+ its('Port') { should cmp 22 }
10
+ its('Port') { should cmp 22.0 }
11
+ its('Port') { should_not cmp 22.1 }
12
+
13
+ its('LogLevel') { should eq 'INFO' }
14
+ its('LogLevel') { should_not eq 'info'}
15
+
16
+ its('LogLevel') { should cmp 'INFO' }
17
+ its('LogLevel') { should cmp 'info' }
18
+ its('LogLevel') { should cmp 'InfO' }
19
+ end
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+
3
+ if os.unix?
4
+ describe etc_group do
5
+ its('gids') { should_not contain_duplicates }
6
+ its('groups') { should include 'root' }
7
+ its('users') { should include 'root' }
8
+ end
9
+
10
+ describe etc_group.where(name: 'root') do
11
+ its('users') { should include 'root' }
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+
3
+ family = os[:family]
4
+
5
+ # use symbol
6
+ describe os[:family] do
7
+ it { should eq family }
8
+ end
9
+
10
+ # use string
11
+ describe os['family'] do
12
+ it { should eq family }
13
+ end
@@ -4,6 +4,6 @@ if os.unix?
4
4
  # check that ssh runs
5
5
  describe port(22) do
6
6
  it { should be_listening }
7
- its('protocol') { should include('tcp') }
7
+ its('protocols') { should include('tcp') }
8
8
  end
9
9
  end
@@ -0,0 +1 @@
1
+ /etc/apache2/conf-enabled/serve-cgi-bin.conf
@@ -0,0 +1 @@
1
+ /etc/apache2/ports.conf
@@ -1,3 +1,5 @@
1
1
  USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
2
2
  root 1 0.0 0.0 18084 3228 ? Ss 14:15 0:00 /bin/bash
3
3
  root 13 0.0 0.0 15284 2148 ? R+ 15:08 0:00 ps aux
4
+ noot 19 0.0 0.0 24521 1536 s001 Ss 09:23 0:00 svc
5
+ noot 23 0.0 0.0 25044 1908 s000 S 08:46 0:00 svc
@@ -0,0 +1,14 @@
1
+ # This is the main Apache server configuration file. It contains comments.
2
+ ServerRoot "/etc/apache2"
3
+
4
+ User ${APACHE_RUN_USER}
5
+ Include ports.conf
6
+
7
+ <Directory />
8
+ Options FollowSymLinks
9
+ AllowOverride None
10
+ Require all denied
11
+ </Directory>
12
+
13
+ # Include generic snippets of statements
14
+ IncludeOptional conf-enabled/*.conf
@@ -0,0 +1,6 @@
1
+ # apache ports.conf
2
+ Listen 80
3
+
4
+ <IfModule ssl_module>
5
+ Listen 443
6
+ </IfModule>
@@ -0,0 +1,20 @@
1
+ <IfModule mod_alias.c>
2
+ <IfModule mod_cgi.c>
3
+ Define ENABLE_USR_LIB_CGI_BIN
4
+ </IfModule>
5
+
6
+ <IfModule mod_cgid.c>
7
+ Define ENABLE_USR_LIB_CGI_BIN
8
+ </IfModule>
9
+
10
+ <IfDefine ENABLE_USR_LIB_CGI_BIN>
11
+ ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
12
+ <Directory "/usr/lib/cgi-bin">
13
+ AllowOverride None
14
+ Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
15
+ Require all granted
16
+ </Directory>
17
+ </IfDefine>
18
+ </IfModule>
19
+
20
+ # vim: syntax=apache ts=4 sw=4 sts=4 sr noet
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+ # author: Stephan Renatus
3
+
4
+ require 'helper'
5
+
6
+ describe 'Inspec::Resources::ApacheConf' do
7
+ let(:resource) { load_resource('apache_conf') }
8
+
9
+ it 'verify content is a string' do
10
+ _(resource.content).must_be_kind_of String
11
+ end
12
+
13
+ it 'verify params is a hashmap' do
14
+ _(resource.params).must_be_kind_of Hash
15
+ end
16
+
17
+ it 'reads values in apache2.conf' do
18
+ _(resource.params('ServerRoot')).must_equal ['"/etc/apache2"']
19
+ end
20
+
21
+ it 'reads values in from the direct include ports.conf' do
22
+ _(resource.params('Listen').sort).must_equal ['443', '80']
23
+ end
24
+
25
+ it 'reads values in from wildcard include serve-cgi-bin.conf' do
26
+ # TODO(sr) currently, the parser only merges parameter across separate
27
+ # source files, not in one file
28
+ _(resource.params('Define')).must_equal ['ENABLE_USR_LIB_CGI_BIN',
29
+ 'ENABLE_USR_LIB_CGI_BIN']
30
+ end
31
+ end