tcell_agent 2.0.0 → 2.5.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.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +2 -2
  3. data/bin/tcell_agent +41 -150
  4. data/lib/tcell_agent/agent.rb +87 -52
  5. data/lib/tcell_agent/config_initializer.rb +63 -0
  6. data/lib/tcell_agent/configuration.rb +72 -267
  7. data/lib/tcell_agent/hooks/login_fraud.rb +1 -1
  8. data/lib/tcell_agent/instrument_servers.rb +14 -18
  9. data/lib/tcell_agent/instrumentation/cmdi.rb +47 -15
  10. data/lib/tcell_agent/instrumentation/lfi.rb +72 -15
  11. data/lib/tcell_agent/instrumentation/monkey_patches/ruby_2/file.rb +21 -0
  12. data/lib/tcell_agent/instrumentation/monkey_patches/ruby_2/io.rb +75 -0
  13. data/lib/tcell_agent/instrumentation/monkey_patches/ruby_2/kernel.rb +80 -0
  14. data/lib/tcell_agent/instrumentation/monkey_patches/ruby_3/file.rb +21 -0
  15. data/lib/tcell_agent/instrumentation/monkey_patches/ruby_3/io.rb +75 -0
  16. data/lib/tcell_agent/instrumentation/monkey_patches/ruby_3/kernel.rb +80 -0
  17. data/lib/tcell_agent/instrumentation.rb +14 -6
  18. data/lib/tcell_agent/logger.rb +3 -4
  19. data/lib/tcell_agent/policies/command_injection_policy.rb +1 -1
  20. data/lib/tcell_agent/policies/dataloss_policy.rb +15 -8
  21. data/lib/tcell_agent/policies/headers_policy.rb +2 -2
  22. data/lib/tcell_agent/policies/patches_policy.rb +8 -4
  23. data/lib/tcell_agent/policies/policies_manager.rb +1 -0
  24. data/lib/tcell_agent/policies/policy_polling.rb +4 -3
  25. data/lib/tcell_agent/rails/auth/authlogic.rb +49 -44
  26. data/lib/tcell_agent/rails/auth/authlogic_helper.rb +20 -0
  27. data/lib/tcell_agent/rails/auth/devise.rb +103 -102
  28. data/lib/tcell_agent/rails/auth/devise_helper.rb +29 -0
  29. data/lib/tcell_agent/rails/auth/doorkeeper.rb +54 -57
  30. data/lib/tcell_agent/{userinfo.rb → rails/auth/userinfo.rb} +0 -0
  31. data/lib/tcell_agent/rails/better_ip.rb +7 -19
  32. data/lib/tcell_agent/rails/csrf_exception.rb +0 -8
  33. data/lib/tcell_agent/rails/dlp/process_request.rb +5 -0
  34. data/lib/tcell_agent/rails/dlp.rb +58 -56
  35. data/lib/tcell_agent/rails/dlp_handler.rb +9 -10
  36. data/lib/tcell_agent/rails/js_agent_insert.rb +2 -3
  37. data/lib/tcell_agent/rails/middleware/context_middleware.rb +2 -1
  38. data/lib/tcell_agent/rails/middleware/global_middleware.rb +3 -4
  39. data/lib/tcell_agent/rails/middleware/headers_middleware.rb +1 -0
  40. data/lib/tcell_agent/rails/{on_start.rb → railties/tcell_agent_railties.rb} +9 -16
  41. data/lib/tcell_agent/rails/railties/tcell_agent_unicorn_railties.rb +8 -0
  42. data/lib/tcell_agent/rails/routes/grape.rb +5 -12
  43. data/lib/tcell_agent/rails/routes.rb +6 -9
  44. data/lib/tcell_agent/rails/settings_reporter.rb +3 -6
  45. data/lib/tcell_agent/rails/tcell_body_proxy.rb +4 -7
  46. data/lib/tcell_agent/routes/table.rb +3 -0
  47. data/lib/tcell_agent/rust/agent_config.rb +62 -33
  48. data/lib/tcell_agent/rust/{libtcellagent-4.14.0.so → libtcellagent-alpine.so} +0 -0
  49. data/lib/tcell_agent/rust/{libtcellagent-4.14.0.dylib → libtcellagent-x64.dll} +0 -0
  50. data/lib/tcell_agent/rust/{libtcellagent-alpine-4.14.0.so → libtcellagent.dylib} +0 -0
  51. data/lib/tcell_agent/rust/libtcellagent.so +0 -0
  52. data/lib/tcell_agent/rust/models.rb +9 -0
  53. data/lib/tcell_agent/rust/native_agent.rb +61 -51
  54. data/lib/tcell_agent/rust/native_library.rb +8 -10
  55. data/lib/tcell_agent/sensor_events/server_agent.rb +3 -100
  56. data/lib/tcell_agent/sensor_events/util/sanitizer_utilities.rb +1 -0
  57. data/lib/tcell_agent/servers/puma.rb +30 -13
  58. data/lib/tcell_agent/servers/rack_puma_handler.rb +33 -0
  59. data/lib/tcell_agent/servers/rails_server.rb +4 -4
  60. data/lib/tcell_agent/servers/unicorn.rb +1 -1
  61. data/lib/tcell_agent/servers/webrick.rb +12 -3
  62. data/lib/tcell_agent/settings_reporter.rb +0 -93
  63. data/lib/tcell_agent/sinatra.rb +1 -0
  64. data/lib/tcell_agent/tcell_context.rb +16 -7
  65. data/lib/tcell_agent/utils/headers.rb +0 -1
  66. data/lib/tcell_agent/utils/strings.rb +2 -2
  67. data/lib/tcell_agent/version.rb +1 -1
  68. data/lib/tcell_agent.rb +8 -16
  69. data/spec/cruby_spec_helper.rb +26 -0
  70. data/spec/lib/tcell_agent/configuration_spec.rb +62 -212
  71. data/spec/lib/tcell_agent/instrument_servers_spec.rb +95 -0
  72. data/spec/lib/tcell_agent/instrumentation/cmdi/io_cmdi_spec.rb +2 -2
  73. data/spec/lib/tcell_agent/{cmdi_spec.rb → instrumentation/cmdi_spec.rb} +50 -0
  74. data/spec/lib/tcell_agent/instrumentation/lfi/file_lfi_spec.rb +211 -272
  75. data/spec/lib/tcell_agent/instrumentation/lfi/io_lfi_spec.rb +213 -223
  76. data/spec/lib/tcell_agent/instrumentation/lfi/kernel_lfi_spec.rb +95 -61
  77. data/spec/lib/tcell_agent/instrumentation/lfi_spec.rb +120 -2
  78. data/spec/lib/tcell_agent/patches_spec.rb +2 -1
  79. data/spec/lib/tcell_agent/policies/clickjacking_policy_spec.rb +1 -2
  80. data/spec/lib/tcell_agent/policies/content_security_policy_spec.rb +5 -6
  81. data/spec/lib/tcell_agent/policies/patches_policy_spec.rb +21 -2
  82. data/spec/lib/tcell_agent/policies/policies_manager_spec.rb +1 -1
  83. data/spec/lib/tcell_agent/policies/secure_headers_policy_spec.rb +13 -8
  84. data/spec/lib/tcell_agent/rails/better_ip_spec.rb +9 -11
  85. data/spec/lib/tcell_agent/rails/csrf_exception_spec.rb +6 -6
  86. data/spec/lib/tcell_agent/rails/dlp_spec.rb +1 -0
  87. data/spec/lib/tcell_agent/rails/js_agent_insert_spec.rb +10 -2
  88. data/spec/lib/tcell_agent/rails/middleware/tcell_body_proxy_spec.rb +2 -1
  89. data/spec/lib/tcell_agent/rails/routes/route_id_spec.rb +4 -4
  90. data/spec/lib/tcell_agent/rust/agent_config_spec.rb +27 -0
  91. data/spec/lib/tcell_agent/settings_reporter_spec.rb +2 -89
  92. data/spec/lib/tcell_agent/tcell_context_spec.rb +6 -5
  93. data/spec/spec_helper.rb +9 -1
  94. data/spec/support/builders.rb +8 -7
  95. data/spec/support/server_mocks/passenger_mock.rb +7 -0
  96. data/spec/support/server_mocks/puma_mock.rb +21 -0
  97. data/spec/support/server_mocks/rails_mock.rb +7 -0
  98. data/spec/support/server_mocks/thin_mock.rb +7 -0
  99. data/spec/support/server_mocks/unicorn_mock.rb +11 -0
  100. data/spec/support/shared_spec.rb +29 -0
  101. data/tcell_agent.gemspec +14 -14
  102. metadata +46 -29
  103. data/Rakefile +0 -18
  104. data/lib/tcell_agent/authlogic.rb +0 -23
  105. data/lib/tcell_agent/config/unknown_options.rb +0 -119
  106. data/lib/tcell_agent/devise.rb +0 -33
  107. data/lib/tcell_agent/instrumentation/monkey_patches/file.rb +0 -25
  108. data/lib/tcell_agent/instrumentation/monkey_patches/io.rb +0 -123
  109. data/lib/tcell_agent/instrumentation/monkey_patches/kernel.rb +0 -159
  110. data/lib/tcell_agent/rails/start_agent_after_initializers.rb +0 -12
  111. data/lib/tcell_agent/rust/tcellagent-4.14.0.dll +0 -0
  112. data/spec/lib/tcell_agent/config/unknown_options_spec.rb +0 -195
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # See the file "LICENSE" for the full license governing this code.
2
4
  require 'fileutils'
