From 7efe08a5585ffd76149a2fcf3ad57da4cd1c30df Mon Sep 17 00:00:00 2001 From: Kevin Fenzi Date: Fri, 18 Jul 2014 17:50:29 +0000 Subject: [PATCH] Add epylog role to log01. --- playbooks/hosts/logserver.yml | 1 + roles/epylog/files/epylog-default.cron | 6 + roles/epylog/files/epylog-merged.cron | 1 + roles/epylog/files/epylog-web.conf | 15 + roles/epylog/files/merged/epylog.conf | 32 + .../merged/modules.d/common_unparsed.conf | 14 + .../files/merged/modules.d/kojiload.conf | 10 + .../epylog/files/merged/modules.d/logins.conf | 50 ++ roles/epylog/files/merged/modules.d/mail.conf | 20 + .../files/merged/modules.d/notices.conf | 26 + .../files/merged/modules.d/packets.conf | 33 + .../epylog/files/merged/modules.d/rsyncd.conf | 16 + .../files/merged/modules.d/selinux.conf | 11 + .../epylog/files/merged/modules.d/spamd.conf | 28 + roles/epylog/files/merged/modules.d/sudo.conf | 11 + .../epylog/files/merged/modules.d/weeder.conf | 30 + roles/epylog/files/merged/notice_dist.xml | 87 ++ roles/epylog/files/merged/notice_local.xml | 94 ++ .../epylog/files/merged/report_template.html | 22 + roles/epylog/files/merged/trojans.list | 410 +++++++++ roles/epylog/files/merged/weed_dist.cf | 179 ++++ roles/epylog/files/merged/weed_local.cf | 305 +++++++ .../epylog/files/modules/common_unparsed.conf | 12 + .../files/modules/common_unparsed_mod.py | 118 +++ roles/epylog/files/modules/kojiload.conf | 10 + roles/epylog/files/modules/kojiload_mod.py | 102 +++ roles/epylog/files/modules/logins_mod.py | 849 ++++++++++++++++++ roles/epylog/files/modules/rsyncd.conf | 14 + roles/epylog/files/modules/rsyncd_mod.py | 219 +++++ roles/epylog/files/modules/selinux.conf | 11 + roles/epylog/files/modules/selinux_mod.py | 116 +++ roles/epylog/files/modules/sudo.conf | 11 + roles/epylog/files/modules/sudo_mod.py | 191 ++++ roles/epylog/tasks/main.yml | 48 + 34 files changed, 3102 insertions(+) create mode 100644 roles/epylog/files/epylog-default.cron create mode 100644 roles/epylog/files/epylog-merged.cron create mode 100644 roles/epylog/files/epylog-web.conf create mode 100644 roles/epylog/files/merged/epylog.conf create mode 100644 roles/epylog/files/merged/modules.d/common_unparsed.conf create mode 100644 roles/epylog/files/merged/modules.d/kojiload.conf create mode 100644 roles/epylog/files/merged/modules.d/logins.conf create mode 100644 roles/epylog/files/merged/modules.d/mail.conf create mode 100644 roles/epylog/files/merged/modules.d/notices.conf create mode 100644 roles/epylog/files/merged/modules.d/packets.conf create mode 100644 roles/epylog/files/merged/modules.d/rsyncd.conf create mode 100644 roles/epylog/files/merged/modules.d/selinux.conf create mode 100644 roles/epylog/files/merged/modules.d/spamd.conf create mode 100644 roles/epylog/files/merged/modules.d/sudo.conf create mode 100644 roles/epylog/files/merged/modules.d/weeder.conf create mode 100644 roles/epylog/files/merged/notice_dist.xml create mode 100644 roles/epylog/files/merged/notice_local.xml create mode 100644 roles/epylog/files/merged/report_template.html create mode 100644 roles/epylog/files/merged/trojans.list create mode 100644 roles/epylog/files/merged/weed_dist.cf create mode 100644 roles/epylog/files/merged/weed_local.cf create mode 100644 roles/epylog/files/modules/common_unparsed.conf create mode 100644 roles/epylog/files/modules/common_unparsed_mod.py create mode 100644 roles/epylog/files/modules/kojiload.conf create mode 100644 roles/epylog/files/modules/kojiload_mod.py create mode 100644 roles/epylog/files/modules/logins_mod.py create mode 100644 roles/epylog/files/modules/rsyncd.conf create mode 100644 roles/epylog/files/modules/rsyncd_mod.py create mode 100644 roles/epylog/files/modules/selinux.conf create mode 100644 roles/epylog/files/modules/selinux_mod.py create mode 100644 roles/epylog/files/modules/sudo.conf create mode 100644 roles/epylog/files/modules/sudo_mod.py create mode 100644 roles/epylog/tasks/main.yml diff --git a/playbooks/hosts/logserver.yml b/playbooks/hosts/logserver.yml index 2471de9999..ce7d2fef28 100644 --- a/playbooks/hosts/logserver.yml +++ b/playbooks/hosts/logserver.yml @@ -36,6 +36,7 @@ - collectd/base - collectd/server - sudo + - epylog tasks: - include: "{{ tasks }}/yumrepos.yml" diff --git a/roles/epylog/files/epylog-default.cron b/roles/epylog/files/epylog-default.cron new file mode 100644 index 0000000000..33daaaed84 --- /dev/null +++ b/roles/epylog/files/epylog-default.cron @@ -0,0 +1,6 @@ +#!/bin/sh +# Run epylog daily. +# +# just disable this so we don't run the global one anywhere +# better to run a specific one (or ones) +#/usr/sbin/epylog --cron diff --git a/roles/epylog/files/epylog-merged.cron b/roles/epylog/files/epylog-merged.cron new file mode 100644 index 0000000000..c7a59837de --- /dev/null +++ b/roles/epylog/files/epylog-merged.cron @@ -0,0 +1 @@ +30 2,8,14,20 * * * root /usr/sbin/epylog --cron -c /etc/epylog/merged/epylog.conf --last 6h diff --git a/roles/epylog/files/epylog-web.conf b/roles/epylog/files/epylog-web.conf new file mode 100644 index 0000000000..dc7fe5a0ac --- /dev/null +++ b/roles/epylog/files/epylog-web.conf @@ -0,0 +1,15 @@ +Alias /epylog /srv/web/epylog + +# need these to do the auth +LoadModule auth_basic_module modules/mod_auth_basic.so +LoadModule authn_file_module modules/mod_authn_file.so + + + Options FollowSymLinks Indexes + AuthType Basic + AuthName "Fedora Log Server" + AuthBasicProvider file + AuthUserFile /srv/web/epylog/.htpasswd + Require valid-user + + diff --git a/roles/epylog/files/merged/epylog.conf b/roles/epylog/files/merged/epylog.conf new file mode 100644 index 0000000000..6ca7321238 --- /dev/null +++ b/roles/epylog/files/merged/epylog.conf @@ -0,0 +1,32 @@ +## +# Main Epylog configuration file. See epylog.conf(5) for more info. +# +[main] +cfgdir = /etc/epylog/merged +tmpdir = /var/tmp +vardir = /var/lib/epylog/merged + +[report] +title = Merged system events: @@LOCALTIME@@ +template = /etc/epylog/merged/report_template.html +include_unparsed = yes +publishers = file + +[mail] +method = mail +smtpserv = /usr/sbin/sendmail -t +mailto = sysadmin-logs-members@fedoraproject.org +format = plain +lynx = /usr/bin/lynx +include_rawlogs = no +rawlogs_limit = 200 + +[file] +method = file +path = /srv/web/epylog/merged/ +dirmask = %Y-%b-%d_%a +filemask = %H%M +expire_in = 7 +notify = sysadmin-logs-members@fedoraproject.org +smtpserv = /usr/sbin/sendmail -t +pubroot = https://admin.fedoraproject.org/epylog/merged diff --git a/roles/epylog/files/merged/modules.d/common_unparsed.conf b/roles/epylog/files/merged/modules.d/common_unparsed.conf new file mode 100644 index 0000000000..1369fe45b9 --- /dev/null +++ b/roles/epylog/files/merged/modules.d/common_unparsed.conf @@ -0,0 +1,14 @@ +[module] +desc = Common Unparsed Similar Strings Module +exec = /usr/share/epylog/modules/common_unparsed_mod.py +files = /var/log/merged/messages.log[.#.gz], /var/log/merged/secure.log[.#.gz] +enabled = no +internal = yes +outhtml = yes +priority = 10 + + +[conf] +# how similar the strings need to be 0-100 - 0 being not at all (bad idea) 100 being almost exactly. +match_percentage = 95 +debug_dump = 0 \ No newline at end of file diff --git a/roles/epylog/files/merged/modules.d/kojiload.conf b/roles/epylog/files/merged/modules.d/kojiload.conf new file mode 100644 index 0000000000..c5c7ee5e79 --- /dev/null +++ b/roles/epylog/files/merged/modules.d/kojiload.conf @@ -0,0 +1,10 @@ +[module] +desc = KojiLoad summary +exec = /usr/share/epylog/modules/kojiload_mod.py +files = /var/log/merged/messages.log[.#.gz] +enabled = yes +internal = yes +outhtml = yes +priority = 7 + +[conf] diff --git a/roles/epylog/files/merged/modules.d/logins.conf b/roles/epylog/files/merged/modules.d/logins.conf new file mode 100644 index 0000000000..9db7c058d6 --- /dev/null +++ b/roles/epylog/files/merged/modules.d/logins.conf @@ -0,0 +1,50 @@ +[module] +desc = Logins +exec = /usr/share/epylog/modules/logins_mod.py +files = /var/log/merged/messages.log[.#.gz], /var/log/merged/secure.log[.#.gz] +enabled = yes +internal = yes +outhtml = yes +priority = 0 + +[conf] +## +# Only enable things useful for your configuration to speed things +# up. The more stuff you enable, the slower matching will be. +# +enable_pam = 1 +enable_xinetd = 1 +enable_sshd = 1 +enable_uw_imap = 0 +enable_dovecot = 0 +enable_courier = 0 +enable_imp = 0 +enable_proftpd = 0 +## +# This is a fun setting. You can list domains that are "safe" here. +# E.g. if your org's domain is example.com and you generally don't +# expect logins from hosts in example.com domain to be suspicious, you +# can add "example.com$" as a safe domain. This way anyone logging in from +# a remote host not matching *.example.com will be flagged in red and the +# full hostname of the connecting machine will be printed in the report. +# List multiple values separated by comma. +# E.g.: safe_domains = example.com$, foo.edu$ +# The default is .*, meaning all domains are considered safe. To turn +# this off specify something like: +# safe_domains = !.* +safe_domains = .* +## +# If you have too many systems, wide-scale probing may turn ugly. This +# will collapse the reports. +systems_collapse = 10 + + +# comma/space separated list of users to ignore - unknown is the internal "no user given" +ignore_users = unknown +# path to where we keep the logins db +loginsdb_path = /var/lib/epylog/logins_db.sqlite +# clean up entries in the db which are more than this many days old +remove_older_than = 14 +# time fuzz - default time (in minutes) which is valid fuzzy match for a login to not be listed +time_fuzz = 60 + diff --git a/roles/epylog/files/merged/modules.d/mail.conf b/roles/epylog/files/merged/modules.d/mail.conf new file mode 100644 index 0000000000..3b1e93bfc7 --- /dev/null +++ b/roles/epylog/files/merged/modules.d/mail.conf @@ -0,0 +1,20 @@ +[module] +desc = Mail Report +exec = /usr/share/epylog/modules/mail_mod.py +files = /var/log/merged/mail.log[.#.gz] +enabled = no +internal = yes +outhtml = yes +priority = 5 + +[conf] +## +# Enable sendmail, postfix, or both +# +enable_sendmail = 1 +enable_postfix = 1 +enable_qmail = 0 +## +# Report at most this many "top things" +# +top_report_limit = 5 diff --git a/roles/epylog/files/merged/modules.d/notices.conf b/roles/epylog/files/merged/modules.d/notices.conf new file mode 100644 index 0000000000..65289cc532 --- /dev/null +++ b/roles/epylog/files/merged/modules.d/notices.conf @@ -0,0 +1,26 @@ +[module] +desc = Notices +exec = /usr/share/epylog/modules/notices_mod.py +files = /var/log/merged/messages.log[.#.gz], /var/log/merged/secure.log[.#.gz] +enabled = yes +internal = yes +outhtml = yes +priority = 7 + +[conf] +## +# Where is your notice_dist.xml file? +# +notice_dist = /etc/epylog/merged/notice_dist.xml +## +# Add your own notices into notice_local.xml, not into notice_dist.xml! +# This way you don't risk missing future revisions to notice_dist.xml +# +notice_local = /etc/epylog/merged/notice_local.xml +## +# You can list the ids of members from notice_dist.xml here +# namely, or you can use ALL to enable all of them. There is no need +# to add members from notice_local.xml here -- they will be enabled +# automatically. +# +enable = ALL diff --git a/roles/epylog/files/merged/modules.d/packets.conf b/roles/epylog/files/merged/modules.d/packets.conf new file mode 100644 index 0000000000..e1b61926cb --- /dev/null +++ b/roles/epylog/files/merged/modules.d/packets.conf @@ -0,0 +1,33 @@ +[module] +desc = Packet Filter +exec = /usr/share/epylog/modules/packets_mod.py +files = /var/log/merged/messages.log[.#.gz] +enabled = yes +internal = yes +outhtml = yes +priority = 1 + +[conf] +## +# Where to look for the trojans list. +# +trojan_list = /etc/epylog/merged/trojans.list +## +# If a remote host hits this many systems, then don't list them namely, +# but collapse them into a nice report, e.g.: [50 hosts] +# +systems_collapse = 5 +## +# Useful for massive portscans. Don't list all the ports namely, but +# present them in a collapsed view. E.g.: [50 ports] +ports_collapse = 5 +## +# Enable iptables, ipchains, ipfilter, or all three. +# +enable_iptables = 1 +enable_ipchains = 1 +enable_ipfilter = 0 +## +# Sort by any of the following: packets, source, system, port +# +sortby=port diff --git a/roles/epylog/files/merged/modules.d/rsyncd.conf b/roles/epylog/files/merged/modules.d/rsyncd.conf new file mode 100644 index 0000000000..147133b3ed --- /dev/null +++ b/roles/epylog/files/merged/modules.d/rsyncd.conf @@ -0,0 +1,16 @@ +[module] +desc = Rsyncd +exec = /usr/share/epylog/modules/rsyncd_mod.py +files = /var/log/merged/messages.log[.#.gz] +enabled = yes +internal = yes +outhtml = yes +priority = 7 + +[conf] +## +# Report this many "top ranking hosts" +# +report_top = 10 +ignore_hosts = log02.vpn.fedoraproject.org log02.phx2.fedoraproject.org proxy3.vpn.fedoraproject.org proxy04.vpn.fedoraproject.org proxy6.vpn.fedoraproject.org proxy01.phx2.fedoraproject.org proxy07.vpn.fedoraproject.org proxy02.vpn.fedoraproject.org proxy03.vpn.fedoraproject.org proxy06.vpn.fedoraproject.org collab04.fedoraproject.org hosted04.fedoraproject.org admin.fedoraproject.org proxy01.stg.phx2.fedoraproject.org proxy08.vpn.fedoraproject.org proxy09.vpn.fedoraproject.org + diff --git a/roles/epylog/files/merged/modules.d/selinux.conf b/roles/epylog/files/merged/modules.d/selinux.conf new file mode 100644 index 0000000000..45e4d87d6b --- /dev/null +++ b/roles/epylog/files/merged/modules.d/selinux.conf @@ -0,0 +1,11 @@ +[module] +desc = SELinux Report +exec = /usr/share/epylog/modules/selinux_mod.py +files = /var/log/merged/messages.log[.#.gz] +enabled = yes +internal = yes +outhtml = yes +priority = 5 + +[conf] +enable_selinux = 1 diff --git a/roles/epylog/files/merged/modules.d/spamd.conf b/roles/epylog/files/merged/modules.d/spamd.conf new file mode 100644 index 0000000000..61e6ae153f --- /dev/null +++ b/roles/epylog/files/merged/modules.d/spamd.conf @@ -0,0 +1,28 @@ +[module] +desc = Spamassassin +exec = /usr/share/epylog/modules/spamd_mod.py +files = /var/log/merged/mail.log[.#.gz] +enabled = no +internal = yes +outhtml = yes +priority = 7 + +[conf] +## +# Report this many "top ranking users" +# +report_top = 10 +## +# Consider this the spam threshold when reporting the scores. +# Anything above this will be flagged as spam. The last column shows +# the score and then non-spam/spam in the parenthesis. E.g.: +# -1.3 (10/3) -- the mean score is -1.3, 10 messages under spam_threshold, +# and 3 messages over it. +# +spam_threshold = 5 +## +# Rank the top users according to this parameter. Valid entries are: +# "most spammed" -- sorts by users with the topmost score +# "most messages" -- sorts by users who received most messages +# +sort_by = most spammed diff --git a/roles/epylog/files/merged/modules.d/sudo.conf b/roles/epylog/files/merged/modules.d/sudo.conf new file mode 100644 index 0000000000..fef86768f5 --- /dev/null +++ b/roles/epylog/files/merged/modules.d/sudo.conf @@ -0,0 +1,11 @@ +[module] +desc = Sudo Report +exec = /usr/share/epylog/modules/sudo_mod.py +files = /var/log/merged/secure.log[.#.gz] +enabled = yes +internal = yes +outhtml = yes +priority = 5 + +[conf] +enable_sudo = 1 diff --git a/roles/epylog/files/merged/modules.d/weeder.conf b/roles/epylog/files/merged/modules.d/weeder.conf new file mode 100644 index 0000000000..160a13167c --- /dev/null +++ b/roles/epylog/files/merged/modules.d/weeder.conf @@ -0,0 +1,30 @@ +[module] +desc = Weedeater +exec = /usr/share/epylog/modules/weeder_mod.py +files = /var/log/merged/messages.log[.#.gz], /var/log/merged/secure.log[.#.gz] +enabled = yes +internal = yes +outhtml = yes +priority = 9 + +[conf] +## +# Where to look for a weed_dist.cf file. +# +weed_dist = /etc/epylog/merged/weed_dist.cf +## +# Where to look for a weed_local.cf file +# +weed_local = /etc/epylog/merged/weed_local.cf +## +# This is where it gets interesting. +# If you look into weed_dist.cf, you will notice that the entries +# are listed by section titles. List here only the sections that are +# relevant to your setup to speed things up. The more sections you +# enable, the slower matching will go, as it has to try more +# regexes. Note that [ADD] and [REMOVE] sections in weed_local are +# special, any other sections in that file will be ignored. +# +# You can use 'ALL' to enable all sections. +# +enable = ALL diff --git a/roles/epylog/files/merged/notice_dist.xml b/roles/epylog/files/merged/notice_dist.xml new file mode 100644 index 0000000000..c717280606 --- /dev/null +++ b/roles/epylog/files/merged/notice_dist.xml @@ -0,0 +1,87 @@ + + + + + gconfd.*: Failed to get lock.*Failed to create + gconfd.*: Error releasing lockfile + gconfd.*: .* Could not lock temporary file + gconfd.*: .* another process has the lock + GConf locking errors + + + + Fatal X error + Fatal X errors + + + + floppy0:|\(floppy\) + Misc floppy errors + + + + ypserv.*:\srefused\sconnect\sfrom\s(\S+):\d+\sto\sprocedure\s(\S+) + %s denied for %s + + + + kernel:\sLinux\sversion\s(\S*) + Rebooted with Linux kernel %s + + + + VFS: busy inodes on changed media + dirty CDROM mount + + + + kernel: cdrom: This disc doesn + kernel: .*Make sure there is a disc in the drive. + Misc CDROM errors + + + + attempt to access beyond end of device + rw=\d+, want=\d+, limit=\d+ + Directory sread .* failed + kernel: bread in fat_access failed + Dirty floppy mount [non-indicative] + + + + nfs: server (\S+) not responding + nfs: server (\S+) OK + NFS timeouts to server %s + + + + insmod: Hint: insmod errors + insmod errors + + + + audit\S+:\s+avc:\s+denied\s+\{\s([^\}]+)\s\}.*exe=(\S+).*scontext=(\S+) + SELinux: denied "%s" for "%s" (scontext=%s) + + + + CROND\S+: \((\S+)\) CMD \(([^\)]+)\) + crond\S+: \((\S+)\) CMD \(([^\)]+)\) + Cron: user '%s' (%s) + + + + diff --git a/roles/epylog/files/merged/notice_local.xml b/roles/epylog/files/merged/notice_local.xml new file mode 100644 index 0000000000..70919136b9 --- /dev/null +++ b/roles/epylog/files/merged/notice_local.xml @@ -0,0 +1,94 @@ + + + + + + kernel: (\S+) invoked oom-killer.* + %s invoked oom-killer - see unparsed + + + + kernel: Call Trace + kernel call trace - see unparsed for details + + + + + Rootkit Hunter:.*Please inspect this machine, because it may be infected.* + Rootkit Hunter has noticed a potential issue + + + puppet_yamltest: cleaning damaged puppet yaml file:(.*) + Corrupted yaml file %s + + + kernel: nf_conntrack: table full.* + Connection tracking table full. + + + + openvpn\[\d+\]: .*:\d+ \[(.*)\] Peer Connection Initiated with .*:\d+ + openvpn [re]connect from %s. + + + + openvpn\[\d+\]: (.*)/.* TLS Error: TLS handshake failed + openvpn TLS handshake failed: %s + + + openvpn\[\d+\]: (.*)/.* TLS Error: TLS key negotiation failed ot occur within.* + openvpn TLS handshake failed - timeout: %s + + + openvpn\[\d+\]: (.*)/.* Authenticate/Decrypt packet error: bad packet ID.* + openvpn auth/decrypt - bad packet id: %s + + + + stunnel:.*websockets accepted connection from (.*):.* + stunnel: websocket connection from %s + + + + nagios:.*HOST.*ALERT:.* + nagios alerts: + + + + nagios:.*HOST.*NOTIFICATION:.*kevin-emergency.* + nagios pages: + + + + totp\.cgi.*: Success: user=(\S+),.*host=(\S+), + totpcgi: %s from %s (Success) + + + totp\.cgi.*: Failure: user=(\S+),.*host=(\S+), + totpcgi: %s from %s (Failure) + + + kernel:.* EXT4-fs error.* + EXT4 Error/disk failure noticed + + + diff --git a/roles/epylog/files/merged/report_template.html b/roles/epylog/files/merged/report_template.html new file mode 100644 index 0000000000..4d60b3862c --- /dev/null +++ b/roles/epylog/files/merged/report_template.html @@ -0,0 +1,22 @@ + + + @@TITLE@@ + + + +

