check_wins.pl 7.6 KB

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