poodad

Palo GP clients

Jul 29th, 2023
151
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 10.49 KB | None | 0 0
  1. ###############################################################################
  2. #
  3. # Display list of GlobalProtect users
  4. #
  5. # Ken Cornetet - Kimball Electronics
  6. #
  7. #
  8. # Revision History
  9. #
  10. # When        Who      What
  11. # -----------------------------------------------------------------------------
  12. # 2020-02-27  kcornet  Original
  13. # 2021-12-28  kcornet  Get Palos from network inventory database
  14. #
  15. ###############################################################################
  16.  
  17. use strict;
  18. use CGI qw/:standard/;
  19. use CGI::Carp qw(fatalsToBrowser);
  20. use Data::Dumper;
  21. use Text::Unidecode;
  22. use Net::Ping;
  23. use KII::kii_ad;
  24. use DBI;
  25.  
  26.  
  27. use 5.010;
  28.  
  29. my $t0 = time();
  30.  
  31. print "Content-type: text/html\n\n";
  32.  
  33. #print qq(<head><meta http-equiv="refresh" content="60"></head>);
  34.  
  35. my $userid = remote_user();
  36. $userid = '' unless defined $userid;
  37. $userid =~ s/..*\\//;
  38. $userid = lc($userid);
  39.  
  40. my $password = $ENV{AUTH_PASSWORD};
  41.  
  42.  
  43.  
  44. my $palo = param('palo');
  45.  
  46. if( ! $palo ) {             # Initial call, create form
  47.     step1();
  48. } else {
  49.     step2();
  50. }
  51.  
  52. exit 0;
  53.  
  54.  
  55. ###############################################################################
  56. #
  57. # Draw the initial form asking the user what router to manage
  58. #
  59. ###############################################################################
  60.  
  61. sub step1 {
  62.  
  63.     my %netinv;
  64.     my @units;
  65.    
  66.     LoadNetInventory(\%netinv);
  67.     foreach my $device ( sort keys %netinv ) {
  68.         push @units, $device if $netinv{$device}->{MODEL1} =~ /^pa-/i;
  69.     }
  70.    
  71.     print start_form;
  72.     print "<p>Pick the Palo to view: \n";
  73.  
  74.     print "<select name=palo>\n";
  75.     print "<option value=\"all\">all\n";
  76.    
  77.     foreach my $unit (sort @units) {
  78.         $unit = uc $unit;
  79.         print "<option value=\"$unit\">$unit\n";
  80.     }
  81.     print "</select>\n";
  82.     print '<p><input type=submit value="Next" name=button>';
  83.     print end_form;
  84. }
  85.  
  86.  
  87.  
  88. sub step2 {
  89.     my $unit = param('palo');
  90.  
  91.     my @units;
  92.    
  93.     if( $palo eq 'all' ) {
  94.         my %netinv;
  95.         LoadNetInventory(\%netinv);
  96.            
  97.         foreach my $device (sort keys %netinv) {
  98.             push @units, $device if $netinv{$device}->{MODEL1} =~ /^pa-/i;
  99.         }
  100.     } else {
  101.         push @units, $unit;
  102.     }
  103.  
  104.     my $total = 0;
  105.  
  106.  
  107.     foreach my $unit (sort @units) {
  108.         my $pa = PaloAltoBasicAuth::new($unit, $userid, $password);
  109.    
  110.         if( ! $pa ) {
  111.             print "<h3>Error: could not open session to $unit</h3><p>\n";
  112.             next;
  113.         }
  114.    
  115.         next unless IsActive($pa);
  116.        
  117.         my @gateways = GetGateways($pa);
  118.      
  119.         foreach my $gw (sort @gateways) {
  120.             next unless $gw;
  121.             my $res = GetUsers($pa, $gw);
  122.             next unless $res;
  123.    
  124.             #print "<pre>\n", Dumper($res), "</pre><p>\n";
  125.            
  126.             my $n = UserCount($res);
  127.             $total += $n;
  128.            
  129.             print "<font size=+1><b>", uc($unit), "</b> $gw Users: $n</font><br>";
  130.    
  131.             HandleUser($res);
  132.    
  133.         }
  134.         print "<hr>\n";
  135.        
  136.     }
  137.     print "<p>Total GlobalProtect users: $total\n";
  138.    
  139.     print "<hr><font size=-1>\n";
  140.     print "Run time         : ", time() - $t0, " seconds<br>";
  141.     print "CPU time (user)  : ", (times)[0], " seconds<br>";
  142.     print "CPU time (system): ", (times)[1], " seconds<br>\n";
  143.     print "</font>\n";
  144.  
  145.  
  146. }
  147.  
  148. ###############################################################################
  149. #
  150. # Get user's display name from AD
  151. #
  152. ###############################################################################
  153.  
  154.  
  155. sub AdInfo {
  156.     my $id = shift;
  157.    
  158.     state $objAD;
  159.     $objAD = kii_ad->new( warn=>0 ) unless $objAD;
  160.    
  161.     return undef unless $objAD;
  162.  
  163.     my ($adsPath) = $objAD->Find( filter=>"(samAccountName=$id)" );
  164.     return undef unless $adsPath;
  165.  
  166.  
  167.     my $objUser = $objAD->GetObject($adsPath);
  168.     return undef unless $objUser;
  169.    
  170.     return ( $objUser->Get("DisplayName"), $objUser->Get("Company") );
  171.  
  172. }
  173.  
  174. ###############################################################################
  175. #
  176. # Get total count of users from this record
  177. #
  178. ###############################################################################
  179.  
  180. sub UserCount {
  181.     my $res = shift;
  182.    
  183.     my $entries = $res->{result}->{entry};
  184.     return 0 unless $entries;
  185.     return scalar @{$entries};
  186.    
  187. }
  188.  
  189. ###############################################################################
  190. #
  191. # Display user information
  192. #
  193. ###############################################################################
  194.  
  195. sub HandleUser {
  196.     my $res = shift;
  197.    
  198.     my $entries = $res->{result}->{entry};
  199.     return unless $entries;
  200.     return unless scalar @{$entries};
  201.    
  202.     print "<table border=1>\n";
  203.     print "<tr><th>USERID<th>USER<th>COMPUTER<th>LOGIN TIME<th>CLIENT<th>VIRTUAL IP<th>PUBLIC IP<th>VPN TYPE<th>TUNNEL TYPE<th>PINGS\n";
  204.  
  205.    
  206.     foreach my $entry ( sort byuser @{$entries} ) {
  207.         my ($disp, $comp) = AdInfo($entry->{username});
  208.  
  209.         print "<tr>";
  210.         print "<td>", $entry->{username};
  211.         print "<td> $disp ($comp)";
  212.         print "<td>", unidecode($entry->{computer});
  213.         print "<td>", $entry->{'login-time'};
  214.         print "<td>", $entry->{client};
  215.         print "<td>", $entry->{'virtual-ip'};
  216.         print "<td>";
  217.         print "<a href=\"/scripts/arin.pl?ip=$entry->{'public-ip'}\">$entry->{'public-ip'}</a>";
  218.         print "<td>", $entry->{'vpn-type'};
  219.         print "<td>", $entry->{'tunnel-type'};
  220.         print "<td>", IsAlive($entry->{'virtual-ip'}) ? "yes":"no";
  221.         print "\n";
  222.     }
  223.  
  224.     print "</table><p>\n";
  225.  
  226.  
  227. }
  228.  
  229. ###############################################################################
  230. #
  231. # Function to allow sorting by user name
  232. #
  233. ###############################################################################
  234.  
  235. sub byuser {
  236.     return lc $a->{username} cmp lc $b->{username};
  237. }
  238.  
  239. ###############################################################################
  240. #
  241. # Ping global protect client
  242. #
  243. ###############################################################################
  244.  
  245.  
  246. sub IsAlive {
  247.     my $host = shift;
  248.  
  249.     my $p = Net::Ping->new("icmp", 2);
  250.     return 1 if $p->ping($host);
  251.     return undef;
  252. }
  253.  
  254. ###############################################################################
  255. #
  256. # Get the gateways defined on a given Palo
  257. #
  258. ###############################################################################
  259.  
  260. sub GetGateways {
  261.     my $pa = shift;
  262.    
  263.     my $res = $pa->get( qq(/api/?type=op&cmd=<show><global-protect-gateway><statistics></statistics></global-protect-gateway></show>) );
  264.  
  265.     my @ret;
  266.    
  267.     my $gateways = $res->{result}->{Gateway};
  268.    
  269.     return undef unless $gateways;
  270.    
  271. #    print "<pre>\n";
  272. #    print Dumper($gateways);
  273. #    print "</pre>\n";
  274.    
  275.     if( ref $gateways eq 'ARRAY' ) {
  276.         foreach my $gw ( @{$gateways} ) {
  277.             push @ret, $gw->{name};
  278.         }
  279.     } else {
  280.         push @ret, $gateways->{name};
  281.     }
  282.    
  283.     return @ret;
  284. }
  285.  
  286. ###############################################################################
  287. #
  288. # Get users for a given gateway
  289. #
  290. ###############################################################################
  291.  
  292. sub GetUsers {
  293.     my $pa = shift;
  294.     my $gateway = shift;
  295.    
  296.     my $res = $pa->get( qq(/api/?type=op&cmd=<show><global-protect-gateway><current-user><gateway>$gateway</gateway></current-user></global-protect-gateway></show>) );
  297.  
  298.     return $res;
  299. }
  300.  
  301. ###############################################################################
  302. #
  303. # Is this Palo a single unit, or an active HA unit?
  304. #
  305. ###############################################################################
  306.  
  307. sub IsActive {
  308.     my $pa = shift;
  309.    
  310.     my $res = $pa->get( qq(/api/?type=op&cmd=<show><high-availability><state></state></high-availability></show>) );
  311.  
  312.     #print "<pre>\n";
  313.     #print Dumper($res);
  314.     #print "</pre>\n";
  315.    
  316.     return 1 if $res->{result}->{enabled} eq 'no';              # not HA
  317.    
  318.     return 1 if $res->{result}->{enabled} eq 'yes' and $res->{result}->{group}->{'local-info'}->{state} eq 'active';
  319.  
  320.     return 0;
  321. }
  322.  
  323.  
  324. ###############################################################################
  325. #
  326. # Load network inventory
  327. #
  328. ###############################################################################
  329.  
  330.  
  331. sub LoadNetInventory {
  332.     my $r = shift;
  333.  
  334. # Redacted because it is site specific
  335.    
  336. }
  337.  
  338. ###############################################################################
  339. #
  340. # Package to access Palo API using userid/password authentication
  341. #
  342. ###############################################################################
  343.  
  344. package PaloAltoBasicAuth;
  345. use LWP::UserAgent;
  346. use HTTP::Request::Common qw(POST GET );
  347. use Data::Dumper;
  348. use XML::Simple qw(:strict);
  349. use MIME::Base64;
  350.  
  351. ##################################################################################################
  352. #
  353. # Create object. Requires server, userid, password
  354. #
  355. ##################################################################################################
  356.  
  357. our $content;
  358.  
  359. sub new {
  360.     #my $class = shift;
  361.     my $server = shift;
  362.     my $user = shift;
  363.     my $passwd = shift;
  364.  
  365.    
  366.     my $self = {};
  367.  
  368.     $self->{server} = $server;
  369.     #$self->{user} = $user;
  370.     #$self->{passwd} = $passwd;
  371.    
  372.     $self->{auth} = encode_base64("$user:$passwd");
  373.     $self->{ua} = LWP::UserAgent->new( ssl_opts => { verify_hostname => 0 } );
  374.     $self->{ua}->default_header('Authorization' => "Basic $self->{auth}");
  375.  
  376.     bless $self;
  377.    
  378.     return $self;
  379. }
  380.  
  381.  
  382. ##################################################################################################
  383. #
  384. # Perform an http GET
  385. #
  386. # Builds a URL out of the passed controller name and cached appid, then does a http GET
  387. #
  388. # If request fails, return undef
  389. #
  390. # If request succeeds, decode returned JSON into a perl hash and return ref to it
  391. #
  392. ##################################################################################################
  393.  
  394. sub get {
  395.     my $self = shift;
  396.     my $s = shift;
  397.    
  398.     my $url = "https://$self->{server}$s";
  399.    
  400.     my $req = (GET $url);
  401.  
  402.     my $res = $self->{ua}->request($req);
  403.  
  404.     return undef unless $res->code() == 200;
  405.  
  406.     #print Dumper($res->content());
  407.     #print "\n\n";
  408.    
  409.     my $ref = XMLin($res->content(),  ForceArray => ['entry'], KeyAttr => '');
  410.    
  411.     #print Dumper($ref);
  412.  
  413.     return $ref;
  414.    
  415. }
  416.  
  417. sub name {
  418.     my $self = shift;
  419.     return $self->{server};
  420. }
  421.  
  422.  
Add Comment
Please, Sign In to add comment