root / plugins / security / forefront_ @ 2c912170
Historique | Voir | Annoter | Télécharger (11,6 ko)
| 1 | b25acbbd | Rune Nordb?e Skillingstad | #!/usr/bin/perl |
|---|---|---|---|
| 2 | # |
||
| 3 | # Plugin to monitor Forefront Client Security status in MOM database |
||
| 4 | # |
||
| 5 | 3bc93969 | Lars Kruse | # Copyright (c) 2008 Rune Nordbøe Skillingstad - <rune.skillingstad@ntnu.no> |
| 6 | 17f78427 | Lars Kruse | # |
| 7 | b25acbbd | Rune Nordb?e Skillingstad | # This program is free software; you can redistribute it and/or modify |
| 8 | # it under the terms of the GNU General Public License as published by |
||
| 9 | # the Free Software Foundation; version 2 dated June, 1991. |
||
| 10 | # |
||
| 11 | # This program is distributed in the hope that it will be useful, but |
||
| 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of |
||
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
| 14 | # General Public License for more details. |
||
| 15 | # |
||
| 16 | # You should have received a copy of the GNU General Public License |
||
| 17 | # along with this program; if not, write to the Free Software |
||
| 18 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
||
| 19 | # USA. |
||
| 20 | # |
||
| 21 | 17f78427 | Lars Kruse | # Parameters: |
| 22 | b25acbbd | Rune Nordb?e Skillingstad | # |
| 23 | # config |
||
| 24 | # autoconf |
||
| 25 | # suggest |
||
| 26 | # |
||
| 27 | # Config variables |
||
| 28 | 17f78427 | Lars Kruse | # |
| 29 | b25acbbd | Rune Nordb?e Skillingstad | # dsn - If DSN name differs from hostname |
| 30 | 8589c6df | klemens | # dbuser - Valid MS SQL user (Windows authentication is possible using "DOMAIN\user") |
| 31 | 17f78427 | Lars Kruse | # dbpass - Password |
| 32 | b25acbbd | Rune Nordb?e Skillingstad | # |
| 33 | # Install guide: |
||
| 34 | # This plugin relies on correct configured ODBC for the MOM database |
||
| 35 | 2c912170 | Lars Kruse | # Prerequisites: |
| 36 | b25acbbd | Rune Nordb?e Skillingstad | # * Install and configure FreeTDS and DBD::Sybase (packages tdsodbc and libdbd-sybase-perl on Ubuntu) |
| 37 | fba800ae | Veres Lajos | # - DBD::Sybase is preferred over ODBC because of strange TEXT field handling in DBD::ODBC |
| 38 | b25acbbd | Rune Nordb?e Skillingstad | # |
| 39 | 17f78427 | Lars Kruse | # Example |
| 40 | b25acbbd | Rune Nordb?e Skillingstad | # /etc/freetds/freetds.conf: |
| 41 | # [MyHost] |
||
| 42 | # host = MyHost.domain.tld |
||
| 43 | # port = 1433 |
||
| 44 | # tds version = 7.0 |
||
| 45 | 17f78427 | Lars Kruse | # |
| 46 | b25acbbd | Rune Nordb?e Skillingstad | # Copy this script to /usr/share/munin/plugins and run "munin-node-configure --shell" |
| 47 | # If freetds.conf has one or more lines containing "host = <server>", the output will be something like this: |
||
| 48 | # ln -s /usr/share/munin/plugins/forefront_ /etc/munin/plugins/forefront_MyHost.Domain.tld_computers |
||
| 49 | # ln -s /usr/share/munin/plugins/forefront_ /etc/munin/plugins/forefront_MyHost.domain.tld_deployments |
||
| 50 | # ln -s /usr/share/munin/plugins/forefront_ /etc/munin/plugins/forefront_MyHost.domain.tld_status |
||
| 51 | # |
||
| 52 | 17f78427 | Lars Kruse | # To manually add, symlink forefront_ to forefront_MyHost.domain.tld_computers, |
| 53 | # forefront_MyHost.domain.tld_deployments and forefront_MyHost.domain.tld_status |
||
| 54 | b25acbbd | Rune Nordb?e Skillingstad | # |
| 55 | # Add your DSN and user/password to /etc/munin/plugin-conf.d/munin-node: |
||
| 56 | # [forefront_MyHost.domain.tld_*] |
||
| 57 | # env.dsn MyHost |
||
| 58 | # env.dbuser <user> |
||
| 59 | # env.dbpass <password> |
||
| 60 | 17f78427 | Lars Kruse | # |
| 61 | b25acbbd | Rune Nordb?e Skillingstad | # On your munin server, add this to /etc/munin/munin.conf |
| 62 | # |
||
| 63 | # [MyHost.domain.tld] |
||
| 64 | # address <ip address to node running this plugin> |
||
| 65 | # use_node_name no |
||
| 66 | # |
||
| 67 | # Magic markers (optional - used by munin-config and some installation |
||
| 68 | # scripts): |
||
| 69 | # |
||
| 70 | #%# family=auto |
||
| 71 | #%# capabilities=autoconf suggest |
||
| 72 | |||
| 73 | use strict; |
||
| 74 | |||
| 75 | my $host = undef; |
||
| 76 | my $stat = undef; |
||
| 77 | |||
| 78 | my @stats = qw(computers status deployments); |
||
| 79 | |||
| 80 | if($0 =~ /^(?:|.*\/)forefront_(.+?)_([^_]+)$/) {
|
||
| 81 | $host = $1; |
||
| 82 | $stat = $2; |
||
| 83 | $host =~ s/_/-/g; |
||
| 84 | } |
||
| 85 | my $dsn = $ENV{dsn} || $host;
|
||
| 86 | my $dbuser = $ENV{dbuser} || undef;
|
||
| 87 | my $dbpass = $ENV{dbpass} || undef;
|
||
| 88 | |||
| 89 | my $ret = undef; |
||
| 90 | if(!eval "require DBI;") {
|
||
| 91 | $ret = "DBI not found "; |
||
| 92 | } |
||
| 93 | if(!eval "require DBD::Sybase;") {
|
||
| 94 | $ret .= "DBD::Sybase not found "; |
||
| 95 | } |
||
| 96 | if(!eval "require MIME::Base64;") {
|
||
| 97 | $ret .= "MIME::Base64 not found "; |
||
| 98 | } else {
|
||
| 99 | use MIME::Base64; |
||
| 100 | } |
||
| 101 | |||
| 102 | if($ARGV[0] and $ARGV[0] eq "autoconf") {
|
||
| 103 | if($ret) {
|
||
| 104 | e4cd049b | Lars Kruse | print "no ($ret)\n"; |
| 105 | } else {
|
||
| 106 | print "yes\n"; |
||
| 107 | b25acbbd | Rune Nordb?e Skillingstad | } |
| 108 | exit 0; |
||
| 109 | } |
||
| 110 | |||
| 111 | if($ARGV[0] and $ARGV[0] eq "suggest") {
|
||
| 112 | if("/etc/odbc.ini") {
|
||
| 113 | my $dsn = undef; |
||
| 114 | my $host = undef; |
||
| 115 | open(IN, "</etc/freetds/freetds.conf") || die "Can't read FreeTDS config file"; |
||
| 116 | while(<IN>) {
|
||
| 117 | next if(/^[;#]/); |
||
| 118 | if(/host\s*=\s*([\w.-]+)/) {
|
||
| 119 | my $host = $1; |
||
| 120 | $host =~ s/-/_/g; |
||
| 121 | print $host."_".join("\n".$host."_",@stats)."\n";
|
||
| 122 | } |
||
| 123 | } |
||
| 124 | close(IN); |
||
| 125 | exit 0; |
||
| 126 | } |
||
| 127 | exit 1; |
||
| 128 | } |
||
| 129 | |||
| 130 | |||
| 131 | |||
| 132 | if(!grep(/$stat/, @stats)) {
|
||
| 133 | print STDERR "\"$stat\" is not a valid script ending\n"; |
||
| 134 | exit 1; |
||
| 135 | } |
||
| 136 | |||
| 137 | if($ARGV[0] and $ARGV[0] eq "config") {
|
||
| 138 | eval "&".$stat."_config()"; |
||
| 139 | exit 0; |
||
| 140 | } |
||
| 141 | |||
| 142 | eval "&".$stat."_fetch()"; |
||
| 143 | |||
| 144 | sub computers_config {
|
||
| 145 | print <<EOF; |
||
| 146 | host_name $host |
||
| 147 | graph_title Number of computers using Forefront |
||
| 148 | graph_args --base 1000 -l 0 -X 0 |
||
| 149 | graph_vlabel number of computers |
||
| 150 | graph_category security |
||
| 151 | graph_scale no |
||
| 152 | graph_info This graph shows the number of computers registered in MOM database for Forefront Client Security. |
||
| 153 | graph_order missing672 missing168 missing computers pending |
||
| 154 | missing672.label Not reported 28d |
||
| 155 | missing672.draw AREA |
||
| 156 | missing672.info Number of computers not reported in 28 days |
||
| 157 | missing168.label Not reported 7d |
||
| 158 | missing168.draw STACK |
||
| 159 | missing168.info Number of computers not reported in 7 days |
||
| 160 | missing.label Not reported 1d |
||
| 161 | missing.draw STACK |
||
| 162 | missing.info Number of computers not reported in 24 hours |
||
| 163 | computers.label Computers |
||
| 164 | computers.draw STACK |
||
| 165 | computers.info Number of computers registered. |
||
| 166 | pending.label Pending |
||
| 167 | pending.draw STACK |
||
| 168 | pending.info Number of computers pending approval. |
||
| 169 | totl.label Total |
||
| 170 | totl.cdef missing672,missing168,+,missing,+,computers,+,pending,+ |
||
| 171 | totl.colour 000000 |
||
| 172 | totl.info Total number of computers. |
||
| 173 | totl.draw LINE1 |
||
| 174 | EOF |
||
| 175 | } |
||
| 176 | |||
| 177 | sub status_config {
|
||
| 178 | my %alerts; |
||
| 179 | my $dbh = DBI->connect("DBI:Sybase:$dsn", $dbuser, $dbpass, { PrintError => 1, AutoCommit => 1 });
|
||
| 180 | my $sth = $dbh->prepare("SELECT Level, Name FROM AlertLevel ORDER BY Level", {odbc_exec_direct => 1});
|
||
| 181 | $sth->execute(); |
||
| 182 | while(my @row = $sth->fetchrow_array) {
|
||
| 183 | $alerts{$row[0]} = $row[1];
|
||
| 184 | } |
||
| 185 | print <<EOF; |
||
| 186 | host_name $host |
||
| 187 | graph_title Forefront client status |
||
| 188 | graph_args --base 1000 -l 0 -X 0 |
||
| 189 | graph_vlabel % |
||
| 190 | graph_category security |
||
| 191 | graph_scale no |
||
| 192 | graph_info This graph shows the Forefront client status in percentage |
||
| 193 | EOF |
||
| 194 | foreach my $level (sort(keys(%alerts))) {
|
||
| 195 | print "alert" . $level . ".label " . $alerts{$level} . "\n";
|
||
| 196 | print "alert" . $level . ".draw LINE2\n"; |
||
| 197 | print "alert" . $level . ".info Computers reporting " . $alerts{$level} . " status\n";
|
||
| 198 | } |
||
| 199 | } |
||
| 200 | |||
| 201 | sub deployments_config {
|
||
| 202 | print <<EOF; |
||
| 203 | host_name $host |
||
| 204 | graph_title Policy deployment status |
||
| 205 | graph_args --base 1000 -l 0 -X 0 |
||
| 206 | graph_vlabel number of computers |
||
| 207 | graph_category security |
||
| 208 | graph_scale no |
||
| 209 | graph_info This graph shows policy deployment status for Forefront Client Security |
||
| 210 | EOF |
||
| 211 | my %profiles = &deployments_general(); |
||
| 212 | foreach my $policy (sort(keys(%profiles))) {
|
||
| 213 | my $field = encode_base64($policy); |
||
| 214 | 17f78427 | Lars Kruse | chomp($field); |
| 215 | b25acbbd | Rune Nordb?e Skillingstad | print $field . ".label " . $profiles{$policy}{'name'} . "\n";
|
| 216 | print $field . ".draw LINE2\n"; |
||
| 217 | 2c912170 | Lars Kruse | print $field . ".info Number of computers having the " .$profiles{$policy}{'name'} . " profile.\n";
|
| 218 | b25acbbd | Rune Nordb?e Skillingstad | if($profiles{$policy}{'old'}) {
|
| 219 | print $field . "old.label " . $profiles{$policy}{'name'} . " (old)\n";
|
||
| 220 | print $field . "old.draw LINE2\n"; |
||
| 221 | 2c912170 | Lars Kruse | print $field . "old.info Number of computers having an old version of the " .$profiles{$policy}{'name'} . " profile.\n";
|
| 222 | b25acbbd | Rune Nordb?e Skillingstad | } |
| 223 | } |
||
| 224 | } |
||
| 225 | |||
| 226 | sub computers_fetch {
|
||
| 227 | my ($sec,$min,$hour,$mday,$mon,$year,$wday, |
||
| 228 | $yday,$isdst)=localtime(time-86400); |
||
| 229 | my $oneday = sprintf "%4d-%02d-%02d %02d:%02d:%02d", |
||
| 230 | $year+1900,$mon+1,$mday,$hour,$min,$sec; |
||
| 231 | ($sec,$min,$hour,$mday,$mon,$year,$wday, |
||
| 232 | $yday,$isdst)=localtime(time-604800); |
||
| 233 | my $sevendays = sprintf "%4d-%02d-%02d %02d:%02d:%02d", |
||
| 234 | $year+1900,$mon+1,$mday,$hour,$min,$sec; |
||
| 235 | ($sec,$min,$hour,$mday,$mon,$year,$wday, |
||
| 236 | $yday,$isdst)=localtime(time-2419200); |
||
| 237 | my $twentyeightdays = sprintf "%4d-%02d-%02d %02d:%02d:%02d", |
||
| 238 | $year+1900,$mon+1,$mday,$hour,$min,$sec; |
||
| 239 | |||
| 240 | my $dbh = DBI->connect("DBI:Sybase:$dsn", $dbuser, $dbpass, { PrintError => 1, AutoCommit => 1 });
|
||
| 241 | my $sth = $dbh->prepare("SELECT COUNT(*) FROM Computer WHERE PendingAction = 0 AND LastHeartbeat < '$twentyeightdays'", {odbc_exec_direct => 1});
|
||
| 242 | $sth->execute(); |
||
| 243 | my($count) = $sth->fetchrow_array; |
||
| 244 | print "missing672.value $count\n"; |
||
| 245 | my $sth = $dbh->prepare("SELECT COUNT(*) FROM Computer WHERE PendingAction = 0 AND LastHeartbeat < '$sevendays' AND LastHeartbeat >= '$twentyeightdays'", {odbc_exec_direct => 1});
|
||
| 246 | $sth->execute(); |
||
| 247 | my($count) = $sth->fetchrow_array; |
||
| 248 | print "missing168.value $count\n"; |
||
| 249 | my $sth = $dbh->prepare("SELECT COUNT(*) FROM Computer WHERE PendingAction = 0 AND LastHeartbeat < '$oneday' AND LastHeartbeat >= '$sevendays'", {odbc_exec_direct => 1});
|
||
| 250 | $sth->execute(); |
||
| 251 | my($count) = $sth->fetchrow_array; |
||
| 252 | print "missing.value $count\n"; |
||
| 253 | $sth = $dbh->prepare("SELECT COUNT(*) FROM Computer WHERE PendingAction = 0 AND LastHeartbeat >= '$oneday'", {odbc_exec_direct => 1});
|
||
| 254 | $sth->execute(); |
||
| 255 | ($count) = $sth->fetchrow_array; |
||
| 256 | print "computers.value $count\n"; |
||
| 257 | $sth = $dbh->prepare("SELECT COUNT(*) FROM Computer WHERE PendingAction <> 0", {odbc_exec_direct => 1});
|
||
| 258 | $sth->execute(); |
||
| 259 | ($count) = $sth->fetchrow_array; |
||
| 260 | print "pending.value $count\n"; |
||
| 261 | } |
||
| 262 | |||
| 263 | sub status_fetch {
|
||
| 264 | my %alerts; |
||
| 265 | my $dbh = DBI->connect("DBI:Sybase:$dsn", $dbuser, $dbpass, { PrintError => 1, AutoCommit => 1 });
|
||
| 266 | my $sth = $dbh->prepare("SELECT Level FROM AlertLevel ORDER BY Level", {odbc_exec_direct => 1});
|
||
| 267 | $sth->execute(); |
||
| 268 | while(my @row = $sth->fetchrow_array) {
|
||
| 269 | $alerts{$row[0]} = 0;
|
||
| 270 | } |
||
| 271 | 17f78427 | Lars Kruse | $sth = $dbh->prepare("SELECT al.Level, COUNT(a.AlertLevel) FROM Alert a, AlertLevel al WHERE a.AlertLevel = al.Level AND a.ResolutionState <> 255 GROUP BY al.Level",
|
| 272 | b25acbbd | Rune Nordb?e Skillingstad | {odbc_exec_direct => 1});
|
| 273 | $sth->execute(); |
||
| 274 | while(my @row = $sth->fetchrow_array) {
|
||
| 275 | $alerts{$row[0]} = $row[1];
|
||
| 276 | } |
||
| 277 | foreach my $level (sort(keys(%alerts))) {
|
||
| 278 | printf "alert%d.value %d\n", $level, $alerts{$level};
|
||
| 279 | } |
||
| 280 | } |
||
| 281 | |||
| 282 | sub deployments_fetch {
|
||
| 283 | my %profiles = &deployments_general(); |
||
| 284 | foreach my $policy (sort(keys(%profiles))) {
|
||
| 285 | my $field = encode_base64($policy); |
||
| 286 | chomp($field); |
||
| 287 | print $field . ".value " . $profiles{$policy}{'count'} . "\n";
|
||
| 288 | if($profiles{$policy}{'old'}) {
|
||
| 289 | print $field . "old.value " . $profiles{$policy}{'old'} . "\n";
|
||
| 290 | } |
||
| 291 | } |
||
| 292 | } |
||
| 293 | |||
| 294 | sub deployments_general {
|
||
| 295 | my %profiles; |
||
| 296 | $profiles{'00000000-0000-0000-0000-000000000000'}{'name'} = "Unknown Policy";
|
||
| 297 | $profiles{'00000000-0000-0000-0000-000000000000'}{'instance'} = "";
|
||
| 298 | $profiles{'00000000-0000-0000-0000-000000000000'}{'count'} = 0;
|
||
| 299 | $profiles{'d3b75be9-7125-4db1-8b24-93004bd9d88e'}{'name'} = "No Policy";
|
||
| 300 | $profiles{'d3b75be9-7125-4db1-8b24-93004bd9d88e'}{'instance'} = "";
|
||
| 301 | $profiles{'d3b75be9-7125-4db1-8b24-93004bd9d88e'}{'count'} = 0;
|
||
| 302 | my $dbh = DBI->connect("DBI:Sybase:$dsn", $dbuser, $dbpass, { PrintError => 1, AutoCommit => 1});
|
||
| 303 | 17f78427 | Lars Kruse | |
| 304 | b25acbbd | Rune Nordb?e Skillingstad | my $sth = $dbh->prepare("SELECT Id, Name, LatestInstanceID From fcs_Profiles", {odbc_exec_direct => 1});
|
| 305 | $sth->execute(); |
||
| 306 | while(my @row = $sth->fetchrow_array) {
|
||
| 307 | $profiles{lc($row[0])}{'name'} = $row[1];
|
||
| 308 | $profiles{lc($row[0])}{'instance'} = lc($row[2]);
|
||
| 309 | $profiles{lc($row[0])}{'count'} = 0;
|
||
| 310 | $profiles{lc($row[0])}{'old'} = 0;
|
||
| 311 | } |
||
| 312 | |||
| 313 | $sth = $dbh->prepare("SELECT COUNT(*), a1.Value AS Policy, a2.Value AS Instance ".
|
||
| 314 | "FROM Attribute a1, Attribute a2, ClassDefinition cd, ClassAttribute ca1, ClassAttribute ca2 ". |
||
| 315 | "WHERE ca2.ClassID = cd.ClassID ". |
||
| 316 | "AND cd.Name = 'Microsoft Forefront Client Security Agent' ". |
||
| 317 | "AND ca1.ClassAttributeName = 'Profile ID' " . |
||
| 318 | "AND ca2.ClassAttributeName = 'Profile Instance ID' ". |
||
| 319 | "AND a1.ClassAttributeID = ca1.ClassAttributeID ". |
||
| 320 | "AND a2.ClassAttributeID = ca2.ClassAttributeID ". |
||
| 321 | "AND a1.InstanceID = a2.InstanceID " . |
||
| 322 | "GROUP BY a1.Value, a2.Value ". |
||
| 323 | "ORDER BY Policy", |
||
| 324 | {odbc_exec_direct => 1});
|
||
| 325 | $sth->execute(); |
||
| 326 | while(my @row = $sth->fetchrow_array) {
|
||
| 327 | if(!$row[1]) {
|
||
| 328 | $profiles{'00000000-0000-0000-0000-000000000000'}{'count'} += $row[0];
|
||
| 329 | } elsif(lc($row[1]) eq 'd3b75be9-7125-4db1-8b24-93004bd9d88e') {
|
||
| 330 | $profiles{'d3b75be9-7125-4db1-8b24-93004bd9d88e'}{'count'} += $row[0];
|
||
| 331 | } else {
|
||
| 332 | if(lc($row[2]) ne $profiles{lc($row[1])}{'instance'}) {
|
||
| 333 | $profiles{lc($row[1])}{'old'} += $row[0];
|
||
| 334 | } else {
|
||
| 335 | $profiles{lc($row[1])}{'count'} += $row[0];
|
||
| 336 | } |
||
| 337 | } |
||
| 338 | } |
||
| 339 | return %profiles; |
||
| 340 | } |
||
| 341 | |||
| 342 | exit 0; |