@@HOSTNAME@@

+

First event: @@STARTTIME@@
+ Last event: @@ENDTIME@@

+
+ @@MODULE_REPORTS@@ +
+

Unparsed Strings:

+ @@UNPARSED_STRINGS@@ +
+

Brought to you by + @@VERSION@@

+ + diff --git a/roles/epylog/files/merged/trojans.list b/roles/epylog/files/merged/trojans.list new file mode 100644 index 0000000000..09b795b4c3 --- /dev/null +++ b/roles/epylog/files/merged/trojans.list @@ -0,0 +1,410 @@ +1/udp Sockets des Troie +2/tcp Death +30/tcp Agent 40421 +31/tcp Agent 31 +41/tcp Deep Throat +48/tcp DRAT +58/tcp DMSetup +59/tcp DMSetup +79/tcp CDK +81/tcp RemoConChubo +99/tcp Hidden Port +121/tcp Attack Bot +133/tcp Farnaz +142/tcp NetTaxi +146/tcp Infector +146/udp Infector +170/tcp A-trojan +334/tcp Backage +411/tcp Backage +420/tcp Breach +421/tcp TCP Wrappers trojan +455/tcp Fatal Connections +456/tcp Hackers Paradise +513/tcp Grlogin +514/tcp RPC Backdoor +531/tcp Net666, Rasmin +555/tcp Seven-Eleven +605/tcp Secret Service +666/tcp The Ripperz +667/tcp SniperNet +669/tcp DP trojan +692/tcp GayOL +777/tcp AimSpy +808/tcp WinHole +911/tcp Dark Shadow +999/tcp Deep Throat +1000/tcp Der Spaeher +1001/tcp Der Spaeher +1010/tcp Doly Trojan +1011/tcp Doly Trojan +1012/tcp Doly Trojan +1015/tcp Doly Trojan +1016/tcp Doly Trojan +1020/tcp Vampire +1024/tcp NetSpy +1025/tcp Remote Storm +1025/udp Remote Storm +1035/tcp Multidropper +1042/tcp BLA trojan +1045/tcp Rasmin +1049/tcp /sbin/initd +1050/tcp MiniCommand +1053/tcp The Thief +1054/tcp AckCmd +1080/tcp WinHole +1081/tcp WinHole +1082/tcp WinHole +1083/tcp WinHole +1090/tcp Xtreme +1095/tcp RAT +1097/tcp RAT +1098/tcp RAT +1099/tcp RAT +1150/tcp Orion +1151/tcp Orion +1170/tcp PSS +1200/udp NoBackO +1201/udp NoBackO +1207/tcp SoftWAR +1208/tcp Infector +1212/tcp Kaos +1234/tcp SubSeven +1243/tcp BackDoor-G +1245/tcp VooDoo Doll +1255/tcp Scarab +1256/tcp Project nEXT +1269/tcp Matrix +1272/tcp The Matrix +1313/tcp NETrojan +1338/tcp Millenium Worm +1349/tcp Bo dll +1394/tcp GoFriller +1441/tcp Remote Storm +1492/tcp FTP99CMP +1524/tcp Trinoo +1568/tcp Remote Hack +1600/tcp Shivka-Burka +1703/tcp Exploiter +1777/tcp Scarab +1807/tcp SpySender +1966/tcp Fake FTP +1967/tcp WM FTP Server +1969/tcp OpC BO +1981/tcp Bowl, Shockrave +1999/tcp SubSeven +2000/tcp Der Spaeher +2001/tcp Der Späher +2023/tcp Ripper Pro +2080/tcp WinHole +2115/tcp Bugs +2130/udp Mini Backlash +2140/tcp The Invasor +2140/udp Deep Throat +2155/tcp Illusion Mailer +2255/tcp Nirvana +2283/tcp Hvl RAT +2300/tcp Xplorer +2311/tcp Studio 54 +2330/tcp Contact +2331/tcp Contact +2332/tcp Contact +2333/tcp Contact +2334/tcp Contact +2335/tcp Contact +2336/tcp Contact +2337/tcp Contact +2338/tcp Contact +2339/tcp Contact +2339/udp Voice Spy +2345/tcp Doly Trojan +2565/tcp Striker trojan +2583/tcp WinCrash +2600/tcp Digital RootBeer +2716/tcp The Prayer +2773/tcp SubSeven +2774/tcp SubSeven +2801/tcp Phineas Phucker +2989/udp RAT +3000/tcp Remote Shut +3024/tcp WinCrash +3031/tcp Microspy +3128/tcp Ringzero +3129/tcp Masters Paradise +3150/tcp The Invasor +3150/udp Deep Throat +3456/tcp Terror trojan +3459/tcp Eclipse 2000 +3700/tcp Portal of Doom +3777/tcp PsychWard +3791/tcp Total Solar Eclypse +3801/tcp Total Solar Eclypse +4000/tcp SkyDance +4092/tcp WinCrash +4242/tcp VHM +4321/tcp BoBo +4444/tcp Prosiak +4567/tcp File Nail +4590/tcp ICQ Trojan +4950/tcp ICQ Trogen (Lm) +5000/tcp Back Door Setup +5001/tcp Back Door Setup +5002/tcp cd00r +5010/tcp Solo +5011/tcp OOTLT +5025/tcp WM Remote KeyLogger +5031/tcp Net Metropolitan +5032/tcp Net Metropolitan +5321/tcp Firehotcker +5333/tcp Backage +5343/tcp wCrat +5400/tcp Back Construction +5401/tcp Back Construction +5402/tcp Back Construction +5512/tcp Illusion Mailer +5534/tcp The Flu +5550/tcp Xtcp +5555/tcp ServeMe +5556/tcp BO Facil +5557/tcp BO Facil +5569/tcp Robo-Hack +5637/tcp PC Crasher +5638/tcp PC Crasher +5742/tcp WinCrash +5760/tcp Portmap Remote Root Linux Exploit +5880/tcp Y3K RAT +5882/tcp Y3K RAT +5882/udp Y3K RAT +5888/tcp Y3K RAT +5888/udp Y3K RAT +5889/tcp Y3K RAT +6000/tcp The Thing +6006/tcp Bad Blood +6272/tcp Secret Service +6400/tcp The Thing +6661/tcp TEMan +6666/tcp Dark Connection Inside +6667/tcp Dark FTP +6669/tcp Host Control, Vampire +6670/tcp BackWeb Server +6711/tcp BackDoor-G +6712/tcp Funny trojan +6713/tcp SubSeven +6723/tcp Mstream +6771/tcp Deep Throat +6776/tcp 2000 Cracks +6838/udp Mstream +6883/tcp Delta Source DarkStar (??) +6912/tcp Shit Heep +6939/tcp Indoctrination +6969/tcp GateCrasher +6970/tcp GateCrasher +7000/tcp Exploit Translation Server +7001/tcp Freak88 +7215/tcp SubSeven +7300/tcp NetMonitor +7301/tcp NetMonitor +7306/tcp NetMonitor +7307/tcp NetMonitor +7308/tcp NetMonitor +7424/tcp Host Control +7424/udp Host Control +7597/tcp Qaz +7626/tcp Glacier +7777/tcp God Message, Tini +7789/tcp Back Door Setup, ICKiller +7891/tcp The ReVeNgEr +7983/tcp Mstream +8080/tcp Brown Orifice +8787/tcp Back Orifice 2000 +8988/tcp BacHack +8989/tcp Rcon +9000/tcp Netministrator +9325/udp Mstream +9400/tcp InCommand +9872/tcp Portal of Doom +9873/tcp Portal of Doom +9874/tcp Portal of Doom +9875/tcp Portal of Doom +9876/tcp Cyber Attacker, Rux +9878/tcp TransScout +9989/tcp Ini-Killer +9999/tcp The Prayer +10000/tcp OpwinTRojan +10005/tcp OpwinTRojan +10067/udp Portal of Doom +10085/tcp Syphillis +10086/tcp Syphillis +10100/tcp Control Total +10101/tcp BrainSpy +10167/udp Portal of Doom +10520/tcp Acid Shivers +10528/tcp Host Control +10607/tcp Coma +10666/udp Ambush +11000/tcp Senna Spy Trojan Generator +11050/tcp Host Control +11051/tcp Host Control +11223/tcp Progenic trojan +12076/tcp Gjamer +12223/tcp Hack-99 KeyLogger +12345/tcp Ashley +12346/tcp Fat Bitch +12349/tcp BioNet +12361/tcp Whack-a-mole +12362/tcp Whack-a-mole +12363/tcp Whack-a-mole +12623/udp DUN Control +12624/tcp ButtMan +12631/tcp Whack Job +12754/tcp Mstream +13000/tcp Senna Spy +13010/tcp Hacker Brasil - HBR +13013/tcp PsychWard +13014/tcp PsychWard +13223/tcp Hack´99 KeyLogger +13473/tcp Chupacabra +14500/tcp PC Invader +14501/tcp PC Invader +14502/tcp PC Invader +14503/tcp PC Invader +15000/tcp NetDemon +15092/tcp Host Control +15104/tcp Mstream +15382/tcp SubZero +15858/tcp CDK +16484/tcp Mosucker +16660/tcp Stacheldraht +16772/tcp ICQ Revenge +16959/tcp SubSeven +16969/tcp Priority +17166/tcp Mosaic +17300/tcp Kuang2 the virus +17449/tcp Kid Terror +17499/tcp CrazzyNet +17500/tcp CrazzyNet +17569/tcp Infector +17593/tcp Audiodoor +17777/tcp Nephron +18753/udp Shaft +19864/tcp ICQ Revenge +20000/tcp Millenium +20001/tcp Millenium +20002/tcp AcidkoR +20005/tcp Mosucker +20023/tcp VP Killer +20034/tcp NetBus +20203/tcp Chupacabra +20331/tcp BLA trojan +20432/tcp Shaft +20433/udp Shaft +21544/tcp GirlFriend, Kid Terror +21554/tcp Exploiter +22222/tcp Donald Dick +23005/tcp NetTrash +23006/tcp NetTrash +23023/tcp Logged +23032/tcp Amanda +23432/tcp Asylum +23456/tcp Evil FTP +23476/tcp Donald Dick +23476/udp Donald Dick +23477/tcp Donald Dick +23777/tcp InetSpy +24000/tcp Infector +25685/tcp Moonpie +25686/tcp Moonpie +25982/tcp Moonpie +26274/udp Delta Source +26681/tcp Voice Spy +27374/tcp Bad Blood +27444/udp Trinoo +27573/tcp SubSeven +27665/tcp Trinoo +28678/tcp Exploiter +29104/tcp NetTrojan +29369/tcp ovasOn +29891/tcp The Unexplained +30000/tcp Infector +30001/tcp ErrOr32 +30003/tcp Lamers Death +30029/tcp AOL trojan +30100/tcp NetSphere +30101/tcp NetSphere +30102/tcp NetSphere +30103/tcp NetSphere +30103/udp NetSphere +30133/tcp NetSphere +30303/tcp Sockets des Troie +30947/tcp Intruse +30999/tcp Kuang2 +31335/tcp Trinoo +31336/tcp Bo Whack, Butt Funnel +31337/tcp Back Fire +31337/udp Back Orifice +31338/tcp Back Orifice +31338/udp Deep BO +31339/tcp NetSpy (DK) +31666/tcp BOWhack +31785/tcp Hack´a´Tack +31787/tcp Hack´a´Tack +31788/tcp Hack´a´Tack +31789/udp Hack´a´Tack +31790/tcp Hack´a´Tack +31791/udp Hack´a´Tack +31792/tcp Hack´a´Tack +32001/tcp Donald Dick +32100/tcp Peanut Brittle +32418/tcp Acid Battery +33270/tcp Trinity +33333/tcp Blakharaz +33577/tcp Son of PsychWard +33777/tcp Son of PsychWard +33911/tcp Spirit 2000 +34324/tcp Big Gluck +34444/tcp Donald Dick +34555/udp Trinoo +35555/udp Trinoo +37237/tcp Mantis +37651/tcp Yet Another Trojan - YAT +40412/tcp The Spy +40421/tcp Agent 40421 +40422/tcp Masters Paradise +40423/tcp Masters Paradise +40425/tcp Masters Paradise +40426/tcp Masters Paradise +41337/tcp Storm +41666/tcp RBT +44444/tcp Prosiak +44575/tcp Exploiter +47262/udp Delta Source +49301/tcp OnLine KeyLogger +50130/tcp Enterprise +50505/tcp Sockets des Troie +50766/tcp Fore +51966/tcp Cafeini +52317/tcp Acid Battery 2000 +53001/tcp RWS +54283/tcp SubSeven +54320/tcp Back Orifice 2000 +54321/tcp Back Orifice 2000 +55165/tcp File Manager trojan +55166/tcp WM Trojan Generator +57341/tcp NetRaider +58339/tcp Butt Funnel +60000/tcp Deep Throat +60001/tcp Trinity +60068/tcp Xzip 6000068 +60411/tcp Connection +61348/tcp Bunker-Hill +61466/tcp TeleCommando +61603/tcp Bunker-Hill +63485/tcp Bunker-Hill +64101/tcp Taskman +65000/tcp Devil +65390/tcp Eclypse +65421/tcp Jade +65432/tcp The Traitor (= th3tr41t0r) +65432/udp The Traitor (= th3tr41t0r) +65534/tcp /sbin/initd +65535/tcp RC1 trojan diff --git a/roles/epylog/files/merged/weed_dist.cf b/roles/epylog/files/merged/weed_dist.cf new file mode 100644 index 0000000000..dd87e2d351 --- /dev/null +++ b/roles/epylog/files/merged/weed_dist.cf @@ -0,0 +1,179 @@ +## +# NOTE: +# Editing this file is not recommended. If you do, you might miss newer +# revisions of this list in the future versions. +# See weed_local.cf for instructions on how to add or delete rules. +# + +[pam] +\(pam_unix\).*: session closed for +\(pam_unix\).*: check pass; + +[dhcpd] +dhcpd: DHCPREQUEST +dhcpd: DHCPACK +dhcpd: DHCPDISCOVER +dhcpd: DHCPOFFER +dhcpd: DHCPRELEASE +dhcpd: DHCPINFORM + +[rpc] +rpc.mountd: authenticated mount request from +rpc.mountd: authenticated unmount request +rpc.statd.*: Version .* Starting +rpc.statd.*: Caught signal 15, un-registering and exiting + +[automount] +automount.*: expired +automount.*: attempting to mount entry +automount.*: lookup\(file\): .* failed +automount.*: starting automounter +automount.*: using kernel protocol +automount.*: shutting down +automount.*: .* No such key in map + +[crond] +CROND.*: \(mailman\) CMD \(/usr/bin/python +CROND.*: \(root\) CMD \(.*/sbin/rmmod -as\) +CROND.*: \(root\) CMD \(/usr/lib/sa/sa\d +CROND.*: \(root\) CMD \(run-parts +anacron.*: Updated timestamp for job + +[bind] +named.*: lame server resolving +named.*: .* NS points to CNAME +named.*: Response from unexpected source +named.*: .* All possible A RR's lame +named.*: bad referral +named.*: Cleaned cache +named.*: USAGE +named.*: NSTATS +named.*: XSTATS +named.*: .* points to a CNAME +named.*: denied update from +named.*: .* Bogus LOOPBACK + +[gnome] +gnome-name-server.*: input condition is: +gnome-name-server.*: name server starting +gnome-name-server.*: starting +gnome-name-server.*: name server was running +gconfd.*: Resolved address +gconfd.*: GConf server is not in use +gconfd.*: Exiting +gconfd.*: starting +gconfd.*: .* shutting down cleanly +gdm.*: Couldn't authenticate user +xscreensaver.*: FAILED LOGIN + +[sshd] +sshd.*: Generating new .* key. +sshd.*: .* key generation complete +sshd.*: Connection closed +sshd.*: Could not reverse map address +sshd.*: Received disconnect from +sshd.*: error: Could not get shadow information for +sshd.*: Invalid user .* from + +[xinetd] +xinetd.*: .* Transport endpoint is not connected +xinetd.*: EXIT: + +[uw-imap] +imapd.*: AUTHENTICATE +imapd.*: Logout +imapd.*: Killed +imapd.*: imap.*service init +imapd.*: Command stream end of file +imapd.*: Autologout +imapd.*: Connection reset by peer +ipop3d.*: AUTHENTICATE +ipop3d.*: Logout +ipop3d.*: Killed +ipop3d.*: Autologout +ipop3d.*: pop3.*service init + +[courier-imap] +imapd.*: Connection, ip=\[\S+\] +imapd.*: LOGOUT, user=\S+, ip=\[\S+\] +imapd.*: Disconnected, ip=\[\S+\] +imapd.*: DISCONNECTED, user=\S+, ip=\[\S+\] +imapd.*: LOGOUT, ip=\[\S+\] +pop3d.*: Connection, ip=\[\S+\] +pop3d.*: LOGOUT, user=\S+, ip=\[\S+\] +pop3d.*: Disconnected, ip=\[\S+\] +pop3d.*: DISCONNECTED, user=\S+, ip=\[\S+\] +pop3d.*: LOGOUT, ip=\[\S+\] + +[postfix] +postfix/smtp\[\d+\]: connect to +postfix/smtp\[\d+\]: warning: no MX host +postfix/smtp\[\d+\]: warning: numeric domain name in resource data +postfix/smtp\[\d+\]: warning: host .* with my own hostname +postfix/smtpd.*: connect from +postfix/smtpd.*: disconnect from +postfix/smtpd.*: TLS connection established +postfix/smtpd.*: lost connection +postfix/cleanup +postfix/pickup + +[sendmail] +sendmail\[.*:.*NOQUEUE: Null connection from +sendmail\[.*:.*timeout waiting for input + +[qmail] +qmail:.* new msg +qmail:.* end msg +qmail:.* status: + +[spamd] +spamd\[.*: info: +spamd\[.*: processing message +spamd\[.*: checking message +spamd\[.*: connection from +spamd\[.*: Creating default_prefs + +[printer] +printer: ready to print +printer: status change +printer: printing +printer: peripheral low-power state + +[pumpd] +pumpd.*: renewed lease for interface +pumpd.*: configured interface + +[afpd] +afpd.*: ASIP session: +afpd.*: afp_flushfork: +afpd.*: .*B read,.*B written + +[ntpd] +ntpd.*: kernel time discipline status change + +[kernel] +kernel: application .* uses obsolete OSS audio interface +kernel: SELinux: initialized +kernel: device .* left promiscuous mode +kernel: .*: disabled promiscuous mode +usb-uhci.c: interrupt, status +PCI: Found IRQ +PCI: Sharing IRQ +PCI: Setting latency timer +kernel: agpgart: Found +kernel: agpgart: Putting + +[misc] +modprobe: Can't locate module +logger: punching nameserver .* through the firewall +HORDE\[\S*\s*\[imp\] Logout +LOGIN ON tty. +dhclient: DHCPREQUEST +dhclient: DHCPACK +dhclient: DHCPDISCOVER +dhclient: bound to +dbus: avc: .* buckets used + + + +## $Revision: 1.14.2.4 $ ## diff --git a/roles/epylog/files/merged/weed_local.cf b/roles/epylog/files/merged/weed_local.cf new file mode 100644 index 0000000000..77c1ea5a92 --- /dev/null +++ b/roles/epylog/files/merged/weed_local.cf @@ -0,0 +1,305 @@ +[ADD] +## +# Here is where you add your own rules +# + +ansible.*: Invoked.* +ansible-accelerate:.* +auditd.*: Audit daemon rotating log files +collectd.*: Filter subsystem.* +collectd.*: Value too old.* +collectd.*: processes plugin: Failed to read from.* +dbus.*:.*avc:.*received.* +dbus.*:.*Reloaded configuration.* +dbus.*:.*Successfully activated service 'org.fedoraproject.Setroubleshootd'.* +dbus.*:.*\[system\].*Activating.*using servicehelper.* +dbus-daemon.*:.*Successfully activated service \'org.fedoraproject.Setroubleshootd\'.* +dhclient.*: bound to.* +dhclient.*: DHCPDISCOVER.* +dhclient.*: DHCPACK.* +dhclient.*: DHCPREQUEST.* +dhcpd:.*Wrote.*leases file.* +dnsmasq-dhcp.* +# work around bug https://bugzilla.redhat.com/show_bug.cgi?id=947989 +dhclient.*: send_packet: Operation not permitted +dhclient.*: dhclient.c:2663: Failed to send 300 byte long packet over fallback interface. +dhclient.*: Internet Systems Consortium DHCP Client.* +dhclient.*: Copyright 2004-2013 Internet Systems Consortium. +dhclient.*: All rights reserved. +dhclient.*: For info, please visit https://www.isc.org/software/dhcp/ +dhclient.*: Listening on.* +dhclient.*: Sending on.* +dhclient.*: Sending on.* +dhclient.*: $ +freshclam.*: Can't connect to port 80 of host.* +freshclam.*: connect_error:.* +freshclam.*: Downloading.* +freshclam.*:.*is up to date.* +freshclam.*:.*updated.* +freshclam.*: Database updated.* +freshclam.*: ClamAV update process started +git-daemon.*: Connection from.* +git-daemon.*: Connection reset by peer +git-daemon.*: .* does not appear to be a git repository +git-daemon.*: Extended attributes.* +git-daemon.*: Request upload-pack.* +git-daemon.*: The remote end hung up unexpectedly +git-daemon.*: userpath.* +git-daemon.*: Request upload-archive for.* +git-daemon.*: fatal: write error: Connection timed out +groupadd.*: group added to.*: name=(mockbuild|dialout|floppy|cdrom|tape|utmp|utempter|dbus|avahi-autoipd|rpc|rpcuser|nfsnobody|ssh_keys).* +(group|user)add.*: new (user|group): name=(mockbuild|dialout|floppy|cdrom|tape|utmp|utempter|dbus|avahi-autoipd|rpc|rpcuser|nfsnobody|ssh_keys).* +heartbeat.* info:.* +heartbeat.*:info.* +heartbeat.*:WARN: Gmain_timeout_dispatch: Dispatch function for retransmit request took too long to execute.* +in.tftpd.*: tftp: client does not accept options +kernel:.*CPU.*power limit.* +kernel:.*dma-pl330 fff3d000.dma: Reset Channel.* +kernel: TCPv6: Possible SYN flooding on port 80. Sending cookies. +kernel: TCPv6: Possible SYN flooding on port 80. Dropping request. +kernel: possible SYN flooding on port 80. Sending cookies. +kernel: EXT4-fs \(.*\): mounted filesystem with ordered data mode.* +kernel: ioctl32\(e2fsck.* +kernel: ioctl32\(resize2fs.* +kernel: md: data-check of RAID array.* +kernel: md: delaying data-check of.* +kernel: md: md.*: data-check done. +kernel: md: minimum _guaranteed_ speed.* +kernel: md: using 128k window.* +kernel: md: using maximum available idle IO bandwidth.* +kernel: printk.*suppressed. +kernel: __ratelimit:.*callbacks suppressed +kernel:.*subj=.* +kernel:.*exe=.* \(sauid=.*, hostname=.* addr=.* terminal=.*\) +kernel:.*type=.*audit\(.* +kernel:.*audit_printk_skb:.*callbacks suppressed +lvm.*: Another thread is handling an event. Waiting...* +nagios: Auto-save of retention data completed successfully +nagios: CURRENT.* +nagios: EXTERNAL COMMAND.* +nagios: LOG.* +nagios: PASSIVE SERVICE CHECK.* +nagios: SERVICE ALERT.* +nagios: SERVICE FLAPPING ALERT.* +nagios: SERVICE NOTIFICATION.* +nagios: Warning:.*Passive check result was received for service.* +nagios: Warning: The results of service.* are stale.* +named.*: .* general: info:.* +named.*: .* notify: info:.* +named.*: .* general: error: zone.*unchanged. zone may fail to transfer to slaves. +named.*: .* resolver: notice: DNS format error from.*: invalid response +named.*: .* resolver: notice: DNS format error from.*: non-improving referral +named.*: .* security: info: client.*: view.*: query (cache).*denied +named.*: .* edns-disabled: info: success resolving.*after.* +named.*: .* security: info: client.*denied +named.*: .* rate-limit: info:.* +named.*: .* general: warning: checkhints: view.* +NetworkManager.*: \.* +NetworkManager.*: \.* +ntpd.*: synchronized.* +ntpd.*: time reset.* +openvpn.*: Auth read bytes.* +openvpn.*: CLIENT_LIST.* +openvpn.*: END +openvpn.*: event_wait : Interrupted system call.* +openvpn.*: GLOBAL_STATS.* +openvpn.*: HEADER.* +openvpn.*: OpenVPN STATISTICS +openvpn.*: post-compress bytes.* +openvpn.*: post-decompress bytes.* +openvpn.*: pre-compress bytes.* +openvpn.*: pre-decompress bytes.* +openvpn.*: ROUTING_TABLE.* +openvpn.*: TCP/UDP.* +openvpn.*: TCP/UDP.* +openvpn.*: TIME.* +openvpn.*: TITLE.* +openvpn.*: TUN/TAP.* +openvpn.*: UDPv4 link (local|remote).* +openvpn.*: SIGUSR1.* +openvpn.*: Updated.* +openvpn.*:.*Re-using SSL/TLS context.* +openvpn.*:.*LZO compression.* +openvpn.*: NOTE: the current --script-security setting may allow this configuration to call user-defined scripts.* +openvpn.*: WARNING: No server certificate verification method has been enabled.* +pam_unix\(.*\): account .* has password changed in future +postfix/anvil.*: statistics.* +postfix/bounce.*sender non-delivery notification.* +postfix/error.*:.*delivery temporarily suspended.*Connection timed out.* +postfix/error.*:.*delivery temporarily suspended.*No route to host.* +postfix/error.*:.*delivery temporarily suspended.*temporarily deferred due to user complaints.* +postfix/error.*:.*delivery temporarily suspended.*while receiving the initial server greeting.* +postfix/error.*:.*delivery temporarily suspended.*Host or domain name not found.* +postfix/error.*:.*delivery temporarily suspended.*Connection refused.* +postfix/error.*:.*delivery temporarily suspended.*conversation with.* +postfix/error.*:.*delivery temporarily suspended.*service not available, closing transmission channel.* +postfix/error.*:.*delivery temporarily suspended.*Network is unreachable.* +postfix/error.*:.*refused to talk to me.* +postfix/lmtp.*:.*250.*Ok.* +postfix/lmtp.*: 503.* +postfix/local.*: table.*has changed -- restarting.* +postfix/master.*: daemon started.* +postfix/master.*: terminating on signa.* +postfix/pipe.*:.*delivered via spamassassin.* +postfix/postfix-script.*: starting the Postfix mail system +postfix/postfix-script.*: stopping the Postfix mail system +postfix/postfix-script.*: waiting for the Postfix mail system to terminate +postfix/scache.*: statistics.* +postfix/smtp.*: 400.* +postfix/smtp.*: 421.* +postfix/smtp.*: 450.* +postfix/smtp.*: 451.* +postfix/smtp.*: 452.* +postfix/smtp.*: 454.* +postfix/smtp.*: 503.* +postfix/smtp.*: conversation.* timed out.* +postfix/smtpd.*: table.*has changed -- restarting.* +postfix/smtpd.*: timeout.* +postfix/smtpd.*: too many errors after RCPT.* +postfix/smtp.*: enabling PIX.* +postfix/smtp.*: lost connection.* +postfix/smtp.*:.*refused to talk to me.* +postfix/smtp.*: warning: malformed domain name.* +postfix/smtp.*: warning: valid_hostname:.* +postfix/smtp.*:.*yahoo.*refused to talk to me.* +puppet(d|-agent).*: Applying.* +puppet(d|-agent).*: Caching catalog for.* +puppet(d|-agent).*: Caching certificate for.* +puppet(d|-agent).*: Compiled.* +puppet(d|-agent).*: Could not request certificate:.* +puppet(d|-agent).*: Creating a new SSL key for +puppet(d|-agent).*: \(/File.* +puppet(d|-agent).*: FileBucket.* +puppet(d|-agent).*: Finished.* +puppet(d|-agent).*: Loading facts in datacenter +puppet(d|-agent).*: Loading facts in distrorelease +puppet(d|-agent).*: Loading facts in git_exec_path +puppet(d|-agent).*: Loading facts in libdir +puppet(d|-agent).*: Loading facts in location +puppet(d|-agent).*: Loading facts in pythonsitelib +puppet(d|-agent).*: Loading facts in pythonsitearch +puppet(d|-agent).*: Loading facts in /var/lib/puppet/lib/facter/datacenter.rb +puppet(d|-agent).*: Loading facts in /var/lib/puppet/lib/facter/distrorelease.rb +puppet(d|-agent).*: Loading facts in /var/lib/puppet/lib/facter/git_exec_path.rb +puppet(d|-agent).*: Loading facts in /var/lib/puppet/lib/facter/libdir.rb +puppet(d|-agent).*: Loading facts in /var/lib/puppet/lib/facter/location.rb +puppet(d|-agent).*: Loading facts in /var/lib/puppet/lib/facter/pythonsitelib.rb +puppet(d|-agent).*: Loading facts in /var/lib/puppet/lib/facter/pythonsitearch.rb +puppet(d|-agent).*: Retrieving plugin +puppet(d|-agent).*: Run of Puppet configuration client already in progress; skipping +puppet(d|-agent).*: \(/Stage.* +puppet(d|-agent).*: Failed to set SELinux context system_u:object_r:var_t:s0 on /srv/reviewboard/htdocs/media/rb +puppet(d|-agent).*: Failed to set SELinux context system_u:object_r:var_t:s0 on /srv/reviewboard/htdocs/media/djblets +puppet-master.*: Compiled.* +python.*: ansible-.* +ResourceManager.*: info:.* +restorecond: Reset file context /etc/aliases.* +restorecond: Reset file context /var/db/shadow.db.* +restorecond: Unable to watch.* +Rootkit Hunter: Rootkit hunter.* +Rootkit Hunter: Scanning.* +root: time debug:.* +rpc.idmapd.*: nss_getpwnam: name.*apache.* +rpc.idmapd.*: nss_getpwnam: name.*masher.* +rpc.idmapd.*: nss_getpwnam: name.*root@fedora.* +rpc.idmapd.*: nss_getpwnam: name.*root@localdomain* +rsyncd.*: building.* +rsyncd.*: connect from.* +rsyncd.*: file has vanished: +rsyncd.*: name lookup failed for.* +rsyncd.*: rsync: connection unexpectedly closed.* +rsyncd.*: rsync error: error in rsync protocol data stream.* +rsyncd.*: sent.* +#rsync.*: rsync on.* +rsyslogd-2163:epoll_ctl failed +#goofy-ass rsyslogd error :( +^\(\':\',.* +setfiles: relabeling .* +spamc.*: connect to spamd on.* +spamc.*: skipped message, greater.* +spamd.*: bayes: cannot open bayes databases.* +spamd.*: logger: removing.* +spamd.*: prefork.* +spamd.*: pyzor:.* error: TERMINATED +spamd: result:.* +spamd.*: spamd: clean message.* +spamd.*: spamd: clean message.* +spamd.*: spamd: handled cleanup.* +spamd.*: spamd: identified spam.* +spamd.*: spamd: server killed.* +spamd.*: spamd: server pid.* +spamd.*: spamd: server started.* +spamd.*: spamd: server successfully.* +spamd.* spamd: setuid to.* +sshd.*: Address.*maps to.*but this does not map back to the address - POSSIBLE BREAK-IN ATTEMPT.* +sshd.*: Did not receive identification.* +sshd.*: Disconnecting: Too many authentication failures for root.* +sshd.*: error: connect_to +sshd.*: error: ssh_selinux_setup_pty: +sshd.*: Found matching RSA key:.* +sshd.*: input_userauth_request: invalid user.* +sshd.*: pam_unix\(sshd:session\): session closed for user.* +sshd.*: pam_unix\(sshd:session\): session opened for user.* +sshd.*: Postponed publickey for.* +sshd.*: refused connect from.* +sshd.*: reverse mapping checking getaddrinfo.*POSSIBLE BREAK-IN ATTEMPT.* +sshd.*: Server listening on.* +sshd.*: subsystem request for sftp +sshd.*: pam_namespace.*: Unmount of \/tmp failed, Device or resource busy.* +sshd.*: Set /proc/self/oom_score_adj.* +sshd.*: Connection from.* port.* +sshd.*: Transferred: sent.*, received.*bytes +sshd.*: Closing connection to.*port.* +sshd.*: User child is on pid.* +sshd.*: Read error from remote host.*: Connection reset by peer +sshd.*: error: Could not load host key: /etc/ssh/ssh_host_dsa_key +sshd.*: Starting session: command.* +stunnel:.*websockets connected remote.* +stunnel:.*SSL_read.* +stunnel:.*Connection reset.* +stunnel:.*connect_blocking.* +stunnel:.*Connection closed.* +su: pam_unix\(su-l:session\): session .* for user dbbackup.* +su: pam_unix\(su-l:session\): session .* for user postgres.* +runuser: pam_unix\(runuser-l:session\).* session opened for user postgres by.* +runuser: pam_unix\(runuser-l:session\).* session closed for user postgres +systemd-logind.* +systemd.*: Start.* +systemd.*: Stop.* +systemd.*: Reached.* +systemd: pam_unix\(systemd-user:session\): session opened for user root by (uid=0) +systemd: pam_unix\(systemd-user:session\): session closed for user root +systemd: pam_unix\(systemd-user:session\): session.* +systemd.*: Start.* Cleanup of Temporary Directories.* +systemd-machine-id-setup.*: Initializing machine ID.* +systemd.*: Created slice user-0.slice. +systemd.*: Removed slice user-0.slice. +systemd.*: Received SIGRTMIN\+24 from PID.* +unix_chkpwd.*: account .* has password changed in future +userhelper.*: running \'/usr/sbin/mock.* +groupadd.*: new group.* +groupadd.*: group added to /etc/g.* +useradd.*: new user.* +varnishd.*: Child .* said missing \)CLI.* +varnishd.*: Child .* said nothing to repeatCLI result.* +xinetd.*: Exiting.* +xinetd.*: FAIL: git per_source_limit.* +xinetd.*: readjusting service rsync +xinetd.*: Reconfigured.* +xinetd.*: Started.* +xinetd.*: Starting reconfiguration +xinetd.*: Swapping defaults +xinetd.*: xinetd Version.* +ykksm.*: SUCCESS.* +ykval.*: LOG_INFO.* +ykval.*: LOG_WARNING.* +ykval.*: SUCCESS.* +ykval.*: WARNING.* +yum.*: Installed:.* +yum.*: Updated:.* + + +[REMOVE] +## +# Here is where you put the rules (VERBATIM) from the weed_dist.cf file +# diff --git a/roles/epylog/files/modules/common_unparsed.conf b/roles/epylog/files/modules/common_unparsed.conf new file mode 100644 index 0000000000..73ec8ee320 --- /dev/null +++ b/roles/epylog/files/modules/common_unparsed.conf @@ -0,0 +1,12 @@ +[module] +desc = Common Unparsed Similar Strings Module +exec = /usr/share/epylog/modules/common_unparsed_mod.py +files = /var/log/messages[.#] /var/log/secure[.#] +enabled = yes +internal = yes +outhtml = yes +priority = 5 + +[conf] +# how similar the strings need to be 0-100 - 0 being not at all (bad idea) 100 being almost exactly. +match_percentage = 95 diff --git a/roles/epylog/files/modules/common_unparsed_mod.py b/roles/epylog/files/modules/common_unparsed_mod.py new file mode 100644 index 0000000000..d2aa635fbb --- /dev/null +++ b/roles/epylog/files/modules/common_unparsed_mod.py @@ -0,0 +1,118 @@ +#!/usr/bin/python -tt +""" +This module should run after all other modules. + +Takes the remaining logs, saves them out to a tmpfile. +Uses difflib.SequenceMatcher() to return logs which occur most often and are +at least a set percentage similar. This lets you catch logs which are +from multiple machines and more or less the same or similar logs (with memory +or process id offsets) from the same machine. + +""" + +import sys +import re +import difflib +from operator import itemgetter +import tempfile +import os +import shutil + +## +# This is for testing purposes, so you can invoke this from the +# modules directory. See also the testing notes at the end of the +# file. +# +sys.path.insert(0, '../py/') +from epylog import Result, InternalModule + +class common_unparsed_mod(InternalModule): + def __init__(self, opts, logger): + InternalModule.__init__(self) + self.logger = logger + rc = re.compile + + self.match_percentage = int(opts.get('match_percentage', '95')) + self.debug_dump = int(opts.get('debug_dump', '1')) + self.regex_map = {rc('^.+$'):self.expand_out_line} + self.tmpdir = tempfile.mkdtemp(prefix='epylog-common-unparsed', dir='/var/tmp') + self.matchfile = self.tmpdir + '/match_limited' + self.matchfile_f = open(self.matchfile, 'w') + self.complete = self.tmpdir + '/complete' + self.complete_f = open(self.complete, 'w') + + + ## + # Line-matching routines + # + def expand_out_line(self, linemap): + sys, msg, mult = self.get_smm(linemap) + matchout = '%s\n' % (msg) + com_out = '%s' % (linemap['line']) + for i in range(0, int(mult)): + self.complete_f.write(com_out) + self.matchfile_f.write(matchout) + + #dirty like zebra + if not os.path.exists(self.tmpdir + '/returned'): + open(self.tmpdir + '/returned', 'w').close() + return {'match':0} + else: + return None + + + def finalize(self, rs): + #FIXME - enable a debug mode where it writes + # out to a file all of the first line and things which match it + # and percentages of match for later investigation + self.complete_f.close() + self.matchfile_f.close() + matches = {} + full_matches = {} + lines_matched = set() + where = 0 + rl = open(self.matchfile, 'r') + for l in rl: + where += 1 + sub_where = 0 + for ol in open(self.matchfile, 'r'): + sub_where += 1 + if sub_where < where: # if we're before it in the file we've already matched it + continue + if sub_where in lines_matched: + continue + + c = difflib.SequenceMatcher(isjunk=lambda x: x in ('1','2','3','4','5','6','7','8','9','0'),a=l, b=ol) + rq_ratio = int(c.real_quick_ratio()*100) # do the fast upper bound - find out if we should even glance at it. + if rq_ratio < 60: + continue + ratio = int(c.ratio()*100) + if ratio >= self.match_percentage: + lines_matched.add(sub_where) + if l not in matches: + matches[l] = 0 + full_matches[l] = [] + matches[l] += 1 + full_matches[l].append((ol,ratio)) + if self.debug_dump: + fm_db = open(self.tmpdir + '/debug-match', 'w') + for k in full_matches: + fm_db.write(k) + for (v,r) in full_matches[k]: + fm_db.write(' %s %s' % (r, v)) + fm_db.close() + + res = "\n\n" + for (k,v) in sorted(matches.items(), key=itemgetter(1), reverse=True)[:20]: # take the top 20 most common provided there are more than 1 + if v > 1: + res += "\n\n" % (v, k) + res += "\n\n\n
CountLog
%s%s
\n

