check_ms_spooler.pl 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. #!/usr/bin/perl -w
  2. # $Id: check_ms_spooler.pl 64 2002-07-16 00:04:42Z stanleyhopcroft $
  3. # Revision 1.1 2002/07/16 00:04:42 stanleyhopcroft
  4. # Primitive and in need of refinement test of MS spooler (with smbclient)
  5. #
  6. # Revision 2.5 2002-02-13 07:36:08+11 anwsmh
  7. # Correct 'apostrophe' disaster.
  8. # Apostrophes in plugin output cause Netsaint notification commands
  9. # ( sh echo 'yada $PLUGINOUTPUT$ ..') to fail, usually mysteriously
  10. # eg notify OK works but notify CRITICAL does not.
  11. # Replace '$var' in print "output" with \"$var\".
  12. #
  13. # Revision 2.4 2001-11-21 21:36:05+11 anwsmh
  14. # Minor corrections
  15. # . replace 'die' by print .. exit $ERRORS{CRITICAL}
  16. # . change concluding message to list the queues (sorted) if there are no enqueued docs.
  17. #
  18. # Revision 2.3 2001-11-20 11:00:58+11 anwsmh
  19. # Major corrections.
  20. # 1. to sub AUTOLOAD: coderef parms must be @_ (ie the parm when the new sub is called)
  21. # 2. to processing of queue report (no inspection of $last_line; entire $queue_report is
  22. # checked for errors)
  23. # 3. cosmetic and debug changes in many places.
  24. #
  25. # Revision 2.2 2001-11-17 23:30:34+11 anwsmh
  26. # After adapting two different queue reports resulting from
  27. # different name resolution methods.
  28. #
  29. # Revision 2.1 2001-11-17 13:21:54+11 anwsmh
  30. # Adapt to Netsaint ('use utils, Getopt::Long, and standard switch processing).
  31. # Fix many peculiarities.
  32. #
  33. use strict ;
  34. use Getopt::Long ;
  35. use utils ;
  36. use vars qw($opt_H $opt_s $opt_W $opt_u $opt_p $opt_w $opt_c $debug);
  37. use vars '$AUTOLOAD' ;
  38. use utils qw($TIMEOUT %ERRORS &print_revision &support &usage);
  39. my $PROGNAME = 'check_ms_spooler' ;
  40. sub print_help ();
  41. sub print_usage ();
  42. sub help ();
  43. sub version ();
  44. delete @ENV{'PATH', 'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
  45. use constant SMBCLIENT_PATH => '/usr/local/samba/bin/smbclient' ;
  46. use constant MAX_QUEUES_TO_CHECK => 20 ; # So that the check doesn't take longer than $TIMEOUT
  47. use constant SMBCLIENT_SVC => sub { return `${\SMBCLIENT_PATH} -L //$_[0] -U $_[1]%$_[2]` } ;
  48. use constant SMBCLIENT_QUEUE => sub { return `${\SMBCLIENT_PATH} //$_[0]/$_[1] -U $_[2]%$_[3] -c 'queue; quit' 2>/dev/null` } ;
  49. # The queue results depend on the name resolution method.
  50. # Forcing 'wins' or 'bcat' name resolution makes the queue results the
  51. # same for all spoolers (those that are resolved with WINS have an extra line
  52. # 'Got a positive name query response from <ip address of WINS> ..)
  53. # but would fail if there is no WINS and when miscreant spoolers
  54. # don't respond to broadcasts.
  55. use constant MIN => sub { my $min = $_[0] ; foreach (@_) { $min = $_ if $_ <= $min; } return $min ; } ;
  56. $SIG{"ALRM"} = sub { die "Alarm clock restart" } ;
  57. Getopt::Long::Configure('bundling', 'no_ignore_case');
  58. GetOptions
  59. ("V|version" => \&version,
  60. "h|help" => \&help,
  61. "d|debug" => \$debug,
  62. "p|password=s" => \$opt_p,
  63. "u|username=s" => \$opt_u,
  64. "H|hostname=s" => \$opt_H);
  65. ($opt_H) || usage("MS Spooler name not specified\n");
  66. my $spooler = $1 if $opt_H =~ m#(\w+)# ; # MS host names allow __any__ characters (more than \w)
  67. ($spooler) || usage("Invalid MS spooler name: $opt_H\n");
  68. ($opt_u) || ($opt_u = 'guest');
  69. my $user = $1 if $opt_u =~ m#(\w+)# ;
  70. ($user) || usage("Invalid user: $opt_u\n");
  71. ($opt_p) || ($opt_p = 'guest');
  72. my $pass = $1 if ($opt_p =~ /(.*)/);
  73. ($pass) || usage("Invalid password: $opt_p\n");
  74. my ($printer, $queue, @queues, $ms_spooler_status, @results, %junk) ;
  75. my (@fault_messages, @queue_contents, @services, @prandom_queue_indices) ;
  76. my ($queue_contents, $number_of_queues, $state, $queue_report) ;
  77. $state = "getting service list (${\SMBCLIENT_PATH} -L $spooler -U $user%$pass) from spooler\n" ;
  78. eval {
  79. alarm($TIMEOUT) ;
  80. @services = SMBCLIENT_SVC->( $spooler, $user, $pass ) ;
  81. } ;
  82. alarm(0) ;
  83. if ($@ and $@ !~ /Alarm clock restart/) {
  84. print "Failed. $PROGNAME failed $state. Got \"$@\"\n" ;
  85. exit $ERRORS{"CRITICAL"} ;
  86. }
  87. if ($@ and $@ =~ /Alarm clock restart/) {
  88. print "Failed. $PROGNAME timed out $state. Got \"@services\"\n" ;
  89. exit $ERRORS{"CRITICAL"} ;
  90. }
  91. # tsitc> /usr/local/samba/bin/smbclient //ipaprint1/tt03 -U blah%blah -P -c 'queue; quit'
  92. # Added interface ip=10.0.100.252 bcast=10.255.255.255 nmask=255.0.0.0
  93. # Connection to ipaprint1 failed
  94. # tsitc> /usr/local/samba/bin/smbclient -L sna_spl1 -U blah%blah | & more
  95. # Added interface ip=10.0.100.252 bcast=10.255.255.255 nmask=255.0.0.0
  96. # Got a positive name query response from 10.0.100.29 ( 10.0.6.20 )
  97. # session setup failed: ERRDOS - ERRnoaccess (Access denied.)
  98. if ( grep /Connection to $spooler failed|ERR/, @services ) {
  99. print "Failed. $PROGNAME failed $state. Got \"@services\"\n" ;
  100. # print "Failed. Request for services list to $spooler failed. Got \"@services\"\n" ;
  101. exit $ERRORS{"CRITICAL"} ;
  102. }
  103. # tsitc# /usr/local/samba/bin/smbclient -L ipaprint -U blah%blah
  104. # Added interface ip=10.0.100.252 bcast=10.255.255.255 nmask=255.0.0.0
  105. # Domain=[IPAUSTRALIA] OS=[Windows NT 4.0] Server=[NT LAN Manager 4.0]
  106. #
  107. # Sharename Type Comment
  108. # --------- ---- -------
  109. # TH02 Printer TH02
  110. # ADMIN$ Disk Remote Admin
  111. # IPC$ IPC Remote IPC
  112. # S431 Printer S431
  113. # S402 Printer S402
  114. # S401 Printer S401
  115. # C$ Disk Default share
  116. # BW01 Printer BW01
  117. # BW02 Printer BW02
  118. # TL11 Printer TL11
  119. # TL07 Printer TL07
  120. # S225 Printer Discovery South - 2nd Floor - HP CLJ4500
  121. # S224 Printer S224
  122. # S223 Printer Discovery South 2nd Floor Trademarks Training
  123. # S222 Printer S222
  124. # S203 Printer S203
  125. # S202 Printer S202
  126. my @printers = map { my @junk = split; $junk[0] }
  127. grep { my @junk = split; defined $junk[1] and $junk[1] eq 'Printer' } @services ;
  128. # don't check IPC$, ADMIN$ etc.
  129. $ms_spooler_status = 0 ;
  130. $number_of_queues = MIN->(MAX_QUEUES_TO_CHECK, (scalar(@services) >> 3) + 1) ;
  131. $state = "checking queues on $spooler" ;
  132. eval {
  133. # foreach queues to check
  134. # generate a pseudo-random int in 0 .. $#printers
  135. # drop it if the index has already been generated ;
  136. %junk = () ;
  137. @prandom_queue_indices = grep { ! $junk{$_}++ }
  138. map { int( rand($#printers) ) } ( 1 .. $number_of_queues ) ;
  139. @queues = @printers[@prandom_queue_indices] ;
  140. # @queues = @printers[ map { int( rand($#printers) ) } ( 1 .. $number_of_queues ) ] ;
  141. alarm($TIMEOUT) ;
  142. @queue_contents = @fault_messages = () ;
  143. foreach $printer (sort @queues) {
  144. # Expect 3 lines from a queue report.
  145. # If queue is empty, last line is null otherwise
  146. # it will contain a queue report or an SMB error
  147. # Empty Queue.
  148. # Added interface ip=10.0.100.252 bcast=10.255.255.255 nmask=255.0.0.0
  149. # Domain=[IPAUSTRALIA] OS=[Windows NT 4.0] Server=[NT LAN Manager 4.0]
  150. # Queue command from a spooler with a DNS name.
  151. # Added interface ip=10.0.100.252 bcast=10.255.255.255 nmask=255.0.0.0
  152. # Domain=[IPAUSTRALIA] OS=[Windows NT 4.0] Server=[NT LAN Manager 4.0]
  153. # 65 16307 Microsoft Word - Servicesweoffer2.doc
  154. # 68 10410 Microsoft Word - Servicesweoffer.doc
  155. # 143 24997 Microsoft Word - Miss Samantha Anne Craig.doc
  156. # 182 15635 Microsoft Word - services we provide.doc
  157. # Error.
  158. # Added interface ip=10.0.100.252 bcast=10.255.255.255 nmask=255.0.0.0
  159. # Domain=[IPAUSTRALIA] OS=[Windows NT 4.0] Server=[NT LAN Manager 4.0]
  160. # tree connect failed: ERRDOS - ERRnosuchshare (You specified an invalid share name)
  161. # Can't connect error.
  162. # Added interface ip=10.0.100.252 bcast=10.255.255.255 nmask=255.0.0.0
  163. # Connection to sna_spl2 failed
  164. # Empty Queue from a spooler with no DNS name, NetBIOS name resolved by WINS.
  165. # Added interface ip=10.0.100.252 bcast=10.255.255.255 nmask=255.0.0.0
  166. # Got a positive name query response from 10.0.100.29 ( 10.0.6.20 )
  167. # Domain=[SNA_PRINT] OS=[Windows NT 4.0] Server=[NT LAN Manager 4.0]
  168. # There are 3 lines of output from smbclient for those spoolers whose names are
  169. # resolved by WINS (because those names are NetBIOS and therefore not in DNS);
  170. # 4 lines for errors or enqueued jobs
  171. print STDERR "${\SMBCLIENT_PATH} //$spooler/$printer -U $user%$pass -c 'queue; quit' ==>\n" if $debug ;
  172. @results = SMBCLIENT_QUEUE->( $spooler, $printer, $user, $pass ) ;
  173. print STDERR "\"@results\"\n" if $debug ;
  174. # set $ms_spooler_status somehow
  175. chomp( @results ) ;
  176. $queue_report = queue_report->(@results) ;
  177. print STDERR '$queue_report for $printer ', "$printer: \"$queue_report\"\n\n" if $debug ;
  178. if ( defined $queue_report and ($queue_report !~ /ERR/ && $queue_report !~ /failed/) ) {
  179. $ms_spooler_status = 1 ;
  180. push @queue_contents, "$printer: $queue_report" if $queue_report ;
  181. } else {
  182. push @fault_messages, "$printer: $queue_report" ;
  183. }
  184. }
  185. alarm(0) ;
  186. } ;
  187. if ($@ and $@ !~ /Alarm clock restart/) {
  188. print "Failed. $PROGNAME failed at $state. Got \"$@\"\n" ;
  189. exit $ERRORS{"CRITCAL"} ;
  190. }
  191. if ($@ and $@ =~ /Alarm clock restart/) {
  192. my $i ;
  193. foreach (@queues) { $i++ ; last if $_ eq $printer }
  194. print "Failed. Timed out connecting to $printer ($i of $number_of_queues) on //$spooler after $TIMEOUT secs. Got \"@fault_messages\"\n" ;
  195. exit $ERRORS{"CRITICAL"} ;
  196. }
  197. if (! $ms_spooler_status) {
  198. print "Failed. Couldn't connect to @queues on //$spooler as user $user. Got \"@fault_messages\"\n" ;
  199. exit $ERRORS{"CRITICAL"} ;
  200. }
  201. $queue_contents = ( @queue_contents != 0 ? join(" ", (@queue_contents == 1 ? "Queue" : "Queues"), @queue_contents) :
  202. "All Queues empty" ) ;
  203. print "Ok. Connected to ", $queue_contents =~ /empty$/ ? "@{[sort @queues]}" : scalar @queues, " queues on //$spooler. $queue_contents\n" ;
  204. exit $ERRORS{"OK"} ;
  205. sub print_usage () {
  206. print "Usage: $PROGNAME -H <spooler> -u <user> -p <password>\n";
  207. }
  208. sub print_help () {
  209. print_revision($PROGNAME,'$Revision: 64 $ ');
  210. print "Copyright (c) 2001 Karl DeBisschop/S Hopcroft
  211. Perl Check MS Spooler plugin for NetSaint. Display a subset of the queues on an SMB (Samba or MS) print spooler.
  212. ";
  213. print_usage();
  214. print '
  215. -H, --hostname=STRING
  216. NetBIOS name of the SMB Print spooler (Either Samba or MS spooler)
  217. -u, --user=STRING
  218. Username to log in to server. (Default: "guest")
  219. -p, --password=STRING
  220. Password to log in to server. (Default: "guest")
  221. -d, --debug
  222. Debugging output.
  223. -h, --help
  224. This stuff.
  225. ';
  226. support();
  227. }
  228. sub version () {
  229. print_revision($PROGNAME,'$Revision: 64 $ ');
  230. exit $ERRORS{'OK'};
  231. }
  232. sub help () {
  233. print_help();
  234. exit $ERRORS{'OK'};
  235. }
  236. sub AUTOLOAD {
  237. my @queue_rep = @_ ;
  238. # 'Object Oriented Perl', D Conway, p 95
  239. no strict 'refs' ;
  240. if ( $AUTOLOAD =~ /.*::queue_report/ ) {
  241. if ( grep /Got a positive name query response from/, @queue_rep ){
  242. *{$AUTOLOAD} = sub { return join ' ', splice(@_, 3) } ;
  243. return join '', splice(@queue_rep, 3) ;
  244. } else {
  245. *{$AUTOLOAD} = sub { return join ' ',splice(@_, 2) } ;
  246. return join '', splice(@queue_rep, 2) ;
  247. }
  248. } else {
  249. die "No such subroutine: $AUTOLOAD" ;
  250. }
  251. }