openvas-cli 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/Gemfile +2 -0
  2. data/Gemfile.lock +50 -0
  3. data/VERSION +1 -1
  4. data/lib/openvas-cli/configuration.rb +25 -0
  5. data/lib/openvas-cli/conn_addin.rb +27 -0
  6. data/lib/openvas-cli/immutable_children_validator.rb +15 -0
  7. data/lib/openvas-cli/vas_administrator.rb +7 -0
  8. data/lib/openvas-cli/vas_base.rb +20 -30
  9. data/lib/openvas-cli/vas_config.rb +127 -0
  10. data/lib/openvas-cli/vas_connection.rb +140 -0
  11. data/lib/openvas-cli/vas_exceptions.rb +9 -7
  12. data/lib/openvas-cli/vas_lsc_credential.rb +110 -0
  13. data/lib/openvas-cli/vas_nvt.rb +64 -64
  14. data/lib/openvas-cli/vas_nvt_family.rb +39 -30
  15. data/lib/openvas-cli/vas_override.rb +6 -4
  16. data/lib/openvas-cli/vas_period.rb +89 -0
  17. data/lib/openvas-cli/vas_preference.rb +139 -49
  18. data/lib/openvas-cli/vas_report.rb +110 -103
  19. data/lib/openvas-cli/vas_result.rb +90 -89
  20. data/lib/openvas-cli/vas_schedule.rb +163 -55
  21. data/lib/openvas-cli/vas_target.rb +200 -23
  22. data/lib/openvas-cli/vas_task.rb +229 -30
  23. data/lib/openvas-cli/vas_task_progress.rb +29 -0
  24. data/lib/openvas-cli/xml_addin.rb +34 -0
  25. data/lib/openvas_cli.rb +19 -0
  26. data/openvas-cli.gemspec +28 -6
  27. data/spec/openvas-cli/vas_administrator_spec.rb +6 -0
  28. data/spec/openvas-cli/vas_config_spec.rb +81 -0
  29. data/spec/openvas-cli/vas_lsc_credential_spec.rb +72 -0
  30. data/spec/openvas-cli/vas_nvt_family_spec.rb +7 -5
  31. data/spec/openvas-cli/vas_nvt_spec.rb +30 -26
  32. data/spec/openvas-cli/vas_period_spec.rb +7 -0
  33. data/spec/openvas-cli/vas_preference_spec.rb +23 -21
  34. data/spec/openvas-cli/vas_report_spec.rb +65 -63
  35. data/spec/openvas-cli/vas_result_spec.rb +94 -93
  36. data/spec/openvas-cli/vas_schedule_spec.rb +154 -57
  37. data/spec/openvas-cli/vas_target_spec.rb +140 -28
  38. data/spec/openvas-cli/vas_task_spec.rb +92 -11
  39. data/spec/spec_helper.rb +15 -5
  40. metadata +72 -24
  41. data/lib/openvas-cli/openvas-cli.rb +0 -273
  42. data/spec/openvas-cli/openvas-cli_spec.rb +0 -45
data/Gemfile CHANGED
@@ -3,7 +3,9 @@ source "http://rubygems.org"
3
3
  # Example:
4
4
  gem "activesupport", ">= 3.0.5"
5
5
  gem 'activerecord', '>= 3.0.5'
6
+ gem 'rails', '>=3.0.5'
6
7
  gem 'nokogiri', '>= 1.4.4'
8
+ gem 'ipaddress', '>=0.7.0'
7
9
 
8
10
  # Add dependencies to develop your gem here.
9
11
  # Include everything needed to run rake, tests, features, etc.
data/Gemfile.lock CHANGED
@@ -2,6 +2,20 @@ GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
4
  ZenTest (4.5.0)
5
+ abstract (1.0.0)
6
+ actionmailer (3.0.5)
7
+ actionpack (= 3.0.5)
8
+ mail (~> 2.2.15)
9
+ actionpack (3.0.5)
10
+ activemodel (= 3.0.5)
11
+ activesupport (= 3.0.5)
12
+ builder (~> 2.1.2)
13
+ erubis (~> 2.6.6)
14
+ i18n (~> 0.4)
15
+ rack (~> 1.2.1)
16
+ rack-mount (~> 0.6.13)
17
+ rack-test (~> 0.5.7)
18
+ tzinfo (~> 0.3.23)
5
19
  activemodel (3.0.5)
