Code

0d11737f3054efdd9d03c74a98530760d18538ca
[nagiosplug.git] / contrib / check_wins.pl
1 #!/usr/bin/perl -w
3 # $Id$
5 # $Log$
6 # Revision 1.3  2004/11/25 04:46:16  stanleyhopcroft
7 # Non functional tidy ups to check_wins
8 #
9 # Revision 1.2  2003/08/20 08:31:49  tonvoon
10 # Changed netsaint to nagios in use lib
11 #
12 # Revision 1.1  2003/02/09 14:16:28  sghosh
13 # more contribs
14 #
16 use strict ;
18 use Getopt::Long ;
19 use vars qw($opt_H $opt_D $opt_W $opt_T $debug @my_dcs);
21 use lib '/usr/local/nagios/libexec/' ;
22 use utils qw($TIMEOUT %ERRORS &print_revision &support &usage);
24 my $PROGNAME = 'check_wins' ;
26 use constant SAMBA_DEBUG_LVL    => 2 ;
27 use constant MY_DCS             => ('dc1','dc2') ;
29 my $NMBLOOKUP_PATH              = '/usr/bin/nmblookup' ;
30 my $NMBLOOKUP                   = sub { return `$NMBLOOKUP_PATH $_[2] -R -U $_[0] $_[1]` } ;
31 my $NMBLOOKUP_CMD               = $NMBLOOKUP_PATH  . ' -R -U' ;
33 sub print_help ();
34 sub print_usage ();
35 sub help ();
36 sub version ();
38 delete @ENV{'PATH', 'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
40 $SIG{"ALRM"} = sub { die "Alarm clock restart" } ;
42 Getopt::Long::Configure('bundling', 'no_ignore_case');
43 GetOptions
44         ("V|version"     => \&version,
45          "h|help"        => \&help,
46          "d|debug"       => \$debug,
47          "C|controllers:s" => \@my_dcs,
48          "T|timeout:i"   => \$opt_T,
49          "W|wins=s"      => \$opt_W,
50          "D|domain=s"    => \$opt_D);
53 ($opt_D) || usage("MS Domain name not specified\n");
54 my $domain = $1 if $opt_D =~ m#(\w+)# ;                # NetBIOS names allow __any__ characters (more than \w)
55 ($domain) || usage("Invalid MS D name: $opt_D\n");
57 ($opt_W) || usage("WINS hostname or address not specified\n");
58 my $wins = $1 if $opt_W =~ m#((?:^\w+$)|(?:\d+(?:\.\d+){3,3}$))# ;
59 ($wins) || usage("Invalid WINS hostname or address: $opt_W\n");
61 usage("You must provide the names of your domain controllers by updating MY_DCS in the text or use -C dc_name1 -C dc_name2 ..\n")
62   unless (@my_dcs or MY_DCS) ;
64 @my_dcs = MY_DCS        unless defined $my_dcs[0] ;
65 $TIMEOUT = $opt_T       if defined $opt_T ;
67 my ($netbios_name, @dcs_of_domain, @dc_addresses) ;
68 my (@addr_dcs_of_domain, @found_dcs, %address2dc) ;
69 my (@dc_query) ;
71 # tsitc> /usr/local/samba/bin/nmblookup -R -U wins ipa01
72 # Sending queries to 192.168.1.29
73 # 192.168.1.16 ipa01<00>
75 eval {
76   alarm($TIMEOUT) ;
77   @dc_query = $debug ? map { $NMBLOOKUP->($wins, "$_#20", '-d ' . SAMBA_DEBUG_LVL) } @my_dcs :
78                        map { ( $NMBLOOKUP->($wins, "$_#20", '') )[1] } @my_dcs ;
79   alarm(0) ;
80 } ;
82 if ($@ and $@ =~ /Alarm clock restart/) {
83   print qq(Failed. Timeout while waiting for response from  (one of) "$NMBLOOKUP_CMD $wins @my_dcs"\n) ;
84   exit $ERRORS{"CRITICAL"} ;
85 }
87 if ($@ and $@ !~ /Alarm clock restart/) {
88   print qq(Failed. "$@" in response to "NMBLOOKUP_CMD $wins @my_dcs"\n) ;
89   exit $ERRORS{"UNKNOWN"} ;
90 }
92 chomp @dc_query ;
93 if ( scalar grep(/name_query failed/, @dc_query) ) {
94   print qq(Failed. WINS "$wins" failed to resolve), scalar @my_dcs > 1 ? ' at least one of ' : ' ', qq("@my_dcs", the domain controller(s) of "$domain". Got "@dc_query"\n) ;
95   exit $ERRORS{"CRITICAL"} ;
96 }
98 =begin comment
100 the results of looking up the DCs (by their name) in the WINS 
102 192.168.1.16 ipa01<20>
103 192.168.1.1 ipa02<20>
104 192.168.1.104 ipa03<20>
106 =end comment
108 =cut
110 @dc_addresses = () ;
111 foreach (@dc_query) {
112   next unless /^(\S+)\s+(\S+?)<\S+?>$/ ;
113   $address2dc{$1} = $2 ;
114   push @dc_addresses, $1 ;
117 $netbios_name = "$domain#1C"  ;
119 eval {
120   alarm($TIMEOUT) ;
121   @dcs_of_domain = $NMBLOOKUP->($wins, $netbios_name, defined $debug ? '-d ' . SAMBA_DEBUG_LVL : '') ;
122   alarm(0) ;
124 } ;
126 if ($@ and $@ =~ /Alarm clock restart/) {
127   print qq(Failed. Timeout while waiting for response from "$NMBLOOKUP_CMD $wins $netbios_name"\n) ;
128   exit $ERRORS{"CRITICAL"} ;
129
131 if ($@ and $@ !~ /Alarm clock restart/) {
132   print qq(Failed. "$@" in response to "$NMBLOOKUP_CMD $wins $netbios_name"\n) ;
133   exit $ERRORS{"UNKNOWN"} ;
136 shift @dcs_of_domain ;
137 chomp @dcs_of_domain ;
138 @addr_dcs_of_domain = map /^(\S+)/, @dcs_of_domain ;
140 =begin comment
142 tsitc> /usr/local/samba/bin/nmblookup -R -U wins ipaustralia#1c
143 Sending queries to 192.168.1.29
144 192.168.1.114 ipaustralia<1c>
145 192.168.1.221 ipaustralia<1c>
146 192.168.1.61 ipaustralia<1c>
147 192.168.1.129 ipaustralia<1c>
148 192.168.1.128 ipaustralia<1c>
149 192.168.1.214 ipaustralia<1c>
150 192.168.1.67 ipaustralia<1c>
151 tsitc> 
153 =end comment
155 =cut
158 my %x ;
159 @found_dcs = grep { ! $x{$_}++ } @address2dc{ grep exists $address2dc{$_}, @addr_dcs_of_domain} ;
160 # @found_dcs = grep { defined $_} @address2dc{ grep exists $address2dc{$_}, @addr_dcs_of_domain} ;
161                                                                 # Gotcha.
162                                                                 # 'exists' is necessary to prevent autovivificatiton
163                                                                 # of keys in %address2dc
165 if ( &set_eq( \@found_dcs, [ values %address2dc ] ) ) {
166   print $debug ? qq(Ok. WINS named "$wins" resolved addresses of "@my_dcs" as "@dc_query" and controllers of domain "$domain" as "@dcs_of_domain"\n) :
167                  qq(Ok. Found controllers named "@my_dcs" in response to "$domain#1C" name query from WINS named "$wins".\n) ;
168   exit $ERRORS{"OK"} ;
169 } elsif ( scalar @found_dcs == 0 ) {
170   print qq(Failed. Found __no__ controllers named "@my_dcs" in response to "$domain#1C" query from WINS named "$wins". Got "@dcs_of_domain"\n) ;
171   exit $ERRORS{"CRITICAL"} ;
172 } elsif ( scalar @found_dcs < scalar keys %address2dc ) {
173   print qq(Warning. Not all domain controllers found in response to "$domain#1C" query from WINS named "$wins". Expected "@my_dcs", got "@found_dcs"\n) ;
174   exit $ERRORS{"WARNING"} ;
177 sub set_eq {
179   return 0 unless scalar @{$_[0]} == scalar @{$_[1]} ;
180   foreach my $a ( @{$_[0]} ) {
181     return 0 unless scalar grep { $a eq $_ } @{$_[1]} ;
182   } 
183   return 1 ;
188 sub print_usage () {
189         print "Usage: $PROGNAME -W <wins> -D <domain>\n";
192 sub print_help () {
193         print_revision($PROGNAME,'$Revision$ ');
194         print "Copyright (c) 2001 Karl DeBisschop/S Hopcroft
196 Perl Check WINS plugin for NetSaint.
198 Returns OK if the addresses of domain controllers are found in the list of domain controllers returned in the WINS response to a 'domain controllers query' 
200 Why would you want to do this ?
202 MS File server clients insist on connecting to file servers using NetBIOS names.
203 If they __don't__ resolve NetBIOS names with a WINS (NBNS) then they'll either fail to logon and  connect to shares or they will
204 broadcast requsts for names.
205 Both problems are eliminated by a healthy WINS.
206 Also, you may have a MS domain spanning a  number of WAN connected sites, with domain controllers far away from powerful local
207 domain controllers.
208 In this case, you want your local clients to have their logon requests validated by the local controllers.
210 The plugin works by
211   asking the WINS to resolve the addresses of the domain controllers (supplied by -C or from the constant MY_DCS)
212   asking the WINS to return the list of addresses of the domain controllers able to validate requests for the domain
213    whose name is given by -D
214   returning Ok          if all controller addresses are in that list (of addresses of domain controllers) or
215   returning WARNING     if not all the controller addresses are in the list or
216   returning CRITICAL    if there is no reply from the WINS or the list contains none of the contoller addresses
218 ";
219         print_usage();
220         print '
221 -W, --wins=STRING
222    Hostname or address of the WINS (Either Samba/nmbd or MS product)
223 -D, --domain=STRING
224    MS Domain name to find the Domain controllers of.
225 -C, --controllers:STRING
226    Optional __name(s)__ of domain controller that __must__ be found in the response to a domain controller name query.
227    If not defined, then use the constant value MY_DCS. You must use either -C or make sure that MY_DCS contains the names 
228    of __your__ domain controllers.
229 -T, --timeout:INTEGER
230 -d, --debug
231    Debugging output.
232 -h, --help
233    This stuff.
235 ';
236         support();
239 sub version () {
240         print_revision($PROGNAME,'$Revision$ ');
241         exit $ERRORS{'OK'};
244 sub help () {
245         print_help();
246         exit $ERRORS{'OK'};