Complete messages

\n
\n"
+        res += ''.join(sorted(open(self.complete, 'r').readlines()))
+        res += "
\n
" + return res + + + +if __name__ == '__main__': + from epylog.helpers import ModuleTest + ModuleTest(common_unparsed_mod, sys.argv) diff --git a/roles/epylog/files/modules/kojiload.conf b/roles/epylog/files/modules/kojiload.conf new file mode 100644 index 0000000000..6192a17cc8 --- /dev/null +++ b/roles/epylog/files/modules/kojiload.conf @@ -0,0 +1,10 @@ +[module] +desc = KojiLoad summary +exec = /usr/share/epylog/modules/kojiload_mod.py +files = /var/log/messages[.#] +enabled = no +internal = yes +outhtml = yes +priority = 7 + +[conf] diff --git a/roles/epylog/files/modules/kojiload_mod.py b/roles/epylog/files/modules/kojiload_mod.py new file mode 100644 index 0000000000..3945b8b0f7 --- /dev/null +++ b/roles/epylog/files/modules/kojiload_mod.py @@ -0,0 +1,102 @@ +#!/usr/bin/python -tt +""" +Rsyncd log parsing module for Epylog +""" + +## +# Copyright (C) 2012 by Red Hat, Inc +# Written by Seth Vidal +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. +# + + +import sys +import re + +## +# This is for testing purposes, so you can invoke this from the +# modules directory. See also the testing notes at the end of the +# file. +# +sys.path.insert(0, '../py/') +from epylog import Result, InternalModule + +class kojiload_mod(InternalModule): + ## + # opts: is a map with extra options set in + # [conf] section of the module config, or on the + # command line using -o flag to the module. + # logger: A logging object. API: + # logger.put(loglvl, 'Message') + # Only critical stuff needs to go onto lvl 0. + # Common output goes to lvl 1. + # Others are debug levels. + # + def __init__(self, opts, logger): + ## + # Do a "super-init" so the class we are subclassing gets + # instantiated. + # + InternalModule.__init__(self) + self.logger = logger + ## + # Convenience + # + rc = re.compile + #kojiload: Load: 7.1 Total: 192.0 Use: 3.7% (Very Light Load) + self.regex_map = { + rc('kojiload: Load:.*'): self.load_results + } + # dict to store all of our data + self.loads = [] # list of kojiload percentages + self.kojiloads = rc('kojiload: Load: (.*) Total: (.*) Use: (.*)\%.*') + + + def load_results(self, linemap): + (sys, msg, multi) = self.get_smm(linemap) + load, total, use_percent = self.kojiloads.search(msg).groups() + for i in range(multi): + self.loads.append(float(use_percent)) + return {(load,total): 1} + + + def finalize(self, resultset): + ## + # A resultset is a dictionary of all values returned by your + # handler functions -- except they are unique and show how many + # times each tuple occurs. + # See epylog.Result for some convenience methods to use when + # processing and analyzing the results. + # + if not self.loads: + return "No kojiloads returned, that seems odd." + + max_load = max(self.loads) + min_load = min(self.loads) + avg_load = sum(self.loads)/len(self.loads) + + foo = "Max: %s%%
\nMin: %s%%
\nAvg: %.1f%%
\n" % (max_load, + min_load, avg_load) + return foo + +## +# This is useful when testing your module out. +# Invoke without command-line parameters to learn about the proper +# invocation. +# +if __name__ == '__main__': + from epylog.helpers import ModuleTest + ModuleTest(kojiload_mod, sys.argv) diff --git a/roles/epylog/files/modules/logins_mod.py b/roles/epylog/files/modules/logins_mod.py new file mode 100644 index 0000000000..b4889599c8 --- /dev/null +++ b/roles/epylog/files/modules/logins_mod.py @@ -0,0 +1,849 @@ + + +#!/usr/bin/python -tt +""" +Description will eventually go here. +""" +## +# Copyright (C) 2003 by Duke University +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. +# +# $Id$ +# +# @Author Konstantin Ryabitsev +# @version $Date$ +# + +import sys +import re +import time +import os +import sqlite3 as sqlite +sys.path.insert(0, '../py/') +from epylog import Result, InternalModule + + +def executeSQL(cursor, query, params=None): + """ + Execute a python 2.5 (sqlite3) style query. + + @param cursor: A sqlite cursor + @param query: The query to execute + @param params: An optional list of parameters to the query + """ + if params is None: + return cursor.execute(query) + + return cursor.execute(query, params) + +class logins_mod(InternalModule): + def __init__(self, opts, logger): + InternalModule.__init__(self) + self.logger = logger + self.opts = opts + rc = re.compile + + self.ignore = 0 + self.open = 1 + self.failure = 2 + self.root_open = 11 + self.root_failure = 12 + self.pam_ignore = [] + self.xinetd_ignore = [] + self.logins_db = opts.get('loginsdb_path', '/var/lib/epylog/logins_db.sqlite') # where to keep the loginsdb + self.time_fuzz = int(opts.get('time_fuzz', 60)) # how much to fuzz the time in minutes (default 60m) + remove_older_than = int(opts.get('remove_older_than', 14)) # time in days to start remove from the db + self.oldest_to_keep = time.time() - (remove_older_than*86400) + if remove_older_than == '0': # if it is zero then don't delete any, ever - hah your funeral + self.oldest_to_keep = None + + ig_users = opts.get('ignore_users', '') + ig_users.replace(',',' ') + self.ignore_users = ig_users.split(' ') + + self.db_cx = None + + ## + # PAM reports + # + pam_map = { + rc('\(pam_unix\)\S*:.*authentication\s*failure'): self.pam_failure, + rc('\(pam_unix\)\S*:\ssession\sopened\sfor'): self.pam_open, + rc('\(pam_unix\)\S*:\sbad\susername'): self.pam_baduser, + rc('\(pam_unix\)\S*:\sauth\scould\snot'): self.pam_chelper_failure, + rc('pam_krb5\S*:\s\S+\ssucceeds\sfor'): self.pam_krb5_open, + rc('pam_krb5\S*:\s\S+\sfails\sfor'): self.pam_krb5_failure + } + ## + # XINETD reports + # + xinetd_map = { + rc('xinetd\S*: START:'): self.xinetd_start + } + ## + # SSH reports + # + sshd_map = { + rc('sshd\[\S*: Accepted'): self.sshd_open, + rc('sshd\[\S*: Failed'): self.sshd_failure + } + ## + # IMAPD and IPOP3D + # + uw_imap_map = { + rc('imapd\[\S*: Login\sfail'): self.uw_imap_failure, + rc('imapd\[\S*: Authenticated\suser'): self.uw_imap_open, + rc('imapd\[\S*: Login\suser'): self.uw_imap_open, + rc('ipop3d\[\S*: Login\sfail'): self.uw_imap_failure, + rc('ipop3d\[\S*: Login\suser'): self.uw_imap_open, + rc('ipop3d\[\S*: Auth\suser'): self.uw_imap_open + } + ## + # IMP + # + imp_map = { + rc('IMP\[\S*: Login'): self.imp2_open, + rc('IMP\[\S*: FAILED'): self.imp2_failure, + rc('HORDE\[\S*\s*\[imp\] Login'): self.imp3_open, + rc('HORDE\[\S*\s*\[imp\] FAILED'): self.imp3_failure + } + ## + # DOVECOT + # + dovecot_map = { + rc('imap-login:\sLogin:\s'): self.dovecot_open, + rc('imap-login:\sAborted\slogin\s'): self.dovecot_failure + } + ## + # Courier-IMAP + # + courier_map = { + rc('\sLOGIN,\suser=\S+,\sip=\[\S+\]'): self.courier_open, + rc('\sLOGIN FAILED,\sip=\[\S+\]'): self.courier_failure + } + ## + # Cyrus-IMAP + # + cyrus_map = { + rc('imapd\[\S*: login:'): self.cyrus_open, + rc('pop3d\[\S*: login:'): self.cyrus_open, + rc('imapd\[\S*: badlogin:'): self.cyrus_failure, + rc('pop3d\[\S*: badlogin:'): self.cyrus_failure + } + ## + # Qpopper + # + qpopper_map = { + rc('apop\[\S*:\s\S+\sat\s.*\s\(\S*\):\s-ERR\s\[AUTH\]'): self.qpopper_failure, + rc('apop\[\S*:\s\S+\sat\s.*\s\(\S*\):\s-ERR\s\[IN-USE\]'): self.qpopper_failure, + rc('apop\[\S*:\s\(\S*\)\sPOP\slogin'): self.qpopper_open + } + + ## + # ProFTPD + # + proftpd_map = { + rc('proftpd\[\S*:.*USER.*Login successful'): self.proftpd_open, + rc('proftpd\[\S*:.*no such user found'): self.proftpd_failure, + rc('proftpd\[\S*:.*Login failed'): self.proftpd_failure + } + + regex_map = {} + if opts.get('enable_pam', "1") != "0": regex_map.update(pam_map) + if opts.get('enable_xinetd', "1") != "0": regex_map.update(xinetd_map) + if opts.get('enable_sshd', "1") != "0": + regex_map.update(sshd_map) + self.pam_ignore.append('sshd') + if opts.get('enable_uw_imap', "0") != "0": + regex_map.update(uw_imap_map) + self.xinetd_ignore.append('imaps') + if opts.get('enable_imp', "0") != "0": regex_map.update(imp_map) + if opts.get('enable_dovecot',"0") != "0": regex_map.update(dovecot_map) + if opts.get('enable_courier',"0") != "0": regex_map.update(courier_map) + if opts.get('enable_cyrus', "0") != "0": regex_map.update(cyrus_map) + if opts.get('enable_qpopper',"0") != "0": regex_map.update(qpopper_map) + if opts.get('enable_proftpd',"0") != "0": + regex_map.update(proftpd_map) + self.pam_ignore.append('ftp') + self.xinetd_ignore.append('ftp') + + self.safe_domains = [] + safe_domains = opts.get('safe_domains', '.*') + for domain in safe_domains.split(','): + domain = domain.strip() + if domain: + try: + domain_re = rc(domain) + self.safe_domains.append(domain_re) + except: + logger.put(0, 'Error compiling domain regex: %s' % domain) + logger.put(0, 'Check config for Logins module!') + + self.regex_map = regex_map + + self.pam_service_re = rc('(\S+)\(pam_unix\)') + self.pam_failure_re = rc('.*\slogname=(\S*).*\srhost=(\S*)') + self.pam_failure_user_re = rc('\suser=(\S*)') + self.pam_open_re = rc('.*for user (\S+) by\s(\S*)\s*\(uid=(\S+)\)') + self.pam_failure_more_re = rc('(\S+)\smore\sauthentication\sfailures') + self.pam_baduser_re = rc('\sbad\susername\s\[(.*)\]') + self.pam_chelper_re = rc('password\sfor\s\[(.*)\]') + self.pam_krb5_re = rc("^(\S+?)\[*\d*\]*:\spam_krb5\S*:\sauth.*\sfor\s`(\S+)'") + self.xinetd_start_re = rc('START:\s*(\S*)\s') + self.sshd_open_ruser_re = rc('Accepted\s(\S*)\sfor\s(\S*)\sfrom\s(\S*)\sport\s\d*\sruser\s(\S*)\s*(\S*)') + self.sshd_open_re = rc('Accepted\s(\S*)\sfor\s(\S*)\sfrom\s(\S*)\sport\s\d+\s*(\S*)') + self.sshd_fail_re = rc('Failed\s(\S*)\sfor.*\s(\S+)\sfrom\s(\S*)\sport\s\d*\s*(\S*)') + self.uw_imap_fail_re = rc('auth=(.*)\shost=.*\[(\S*)\]') + self.uw_imap_open_re = rc('user=(.*)\shost=.*\[(\S*)\]') + self.uw_imap_service_re = rc('^(\S*)\[\d*\]:') + self.dovecot_open_re = rc('Login:\s(\S+)\s\[(\S+)\]') + self.dovecot_failure_re = rc('Aborted\slogin\s\[(\S+)\]') + self.courier_open_re = rc('^(\S+?):.*\suser=(\S+),\sip=\[(\S+)\]') + self.courier_failure_re = rc('^(\S+?):.*,\sip=\[(\S+)\]') + self.imp2_open_re = rc('Login\s(\S*)\sto\s(\S*):\S*\sas\s(\S*)') + self.imp2_fail_re = rc('FAILED\s(\S*)\sto\s(\S*):\S*\sas\s(\S*)') + self.imp3_open_re = rc('success\sfor\s(\S*)\s\[(\S*)\]\sto\s\{(\S*):') + self.imp3_fail_re = rc('LOGIN\s(\S*)\sto\s(\S*):\S*\sas\s(\S*)') + self.proftpd_open_re = rc('proftpd\[\S*:.*\[(\S+)\].*USER\s(.*):\sLogin\ssuccessful') + self.proftpd_failure_re = rc('proftpd\[\S*:.*\[(\S+)\].*USER\s([^:\s]*)') + self.qpopper_open_re = rc('user "(.*)" at \(.*\)\s(\S*)') + self.qpopper_fail_re = rc(':\s(.*)\sat\s(\S*)') + self.cyrus_open_re = rc('login:.*\[(\S*)\]\s(\S*)\s') + self.cyrus_fail_re = rc('badlogin:.*\[(\S*)\]\s\S\s(\S*)\sSASL') + self.cyrus_service_re = rc('^(\S*)\[\d*\]:') + + self.sshd_methods = {'password': 'pw', + 'publickey': 'pk', + 'rhosts-rsa': 'rsa', + 'rsa': 'rsa', + 'hostbased': 'host', + 'none': 'none'} + + self.report_wrap = '%s
' + self.subreport_wrap = '

%s

\n%s\n' + + self.root_failures_title = 'ROOT FAILURES' + self.root_logins_title = 'ROOT Logins' + self.user_failures_title = 'User Failures' + self.user_logins_title = 'User Logins' + + self.untrusted_host = '%(system)s::%(rhost)s' + + self.flip = ' bgcolor="#dddddd"' + + self.line_rep = '%s%s%s\n' + + ## + # LINE MATCHING ROUTINES + # + def general_ignore(self, linemap): + restuple = (self.ignore, None, None, None) + return {restuple: 1} + + def pam_failure(self, linemap): + action = self.failure + self.logger.put(5, 'pam_failure invoked') + system, message, mult = self.get_smm(linemap) + service = self._get_pam_service(message) + mo = self.pam_failure_re.search(message) + if not mo: + self.logger.put(3, 'Odd pam failure string: %s' % message) + return None + byuser, rhost = mo.groups() + mo = self.pam_failure_user_re.search(message) + if mo: user = mo.group(1) + else: user = 'unknown' + if ((service == 'xscreensaver' and user == 'root') + or service == 'sshd' or service == 'imap'): + ## + # xscreensaver will always fail as root. + # SSHD is better handled by sshd part itself. + # Imap failures are caught by imap routines. + # Ignore these. + # + result = self.general_ignore(linemap) + return result + mo = self.pam_failure_more_re.search(message) + if mo: mult += int(mo.group(1)) + restuple = self._mk_restuple(action, system, service, user, + byuser, rhost, linemap['stamp']) + return {restuple: mult} + + def pam_open(self, linemap): + action = self.open + system, message, mult = self.get_smm(linemap) + service = self._get_pam_service(message) + if service in self.pam_ignore: + ## + # the service will do a much better job. + # + result = self.general_ignore(linemap) + return result + mo = self.pam_open_re.search(message) + if not mo: + self.logger.put(3, 'Odd pam open string: %s' % message) + return None + user, byuser, byuid = mo.groups() + if byuser == '': byuser = self.getuname(int(byuid)) + restuple = self._mk_restuple(action, system, service, user, byuser, '', linemap['stamp']) + return {restuple: mult} + + def pam_baduser(self, linemap): + action = self.failure + system, message, mult = self.get_smm(linemap) + mo = self.pam_baduser_re.search(message) + if not mo: + self.logger.put(3, 'Odd pam bad user string: %s' % message) + return None + user = mo.group(1) + service = self._get_pam_service(message) + restuple = self._mk_restuple(action, system, service, user, '', '', linemap['stamp']) + return {restuple: mult} + + def pam_chelper_failure(self, linemap): + action = self.failure + system, message, mult = self.get_smm(linemap) + mo = self.pam_chelper_re.search(message) + if not mo: + self.logger.put(3, 'Odd pam console helper string: %s' % message) + return None + user = mo.group(1) + service = self._get_pam_service(message) + restuple = self._mk_restuple(action, system, service, user, '', '', linemap['stamp']) + return {restuple: mult} + + def pam_krb5_open(self, linemap): + action = self.open + system, message, mult = self.get_smm(linemap) + mo = self.pam_krb5_re.search(message) + if not mo: + self.logger.put(3, 'Odd pam_krb5 succeeds line: %s' % message) + return None + service = mo.group(1) + user = mo.group(2) + if service == 'sshd': + ## + # sshd_open will do a much better job. + # + result = self.general_ignore(linemap) + return result + restuple = self._mk_restuple(action, system, service, user, '', '', linemap['stamp']) + return {restuple: mult} + + def pam_krb5_failure(self, linemap): + action = self.failure + system, message, mult = self.get_smm(linemap) + mo = self.pam_krb5_re.search(message) + if not mo: + self.logger.put(3, 'Odd pam_krb5 failure line: %s' % message) + return None + service = mo.group(1) + user = mo.group(2) + if ((service == 'xscreensaver' and user == 'root') + or service == 'sshd' or service == 'imap'): + ## + # xscreensaver will always fail as root. + # SSHD is better handled by sshd part itself. + # Imap failures are caught by imap routines. + # Ignore these. + # + result = self.general_ignore(linemap) + return result + restuple = self._mk_restuple(action, system, service, user, '', '', linemap['stamp']) + return {restuple: mult} + + def xinetd_start(self, linemap): + action = self.open + system, message, mult = self.get_smm(linemap) + mo = self.xinetd_start_re.search(message) + if not mo: + self.logger.put(3, 'Odd xinetd start string: %s' % message) + return None + service = mo.group(1) + if service in self.xinetd_ignore: + ## + # the service will do a much better job. + # + result = self.general_ignore(linemap) + return result + restuple = self._mk_restuple(action, system, service, '', '', '', linemap['stamp']) + return {restuple: mult} + + def sshd_open(self, linemap): + action = self.open + system, message, mult = self.get_smm(linemap) + ruser = '' + mo1 = self.sshd_open_ruser_re.search(message) + mo2 = self.sshd_open_re.search(message) + if mo1: method, user, rhost, ruser, service = mo1.groups() + elif mo2: method, user, rhost, service = mo2.groups() + else: + self.logger.put(3, 'Odd sshd open string: %s' % message) + return None + method = self.sshd_methods.get(method, '??') + rhost = self.gethost(rhost) + if not service: service = 'ssh1' + service = '%s(%s)' % (service, method) + restuple = self._mk_restuple(action, system, service, user, + ruser, rhost, linemap['stamp']) + return {restuple: mult} + + def sshd_failure(self, linemap): + action = self.failure + system, message, mult = self.get_smm(linemap) + mo = self.sshd_fail_re.search(message) + if not mo: + self.logger.put(3, 'Odd sshd FAILURE string: %s' % message) + return None + method, user, rhost, service = mo.groups() + method = self.sshd_methods.get(method, '??') + rhost = self.gethost(rhost) + if not service: service = 'ssh1' + service = '%s(%s)' % (service, method) + restuple = self._mk_restuple(action, system, service, user, '', rhost, linemap['stamp']) + return {restuple: mult} + + def uw_imap_failure(self, linemap): + action = self.failure + system, message, mult = self.get_smm(linemap) + service = self._get_uw_imap_service(message) + service = '%s(uw)' % service + mo = self.uw_imap_fail_re.search(message) + if not mo: + self.logger.put(3, 'Odd imap FAILURE string: %s' % message) + return None + user, rhost = mo.groups() + rhost = self.gethost(rhost) + restuple = self._mk_restuple(action, system, service, user, '', rhost, linemap['stamp']) + return {restuple: mult} + + def uw_imap_open(self, linemap): + action = self.open + system, message, mult = self.get_smm(linemap) + service = self._get_uw_imap_service(message) + service = '%s(uw)' % service + mo = self.uw_imap_open_re.search(message) + if not mo: + self.logger.put(3, 'Odd imap open string: %s' % message) + return None + user, rhost = mo.groups() + rhost = self.gethost(rhost) + restuple = self._mk_restuple(action, system, service, user, '', rhost, linemap['stamp']) + return {restuple: mult} + + def dovecot_open(self, linemap): + action = self.open + system, message, mult = self.get_smm(linemap) + service = 'imap(dc)' + mo = self.dovecot_open_re.search(message) + if not mo: + self.logger.put(3, 'Odd dovecot OPEN string: %s' % message) + return None + user, rhost = mo.groups() + rhost = self.gethost(rhost) + restuple = self._mk_restuple(action, system, service, user, '', rhost, linemap['stamp']) + return {restuple: mult} + + def dovecot_failure(self, linemap): + action = self.failure + system, message, mult = self.get_smm(linemap) + service = 'imap(dc)' + mo = self.dovecot_failure_re.search(message) + if not mo: + self.logger.put(3, 'Odd dovecot FAILURE string: %s' % message) + return None + rhost = mo.group(1) + rhost = self.gethost(rhost) + user = 'unknown' + restuple = self._mk_restuple(action, system, service, user, '', rhost, linemap['stamp']) + return {restuple: mult} + + def courier_open(self, linemap): + action = self.open + system, message, mult = self.get_smm(linemap) + mo = self.courier_open_re.search(message) + if not mo: + self.logger.put(3, 'Odd courier OPEN string: %s' % message) + return None + service, user, rhost = mo.groups() + service = '%s(cr)' % service + rhost = self.gethost(rhost) + restuple = self._mk_restuple(action, system, service, user, '', rhost, linemap['stamp']) + return {restuple: mult} + + def courier_failure(self, linemap): + action = self.failure + system, message, mult = self.get_smm(linemap) + mo = self.courier_failure_re.search(message) + if not mo: + self.logger.put(3, 'Odd courier FAILURE string: %s' % message) + return None + service, rhost = mo.groups() + service = '%s(cr)' % service + rhost = self.gethost(rhost) + user = 'unknown' + restuple = self._mk_restuple(action, system, service, user, '', rhost, linemap['stamp']) + return {restuple: mult} + + def proftpd_open(self, linemap): + action = self.open + system, message, mult = self.get_smm(linemap) + mo = self.proftpd_open_re.search(message) + if not mo: + self.logger.put(3, 'Odd ProFTPD OPEN string: %s' % message) + return None + service = 'ftp(pro)' + rhost, user = mo.groups() + rhost = self.gethost(rhost) + restuple = self._mk_restuple(action, system, service, user, '', rhost, linemap['stamp']) + return {restuple: mult} + + def proftpd_failure(self, linemap): + action = self.failure + system, message, mult = self.get_smm(linemap) + mo = self.proftpd_failure_re.search(message) + if not mo: + self.logger.put(3, 'Odd ProFTPD FAILURE string: %s' % message) + return None + service = 'ftp(pro)' + rhost, user = mo.groups() + rhost = self.gethost(rhost) + restuple = self._mk_restuple(action, system, service, user, '', rhost, linemap['stamp']) + return {restuple: mult} + + def imp2_failure(self, linemap): + action = self.failure + system, message, mult = self.get_smm(linemap) + mo = self.imp2_fail_re.search(message) + if not mo: + self.logger.put(3, 'Odd IMP failure string: %s' % message) + return None + rhost, system, user = mo.groups() + rhost = self.gethost(rhost) + service = 'IMP2' + restuple = self._mk_restuple(action, system, service, user, '', rhost, linemap['stamp']) + return {restuple: mult} + + def imp2_open(self, linemap): + action = self.open + system, message, mult = self.get_smm(linemap) + mo = self.imp2_open_re.search(message) + if not mo: + self.logger.put(3, 'Odd IMP open string: %s' % message) + return None + rhost, system, user = mo.groups() + rhost = self.gethost(rhost) + service = 'IMP2' + restuple = self._mk_restuple(action, system, service, user, '', rhost, linemap['stamp']) + return {restuple: mult} + + def imp3_failure(self, linemap): + action = self.failure + system, message, mult = self.get_smm(linemap) + mo = self.imp3_fail_re.search(message) + if not mo: + self.logger.put(3, 'Odd IMP failure string: %s' % message) + return None + rhost, system, user = mo.groups() + rhost = self.gethost(rhost) + service = 'IMP3' + restuple = self._mk_restuple(action, system, service, user, '', rhost, linemap['stamp']) + return {restuple: mult} + + def imp3_open(self, linemap): + action = self.open + system, message, mult = self.get_smm(linemap) + mo = self.imp3_open_re.search(message) + if not mo: + self.logger.put(3, 'Odd IMP open string: %s' % message) + return None + user, rhost, system = mo.groups() + rhost = self.gethost(rhost) + service = 'IMP3' + restuple = self._mk_restuple(action, system, service, user, '', rhost, linemap['stamp']) + return {restuple: mult} + + def cyrus_failure(self,linemap): + action = self.failure + system, message, mult = self.get_smm(linemap) + service = self._get_cyrus_service(message) + mo = self.cyrus_fail_re.search(message) + if not mo: + self.logger.put(3, 'Odd cyrus FAILURE string: %s' % message) + return None + rhost, user = mo.groups() + rhost = self.gethost(rhost) + restuple = self._mk_restuple(action, system, service, user, '', rhost, linemap['stamp']) + return {restuple: mult} + + def cyrus_open(self,linemap): + action = self.open + system, message, mult = self.get_smm(linemap) + service = self._get_cyrus_service(message) + mo = self.cyrus_open_re.search(message) + if not mo: + self.logger.put(3, 'Odd cyrus open string: %s' % message) + return None + rhost, user = mo.groups() + rhost = self.gethost(rhost) + restuple = self._mk_restuple(action, system, service, user, '', rhost, linemap['stamp']) + return {restuple: mult} + + def qpopper_failure(self, linemap): + action = self.failure + system, message, mult = self.get_smm(linemap) + mo = self.qpopper_fail_re.search(message) + if not mo: + self.logger.put(3, 'Odd qpopper FAILURE string: %s' % message) + return None + user, rhost = mo.groups() + rhost = self.gethost(rhost) + service = 'qpopper' + restuple = self._mk_restuple(action, system, service, user, '', rhost, linemap['stamp']) + return {restuple: mult} + + def qpopper_open(self, linemap): + action = self.open + system, message, mult = self.get_smm(linemap) + mo = self.qpopper_open_re.search(message) + if not mo: + self.logger.put(3, 'Odd qpopper open string: %s' % message) + return None + user, rhost = mo.groups() + rhost = self.gethost(rhost) + service = 'qpopper' + restuple = self._mk_restuple(action, system, service, user, '', rhost, linemap['stamp']) + return {restuple: mult} + ## + # HELPER METHODS + # + def _mk_restuple(self, action, system, service, user, byuser, rhost, stamp): + if user == '': user = 'unknown' + if user == 'root' or user == 'ROOT': + action += 10 + remote = self._mk_userat(byuser, rhost) + restuple = (action, system, service, remote, stamp) + else: + if rhost: + match = 0 + for domain_re in self.safe_domains: + if domain_re.search(rhost): + match = 1 + break + if not match: + tmp = {'system': system, 'rhost': rhost} + system = self.untrusted_host % tmp + restuple = (action, user, service, system, stamp) + return restuple + + def _mk_dots(self, str, lim): + if len(str) > lim: + start = -(lim-2) + str = '..' + str[start:] + return str + + def _get_pam_service(self, str): + service = 'unknown' + mo = self.pam_service_re.search(str) + if mo: service = mo.group(1) + return service + + def _get_uw_imap_service(self, str): + service = 'unknown' + mo = self.uw_imap_service_re.search(str) + if mo: service = mo.group(1) + return service + + def _mk_userat(self, user, host): + if user and host: userat = '%s@%s' % (user, host) + elif user: userat = user + elif host: userat = '@%s' % host + else: userat = 'unknown' + return userat + + def _get_cyrus_service(self, str): + service = 'unknown' + mo = self.cyrus_service_re.search(str) + if mo: service = mo.group(1) + return service + + + + def _check_for_login(self, username, service, hostname, tid): + # check if we have a login which matches in the db, + + if not os.path.exists(self.logins_db): + return False + + p = (username, service, hostname, self.last_entry) + q = "select * from logins where username=? and service=? and host=? and pkey <= ?" + if not self.db_cx: + self._db_cx() + + cur = self.db_cx.cursor() + ob = executeSQL(cur, q, p) + for i in ob: + # if we get any matches if they match within the fuzzed time then + # don't show it + if abs(tid - i[7]) <= self.time_fuzz*60: + return True + return False + + def _add_login(self, username, action, hostname, timestamp, service, u_from=None): + if not self.db_cx: + self._db_cx() + + cur = self.db_cx.cursor() + t_st = time.localtime(int(timestamp)) + time_in_day = int(t_st[3]*60) + int(t_st[4]) + q = "insert into logins values (NULL, ?, ?, ?, ?, ?, ?, ?)" + p = (action, username, hostname, u_from, service, timestamp, time_in_day) + cur.execute(q, p) + + + def _db_cx(self): + if not os.path.exists(self.logins_db): + self.db_cx = self._setup_logins_db() + else: + self.db_cx = sqlite.Connection(self.logins_db) + + q = "select max(pkey) from logins" + last_e = executeSQL(self.db_cx.cursor(), q) + val = last_e.fetchone()[0] + if not val: + self.last_entry = 0 + else: + self.last_entry = val + + def _setup_logins_db(self): + schema = [ + """PRAGMA synchronous="OFF";""", + """CREATE TABLE logins ( pkey INTEGER PRIMARY KEY, action INTEGER, + username TEXT, host TEXT, u_from TEXT, service TEXT, + stamp INTEGER, time_in_day INTEGER);""", + ] + + cx = sqlite.Connection(self.logins_db) + cursor = cx.cursor() + for cmd in schema: + executeSQL(cursor, cmd) + + return cx + + ## + # FINALIZE!! + # + def finalize(self, rs): + logger = self.logger + ## + # Prepare report + # + report = '' + rep = {} + + # FIXME + # go through each item in the rs + # feed them into the db + # pull back from the db all the info you need for the report + # simplifies a lot of this code + + # chuck it all into the db + for (rt,count) in rs.items(): + if rt[0] in (self.root_failure, self.root_open): + (action, host, service, remote, stamp) = rt + user = 'root' + elif rt[0] in (self.open, self.failure): + (action, user, service, host, stamp) = rt + remote = 'NULL' + else: + continue + if user in self.ignore_users: + continue + for num in range(0, count): + self._add_login(user, action, host, stamp, service, remote) + self.db_cx.commit() + + #return "lalallala" + + for action in [self.root_failure, self.root_open, + self.failure, self.open]: + rep[action] = '' + per_user = {} + flipper = '' + q = """select distinct username, service, host from logins where action = ? and pkey > ?""" + p = (action, self.last_entry) + act_tuple = [(i[0],i[1], i[2]) for i in executeSQL(self.db_cx.cursor(), q, p)] + + for entry in act_tuple: + username = entry[0] + if username not in per_user: + per_user[username] = {} + service = entry[1] + if service not in per_user[username]: + per_user[username][service] = [] + hn = entry[2] + q = """select time_in_day from logins where username = ? and host = ? and service = ? and action = ? and pkey > ?""" + p = (username, hn, service, action, self.last_entry) + + this_logins_times = [row[0] for row in executeSQL(self.db_cx.cursor(), q, p)] + count = 0 + for t in this_logins_times: + if not self._check_for_login(username, service, hn, t): + # DEBUG print 'new login %s %s %s %s' % (username, service, hn, t) + count += 1 + + if count: + per_user[username][service].append('%s(%d)' % (hn, count)) + + blank = 0 + for username in sorted(per_user): + if flipper: flipper = '' + else: flipper = self.flip + for (svc,reps) in per_user[username].items(): + if blank: key = ' ' + else: blank = 1 + if reps: + rep[action] += self.line_rep % (flipper, username, + svc, ', '.join(reps)) + + if rep[self.root_failure]: + report += self.subreport_wrap % (self.root_failures_title, + rep[self.root_failure]) + if rep[self.root_open]: + report += self.subreport_wrap % (self.root_logins_title, + rep[self.root_open]) + if rep[self.failure]: + report += self.subreport_wrap % (self.user_failures_title, + rep[self.failure]) + if rep[self.open]: + report += self.subreport_wrap % (self.user_logins_title, + rep[self.open]) + + report = self.report_wrap % report + + if self.oldest_to_keep: + q = """delete from logins where stamp < ?""" + p = (self.oldest_to_keep,) + executeSQL(self.db_cx.cursor(), q, p) + self.db_cx.commit() + + return report + +if __name__ == '__main__': + from epylog.helpers import ModuleTest + ModuleTest(logins_mod, sys.argv) + diff --git a/roles/epylog/files/modules/rsyncd.conf b/roles/epylog/files/modules/rsyncd.conf new file mode 100644 index 0000000000..1f1bcd6dac --- /dev/null +++ b/roles/epylog/files/modules/rsyncd.conf @@ -0,0 +1,14 @@ +[module] +desc = Rsyncd +exec = /usr/share/epylog/modules/rsyncd_mod.py +files = /var/log/messages[.#] +enabled = no +internal = yes +outhtml = yes +priority = 7 + +[conf] +## +# Report this many "top ranking hosts" +# +report_top = 10 diff --git a/roles/epylog/files/modules/rsyncd_mod.py b/roles/epylog/files/modules/rsyncd_mod.py new file mode 100644 index 0000000000..5ec899c769 --- /dev/null +++ b/roles/epylog/files/modules/rsyncd_mod.py @@ -0,0 +1,219 @@ +#!/usr/bin/python -tt +""" +Rsyncd log parsing module for Epylog +""" + +## +# Copyright (C) 2003 by Duke University +# Written by Seth Vidal +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. +# + + +import sys +import re + +## +# This is for testing purposes, so you can invoke this from the +# modules directory. See also the testing notes at the end of the +# file. +# +sys.path.insert(0, '../py/') +from epylog import Result, InternalModule + +class rsyncd_mod(InternalModule): + ## + # opts: is a map with extra options set in + # [conf] section of the module config, or on the + # command line using -o flag to the module. + # logger: A logging object. API: + # logger.put(loglvl, 'Message') + # Only critical stuff needs to go onto lvl 0. + # Common output goes to lvl 1. + # Others are debug levels. + # + def __init__(self, opts, logger): + ## + # Do a "super-init" so the class we are subclassing gets + # instantiated. + # + InternalModule.__init__(self) + self.logger = logger + ## + # Convenience + # + rc = re.compile + + self.regex_map = { + rc('rsyncd\[\d+\]: rsync on'): self.rsync_hosts, + rc('rsyncd\[\d+\]: (?:sent|wrote)\s\S*\sbytes'): self.rsync_results + } + self.topcount = int(opts.get('report_top', 5)) #get report_top, default to 5 if not set + ig_s = opts.get('ignore_hosts', '') + ig_s.replace(',',' ') + self.ignore_hosts = ig_s.split(' ') + # dict to store all of our data + self.rsync_pid_bytes = {} + self.rsync_pid_host = {} + self.rsync_host_loc = rc('rsyncd\[(\d+)\]: rsync\son\s(\S*)\sfrom\s.*\((\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\)') + self.rsync_bytes = rc('rsyncd\[(\d+)\]: (?:sent|wrote)\s(\d+) bytes (?:read|received)\s(\d+) bytes total size (\d+)') + + def rsync_hosts(self, linemap): + (sys, msg, multi) = self.get_smm(linemap) + pid, loc, ip = self.rsync_host_loc.search(msg).groups() + host = self.gethost(ip) + if host not in self.ignore_hosts: + self.rsync_pid_host[pid] = (host, loc) + return {(loc, host): 1} + + def rsync_results(self, linemap): + (sys, msg, multi) = self.get_smm(linemap) + pid, wbytes, rbytes, tbytes = self.rsync_bytes.search(msg).groups() + self.rsync_pid_bytes[pid] = (wbytes, rbytes, tbytes) + return {(pid, wbytes): 1} + + def _uniq(self, s): + """Return a list of the elements in s, but without duplicates. + + For example, unique([1,2,3,1,2,3]) is some permutation of [1,2,3], + unique("abcabc") some permutation of ["a", "b", "c"], and + unique(([1, 2], [2, 3], [1, 2])) some permutation of + [[2, 3], [1, 2]]. + + For best speed, all sequence elements should be hashable. Then + unique() will usually work in linear time. + + If not possible, the sequence elements should enjoy a total + ordering, and if list(s).sort() doesn't raise TypeError it's + assumed that they do enjoy a total ordering. Then unique() will + usually work in O(N*log2(N)) time. + + If that's not possible either, the sequence elements must support + equality-testing. Then unique() will usually work in quadratic + time. + """ + + n = len(s) + if n == 0: + return [] + + # Try using a dict first, as that's the fastest and will usually + # work. If it doesn't work, it will usually fail quickly, so it + # usually doesn't cost much to *try* it. It requires that all the + # sequence elements be hashable, and support equality comparison. + u = {} + try: + for x in s: + u[x] = 1 + except TypeError: + del u # move on to the next method + else: + return u.keys() + + # We can't hash all the elements. Second fastest is to sort, + # which brings the equal elements together; then duplicates are + # easy to weed out in a single pass. + # NOTE: Python's list.sort() was designed to be efficient in the + # presence of many duplicate elements. This isn't true of all + # sort functions in all languages or libraries, so this approach + # is more effective in Python than it may be elsewhere. + try: + t = list(s) + t.sort() + except TypeError: + del t # move on to the next method + else: + assert n > 0 + last = t[0] + lasti = i = 1 + while i < n: + if t[i] != last: + t[lasti] = last = t[i] + lasti += 1 + i += 1 + return t[:lasti] + + # Brute force is all that's left. + u = [] + for x in s: + if x not in u: + u.append(x) + return u + + def _sortByVal(self, dict, reverse=0): + if type(dict) is not type({}): return [] + keys = dict.keys() + s = map(lambda k: (dict[k], k), keys) + s.sort() + if reverse: s.reverse() + return s + + def finalize(self, resultset): + ## + # A resultset is a dictionary of all values returned by your + # handler functions -- except they are unique and show how many + # times each tuple occurs. + # See epylog.Result for some convenience methods to use when + # processing and analyzing the results. + # + + hostloc = {} # key = host, val = [loc, loc, loc] + hosttotal = {} # key = host val = totalwbytes + + foo = "\n\t\n" + + for pid in self.rsync_pid_host.keys(): + (host, loc) = self.rsync_pid_host[pid] + if self.rsync_pid_bytes.has_key(pid): + if not hostloc.has_key(host): + hostloc[host] = [] + if not hosttotal.has_key(host): + hosttotal[host] = 0L + hostloc[host].append(loc) + bytes = long(self.rsync_pid_bytes[pid][0]) + hosttotal[host] += bytes + + for host in hostloc.keys(): + hostloc[host] = self._uniq(hostloc[host]) + + hosts = self._sortByVal(hosttotal, 1) + count = 0L + for (tot,host) in hosts[:self.topcount]: + if count % 2: + bgcolor = "#dddddd" + else: + bgcolor = "#ffffff" + count+=1 + line = '\t\t\n' % (bgcolor, host) + line = line + '\t\t\n' + size, marker = self.mk_size_unit(hosttotal[host]) + line = line + '\t\t\n' % (bgcolor, size, marker) + line = line + '\t\n' + foo = foo + line + foo = foo + '
%s\n' % bgcolor + for loc in hostloc[host]: + line = line + '\t\t\t%s
\n' % loc + line = line + '\t\t
%s%s
\n' + return foo + +## +# This is useful when testing your module out. +# Invoke without command-line parameters to learn about the proper +# invocation. +# +if __name__ == '__main__': + from epylog.helpers import ModuleTest + ModuleTest(rsyncd_mod, sys.argv) diff --git a/roles/epylog/files/modules/selinux.conf b/roles/epylog/files/modules/selinux.conf new file mode 100644 index 0000000000..49a41c112b --- /dev/null +++ b/roles/epylog/files/modules/selinux.conf @@ -0,0 +1,11 @@ +[module] +desc = SELinux Report +exec = /usr/share/epylog/modules/selinux_mod.py +files = /var/log/messages[.#] +enabled = yes +internal = yes +outhtml = yes +priority = 5 + +[conf] +enable_selinux = 1 diff --git a/roles/epylog/files/modules/selinux_mod.py b/roles/epylog/files/modules/selinux_mod.py new file mode 100644 index 0000000000..0e40b2033c --- /dev/null +++ b/roles/epylog/files/modules/selinux_mod.py @@ -0,0 +1,116 @@ +#!/usr/bin/python -tt +""" +Reports on selinux messages + +Jeremy Kindy (kindyjd at wfu.edu), Wake Forest University +""" + +import sys +import re + +## +# This is for testing purposes, so you can invoke this from the +# modules directory. See also the testing notes at the end of the +# file. +# +sys.path.insert(0, '../py/') +from epylog import Result, InternalModule + +class selinux_mod(InternalModule): + def __init__(self, opts, logger): + InternalModule.__init__(self) + self.logger = logger + self.logger.put(3, 'initializing selinux') + rc = re.compile + + self.ignore = 0 + self.preventing = 1 + + selinux_map = { + rc('.*setroubleshoot\: SELinux is preventing'): self.selinux + } + + do_selinux = int(opts.get('enable_selinux', '1')) + + self.regex_map = {} + if do_selinux: self.regex_map.update(selinux_map) + + self.selinux_message_re = rc('setroubleshoot: (.*). For complete SELinux') + + self.selinux_title = 'SELinux Report' + self.selinux_preventing_title = 'SELinux Prevention Report' + + self.report_wrap = '%s
' + self.subreport_wrap = '