6
20
  activesupport (= 3.0.5)
7
21
  builder (~> 2.1.2)
@@ -11,18 +25,49 @@ GEM
11
25
  activesupport (= 3.0.5)
12
26
  arel (~> 2.0.2)
13
27
  tzinfo (~> 0.3.23)
28
+ activeresource (3.0.5)
29
+ activemodel (= 3.0.5)
30
+ activesupport (= 3.0.5)
14
31
  activesupport (3.0.5)
15
32
  arel (2.0.9)
16
33
  builder (2.1.2)
17
34
  diff-lcs (1.1.2)
35
+ erubis (2.6.6)
36
+ abstract (>= 1.0.0)
18
37
  git (1.2.5)
19
38
  i18n (0.5.0)
39
+ ipaddress (0.7.0)
20
40
  jeweler (1.5.2)
21
41
  bundler (~> 1.0.0)
22
42
  git (>= 1.2.5)
23
43
  rake
24
44
  log4r (1.1.9)
45
+ mail (2.2.15)
46
+ activesupport (>= 2.3.6)
47
+ i18n (>= 0.4.0)
48
+ mime-types (~> 1.16)
49
+ treetop (~> 1.4.8)
50
+ mime-types (1.16)
25
51
  nokogiri (1.4.4)
52
+ polyglot (0.3.1)
53
+ rack (1.2.2)
54
+ rack-mount (0.6.13)
55
+ rack (>= 1.0.0)
56
+ rack-test (0.5.7)
57
+ rack (>= 1.0)
58
+ rails (3.0.5)
59
+ actionmailer (= 3.0.5)
60
+ actionpack (= 3.0.5)
61
+ activerecord (= 3.0.5)
62
+ activeresource (= 3.0.5)
63
+ activesupport (= 3.0.5)
64
+ bundler (~> 1.0)
65
+ railties (= 3.0.5)
66
+ railties (3.0.5)
67
+ actionpack (= 3.0.5)
68
+ activesupport (= 3.0.5)
69
+ rake (>= 0.8.7)
70
+ thor (~> 0.14.4)
26
71
  rake (0.8.7)
27
72
  rcov (0.9.9)
28
73
  rspec (2.3.0)
@@ -33,6 +78,9 @@ GEM
33
78
  rspec-expectations (2.3.0)
34
79
  diff-lcs (~> 1.1.2)
35
80
  rspec-mocks (2.3.0)
81
+ thor (0.14.6)
82
+ treetop (1.4.9)
83
+ polyglot (>= 0.3.1)
36
84
  tzinfo (0.3.24)
37
85
 
38
86
  PLATFORMS
@@ -43,8 +91,10 @@ DEPENDENCIES
43
91
  activerecord (>= 3.0.5)
44
92
  activesupport (>= 3.0.5)
45
93
  bundler (~> 1.0.0)
94
+ ipaddress (>= 0.7.0)
46
95
  jeweler (~> 1.5.2)
47
96
  log4r
48
97
  nokogiri (>= 1.4.4)
98
+ rails (>= 3.0.5)
49
99
  rcov
50
100
  rspec (~> 2.3.0)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.2.0
