Guest User

Untitled

a guest
Feb 28th, 2018
129
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.66 KB | None | 0 0
  1. require 'socket'
  2. require 'time'
  3. require 'og'
  4.  
  5. class Logger
  6. def self.method_missing(sym, *args)
  7. $stderr.puts "#{sym.to_s.upcase} #{args.join(', ')}"
  8. end
  9. end
  10.  
  11. class ClamScanner
  12. class ScannerException < RuntimeError
  13. def initialize(message)
  14. Logger.error(message)
  15. end
  16. end
  17.  
  18. attr_accessor :socket, :result
  19.  
  20. def initialize
  21. @socket = '/var/run/clamav/clamd.sock'
  22. end
  23.  
  24. def check
  25. res = talk("PING")
  26. if(res !~ /PONG$/)
  27. Logger.error("check failed: erroneous clam answer: #{res}")
  28. return false
  29. end
  30. return true
  31. end
  32.  
  33. def scan(path)
  34. if(@result)
  35. Logger.info("reusing previous scan result: <#{@result}> of:
  36. <#{path}>")
  37. else
  38. begin
  39. res = talk("SCAN #{path}")
  40. rescue ScannerException
  41. Logger.error("unable to scan message: #{path}")
  42. return nil
  43. end
  44.  
  45. if res =~ /: (.*) FOUND$/
  46. Logger.info("virus: #{$1} in: #{path}")
  47. @result = $1;
  48. elsif res =~ /: (Zip module failure) ERROR$/
  49. Logger.info("broken zip in #{path}")
  50. @result = 'Broken.ZIP.Archive'
  51. elsif res =~ /OK$/
  52. Logger.info("no virus detected in: #{path}")
  53. @result = 'clean'
  54. else
  55. Logger.error("unknown clam resource problem: #{$1}: when
  56. scanning: #{path}")
  57. return nil
  58. end
  59. end
  60.  
  61. return @result
  62. end # end scan
  63.  
  64. def talk(msg)
  65. data = nil
  66. session = nil
  67.  
  68. if msg.nil?
  69. raise ScannerException.new("method called with empty args")
  70. end
  71. begin
  72. session = UNIXSocket.new(@socket)
  73. session.send(msg,0)
  74. data = session.recvfrom(512)[0] # [0] ensures we only get clam's respons
  75. session.close()
  76. rescue
  77. raise ScannerException.new("unable to use socket: #{@socket}")
  78. end
  79. return data
  80. end # end talk
  81.  
  82. end
  83.  
  84. class ClamavScanResult
  85. is Timestamped
  86.  
  87. property :path, String
  88. property :result, String
  89. end
  90.  
  91. class UploadedFile
  92.  
  93. attr_reader :date, :transfertime, :remotecomputer, :filesize, :filename, :transfertype, :actionflag, :direction, :accessmode, :username, :servicename, :authentication, :id, :complete
  94.  
  95. def initialize(options)
  96. options.each do |key, value|
  97. instance_variable_set("@#{key}", value)
  98. end
  99. end
  100.  
  101. # In der angegeben Datei (hier eben: /var/log/proftpd.xferlog) werden
  102. # folgende Werte geloggt:
  103. #
  104. # * aktuelle Zeit
  105. # * Uebertragungszeit in Sekunden
  106. # * Name des Remote Computers
  107. # * Dateigroesse
  108. # * Dateiname
  109. # * Transfertyp ("a": Ascii; "b": Binary)
  110. # * Aktion Flag ("C": Datei war komprimiert; "U": Datei war unkomprimiert;
  111. # "T": Tarball)
  112. # * Richtung ("o": Outgoing; "i": incoming, "d": Delete)
  113. # * Zugriffsmode ("a": Anonym; "r": richtiger User)
  114. # * Username (Achtung bei Anonym das uebergebene Passwort)
  115. # * Service Name (normalerweise "FTP")
  116. # * Authentifizierungsmethode ("0": keine; "1": RFC931 Authentication)
  117. # * Rueckmelde ID ("*": wenn keine Rueckmelde ID kam)
  118. # * Komplett ("c": komplett; "i": nicht komlett). Achtung: uploads sind
  119. # immer "c", da ProFTPD nicht erkennen kann, wann das Ende kommt
  120. #
  121. # Example:
  122. #
  123. # Tue Dec 12 16:40:20 2006 0 port-212-202-55-195.dynamic.qsc.de 245
  124. # /home/BGB1-Jemenit/build/.autotest b _ i r BGB1-Jemenit ftp 1 * c
  125.  
  126. def self.parse(line)
  127. line.strip!
  128. date, transfertime, remotecomputer, filesize, filename, transfertype, actionflag, direction, accessmode, username, servicename, authentication, id, complete =
  129. line.scan(/
  130. (\w+\s+\w+\s+\d+\s+\d+:\d+:\d+\s\d+)\s+ # date
  131. (\d+)\s+ # transfertime
  132. ([^\s]*)\s+ # remotecomputer
  133. (\d+)\s+ # filesize
  134. (.*?)\s+ # filename
  135. ([ab])\s+ # transfertype
  136. ([CUT_])\s+ # actionflag
  137. ([oid])\s+ # direction
  138. ([ar])\s+ # accessmode
  139. ([^\s]+)\s+ # username
  140. (\w+)\s+ # servicename
  141. ([01])\s+ # authentication
  142. ([^\s])\s+ # id
  143. ([ci]) # complete
  144. /mix).first
  145.  
  146. date = Time.parse(date)
  147. transfertime = transfertime.to_i
  148. filesize = filesize.to_i
  149. complete = (complete == 'c' ? true : false)
  150.  
  151. options = {
  152. :date => date,
  153. :transfertime => transfertime,
  154. :remotecomputer => remotecomputer,
  155. :filesize => filesize,
  156. :filename => filename,
  157. :transfertype => transfertype,
  158. :actionflag => actionflag,
  159. :direction => direction,
  160. :accessmode => accessmode,
  161. :username => username,
  162. :servicename => servicename,
  163. :authentication => authentication,
  164. :id => id,
  165. :complete => complete
  166. }
  167.  
  168. UploadedFile.new(options)
  169. end
  170. end
  171.  
  172. Og.start(:store => :mysql, :name => 'clamavdb', :user => 'testuser',
  173. :password => 'private', :classes => [ClamavScanResult])
  174.  
  175. if $0 == __FILE__
  176. if DEBUG
  177. # test scanner
  178. clamav = ClamScanner.new
  179. if !clamav.check
  180. Logger.error("Clamav probably not running")
  181. exit(1)
  182. end
  183. end
  184.  
  185. while io = select([$stdin])
  186. next unless io[0][0].kind_of?(IO) rescue nil
  187.  
  188. line = io[0][0].readline.chomp
  189. file = UploadedFile.parse(line)
  190.  
  191. res = clamav.scan(file.filename)
  192.  
  193. ClamavScanResult.create_with(:path => file.filename, :result => res)
  194. end
  195.  
  196. end
Add Comment
Please, Sign In to add comment