3
5
  require 'json'
@@ -6,315 +8,118 @@ require 'socket'
6
8
  require 'securerandom'
7
9
  require 'uri'
8
10
 
9
- require 'tcell_agent/config/unknown_options'
10
-
11
11
  module TCellAgent
12
12
  class ConfigurationException < StandardError
13
13
  end
14
14
 
15
15
  class << self
16
16
  attr_accessor :configuration
17
+ attr_accessor :initializer_configuration
17
18
  end
18
19
 
19
20
  def self.configure
20
- self.configuration ||= Configuration.new
21
- yield(configuration)
22
- end
23
-
24
- class Configuration # rubocop:disable Metrics/ClassLength
25
- attr_accessor :version,
26
- :app_id,
27
- :api_key,
28
- :hmac_key,
29
- :tcell_api_url,
30
- :tcell_input_url,
31
- :logging_options,
32
- :fetch_policies_from_tcell, :instrument_for_events,
33
- :preload_policy_filename,
34
- :host_identifier,
35
- :uuid,
36
- :event_batch_size_limit, :event_time_limit_seconds,
37
- :base_dir,
38
- :cache_filename,
39
- :cache_folder,
40
- :js_agent_api_base_url,
41
- :js_agent_url,
42
- :config_filename,
43
- :agent_log_dir,
44
- :max_data_ex_db_records_per_request,
45
- :agent_home_dir,
46
- :reverse_proxy,
47
- :reverse_proxy_ip_address_header,
48
- :log_file_name,
49
- :log_tag,
50
- :max_csp_header_bytes,
51
- :demomode,
52
- :allow_payloads,
53
- :password_hmac_key,
54
- :stdout_logger
55
-
56
- attr_accessor :disable_all,
57
- :enabled,
58
- :enable_event_manager, # false = Do not start the even manager
59
- :enable_event_consumer, # false = Do not consume events, drop them
60
- :enable_policy_polling, # false = Do not poll for policies
61
- :enable_instrumentation, # false = Do not add instrumentation
62
- :enable_intercept_requests # false = Do not insert middleware
21
+ require 'tcell_agent/config_initializer'
22
+ self.initializer_configuration ||= ConfigInitializer.new
63
23
 
