#!/usr/bin/env ruby

require 'rubygems'
gem "xmpp4r"

require 'xmpp4r/client'
include Jabber

base = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__
@sigs = File.join(File.dirname(base), 'sigs.txt')

#
# jablog.rb v0.01 - syslog-to-jabber script
# copyright (c) H D Moore -<hdm[at]metasploit.com>
# provided under the BSD license
#


# 1. Set @mine to a jabber account for this script to use
# 2. Set @pass to the password for the above account
# 3. Set @targ to a jabebr account where you can receive messages
# 4. Create a sigs.txt file in the same directory as this script
# 5. Push syslog data into stdin of this script:
#    program("/path/to/jablog.rb")
# 6. Enjoy

@sigt = 0
@host = `hostname`.strip
@mine = "USER@SERVER/#{@host}"    # Change this to your user/pass/server
@pass = "PASSWORD"                # Set a password here
@targ = "USER@SERVER/YourProfile" # Change this to your jabber ID
@q   = []

def load_sigs
	@pats = []
	cnt = 0
	
	fd = File.open(@sigs, "r")
	fd.each_line do |line|
		cnt += 1
		next if line.strip.length == 0
		next if line =~ /^#/
		begin
			@pats << Regexp.new(line.strip, true)
		rescue ::Exception => e
			@q << "bad signature on line #{cnt}: #{line.strip} (#{e})"
		end
	
	end
	
	@q << "loaded #{@pats.length} signatures from #{@sigs}"
	fd.close
end

def check_sigs
	if (File.mtime(@sigs).to_i > @sigt)
		@sigt = File.mtime(@sigs).to_i
		load_sigs()
	end
end



check_sigs()


#
# The master loop
#

@master = true

while(@master)
cl = nil

begin

cl = Client::new(JID::new(@mine))
cl.connect
cl.auth(@pass)
cl.send(Presence::new)

targ_jid = JID.new(@targ)

m = Message::new(targ_jid, "logger bot initialized with pid #{$$}")
cl.send(m)

@running = true
cl.add_message_callback do |m|

	if (m.type == :error)
		sleep(1)
	end
	
	# Only talk to the target jid
	if (m.from == targ_jid)

		if (m.type != :error)

			parts = m.body.split(/\s+/)
			case parts[0]
			when 'exit'
				o = Message::new(m.from, "shutting down")
				o.type = m.type
				cl.send(o)
				@running = false
				@master  = false
			when 'uptime'
				info = "System Uptime\n" + `uptime`
				o = Message::new(m.from, info)
				o.type = m.type
				cl.send(o)					
			when 'netstat'
				info = "Network Connections\n" + `netstat -na`
				o = Message::new(m.from, info)
				o.type = m.type
				cl.send(o)
			when 'dmesg'
				info = "Kernel Log\n" + `dmesg`
				o = Message::new(m.from, info)
				o.type = m.type
				cl.send(o)									
			when 'df'
				info = "Disk Space\n" + `df -h`
				o = Message::new(m.from, info)
				o.type = m.type
				cl.send(o)	
			when 'ps'
				info = "Process Listing\n" + `ps aux -wwwwwwwwwwwww`
				o = Message::new(m.from, info)
				o.type = m.type
				cl.send(o)					
			else
				o = Message::new(m.from, "unknown command: #{parts[0]}")
				o.type = m.type
				cl.send(o)			
			end
		end
	end
end

while(@running)
	r = select([$stdin], nil, nil, 1.0)
	if (r)
		line = $stdin.gets
		if(not line)
			@q << "The standard input was closed"
			@running = false
			@master  = false
			line = ""
		end
		line.strip!
	
		matched = false
		@pats.each do |reg|
			if (line =~ reg)
				matched = true
				break
			end
		end
		
		if(matched)
			m = Message::new(targ_jid, "alert: #{line}")
			cl.send(m)
		end
	end
	
	while(@q.length > 0)
		t = @q.shift
		m = Message::new(targ_jid, "info: #{t}")
		cl.send(m)	
	end
	
	check_sigs()
	
end

rescue ::Interrupt
	raise $!
rescue ::Exception => e
	@q << "#{e.class} #{e} : #{e.backtrace}"
ensure
	cl.close if cl
end

sleep(5)

end # end while