%s

\n%s' + + self.line_rep = '%s%s\n' + + self.flip = ' bgcolor="#dddddd"' + + + ## + # Line-matching routines + # + def selinux(self, linemap): + action = self.preventing + self.logger.put(3, 'selinux invoked') + sys, msg, mult = self.get_smm(linemap) + + self.logger.put(3, 'test selinux %d' % mult) + message = self._get_selinux_message(msg) + self.logger.put(3, 'selinux message: %s' % message) + + restuple = self._mk_restuple(sys, action, message) + self.logger.put(3, 'selinux finished') + return {restuple: mult} + + + ## + # Helpers + # + def _mk_restuple(self, sys, action, message): + return (action, message, sys) + + def _get_selinux_message(self, str): + message = 'unknown' + mo = self.selinux_message_re.search(str) + if mo: message = mo.group(1) + return message + + + #### + # Finalize the report + def finalize(self, rs): + logger = self.logger + ## + # Prepare report + # + report = '' + rep = {} + + # (action, message) + for action in [self.preventing]: + rep[action] = '' + flipper = '' + for message in rs.get_distinct((action,)): + if flipper: flipper = '' + else: flipper = self.flip + service_rep = [] + + for system in rs.get_distinct((action, message,)): + service_rep.append(system) + + system_list = ', '.join(service_rep) + rep[action] += self.line_rep % (flipper, message, system_list) + + if rep[self.preventing]: + report += self.subreport_wrap % (self.selinux_preventing_title, rep[self.preventing]) + logger.put(3, 'selinux report: self.preventing added') + + report = self.report_wrap % report + return report + + +if __name__ == '__main__': + from epylog.helpers import ModuleTest + ModuleTest(selinux_mod, sys.argv) diff --git a/roles/epylog/files/modules/sudo.conf b/roles/epylog/files/modules/sudo.conf new file mode 100644 index 0000000000..843f4c2a81 --- /dev/null +++ b/roles/epylog/files/modules/sudo.conf @@ -0,0 +1,11 @@ +[module] +desc = Sudo Report +exec = /usr/share/epylog/modules/sudo_mod.py +files = /var/log/secure[.#] +enabled = yes +internal = yes +outhtml = yes +priority = 5 + +[conf] +enable_sudo = 1 diff --git a/roles/epylog/files/modules/sudo_mod.py b/roles/epylog/files/modules/sudo_mod.py new file mode 100644 index 0000000000..d411b9fd35 --- /dev/null +++ b/roles/epylog/files/modules/sudo_mod.py @@ -0,0 +1,191 @@ +#!/usr/bin/python -tt +""" +Reports on sudo usage by users. + +Jeremy Kindy (kindyjd at wfu.edu), Wake Forest University +""" + +import sys +import re + +## +# This is for testing purposes, so you can invoke this from the +# modules directory. See also the testing notes at the end of the +# file. +# +sys.path.insert(0, '../py/') +from epylog import Result, InternalModule + +class sudo_mod(InternalModule): + def __init__(self, opts, logger): + InternalModule.__init__(self) + self.logger = logger + self.logger.put(2, 'initializing sudo') + rc = re.compile + + self.ignore = 0 + self.open = 1 + self.not_allowed = 2 + + sudo_map = { + rc('.*sudo\:\s+\S+\s\:\sTTY'): self.sudo, + rc('.*sudo:'): self.sudo_na + } + + do_sudo = int(opts.get('enable_sudo', '1')) + + self.regex_map = {} + if do_sudo: self.regex_map.update(sudo_map) + + self.sudo_user_name_re = rc('sudo:\s*(\S*)') + self.sudo_as_user_re = rc('.*USER=(\S*)\s\;\sCOMMAND') + self.sudo_command_name_re = rc('.*COMMAND=(.*)') + self.sudo_error_message_re = rc('sudo:\s*\S*\s+:\s+(.*)\s+;\s+TTY') + + + self.sudo_title = 'User Sudo Report' + self.sudo_open_title = 'User Sudo Report' + self.sudo_not_allowed_title = 'Disallowed Sudo Commands' + + self.report_wrap = '%s
' + self.subreport_wrap = '