64
- attr_accessor :enabled_instrumentations
24
+ yield(initializer_configuration)
25
+ rescue NoMethodError => e
26
+ logger = TCellAgent::ModuleLogger.new(TCellAgent::RubyLogger.new, name)
27
+ logger.error("Error configuring tcell_agent with initializers: #{e}")
28
+ end
65
29
 
66
- attr_accessor :exp_config_settings
30
+ class Configuration
31
+ # internal Ruby configurations
32
+ attr_accessor :disable_all
67
33
 
68
- attr_accessor :disable_cmdi_exec_instrumentation # true = disable cmdi Kernel::exec instrumentation
34
+ # Common config returned by libtcellagent
35
+ attr_accessor :api_key, :app_id, :disabled_instrumentation, :enabled,
36
+ :enable_intercept_requests, :fetch_policies_from_tcell, :hmac_key,
37
+ :host_identifier, :instrument, :log_dir, :logging_options,
38
+ :password_hmac_key, :reverse_proxy, :reverse_proxy_ip_address_header,
39
+ :tcell_api_url
69
40
 
70
- def should_start_event_manager?
71
- @enabled && @enable_event_manager
72
- end
41
+ # Ruby config returned by libtcellagent
42
+ attr_accessor :enable_policy_polling
73
43
 
74
44
  def should_start_policy_poll?
75
45
  @enabled && @enable_policy_polling && @fetch_policies_from_tcell # fetch_policies_from_tcel = legacy
76
46
  end
77
47
 
78
- def should_instrument?
79
- @enabled && @enable_instrumentation && @instrument_for_events # instrument_for_events = legacy
80
- end
48
+ def should_instrument?(func = nil)
49
+ return false unless @enabled && @instrument # never instrument if disabled
50
+ return true if func.nil? # always instrument if enabled and nothing given
81
51
 
82
- def should_intercept_requests?
83
- @enabled && @enable_instrumentation && @enable_intercept_requests
52
+ !@disabled_instrumentation.include?(func)
84
53
  end
85
54
 
