cookbook-ossec-ng/libraries/core.rb

267 lines
9.1 KiB
Ruby

# Core function for OSSEC
# Used by the server and agent recipes
module OssecCore
def ossec_hostname_search()
# resolve the hostname_search of a rule to a list of hosts
node["ossec"]["rules"].each do |id,params|
if not params.nil?
params[:body].each do |key, value|
if key.eql?('hostname_search')
hosts_list = search(:node,
"(#{value}) AND roles:ossec-agent "\
" AND chef_environment:#{node.chef_environment}"
).map {|n| n.hostname}
if hosts_list.empty?
# search didn't return anything
# store a dummy value in the attributes
Chef::Log.info("OSSEC: Hostname search returned empty result. " +
"'#{value}'")
params[:body][:hostname] = "invalid-search-returned-empty-result"
else
# store in the node params but discard the last char
params[:body][:hostname] = hosts_list.join('|')
end
end
end
end
end
end
def ossec_event_location_search()
# resolve the location search of an email_alert block to a hostname
node["ossec"]["email_alerts"].each do|recipient,params|
if params.has_key?('event_location_search')
if Chef::Config[:solo]
Chef::Log.warn('This recipe uses search. Chef Solo does not support search.')
else
dest = search(:node,
"(#{params[:event_location_search]}) " \
"AND chef_environment:#{node.chef_environment}"
).map {|n| n.hostname}
node.default["ossec"]["email_alerts"][recipient]["resolved_search"] = dest
end
end
end
end
def ossec_set_syscheck_flags!(*args)
# go through the list of command/active-response and check the ones
# that apply to this node
args.each do |config|
unless node["ossec"]["syscheck"][config].nil?
node["ossec"]["syscheck"][config].each do |item, params|
unless params[:apply_to].nil?
locations = search(:node,
"(#{params[:apply_to]}) " \
"AND chef_environment:#{node.chef_environment}"
).map {|n| n.ipaddress}
if locations.include?(node["ipaddress"])
node.default["ossec"]["syscheck"][config][item]["use_here"] = true
else
node.default["ossec"]["syscheck"][config][item]["use_here"] = false
end
else
node.default["ossec"]["syscheck"][config][item]["use_here"] = true
end
end
end
end
end
def ossec_set_filtered_flags!(*args)
# go through the list of command/active-response and check the ones
# that apply to this node
args.each do |config|
unless node["ossec"][config].nil?
node["ossec"][config].each do |item, params|
unless params[:apply_to].nil?
locations = search(:node,
"(#{params[:apply_to]}) " \
"AND chef_environment:#{node.chef_environment}"
).map {|n| n.ipaddress}
if locations.include?(node["ipaddress"])
node.default["ossec"][config][item]["use_here"] = true
else
node.default["ossec"][config][item]["use_here"] = false
end
else
node.default["ossec"][config][item]["use_here"] = true
end
end
end
end
end
def ossec_agent_create_parameters(agent, server)
# Returns a hash with the identiers for this agent
agent_hash = {}
# IP is defined by lanip, if available (ohai plugin network_addr)
# or by the default ipaddress otherwise
agent_hash[:ip] = agent[:network][:lanip] || agent.ipaddress
# Ossec limits the agents name length to 32 characters, so to avoid
# names collisions, we concatenate the agent_ip with the first characters
# of the hostname
name = agent_hash[:ip] + "_" + agent[:hostname]
agent_hash[:name] = name[0,31]
# ossec agent id is an integer used to identify an agent. we force that ID
# to be the IP address without the dots (10.1.2.3 becomes 10123)
agent_hash[:id] = agent_hash[:ip].gsub(".", "")
agent_hash[:key] = "undef"
if server["ossec"]["agents"].has_key?(agent_hash[:id])
if server["ossec"]["agents"][agent_hash[:id]].has_key?('key')
agent_hash[:key] = server["ossec"]["agents"][agent_hash[:id]]["key"]
end
end
agent_hash[:rid] = "none"
return agent_hash
end
def ossec_generate_agent_key(agent_hash)
# Returns a 64 characters double md5 hash, used as a symetric key
seed1 = rand(100000000000).to_s
seed2 = rand(100000000000).to_s
str1 = Digest::MD5.hexdigest(seed1 + \
agent_hash[:id] + \
agent_hash[:ip] + \
seed2)
str2 = Digest::MD5.hexdigest(seed2 + \
agent_hash[:name] + \
seed1 + \
agent_hash[:ip] + \
agent_hash[:id])
key = str1 + str2
return key
end
def ossec_agent_has_valid_key?(agent_hash, server)
# Does the server have a valid key for this agent ?
if server["ossec"]["agents"].key?(agent_hash[:id])
if server["ossec"]["agents"][agent_hash[:id]].key?('key')
if server["ossec"]["agents"][agent_hash[:id]]["key"].length == 64
return true
end
end
end
return false
end
def ossec_agent_knows_key?(agent_hash, agent)
# Does the agent have a key that matches the server ?
if agent.key?('ossec')
if agent["ossec"].key?('agents')
if agent["ossec"]["agents"].key?(agent_hash[:id])
if agent["ossec"]["agents"][agent_hash[:id]].key?('key')
if agent["ossec"]["agents"][agent_hash[:id]]["key"] == agent_hash[:key]
return true
end
end
end
end
end
return false
end
def ossec_verify_agent(agent_hash, server)
# check if this agent (id, name, ip) is defined on the server
if server["ossec"]["agents"].key?(agent_hash[:id])
agent_srv_data = server["ossec"]["agents"][agent_hash[:id]]
if agent_srv_data[:name].eql?(agent_hash[:name])
if agent_srv_data[:ip].eql?(agent_hash[:ip])
return true
else
Chef::Log.info("OSSEC: agent ip mismatch. " +
"server has '#{agent_srv_data[:ip]}' " +
"agent has '#{agent_hash[:ip]}'")
end
else
Chef::Log.info("OSSEC: agent name mismatch. " +
"server has '#{agent_srv_data[:name]}' " +
"agent has '#{agent_hash[:name]}'")
end
else
Chef::Log.info("OSSEC: agent name '#{agent_hash[:name]}' " +
" ip '#{agent_hash[:ip]}'" +
" configuration not found on server.")
end
return false
end
def ossec_agent_is_active?(id)
if File.exists?("/var/ossec/bin/agent_control")
#cmd = Chef::ShellOut.new("/var/ossec/bin/agent_control -s -i #{id}")
cmd = Mixlib::ShellOut.new("/var/ossec/bin/agent_control -s -i #{id}")
cmd_ret = cmd.run_command
status = cmd.stdout.split(",")
if status[3] && status[3].eql?("Active")
return true
end
end
return false
end
def ossec_agent_is_zombie?(id)
if File.exists?("/var/ossec/bin/agent_control")
#cmd = Chef::ShellOut.new("/var/ossec/bin/agent_control -s -i #{id}")
cmd = Mixlib::ShellOut.new("/var/ossec/bin/agent_control -s -i #{id}")
cmd_ret = cmd.run_command
status = cmd.stdout.split(",")
if not status[6] || status[3] =~ /(Never connected|)/
return true
elsif status[6] !~ /Unknown/
last_keep_alive = Time.parse(status[6])
three_days_ago = (Time.now - (24*60*60*3))
if three_days_ago > last_keep_alive
return true
end
end
end
return false
end
def ossec_agent_should_be_removed?(id)
if File.exists?("/var/ossec/bin/agent_control")
#cmd = Chef::ShellOut.new("/var/ossec/bin/agent_control -s -i #{id}")
cmd = Mixlib::ShellOut.new("/var/ossec/bin/agent_control -s -i #{id}")
cmd_ret = cmd.run_command
status = cmd.stdout.split(",")
if not status[6] or status[6] =~ /Unknown/
return true
else
last_keep_alive = Time.parse(status[6])
seven_days_ago = (Time.now - (24*60*60*7))
if seven_days_ago > last_keep_alive
return true
end
end
end
return false
end
def ossec_agent_needs_rid?(id, agent)
# Check if the agent queue needs to be removed, either because the server
# said so, or because the agent asked for it
if agent["ossec"]["agents"][id]["rid"].eql?("todo") \
or node["ossec"]["agents"][id]["rid"].eql?("todo")
return true
else
return false
end
end
end