Projet

Général

Profil

Paste
Télécharger au format
Statistiques
| Branche: | Révision:

root / plugins / security / forefront_ @ 2c912170

Historique | Voir | Annoter | Télécharger (11,6 ko)

1
#!/usr/bin/perl
2
#
3
# Plugin to monitor Forefront Client Security status in MOM database
4
#
5
# Copyright (c) 2008 Rune Nordbøe Skillingstad - <rune.skillingstad@ntnu.no>
6
#
7
# 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
# Parameters:
22
#
23
#     config
24
#     autoconf
25
#     suggest
26
#
27
# Config variables
28
#
29
#     dsn     - If DSN name differs from hostname
30
#     dbuser  - Valid MS SQL user (Windows authentication is possible using "DOMAIN\user")
31
#     dbpass  - Password
32
#
33
# Install guide:
34
# This plugin relies on correct configured ODBC for the MOM database
35
# Prerequisites:
36
# * Install and configure FreeTDS and DBD::Sybase (packages tdsodbc and libdbd-sybase-perl on Ubuntu)
37
# - DBD::Sybase is preferred over ODBC because of strange TEXT field handling in DBD::ODBC
38
#
39
# Example
40
# /etc/freetds/freetds.conf:
41
# [MyHost]
42
#        host = MyHost.domain.tld
43
#        port = 1433
44
#        tds version = 7.0
45
#
46
# 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
# To manually add, symlink forefront_ to forefront_MyHost.domain.tld_computers,
53
# forefront_MyHost.domain.tld_deployments and forefront_MyHost.domain.tld_status
54
#
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
#
61
# 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
        print "no ($ret)\n";
105
    } else {
106
        print "yes\n";
107
    }
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
	chomp($field);
215
	print $field . ".label " . $profiles{$policy}{'name'} . "\n";
216
	print $field . ".draw LINE2\n";
217
	print $field . ".info Number of computers having the " .$profiles{$policy}{'name'} . " profile.\n";
218
	if($profiles{$policy}{'old'}) {
219
	    print $field . "old.label " . $profiles{$policy}{'name'} . " (old)\n";
220
	    print $field . "old.draw LINE2\n";
221
	    print $field . "old.info Number of computers having an old version of the " .$profiles{$policy}{'name'} . " profile.\n";
222
	}
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
    $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
	{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

    
304
    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;