86
- def should_instrument_doorkeeper?
87
- if @enabled_instrumentations.key?('doorkeeper') || @enabled_instrumentations.key?(:doorkeeper)
88
- !!(@enabled_instrumentations['doorkeeper'] || @enabled_instrumentations[:doorkeeper]) # rubocop:disable Style/DoubleNegation
89
- else
90
- true
91
- end
92
- end
93
-
94
- def should_instrument_devise?
95
- if @enabled_instrumentations.key?('devise') || @enabled_instrumentations.key?(:devise)
96
- !!(@enabled_instrumentations['devise'] || @enabled_instrumentations[:devise]) # rubocop:disable Style/DoubleNegation
97
- else
98
- true
99
- end
100
- end
101
-
102
- def should_instrument_authlogic?
103
- if @enabled_instrumentations.key?('authlogic') || @enabled_instrumentations.key?(:authlogic)
104
- !!(@enabled_instrumentations['authlogic'] || @enabled_instrumentations[:authlogic]) # rubocop:disable Style/DoubleNegation
105
- else
106
- true
107
- end
108
- end
109
-
110
- def should_instrument_cmdi_exec?
111
- !@disable_cmdi_exec_instrumentation
55
+ def should_intercept_requests?
56
+ @enabled && @enable_intercept_requests
112
57
  end
113
58
 
114
- def initialize(filename = 'config/tcell_agent.config', _useapp = nil)
115
- # These will be set when the agent starts up, to give rails initializers
116
- # a chance to run
117
- @cache_filename = nil
118
- @agent_log_dir = nil
119
- @log_tag = nil
120
-
121
- @version = 0
122
- @demomode = false
123
-
124
- @fetch_policies_from_tcell = true
125
- @instrument_for_events = true
126
-
59
+ def initialize
60
+ # ruby agent defaults
127
61
  @disable_all = false
128
- @enabled = true
129
- @enable_event_manager = true
130
- @enable_policy_polling = true
131
- @enable_instrumentation = true
132
- @enable_intercept_requests = true
133
-
134
- @enabled_instrumentations = {
135
- :doorkeeper => true,
136
- :devise => true,
137
- :authlogic => true
138
- }
139
-
140
- @disable_cmdi_exec_instrumentation = false
141
-
142
- @log_file_name = 'tcell_agent.log'
143
-
144
- @event_batch_size_limit = 50
145
- @event_time_limit_seconds = 15
146
-
147
- @max_data_ex_db_records_per_request = 1000
148
- @reverse_proxy = true
149
- @reverse_proxy_ip_address_header = 'X-Forwarded-For'
150
- @allow_payloads = true
151
-
152
- @max_csp_header_bytes = nil
153
- @password_hmac_key = nil
154
62
  @logging_options = {}
155
63
 
156
- @agent_home_dir = ENV['TCELL_AGENT_HOME'] || File.join(Dir.getwd, 'tcell')
157
- @cache_folder = File.join(@agent_home_dir, 'cache/')
158
- @agent_log_dir = File.join(@agent_home_dir, 'logs')
159
-
160
- @config_filename = ENV['TCELL_AGENT_CONFIG'] || File.join(Dir.getwd, filename)
161
-
162
- read_config_from_file(@config_filename)
163
- read_config_using_env
164
-
165
- if @demomode
166
- @event_batch_size_limit = 1
167
- @event_time_limit_seconds = 2
168
- end
169
-
170
- @tcell_api_url ||= 'https://us.agent.tcell.insight.rapid7.com/api/v1'
171
- @tcell_input_url ||= 'https://us.input.tcell.insight.rapid7.com/api/v1'
172
- @js_agent_url ||= 'https://us.jsagent.tcell.insight.rapid7.com/tcellagent.min.js'
173
-
174
- if @host_identifier.nil?
175
- begin
176
- @host_identifier = (Socket.gethostname || 'localhost')
177
- rescue StandardError
178
- @host_identifier = 'host_identifier_not_found'
179
- end
180
- end
181
-
182
- @uuid = SecureRandom.uuid
64
+ check_for_disabled_instrumentation(get_config_file_name)
183
65
  end
184
66
 
185
- def read_config_using_env
186
- @app_id = ENV['TCELL_AGENT_APP_ID'] || @app_id
187
- @api_key = ENV['TCELL_AGENT_API_KEY'] || @api_key
188
- @hmac_key = ENV['TCELL_HMAC_KEY'] || @hmac_key
189
- @password_hmac_key = ENV['TCELL_PASSWORD_HMAC_KEY'] || @password_hmac_key
190
- @host_identifier = ENV['TCELL_AGENT_HOST_IDENTIFIER'] || @host_identifier
191
- @tcell_api_url = ENV['TCELL_API_URL'] || @tcell_api_url
192
- @tcell_input_url = ENV['TCELL_INPUT_URL'] || @tcell_input_url
193
- @demomode = ENV['TCELL_DEMOMODE'] || @demomode
194
-
195
- @agent_log_dir = ENV['TCELL_AGENT_LOG_DIR'] || @agent_log_dir
196
- @log_file_name = ENV['TCELL_AGENT_LOG_FILENAME'] || @log_file_name
67
+ def get_config_file_path
68
+ return nil unless ENV['TCELL_AGENT_HOME']
69
+ return nil if ENV['TCELL_AGENT_CONFIG']
197
70
 
