Code

Changed netsaint to nagios in use lib
[nagiosplug.git] / contrib / check_wins.pl
1 #!/usr/bin/perl -w
3 # $Id$
5 # $Log$
6 # Revision 1.2  2003/08/20 08:31:49  tonvoon
7 # Changed netsaint to nagios in use lib
8 #
9 # Revision 1.1  2003/02/09 14:16:28  sghosh
10 # more contribs
11 #
13 use strict ;
15 use Getopt::Long ;
16 use vars qw($opt_H $opt_D $opt_W $opt_T $debug @my_dcs);
18 use lib '/usr/local/nagios/libexec/' ;
19 use utils qw($TIMEOUT %ERRORS &print_revision &support &usage);
21 my $PROGNAME = 'check_wins' ;
23 use constant SAMBA_DEBUG_LVL    => 2 ;
24 use constant MY_DCS             => ('dc1','dc2') ;
25 # use constant MY_DCS           => qw(ipa01 ipa02 ipa03) ;
27 my $NMBLOOKUP_PATH              = '/usr/bin/nmblookup' ;
28 my $NMBLOOKUP                   = sub { return `$NMBLOOKUP_PATH $_[2] -R -U $_[0] $_[1]` } ;
29 my $NMBLOOKUP_CMD               = $NMBLOOKUP_PATH  . ' -R -U' ;
31 sub print_help ();
32 sub print_usage ();
33 sub help ();
34 sub version ();
36 delete @ENV{'PATH', 'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
38 $SIG{"ALRM"} = sub { die "Alarm clock restart" } ;
40 Getopt::Long::Configure('bundling', 'no_ignore_case');
41 GetOptions
42         ("V|version"     => \&version,
43          "h|help"        => \&help,
44          "d|debug"       => \$debug,
45          "C|controllers:s" => \@my_dcs,
46          "T|timeout:i"   => \$opt_T,
47          "W|wins=s"      => \$opt_W,
48          "D|domain=s"    => \$opt_D);
51 ($opt_D) || usage("MS Domain name not specified\n");
52 my $domain = $1 if $opt_D =~ m#(\w+)# ;                # NetBIOS names allow __any__ characters (more than \w)
53 ($domain) || usage("Invalid MS D name: $opt_D\n");
55 ($opt_W) || usage("WINS hostname or address not specified\n");
56 my $wins = $1 if $opt_W =~ m#((?:^\w+$)|(?:\d+(?:\.\d+){3,3}$))# ;
57 ($wins) || usage("Invalid WINS hostname or address: $opt_W\n");
59 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")
60   unless (@my_dcs or MY_DCS) ;
62 @my_dcs = MY_DCS        unless defined $my_dcs[0] ;
63 $TIMEOUT = $opt_T       if defined $opt_T ;
65 my ($netbios_name, @dcs_of_domain, @dc_addresses) ;
66 my (@addr_dcs_of_domain, @found_dcs, %address2dc) ;
67 my (@dc_query) ;
69 # tsitc> /usr/local/samba/bin/nmblookup -R -U wins ipa01
70 # Sending queries to 10.0.100.29
71 # 10.0.100.16 ipa01<00>
73 eval {
74   alarm($TIMEOUT) ;
75   @dc_query = $debug ? map { $NMBLOOKUP->($wins, "$_#20", '-d ' . SAMBA_DEBUG_LVL) } @my_dcs :
76                        map { ( $NMBLOOKUP->($wins, "$_#20", '') )[1] } @my_dcs ;
77   alarm(0) ;
78 } ;
80 if ($@ and $@ =~ /Alarm clock restart/) {
81   print qq(Failed. Timeout while waiting for response from  (one of) "$NMBLOOKUP_CMD $wins @my_dcs"\n) ;
82   exit $ERRORS{"CRITICAL"} ;
83 }
85 if ($@ and $@ !~ /Alarm clock restart/) {
86   print qq(Failed. "$@" in response to "NMBLOOKUP_CMD $wins @my_dcs"\n) ;
87   exit $ERRORS{"UNKNOWN"} ;
88 }
90 chomp @dc_query ;
91 if ( scalar grep(/name_query failed/, @dc_query) ) {
92   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) ;
93   exit $ERRORS{"CRITICAL"} ;
94 }
96 # the results of looking up the DCs (by their name) in the WINS 
98 # 10.0.100.16 ipa01<20>
99 # 10.0.100.1 ipa02<20>
100 # 10.0.100.104 ipa03<20>
102 @dc_addresses = () ;
103 foreach (@dc_query) {
104   next unless /^(\S+)\s+(\S+?)<\S+?>$/ ;
105   $address2dc{$1} = $2 ;
106   push @dc_addresses, $1 ;
109 $netbios_name = "$domain#1C"  ;
111 eval {
112   alarm($TIMEOUT) ;
113   @dcs_of_domain = $NMBLOOKUP->($wins, $netbios_name, defined $debug ? '-d ' . SAMBA_DEBUG_LVL : '') ;
114   alarm(0) ;
116 } ;
118 if ($@ and $@ =~ /Alarm clock restart/) {
119   print qq(Failed. Timeout while waiting for response from "$NMBLOOKUP_CMD $wins $netbios_name"\n) ;
120   exit $ERRORS{"CRITICAL"} ;
121
123 if ($@ and $@ !~ /Alarm clock restart/) {
124   print qq(Failed. "$@" in response to "$NMBLOOKUP_CMD $wins $netbios_name"\n) ;
125   exit $ERRORS{"UNKNOWN"} ;
128 shift @dcs_of_domain ;
129 chomp @dcs_of_domain ;
130 @addr_dcs_of_domain = map /^(\S+)/, @dcs_of_domain ;
132 # tsitc> /usr/local/samba/bin/nmblookup -R -U wins ipaustralia#1c
133 # Sending queries to 10.0.100.29
134 # 10.0.100.114 ipaustralia<1c>
135 # 168.168.102.129 ipaustralia<1c>
136 # 192.168.101.221 ipaustralia<1c>
137 # 10.0.100.61 ipaustralia<1c>
138 # 192.168.108.129 ipaustralia<1c>
139 # 192.168.102.128 ipaustralia<1c>
140 # 10.0.4.126 ipaustralia<1c>
141 # 192.168.106.214 ipaustralia<1c>
142 # 10.0.3.165 ipaustralia<1c>
143 # 192.168.105.214 ipaustralia<1c>
144 # 10.0.6.145 ipaustralia<1c>
145 # 192.168.104.128 ipaustralia<1c>
146 # 10.0.4.59 ipaustralia<1c>
147 # 10.9.99.99 ipaustralia<1c>
148 # 10.99.99.99 ipaustralia<1c>
149 # 10.9.99.254 ipaustralia<1c>
150 # 10.0.3.15 ipaustralia<1c>
151 # 192.168.102.129 ipaustralia<1c>
152 # 192.168.103.129 ipaustralia<1c>
153 # 192.168.105.129 ipaustralia<1c>
154 # 192.168.106.129 ipaustralia<1c>
155 # 192.168.101.129 ipaustralia<1c>
156 # 192.168.104.129 ipaustralia<1c>
157 # 10.0.3.123 ipaustralia<1c>
158 # 10.0.100.67 ipaustralia<1c>
159 # tsitc> 
161 my %x ;
162 @found_dcs = grep { ! $x{$_}++ } @address2dc{ grep exists $address2dc{$_}, @addr_dcs_of_domain} ;
163 # @found_dcs = grep { defined $_} @address2dc{ grep exists $address2dc{$_}, @addr_dcs_of_domain} ;
164                                                                 # Gotcha.
165                                                                 # 'exists' is necessary to prevent autovivificatiton
166                                                                 # of keys in %address2dc
168 if ( &set_eq( \@found_dcs, [ values %address2dc ] ) ) {
169   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) :
170                  qq(Ok. Found controllers named "@my_dcs" in response to "$domain#1C" name query from WINS named "$wins".\n) ;
171   exit $ERRORS{"OK"} ;
172 } elsif ( scalar @found_dcs == 0 ) {
173   print qq(Failed. Found __no__ controllers named "@my_dcs" in response to "$domain#1C" query from WINS named "$wins". Got "@dcs_of_domain"\n) ;
174   exit $ERRORS{"CRITICAL"} ;
175 } elsif ( scalar @found_dcs < scalar keys %address2dc ) {
176   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) ;
177   exit $ERRORS{"WARNING"} ;
180 sub set_eq {
182   return 0 unless scalar @{$_[0]} == scalar @{$_[1]} ;
183   foreach my $a ( @{$_[0]} ) {
184     return 0 unless scalar grep { $a eq $_ } @{$_[1]} ;
185   } 
186   return 1 ;
191 sub print_usage () {
192         print "Usage: $PROGNAME -W <wins> -D <domain>\n";
195 sub print_help () {
196         print_revision($PROGNAME,'$Revision$ ');
197         print "Copyright (c) 2001 Karl DeBisschop/S Hopcroft
199 Perl Check WINS plugin for NetSaint.
201 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' 
203 Why would you want to do this ?
205 MS File server clients insist on connecting to file servers using NetBIOS names.
206 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
207 broadcast requsts for names.
208 Both problems are eliminated by a healthy WINS.
209 Also, you may have a MS domain spanning a  number of WAN connected sites, with domain controllers far away from powerful local
210 domain controllers.
211 In this case, you want your local clients to have their logon requests validated by the local controllers.
213 The plugin works by
214   asking the WINS to resolve the addresses of the domain controllers (supplied by -C or from the constant MY_DCS)
215   asking the WINS to return the list of addresses of the domain controllers able to validate requests for the domain
216    whose name is given by -D
217   returning Ok          if all controller addresses are in that list (of addresses of domain controllers) or
218   returning WARNING     if not all the controller addresses are in the list or
219   returning CRITICAL    if there is no reply from the WINS or the list contains none of the contoller addresses
221 ";
222         print_usage();
223         print '
224 -W, --wins=STRING
225    Hostname or address of the WINS (Either Samba/nmbd or MS product)
226 -D, --domain=STRING
227    MS Domain name to find the Domain controllers of.
228 -C, --controllers:STRING
229    Optional __name(s)__ of domain controller that __must__ be found in the response to a domain controller name query.
230    If not defined, then use the constant value MY_DCS. You must use either -C or make sure that MY_DCS contains the names 
231    of __your__ domain controllers.
232 -T, --timeout:INTEGER
233 -d, --debug
234    Debugging output.
235 -h, --help
236    This stuff.
238 ';
239         support();
242 sub version () {
243         print_revision($PROGNAME,'$Revision$ ');
244         exit $ERRORS{'OK'};
247 sub help () {
248         print_help();
249         exit $ERRORS{'OK'};