Code

Fix for regex input of '|', being output causing problems with Nagios' parsing of
[nagiosplug.git] / contrib / check_wins.pl
1 #!/usr/bin/perl -w
3 # $Id: check_wins.pl 940 2004-11-25 04:46:16Z stanleyhopcroft $
5 # Revision 1.3  2004/11/25 04:46:16  stanleyhopcroft
6 # Non functional tidy ups to check_wins
7 #
8 # Revision 1.2  2003/08/20 08:31:49  tonvoon
9 # Changed netsaint to nagios in use lib
10 #
11 # Revision 1.1  2003/02/09 14:16:28  sghosh
12 # more contribs
13 #
15 use strict ;
17 use Getopt::Long ;
18 use vars qw($opt_H $opt_D $opt_W $opt_T $debug @my_dcs);
20 use lib '/usr/local/nagios/libexec/' ;
21 use utils qw($TIMEOUT %ERRORS &print_revision &support &usage);
23 my $PROGNAME = 'check_wins' ;
25 use constant SAMBA_DEBUG_LVL    => 2 ;
26 use constant MY_DCS             => ('dc1','dc2') ;
28 my $NMBLOOKUP_PATH              = '/usr/bin/nmblookup' ;
29 my $NMBLOOKUP                   = sub { return `$NMBLOOKUP_PATH $_[2] -R -U $_[0] $_[1]` } ;
30 my $NMBLOOKUP_CMD               = $NMBLOOKUP_PATH  . ' -R -U' ;
32 sub print_help ();
33 sub print_usage ();
34 sub help ();
35 sub version ();
37 delete @ENV{'PATH', 'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
39 $SIG{"ALRM"} = sub { die "Alarm clock restart" } ;
41 Getopt::Long::Configure('bundling', 'no_ignore_case');
42 GetOptions
43         ("V|version"     => \&version,
44          "h|help"        => \&help,
45          "d|debug"       => \$debug,
46          "C|controllers:s" => \@my_dcs,
47          "T|timeout:i"   => \$opt_T,
48          "W|wins=s"      => \$opt_W,
49          "D|domain=s"    => \$opt_D);
52 ($opt_D) || usage("MS Domain name not specified\n");
53 my $domain = $1 if $opt_D =~ m#(\w+)# ;                # NetBIOS names allow __any__ characters (more than \w)
54 ($domain) || usage("Invalid MS D name: $opt_D\n");
56 ($opt_W) || usage("WINS hostname or address not specified\n");
57 my $wins = $1 if $opt_W =~ m#((?:^\w+$)|(?:\d+(?:\.\d+){3,3}$))# ;
58 ($wins) || usage("Invalid WINS hostname or address: $opt_W\n");
60 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")
61   unless (@my_dcs or MY_DCS) ;
63 @my_dcs = MY_DCS        unless defined $my_dcs[0] ;
64 $TIMEOUT = $opt_T       if defined $opt_T ;
66 my ($netbios_name, @dcs_of_domain, @dc_addresses) ;
67 my (@addr_dcs_of_domain, @found_dcs, %address2dc) ;
68 my (@dc_query) ;
70 # tsitc> /usr/local/samba/bin/nmblookup -R -U wins ipa01
71 # Sending queries to 192.168.1.29
72 # 192.168.1.16 ipa01<00>
74 eval {
75   alarm($TIMEOUT) ;
76   @dc_query = $debug ? map { $NMBLOOKUP->($wins, "$_#20", '-d ' . SAMBA_DEBUG_LVL) } @my_dcs :
77                        map { ( $NMBLOOKUP->($wins, "$_#20", '') )[1] } @my_dcs ;
78   alarm(0) ;
79 } ;
81 if ($@ and $@ =~ /Alarm clock restart/) {
82   print qq(Failed. Timeout while waiting for response from  (one of) "$NMBLOOKUP_CMD $wins @my_dcs"\n) ;
83   exit $ERRORS{"CRITICAL"} ;
84 }
86 if ($@ and $@ !~ /Alarm clock restart/) {
87   print qq(Failed. "$@" in response to "NMBLOOKUP_CMD $wins @my_dcs"\n) ;
88   exit $ERRORS{"UNKNOWN"} ;
89 }
91 chomp @dc_query ;
92 if ( scalar grep(/name_query failed/, @dc_query) ) {
93   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) ;
94   exit $ERRORS{"CRITICAL"} ;
95 }
97 =begin comment
99 the results of looking up the DCs (by their name) in the WINS 
101 192.168.1.16 ipa01<20>
102 192.168.1.1 ipa02<20>
103 192.168.1.104 ipa03<20>
105 =end comment
107 =cut
109 @dc_addresses = () ;
110 foreach (@dc_query) {
111   next unless /^(\S+)\s+(\S+?)<\S+?>$/ ;
112   $address2dc{$1} = $2 ;
113   push @dc_addresses, $1 ;
116 $netbios_name = "$domain#1C"  ;
118 eval {
119   alarm($TIMEOUT) ;
120   @dcs_of_domain = $NMBLOOKUP->($wins, $netbios_name, defined $debug ? '-d ' . SAMBA_DEBUG_LVL : '') ;
121   alarm(0) ;
123 } ;
125 if ($@ and $@ =~ /Alarm clock restart/) {
126   print qq(Failed. Timeout while waiting for response from "$NMBLOOKUP_CMD $wins $netbios_name"\n) ;
127   exit $ERRORS{"CRITICAL"} ;
128
130 if ($@ and $@ !~ /Alarm clock restart/) {
131   print qq(Failed. "$@" in response to "$NMBLOOKUP_CMD $wins $netbios_name"\n) ;
132   exit $ERRORS{"UNKNOWN"} ;
135 shift @dcs_of_domain ;
136 chomp @dcs_of_domain ;
137 @addr_dcs_of_domain = map /^(\S+)/, @dcs_of_domain ;
139 =begin comment
141 tsitc> /usr/local/samba/bin/nmblookup -R -U wins ipaustralia#1c
142 Sending queries to 192.168.1.29
143 192.168.1.114 ipaustralia<1c>
144 192.168.1.221 ipaustralia<1c>
145 192.168.1.61 ipaustralia<1c>
146 192.168.1.129 ipaustralia<1c>
147 192.168.1.128 ipaustralia<1c>
148 192.168.1.214 ipaustralia<1c>
149 192.168.1.67 ipaustralia<1c>
150 tsitc> 
152 =end comment
154 =cut
157 my %x ;
158 @found_dcs = grep { ! $x{$_}++ } @address2dc{ grep exists $address2dc{$_}, @addr_dcs_of_domain} ;
159 # @found_dcs = grep { defined $_} @address2dc{ grep exists $address2dc{$_}, @addr_dcs_of_domain} ;
160                                                                 # Gotcha.
161                                                                 # 'exists' is necessary to prevent autovivificatiton
162                                                                 # of keys in %address2dc
164 if ( &set_eq( \@found_dcs, [ values %address2dc ] ) ) {
165   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) :
166                  qq(Ok. Found controllers named "@my_dcs" in response to "$domain#1C" name query from WINS named "$wins".\n) ;
167   exit $ERRORS{"OK"} ;
168 } elsif ( scalar @found_dcs == 0 ) {
169   print qq(Failed. Found __no__ controllers named "@my_dcs" in response to "$domain#1C" query from WINS named "$wins". Got "@dcs_of_domain"\n) ;
170   exit $ERRORS{"CRITICAL"} ;
171 } elsif ( scalar @found_dcs < scalar keys %address2dc ) {
172   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) ;
173   exit $ERRORS{"WARNING"} ;
176 sub set_eq {
178   return 0 unless scalar @{$_[0]} == scalar @{$_[1]} ;
179   foreach my $a ( @{$_[0]} ) {
180     return 0 unless scalar grep { $a eq $_ } @{$_[1]} ;
181   } 
182   return 1 ;
187 sub print_usage () {
188         print "Usage: $PROGNAME -W <wins> -D <domain>\n";
191 sub print_help () {
192         print_revision($PROGNAME,'$Revision: 940 $ ');
193         print "Copyright (c) 2001 Karl DeBisschop/S Hopcroft
195 Perl Check WINS plugin for NetSaint.
197 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' 
199 Why would you want to do this ?
201 MS File server clients insist on connecting to file servers using NetBIOS names.
202 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
203 broadcast requsts for names.
204 Both problems are eliminated by a healthy WINS.
205 Also, you may have a MS domain spanning a  number of WAN connected sites, with domain controllers far away from powerful local
206 domain controllers.
207 In this case, you want your local clients to have their logon requests validated by the local controllers.
209 The plugin works by
210   asking the WINS to resolve the addresses of the domain controllers (supplied by -C or from the constant MY_DCS)
211   asking the WINS to return the list of addresses of the domain controllers able to validate requests for the domain
212    whose name is given by -D
213   returning Ok          if all controller addresses are in that list (of addresses of domain controllers) or
214   returning WARNING     if not all the controller addresses are in the list or
215   returning CRITICAL    if there is no reply from the WINS or the list contains none of the contoller addresses
217 ";
218         print_usage();
219         print '
220 -W, --wins=STRING
221    Hostname or address of the WINS (Either Samba/nmbd or MS product)
222 -D, --domain=STRING
223    MS Domain name to find the Domain controllers of.
224 -C, --controllers:STRING
225    Optional __name(s)__ of domain controller that __must__ be found in the response to a domain controller name query.
226    If not defined, then use the constant value MY_DCS. You must use either -C or make sure that MY_DCS contains the names 
227    of __your__ domain controllers.
228 -T, --timeout:INTEGER
229 -d, --debug
230    Debugging output.
231 -h, --help
232    This stuff.
234 ';
235         support();
238 sub version () {
239         print_revision($PROGNAME,'$Revision: 940 $ ');
240         exit $ERRORS{'OK'};
243 sub help () {
244         print_help();
245         exit $ERRORS{'OK'};