198
- @logging_options['enabled'] = to_bool(ENV['TCELL_AGENT_LOG_ENABLED']) unless to_bool(ENV['TCELL_AGENT_LOG_ENABLED']).nil?
199
- @logging_options['level'] = ENV['TCELL_AGENT_LOG_LEVEL'] || @logging_options['level'] unless @logging_options.nil?
200
-
201
- @enabled = to_bool(ENV['TCELL_AGENT_ENABLED']) unless to_bool(ENV['TCELL_AGENT_ENABLED']).nil?
71
+ File.join(Dir.getwd, '/config/tcell_agent.config')
72
+ end
202
73
 
203
- @allow_payloads = to_bool(ENV['TCELL_AGENT_ALLOW_PAYLOADS']) unless to_bool(ENV['TCELL_AGENT_ALLOW_PAYLOADS']).nil?
204
- @disable_cmdi_exec_instrumentation = to_bool(ENV['TCELL_CMDI_EXEC_DISABLED']) || @disable_cmdi_exec_instrumentation
74
+ def get_config_file_name
75
+ ENV['TCELL_AGENT_CONFIG'] || File.join(Dir.getwd, '/config/tcell_agent.config')
205
76
  end
206
77
 
207
- def read_config_from_file(filename)
78
+ def check_for_disabled_instrumentation(filename)
208
79
  return unless File.file?(filename)
209
80
 
210
81
  begin
211
- config_text = File.open(filename).read
212
- config = JSON.parse(config_text)
213
-
214
- messages = TCellAgent::Config::Validate.get_unknown_options(config)
215
- messages.each do |message|
216
- puts message
217
- end
82
+ config = JSON.parse(File.open(filename).read)
218
83
 
219
84
  if config['version'] == 1
220
- # Required
221
- app_data = config['applications'][0] # Default
222
- @version = 1
223
- @app_id = app_data['app_id']
224
- @api_key = app_data['api_key']
225
-
226
- # Optional
227
- @preload_policy_filename = app_data.fetch('preload_policy_filename', nil)
228
-
229
- @disable_all = app_data.fetch('disable_all', @disable_all)
230
- @enabled = app_data.fetch('enabled', @enabled)
231
-
232
- @enable_event_manager = app_data.fetch('enable_event_manager', @enable_event_manager)
233
- @enable_policy_polling = app_data.fetch('enable_policy_polling', @enable_policy_polling)
234
- @enable_instrumentation = app_data.fetch('enable_instrumentation', @enable_instrumentation)
235
- @enable_intercept_requests = app_data.fetch('enable_intercept_requests', @enable_intercept_requests)
236
- @fetch_policies_from_tcell = app_data.fetch('fetch_policies_from_tcell', @fetch_policies_from_tcell)
237
- @instrument_for_events = app_data.fetch('instrument_for_events', @instrument_for_events)
238
-
239
- @logging_options = app_data.fetch('logging_options', {})
240
- @agent_log_dir = app_data.fetch('log_dir', @agent_log_dir)
241
- @log_file_name = @logging_options['filename'] || @log_file_name
242
-
243
- @tcell_api_url = app_data.fetch('tcell_api_url', @tcell_api_url)
244
- @tcell_input_url = app_data.fetch('tcell_input_url', @tcell_input_url)
245
-
246
- @max_csp_header_bytes = app_data.fetch('max_csp_header_bytes', @max_csp_header_bytes)
247
-
248
- @allow_payloads = app_data.fetch(
249
- 'allow_payloads',
250
- @allow_payloads
251
- )
252
-
253
- data_exposure = app_data.fetch('data_exposure', {})
254
- @max_data_ex_db_records_per_request = data_exposure.fetch('max_data_ex_db_records_per_request', @max_data_ex_db_records_per_request)
255
-
256
- @enabled_instrumentations = app_data.fetch('enabled_instrumentations', @enabled_instrumentations)
257
-
258
- @reverse_proxy = app_data.fetch('reverse_proxy', @reverse_proxy)
259
- @reverse_proxy_ip_address_header = app_data.fetch('reverse_proxy_ip_address_header', @reverse_proxy_ip_address_header)
260
-
261
- @host_identifier = app_data.fetch('host_identifier', @host_identifier)
262
- @hmac_key = app_data.fetch('hmac_key', @hmac_key)
263
-
264
- @password_hmac_key = app_data.fetch('password_hmac_key', @password_hmac_key)
265
-
266
- @uuid = SecureRandom.uuid
267
- @uuid = 'secure-random-failed' if @uuid.nil?
268
-
269
- if app_data.key?('js_agent_api_base_url')
270
- @js_agent_api_base_url = app_data['js_agent_api_base_url']
271
- end
272
- if app_data.key?('js_agent_url')
273
- @js_agent_url = app_data['js_agent_url']
274
- end
275
-
276
- @demomode = app_data.fetch('demomode', @demomode)
277
- else
278
- puts ' ********* ********* ********* *********'
279
- puts '* tCell.io *'
280
- puts '* Unsupported config file version *'
281
- puts ' ********* ********* ********* *********'
85
+ app_data = config['applications'][0]
86
+ @disable_all = to_bool(app_data.fetch('disable_all', @disable_all))
282
87
  end