@@ -0,0 +1,25 @@
1
+ module OpenvasCli
2
+ class Configuration
3
+ def initialize
4
+ config_opts = {
5
+ :username => "admin",
6
+ :password => "",
7
+ :host => "localhost",
8
+ :port => 9390,
9
+ :buffer_size => 512,
10
+ :time_out => 60,
11
+ :auto_login => true,
12
+ :max_tries => 3
13
+ }
14
+
15
+ config_opts.each { |key, value|
16
+ add_configuration(key, value)
17
+ }
18
+ end
19
+
20
+ def add_configuration(name, default)
21
+ Configuration.send :attr_accessor, name.to_sym
22
+ instance_variable_set("@#{name.to_s}".to_sym, default)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,27 @@
1
+ require 'vas_connection'
2
+ module OpenvasCli
3
+ module ConnAddin
4
+ def self.included(base)
5
+ base.send :extend, ClassMethods
6
+ end
7
+
8
+ module ClassMethods
9
+ def has_vas_connection(connection_type=:manager)
10
+ @@config = {:password => "Password"}
11
+ if connection_type == :manager
12
+ @@config[:port] = 9390
13
+ elsif connection_type == :administrator
14
+ @@config[:port] = 9393
15
+ end
16
+ end
17
+
18
+ def establish_connection
19
+ VasConnection.new(@@config)
20
+ end
21
+
22
+ def connection
23
+ @@connection ||= establish_connection
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ require 'active_model'
2
+
3
+ module OpenvasCli
4
+ class ImmutableChildrenValidator < ActiveModel::Validator
5
+ def validate(record)
6
+ if record.id
7
+ record.errors[:base] << "Configuration cannot change after creation." \
8
+ if record.config_id_changed?
9
+
10
+ record.errors[:base] << "Target cannot change after creation." \
11
+ if record.target_id_changed? || record.target.changed?
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,7 @@
1
+ require 'vas_base'
2
+
3
+ module OpenvasCli
4
+ class VasAdministrator < VasBase
5
+
6
+ end
7
+ end
@@ -1,40 +1,30 @@
1
1
  require 'active_model'
2
+ require 'base64'
2
3
  Dir["#{File.dirname(__FILE__)}/*_validator.rb"].each {|f| require f}
4
+ require 'vas_exceptions'
5
+ require 'xml_addin'
6
+ require 'conn_addin'
3
7
 
4
8
  # Provides a base from which to build objects that utilize the OpenvasCli object.
5
9
  # Includes support for ActiveModel validations and a helper method (extract_value_from)
6
10
  # to assist in OpenVAS object implementations.
7
- class VasBase
8
- include ActiveModel::Validations
9
-
10
- # OpenvasCli object to be used for communications. Initializes a new instance
11
- # if one does not already exist.
12
- def self.client
13
- @@client ||= OpenvasCli.new
14
- end
15
-
16
- # Helper method to extract a value from a Nokogiri::XML::Node object. If the
17
- # xpath provided contains an @, then the method assumes that the value resides
18
- # in an attribute, otherwise it pulls the text of the last +text+ node.
19
- def self.extract_value_from(x_str, n)
20
- ret = ""
21
- if x_str =~ /@/
22
- ret = n.at_xpath(x_str).value if n.at_xpath(x_str)
23
- else
24
- tn = n.at_xpath(x_str)
25
- if tn
26
- if tn.children.count > 0
27
- tn.children.each { |tnc|
28
- if tnc.text?
29
- ret = tnc.text
30
- end
31
- }
32
- else
33
- ret = tn.text
34
- end
35
- end
11
+ module OpenvasCli
12
+ class VasBase
13
+ include ActiveModel::Validations
14
+ include ActiveModel::Dirty
15
+ include XmlAddin
16
+ include ConnAddin
17
+
18
+ has_vas_connection(:manager)
19
+
20
+ attr_accessor :id
21
+
22
+ def new_record?
23
+ @id == nil || @id.empty?
36
24
  end
37
25
 
38
- ret
26
+ def reset_changes
27
+ @changed_attributes.clear if @changed_attributes
28
+ end
39
29
  end
40
30
  end