%s

\n%s' + self.subreport_na_wrap = '

%s

\n%s' + + self.line_rep = '%s%s%s%s\n' + self.line_rep_na = '%s%s%s%s%s\n' + + self.flip = ' bgcolor="#dddddd"' + + + ## + # Line-matching routines + # + def sudo(self, linemap): + action = self.open + self.logger.put(2, 'sudo invoked') + sys, msg, mult = self.get_smm(linemap) + + self.logger.put(3, 'test sudo %d' % mult) + user = self._get_sudo_user(msg) + self.logger.put(3, 'sudo user: %s' % user) + asuser = self._get_sudo_as_user(msg) + self.logger.put(3, 'sudo asuser: %s' % asuser) + command_name = self._get_sudo_command_name(msg) + self.logger.put(3, 'sudo command: %s' % command_name) + + restuple = self._mk_restuple(sys, action, user, asuser, command_name, None) + self.logger.put(2, 'sudo finished') + return {restuple: mult} + + def sudo_na(self, linemap): + action = self.not_allowed + self.logger.put(2, 'sudo_na invoked') + sys, msg, mult = self.get_smm(linemap) + + self.logger.put(3, 'test sudo %d' % mult) + user = self._get_sudo_user(msg) + self.logger.put(3, 'sudo user: %s' % user) + asuser = self._get_sudo_as_user(msg) + self.logger.put(3, 'sudo asuser: %s' % asuser) + command_name = self._get_sudo_command_name(msg) + self.logger.put(3, 'sudo command: %s' % command_name) + error_message = self._get_sudo_error_message(msg) + self.logger.put(3, 'sudo error_message: %s' % error_message) + + restuple = self._mk_restuple(sys, action, user, asuser, command_name, error_message) + self.logger.put(2, 'sudo finished') + return {restuple: mult} + + def sudo_ignore(self, linemap): + restuple = self._mk_restuple(None, self.ignore, None, None, None, None) + return {restuple: 1} + + ## + # Helpers + # + def _mk_restuple(self, sys, action, user=None, asuser=None, command_name=None, error_message=None): + return (action, user, command_name, asuser, error_message, sys) + #return (sys, action, user, asuser, command_name) + + def _get_sudo_user(self, str): + user = 'unknown' + mo = self.sudo_user_name_re.search(str) + if mo: user = mo.group(1) + return user + + def _get_sudo_as_user(self, str): + asuser = 'unknown' + mo = self.sudo_as_user_re.search(str) + if mo: asuser = mo.group(1) + return asuser + + def _get_sudo_error_message(self, str): + pass_attempts = 0 + mo = self.sudo_error_message_re.search(str) + if mo: pass_attempts = mo.group(1) + return pass_attempts + + def _get_sudo_command_name(self, str): + command_name = 'unknown' + mo = self.sudo_command_name_re.search(str) + if mo: command_name = mo.group(1) + return command_name + + + #### + # Finalize the report + def finalize(self, rs): + logger = self.logger + ## + # Prepare report + # + report = '' + rep = {} + + # (action, user, command_name, system, error_message) + for action in [self.open, self.not_allowed]: + rep[action] = '' + flipper = '' + for user in rs.get_distinct((action,)): + #logger.put(2, 'sudo user: %s' % user) + if flipper: flipper = '' + else: flipper = self.flip + service_rep = [] + blank = 0 + for command_name in rs.get_distinct((action, user)): + for asuser in rs.get_distinct((action, user, command_name)): + for error_message in rs.get_distinct((action, user, command_name, asuser)): + mymap = rs.get_submap((action, user, command_name, asuser, error_message)) + #logger.put(2, 'sudo command_name: %s' % command_name) + key2s = [] + for key2 in mymap.keys(): + hostname = key2[0] + key2s.append('%s(%d)' % (hostname, mymap[key2])) + hostnames = ', '.join(key2s) + #logger.put(2, 'sudo hostnames: %s' % hostnames) + service_rep.append([command_name, hostnames, asuser, error_message]) + for svcrep in service_rep: + #logger.put(2, 'sudo svcrep: %s' % svcrep) + if blank: user = ' ' + else: blank = 1 + if (action == self.open): + rep[action] += self.line_rep % (flipper, user, svcrep[0], svcrep[1], svcrep[2]) + else: + rep[action] += self.line_rep_na % (flipper, user, svcrep[0], svcrep[3], svcrep[1], svcrep[2]) + + + if rep[self.open]: + report += self.subreport_wrap % (self.sudo_open_title, rep[self.open]) + logger.put(2, 'sudo report: self.open added') + + if rep[self.not_allowed]: + report += self.subreport_na_wrap % (self.sudo_not_allowed_title, rep[self.not_allowed]) + logger.put(2, 'sudo report: self.not_allowed added') + + report = self.report_wrap % report + return report + + +if __name__ == '__main__': + from epylog.helpers import ModuleTest + ModuleTest(sudo_mod, sys.argv) diff --git a/roles/epylog/tasks/main.yml b/roles/epylog/tasks/main.yml new file mode 100644 index 0000000000..8060540ac3 --- /dev/null +++ b/roles/epylog/tasks/main.yml @@ -0,0 +1,48 @@ +--- +- name: install epylog package + yum: state=installed name=epylog + tags: + - packages + - epylog + +- name: create directories needed for epylog + file: state=directory owner=root mode=755 + with_items: + - /var/lib/epylog/merged + - /srv/web/epylog + - /srv/web/epylog/merged + +- name: setup extra epylog modules + copy: src={{ item }} dest=/usr/share/epylog/modules/{{ item }} + with_items: + - modules/selinux_mod.py + - modules/rsyncd_mod.py + - modules/sudo_mod.py + - modules/common_unparsed_mod.py + - modules/logins_mod.py + - modules/kojiload_mod.py + +- name: epylog cron + file: src=epylog-default.cron dest=/etc/cron.d/epylog.cron + tags: + - config + - cron + +- name: copy in all the epylog merged files + copy: src=merged dest=/etc/epylog/merged + tags: + - config + +- name: epylog merged cron + copy: src=epylog-merged.cron dest=/etc/cron.d/epylog-merged.cron + tags: + - config + - cron + +- name: epylog httpd config + copy: src=epylog-web.conf dest=/etc/httpd/conf.d/epylog-web.conf + notify: + - restart httpd + tags: + - config + - apache