283
- rescue StandardError => e
284
- puts ' ********* ********* ********* *********'
285
- puts '* tCell.io *'
286
- puts '* Could not load config file *'
287
- puts ' ********* ********* ********* *********'
288
- puts e
88
+ rescue StandardError
89
+ # do nothing
289
90
  end
290
91
  end
291
92
 
292
93
  def to_bool(var)
293
- return unless var
294
- var.to_s.casecmp('true').zero? if %w[true false].include? var.to_s.downcase
295
- end
296
-
297
- def enforce_symbol_keys(hashmap)
298
- hashmap.each_with_object({}) do |(k, v), memo|
299
- memo[k.to_sym] = v
300
- end
301
- end
302
-
303
- def logging_enabled?
304
- @enabled && enforce_symbol_keys(@logging_options || {})[:enabled]
305
- end
306
-
307
- def log_filename
308
- @agent_log_dir ||= File.join(@agent_home_dir, 'logs')
309
- File.join(@agent_log_dir, @log_file_name)
310
- end
311
-
312
- def clean_logging_options
313
- {
314
- :enabled => true,
315
- :level => 'INFO',
316
- :filename => log_file_name
317
- }.merge(enforce_symbol_keys(@logging_options || {}))
94
+ { 'true' => true, 'false' => false }[var.to_s.downcase]
95
+ end
96
+
97
+ def populate_configuration(native_agent_config_response)
98
+ # config
99
+ @enabled = native_agent_config_response['enabled']
100
+ @disabled_instrumentation = Set.new(native_agent_config_response['disabled_instrumentation'])
101
+ @fetch_policies_from_tcell = native_agent_config_response['update_policy']
102
+ @instrument = native_agent_config_response['instrument']
103
+
104
+ # app config
105
+ apps = native_agent_config_response['applications'] ? native_agent_config_response['applications']['first'] : {}
106
+ @app_id = apps['app_id']
107
+ @api_key = apps['api_key']
108
+ @hmac_key = apps['hmac_key']
109
+ @password_hmac_key = apps['password_hmac_key']
110
+
111
+ # proxy config
112
+ @reverse_proxy = apps['reverse_proxy']
113
+ @reverse_proxy_ip_address_header = apps['reverse_proxy_ip_address_header']
114
+
115
+ # endpoint config
116
+ endpoint = native_agent_config_response['endpoint_config'] || {}
117
+ @tcell_api_url = endpoint['api_url']
118
+
119
+ # ruby config
120
+ ruby_config = native_agent_config_response['ruby_config'] || {}
121
+ @enable_policy_polling = ruby_config['enable_policy_polling']
122
+ @enable_intercept_requests = !@disabled_instrumentation.include?('intercept_requests')
318
123
  end
319
124
  end
320
125
 
@@ -3,7 +3,7 @@ require 'tcell_agent/agent'
3
3
  module TCellAgent
4
4
  module Hooks
5
5
  module LoginFraud
6
- # Note: mock out in tests
6
+ # NOTE: mock out in tests
7
7
  def self.get_logger
8
8
  unless defined?(@login_fraud_logger)
9
9
  @login_fraud_logger = TCellAgent::ModuleLogger.new(TCellAgent.logger, name)
@@ -1,25 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  tcell_server = ENV['TCELL_AGENT_SERVER']
2
4
 
3
- if TCellAgent.configuration.should_instrument?
4
- unless tcell_server && tcell_server == 'mock'
5
- if (tcell_server && tcell_server == 'webrick') || defined?(Rails::Server)
6
- require('tcell_agent/servers/rails_server')
5
+ TCellAgent.thread_agent.instrument_built_ins if tcell_server &&
6
+ tcell_server == 'mock'
7
7
 
8
- elsif (tcell_server && tcell_server == 'thin') || defined?(Thin)
9
- require('tcell_agent/servers/thin')
8
+ require('tcell_agent/servers/rails_server') if (tcell_server && tcell_server == 'webrick') ||
9
+ defined?(Rails::Server)
10
10
 