@@ -0,0 +1,127 @@
1
+ require 'vas_base'
2
+ require 'vas_task'
3
+ require 'vas_nvt_family'
4
+ require 'vas_preference'
5
+ require 'vas_exceptions'
6
+
7
+ module OpenvasCli
8
+ class VasConfig < VasBase
9
+ attr_accessor :name
10
+ attr_accessor :comment
11
+ attr_accessor :families_grow
12
+ attr_accessor :rules_grow
13
+ attr_accessor :in_use
14
+
15
+ define_attribute_methods [:name, :comment, :families_grow, :in_use, :tasks,
16
+ :preferences, :families]
17
+
18
+ validates :id, :UUID => true, :if => Proc.new { |o| o.id }
19
+ validates :name, :presence=>true, :length => {:minimum=>1, :maximum=>80}
20
+
21
+ def initialize(attributes = {})
22
+ @id = attributes[:id] if attributes[:id]
23
+ @name = attributes[:name] if attributes[:name]
24
+ @comment = attributes[:comment] if attributes[:comment]
25
+ @families_grow = attributes[:families_grow] if attributes[:families_grow]
26
+ @rules_grow = attributes[:rules_grow] if attributes[:rules_grow]
27
+ end
28
+
29
+ def tasks
30
+ @tasks ||= []
31
+ end
32
+
33
+ def preferences
34
+ @preferences ||= []
35
+ end
36
+
37
+ def families
38
+ @families ||= []
39
+ end
40
+
41
+ def self.get_all(options = {})
42
+ params = {:sort_field => "name"}
43
+ if options[:show_details] && options[:show_details] == true
44
+ params.merge!({:families => "1", :preferences => "1"})
45
+ end
46
+ params[:config_id] = options[:id] if options[:id]
47
+ req = Nokogiri::XML::Builder.new { |xml|
48
+ xml.get_configs(params)
49
+ }
50
+
51
+ resp = connection.send_receive(req.doc)
52
+
53
+ ret = []
54
+ resp.xpath("/get_configs_response/config").each { |xml|
55
+ cfg = VasConfig.new
56
+ cfg.id = extract_value_from("@id", xml)
57
+ cfg.name = extract_value_from("name", xml)
58
+ cfg.comment = extract_value_from("comment", xml)
59
+ cfg.families_grow = extract_value_from("family_count/growing", xml).to_i > 0
60
+ cfg.rules_grow = extract_value_from("nvt_count/growing", xml).to_i > 0
61
+ cfg.in_use = extract_value_from("in_use", xml).to_i > 0
62
+
63
+ xml.xpath("tasks/task").each { |t| cfg.tasks << VasTask.from_xml_node(t) }
64
+ xml.xpath("families/family").each { |f| cfg.families << VasNVTFamily.from_xml_node(f) }
65
+ xml.xpath("preferences/preference").each { |p|
66
+ p = VasPreference.from_xml_node(p)
67
+ p.config_id = cfg.id
68
+ p.reset_changes
69
+ cfg.preferences << p
70
+ }
71
+
72
+ cfg.reset_changes
73
+
74
+ ret << cfg
75
+ }
76
+
77
+ ret
78
+ end
79
+
80
+ def self.copy_config(id, name)
81
+ begin
82
+ req = Nokogiri::XML::Builder.new { |xml|
83
+ xml.create_config {
84
+ xml.copy { xml.text(id) }
85
+ xml.name { xml.text(name) }
86
+ }
87
+ }
88
+
89
+ resp = connection.send_receive(req.doc)
90
+ new_id = extract_value_from("/create_config_response/@id", resp)
91
+
92
+ get_all(:id => new_id, :show_details => true)[0]
93
+ rescue VasExceptions::CommandException => e
94
+ nil
95
+ end
96
+ end
97
+
98
+ def save!
99
+ @previously_changed = changes
100
+ preferences.each{ |p| p.save! if p.changed? }
101
+ @changed_attributes.clear
102
+ end
103
+
104
+ def destroy
105
+ begin
106
+ destroy!
107
+
108
+ true
109
+ rescue Exception => e
110
+ # logger = OpenvasCli.logger
111
+ # logger.error("Could Not Destroy Configuration: (#{e.class})#{e.message}") if logger
112
+
113
+ false
114
+ end
115
+ end
116
+
117
+ def destroy!
118
+ tasks.each { |t| t.destroy! }
119
+
120
+ req = Nokogiri::XML::Builder.new { |xml|
121
+ xml.delete_config(:config_id => @id)
122
+ }
123
+
124
+ VasConfig.connection.send_receive(req.doc)
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,140 @@
1
+ require 'nokogiri'
2
+ require 'vas_exceptions'
3
+ require 'xml_addin'
4
+ require 'openssl'
5
+ require 'timeout'
6
+
7
+ module OpenvasCli
8
+ class VasConnection
9
+ include XmlAddin
10
+ # Initializes the client, connectes to the OpenVas Managment service specified
11
+ # by host & port, and unless auto_login is set to +false+, loggs in using
12
+ # username and password.
13
+ def initialize(config={})
14
+ @logger = OpenvasCli.logger
15
+ @config = OpenvasCli.configuration
16
+
17
+ connect
18
+ if @config.auto_login == true
19
+ login
20
+ end
21
+ end
22
+
23
+ # Closes the active connection and sets it up for re-connection.
24
+ def close
25
+ @socket.close if @socket
26
+ @socket = nil
27
+ end
28
+
29
+ def config
30
+ @config ||= {}
31
+ end
32
+
33
+ # Logs into the OpenVAS Management service using the specified username and
34
+ # passoword. By default, this method is called by new unless auto_login is
35
+ # set to +false+.
36
+ def login
37
+ log_message("Logging in: :user => #{@config.username}", :info)
38
+ areq = Nokogiri::XML::Builder.new { |xml|
39
+ xml.authenticate {
40
+ xml.credentials {
41
+ xml.username { xml.text(@config.username) }
42
+ xml.password { xml.text(@config.password) }
43
+ }
44
+ }
45
+ }
46
+
47
+ send_receive(areq.doc)
48
+ end
49
+
50
+ def state
51
+ @socket ? @socket.state : "closed"
52
+ end
53
+
54
+ def send_receive(request)
55
+ if request.kind_of? String
56
+ tosend = request
57
+ else
58
+ tosend = request.to_xml
59
+ end
60
+
61
+ tries = 0
62
+
63
+ begin
64
+ unless @socket && @socket.state =~ /sslok/i
65
+ log_message("Socket closed, Reconnecting", :info)
66
+ connect
67
+ login
68
+ end
69
+ log_message("Sending: #{tosend}", :debug)
70
+
71
+ @socket.puts(tosend)
72
+
73
+ rbuf=''
74
+ size=0
75
+ begin
76
+ timeout(@config.time_out) {
77
+ a = @socket.sysread(@config.buffer_size)
78
+ size = a.length
79
+ rbuf << a
80
+ }
81
+ end while size >= @config.buffer_size
82
+ rescue Timeout::Error
83
+ msg = "Command Timed Out [#{tries}] (#{$!})\nCommand: #{tosend}"
84
+ log_message msg, :error
85
+ tries += 1
86
+ @socket = nil
87
+ retry if tries < @config.max_tries
88
+ raise VasExceptions::CommunicationException.new(msg)
89
+ rescue EOFError
90
+ msg = "EOFError [#{tries}] (#{$!})\nReceived: #{rbuf}\nCommand: #{tosend}"
91
+ log_message msg, :error
92
+ tries += 1
93
+ @socket = nil
94
+ retry if tries < @config.max_tries
95
+ raise VasExceptions::CommunicationException.new(msg)
96
+ end
97
+
98
+ response = Nokogiri::XML(rbuf)
99
+
100
+ log_message "RECEIVED: #{response.to_xml}", :debug
101
+
102
+ unless VasConnection.extract_value_from("//@status", response) =~ /20\d/
103
+ msg = "Command Failed: #{VasConnection.extract_value_from("//@status_text", response)}\n" +
104
+ "Command Status: #{VasConnection.extract_value_from("//@status", response)}\n" +
105
+ "Command: #{tosend}\n" +
106
+ "Response: #{response.to_xml}"
107
+ log_message msg, :error
108
+ raise VasExceptions::CommandException.new(msg)
109
+ end
110
+
111
+ response
112
+ end
113
+ private
114
+ def log_message(msg, level)
115
+ if @logger
116
+ case level
117
+ when :debug
118
+ @logger.debug msg
119
+ when :info
120
+ @logger.info msg
121
+ when :warn
122
+ @logger.warn msg
123
+ when :error
124
+ @logger.error msg
125
+ when :fatal
126
+ @logger.fatal msg
127
+ end
128
+ end
129
+ end
130
+
131
+ def connect
132
+ log_message("Connecting: :host => #{@config.host}, :port => #{@config.port}", :info)
133
+ plain_socket = TCPSocket.open(@config.host, @config.port)
134
+ ssl_context = OpenSSL::SSL::SSLContext.new
135
+ @socket = OpenSSL::SSL::SSLSocket.new(plain_socket, ssl_context)
136
+ @socket.sync_close = true
137
+ @socket.connect
138
+ end
139
+ end
140
+ end