11
- elsif (tcell_server && tcell_server == 'puma') || defined?(Puma)
12
- require('tcell_agent/servers/puma')
11
+ require('tcell_agent/servers/thin') if (tcell_server && tcell_server == 'thin') ||
12
+ defined?(Thin)
13
13
 
14
- elsif (tcell_server && tcell_server == 'unicorn') || defined?(Unicorn)
15
- require('tcell_agent/servers/unicorn')
14
+ require('tcell_agent/servers/puma') if (tcell_server && tcell_server == 'puma') ||
15
+ defined?(Puma)
16
16
 
17
- elsif (tcell_server && tcell_server == 'passenger') || defined?(PhusionPassenger)
18
- require('tcell_agent/servers/passenger')
19
- end
20
- end
17
+ require('tcell_agent/servers/unicorn') if (tcell_server && tcell_server == 'unicorn') ||
18
+ defined?(Unicorn)
21
19
 
22
- elsif (tcell_server && tcell_server == 'unicorn') || defined?(Unicorn)
23
- # unicorn is always instrumented to support rolling restarts
24
- require('tcell_agent/servers/unicorn')
25
- end
20
+ require('tcell_agent/servers/passenger') if (tcell_server && tcell_server == 'passenger') ||
21
+ defined?(PhusionPassenger)
@@ -25,18 +25,18 @@ module TCellAgent
25
25
  cmd = ''
26
26
 
27
27
  TCellAgent::Instrumentation.safe_block('CMDI Parsing *args') do
28
- unless args.empty?
29
- args_copy = Array.new(args)
30
- args_copy.shift if args_copy.first.is_a?(Hash)
31
- args_copy.pop if args_copy.last.is_a?(Hash)
32
-
33
- if args_copy.first.is_a?(Array)
34
- cmd_n_argv0 = args_copy.shift
35
- args_copy.unshift(cmd_n_argv0.first)
36
- end
28
+ return cmd if args.nil? || args.empty?
29
+
30
+ args_copy = Array.new(args)
31
+ args_copy.shift if args_copy.first.is_a?(Hash)
32
+ args_copy.pop if args_copy.last.is_a?(Hash)
37
33
 
38
- cmd = args_copy.join(' ')
34
+ if args_copy.first.is_a?(Array)
35
+ cmd_n_argv0 = args_copy.shift
36
+ args_copy.unshift(cmd_n_argv0.first)
39
37
  end
38
+
39
+ cmd = args_copy.join(' ')
40
40
  end
41
41
 
42
42
  cmd
@@ -46,15 +46,47 @@ module TCellAgent
46
46
  cmd = ''
47
47
 
48
48
  TCellAgent::Instrumentation.safe_block('CMDI Parsing *args') do
49
- unless args.empty?
50
- args_copy = Array.new(args)
51
- first_arg = args_copy.shift
49
+ return cmd if args.nil? || args.empty?
52
50
 
53
- cmd = first_arg[1..-1] if first_arg && first_arg[0] == '|'
54
- end
51
+ args_copy = Array.new(args)
52
+ first_arg = args_copy.shift
53
+
54
+ cmd = first_arg[1..-1] if first_arg && (first_arg.is_a? String) && first_arg[0] == '|'
55
55
  end
56
56
 
57
57
  cmd
58
58
  end
59
+
60
+ def self.raise_if_block(cmd)
61
+ return unless TCellAgent::Cmdi.block_command?(cmd)
62
+
63
+ raise "tCell.io Agent: Command not allowed by policy: #{cmd}"
64
+ end
65
+
66
+ def self.default_cmdi_handler(args)
67
+ cmd = TCellAgent::Cmdi.parse_command(*args)
68
+
69
+ raise_if_block(cmd)
70
+ end
71
+
72
+ def self.popen_cmdi_handler(args)
73
+ return if args.empty?
74
+
75
+ cmd = ''
76
+
77
+ TCellAgent::Instrumentation.safe_block('CMDI Parsing popen *args') do
78
+ args_copy = Array.new(args)
79
+ args_copy.shift if args_copy.first.is_a?(Hash)
80
+ args_copy.pop if args_copy.last.is_a?(Hash)
81
+
82
+ cmd = if args_copy.first.is_a?(String)
83
+ args_copy.shift
84
+ else
85
+ TCellAgent::Cmdi.parse_command(*args_copy.shift)
86
+ end
87
+ end
88
+
89
+ raise_if_block(cmd)
90
+ end
59
91
  end
60
92
  end
@@ -5,6 +5,8 @@ require 'tcell_agent/configuration'
5
5
  module TCellAgent
6
6
  module Instrumentation
7
7
  module Lfi
8
+ extend TCellAgent::ModuleLoggerAccess
9
+
8
10
  def self.block_file_access?(path, mode)
9
11
  TCellAgent::Instrumentation.safe_block('Checking Local Files Policy') do
10
12
  if TCellAgent::Utils::Strings.present?(path)
@@ -26,18 +28,26 @@ module TCellAgent
26
28
  path = ''
27
29
  mode = ''
28
30
 
29
- return ['', ''] if args.empty?
30
-
31
31
  TCellAgent::Instrumentation.safe_block('LFI Parsing *args') do
32
+ return ['', ''] if args.nil? || args.empty?
33
+
32
34
  args_copy = Array.new(args)
33
35
  path = args_copy.shift
34
36
  mode = args_copy.shift || 'r'
35
- end
36
37
 
37
- if path && path.to_s[0] != '|'
38
- [File.expand_path(path).to_s, convert_mode(mode)]
39
- else
40
- ['', '']
38
+ if path && path.to_s[0] != '|'
39
+ path = File.expand_path(path.to_s)
40
+
41
+ mode = if mode && mode.is_a?(Hash)
42
+ convert_mode(mode[:mode])
43
+ else
44
+ convert_mode(mode)
45
+ end
46
+
47
+ [path, mode]
48
+ else
49
+ ['', '']
50
+ end
41
51
  end
42
52
  end
43
53
 
@@ -46,16 +56,29 @@ module TCellAgent
46
56
  mode = 'Read'
47
57
 
48
58
  TCellAgent::Instrumentation.safe_block('LFI Parsing ARGF') do
49
- if ARGF.eof? && !ARGV.empty?
50
- argv_copy = Array.new(ARGV)
51
- path = argv_copy.shift
52
- else
53
- path = ARGF.filename
59
+ begin
60
+ return ['', ''] if ARGF.file == $stdin
61
+
62
+ if ARGF.eof? && !ARGV.empty?
63
+ argv_copy = Array.new(ARGV)
64
+ path = argv_copy.shift
65
+ else
66
+ path = ARGF.filename
67
+ end
68
+
69
+ if path && path.to_s[0] != '|'
70
+ [File.expand_path(path.to_s), mode]
71
+ else
72
+ ['', '']
73
+ end
74
+ rescue Errno::ENOENT
75
+ module_logger.debug('LFI Parsing ARGF: attempted to read a non-existent file')
76
+ ['', '']
77
+ rescue Errno::EISDIR
78
+ module_logger.debug('LFI Parsing ARGF: attempted to read a directory')
79
+ [ARGF.filename, mode]
54
80
  end
55
81
  end
56
-
57
- path = File.expand_path(path) unless path.nil?
58
- [path.to_s, mode]
59
82
  end
60
83
 
61
84
  def self.convert_mode(mode)
@@ -68,6 +91,40 @@ module TCellAgent
68
91
  end
69
92
  'Read'
70
93
  end
94
+
95
+ def self.raise_if_block(path, mode)
96
+ return unless block_file_access?(path, mode)
97
+
98
+ raise IOError, "tCell.io Agent: Attempted access to file #{path} with mode #{mode} denied"
99
+ end
100
+
101
+ def self.default_open_handler(args, override_mode = '')
102
+ path, mode = extract_path_mode(*args)
103
+
104
+ mode = override_mode unless override_mode.empty?
105
+
106
+ raise_if_block(path, mode)
107
+ end
108
+
109
+ def self.argf_open_handler
110
+ path, mode = TCellAgent::Instrumentation::Lfi.extract_path_mode_argf
111
+
112
+ raise_if_block(path, mode)
113
+ end
114
+
115
+ def self.cmdi_open_handler(args, override_mode = '')
116
+ path, mode = extract_path_mode(*args)
117
+
118
+ mode = override_mode unless override_mode.empty?
119
+
120
+ raise_if_block(path, mode)
121
+
122
+ return unless path.empty?
123
+
124
+ cmd = TCellAgent::Cmdi.parse_command_from_open(*args)
125
+
126
+ TCellAgent::Cmdi.raise_if_block(cmd) if cmd
127
+ end
71
128
  end
72
129
  end
73
130
  end
@@ -0,0 +1,21 @@
1
+ class File
2
+ class << self
3
+ if TCellAgent.configuration.should_instrument?('File::new')
4
+ alias_method :tcell_original_new, :new
5
+ def new(*args, &block)
6
+ TCellAgent::Instrumentation::Lfi.default_open_handler(args)
7
+
8
+ tcell_original_new(*args, &block)
9
+ end
10
+ end
11
+
12
+ if TCellAgent.configuration.should_instrument?('File::open')
13
+ alias_method :tcell_original_open, :open
14
+ def open(*args, &block)
15
+ TCellAgent::Instrumentation::Lfi.default_open_handler(args)
16
+
17
+ tcell_original_open(*args, &block)
18
+ end
19
+ end
20
+ end
21
+ end