File Coverage

blib/lib/Armadito/Agent/Tools/Win32.pm
Criterion Covered Total %
statement 35 37 94.5
branch 1 2 50.0
condition n/a
subroutine 12 14 85.7
pod 0 2 0.0
total 48 55 87.2


line stmt bran cond sub pod time code
1             package Armadito::Agent::Tools::Win32;
2              
3 1     1   1944659 use strict;
  1         3  
  1         46  
4 1     1   8 use warnings;
  1         5  
  1         62  
5 1     1   4 use base 'Exporter';
  1         38  
  1         149  
6 1     1   600 use utf8;
  1         9  
  1         6  
7 1     1   631 use Data::Dumper;
  1         5398  
  1         64  
8              
9 1     1   481 use Readonly;
  1         2777  
  1         89  
10             Readonly my $KEY_WOW64_64 => 0x100;
11             Readonly my $KEY_WOW64_32 => 0x200;
12              
13 0     0 0   sub KEY_WOW64_64 { return $KEY_WOW64_64 }
14 0     0 0   sub KEY_WOW64_32 { return $KEY_WOW64_32 }
15              
16 1     1   5 use UNIVERSAL::require;
  1         1  
  1         14  
17 1     1   21 use English qw(-no_match_vars);
  1         1  
  1         19  
18 1     1   1185 use File::Temp qw(:seekable tempfile);
  1         13123  
  1         152  
19 1     1   6 use File::Basename qw(basename);
  1         1  
  1         75  
20 1     1   4 use File::Basename qw(basename);
  1         2  
  1         43  
21              
22             BEGIN {
23 1 50   1   5 if ( $OSNAME ne "MSWin32" ) {
24              
25             # Test ::Compile exception
26 1         116 exit(0);
27             }
28             }
29              
30             use Win32::EventLog;
31             use Win32::OLE;
32             use Win32::OLE qw(in);
33             use Win32::TieRegistry (
34             Delimiter => '/',
35             ArrayValues => 0,
36             qw/KEY_READ/
37             );
38              
39             our @EXPORT_OK = qw(
40             getRegistryValue
41             getRegistryKey
42             getWMIObjects
43             );
44              
45             Win32::OLE->Option( CP => Win32::OLE::CP_UTF8 );
46              
47             sub getWMIObjects {
48             my (%params) = @_;
49              
50             $params{moniker} = 'winmgmts:{impersonationLevel=impersonate,(security)}!//./';
51              
52             my $WMIService = Win32::OLE->GetObject( $params{moniker} )
53             or return; #die "WMI connection failed: " . Win32::OLE->LastError();
54              
55             my @objects;
56             foreach my $instance ( in( $WMIService->InstancesOf( $params{class} ) ) ) {
57             my $object;
58             foreach my $property ( @{ $params{properties} } ) {
59             if ( defined $instance->{$property} && !ref( $instance->{$property} ) ) {
60              
61             # string value
62             $object->{$property} = $instance->{$property};
63              
64             # despite CP_UTF8 usage, Win32::OLE downgrades string to native
65             # encoding, if possible, ie all characters have code <= 0x00FF:
66             # http://code.activestate.com/lists/perl-win32-users/Win32::OLE::CP_UTF8/
67             utf8::upgrade( $object->{$property} );
68             }
69             elsif ( defined $instance->{$property} ) {
70              
71             # list value
72             $object->{$property} = $instance->{$property};
73             }
74             else {
75             $object->{$property} = undef;
76             }
77             }
78             push @objects, $object;
79             }
80              
81             return @objects;
82             }
83              
84             sub getRegistryValue {
85             my (%params) = @_;
86              
87             my ( $root, $keyName, $valueName );
88             if ( $params{path} =~ m{^(HKEY_\S+)/(.+)/([^/]+)} ) {
89             $root = $1;
90             $keyName = $2;
91             $valueName = $3;
92             }
93             else {
94             $params{logger}->error("Failed to parse '$params{path}'. Does it start with HKEY_?") if $params{logger};
95             return;
96             }
97              
98             my $key = _getRegistryKey(
99             logger => $params{logger},
100             root => $root,
101             keyName => $keyName
102             );
103              
104             return unless ( defined($key) );
105              
106             if ( $valueName eq '*' ) {
107             my %ret;
108             foreach ( keys %$key ) {
109             s{^/}{};
110             $ret{$_} = $params{withtype} ? [ $key->GetValue($_) ] : $key->{"/$_"};
111             }
112             return \%ret;
113             }
114             else {
115             return $params{withtype} ? [ $key->GetValue($valueName) ] : $key->{"/$valueName"};
116             }
117             }
118              
119             sub getRegistryKey {
120             my (%params) = @_;
121              
122             my ( $root, $keyName );
123             if ( $params{path} =~ m{^(HKEY_\S+)/(.+)} ) {
124             $root = $1;
125             $keyName = $2;
126             }
127             else {
128             $params{logger}->error("Failed to parse '$params{path}'. Does it start with HKEY_?") if $params{logger};
129             return;
130             }
131              
132             return _getRegistryKey(
133             logger => $params{logger},
134             root => $root,
135             keyName => $keyName
136             );
137             }
138              
139             sub _getRegistryKey {
140             my (%params) = @_;
141              
142             ## no critic (ProhibitBitwise)
143             my $rootKey
144             = is64bit()
145             ? $Registry->Open( $params{root}, { Access => KEY_READ | KEY_WOW64_64 } )
146             : $Registry->Open( $params{root}, { Access => KEY_READ } );
147              
148             if ( !$rootKey ) {
149             $params{logger}->error("Can't open $params{root} key: $EXTENDED_OS_ERROR") if $params{logger};
150             return;
151             }
152             my $key = $rootKey->Open( $params{keyName} );
153              
154             return $key;
155             }
156              
157             sub getUsersFromRegistry {
158             my (%params) = @_;
159              
160             my $logger = $params{logger};
161              
162             # ensure native registry access, not the 32 bit view
163             my $flags = is64bit() ? KEY_READ | KEY_WOW64_64 : KEY_READ;
164             my $machKey = $Registry->Open(
165             'LMachine',
166             {
167             Access => $flags
168             }
169             ) or $logger->error("Can't open HKEY_LOCAL_MACHINE key: $EXTENDED_OS_ERROR");
170             if ( !$machKey ) {
171             $logger->error("getUsersFromRegistry() : Can't open HKEY_LOCAL_MACHINE key: $EXTENDED_OS_ERROR");
172             return;
173             }
174             $logger->debug2('getUsersFromRegistry() : opened LMachine registry key');
175             my $profileList = $machKey->{"SOFTWARE/Microsoft/Windows NT/CurrentVersion/ProfileList"};
176             next unless $profileList;
177              
178             my $userList;
179             foreach my $profileName ( keys %$profileList ) {
180             $params{logger}->debug2( 'profileName : ' . $profileName );
181             next unless $profileName =~ m{/$};
182             next unless length($profileName) > 10;
183             my $profilePath = $profileList->{$profileName}{'/ProfileImagePath'};
184             my $sid = $profileList->{$profileName}{'/Sid'};
185             next unless $sid;
186             next unless $profilePath;
187             my $user = basename($profilePath);
188             $userList->{$profileName} = $user;
189             }
190              
191             if ( $params{logger} ) {
192             $params{logger}->debug2( 'getUsersFromRegistry() : retrieved ' . scalar( keys %$userList ) . ' users' );
193             }
194             return $userList;
195             }
196              
197             sub parseEventLog {
198             my ($journal_name) = @_;
199              
200             my $recs;
201             my $base;
202             my $hashRef;
203             my $handle = Win32::EventLog->new( $journal_name, $ENV{ComputerName} )
204             or die "Can't open Application EventLog\n";
205             $handle->GetNumber($recs)
206             or die "Can't get number of EventLog records\n";
207             $handle->GetOldest($base)
208             or die "Can't get number of oldest EventLog record\n";
209              
210             my $x = 0;
211             while ( $x < $recs ) {
212             $handle->Read( EVENTLOG_FORWARDS_READ | EVENTLOG_SEEK_READ, $base + $x, $hashRef )
213             or die "Can't read EventLog entry #$x\n";
214              
215             print Dumper($hashRef) . "\n";
216              
217             $x++;
218             }
219             }
220              
221             1;
222             __END__
223              
224             =head1 NAME
225              
226             Armadito::Agent::Tools::Win32 - Windows generic functions
227              
228             =head1 DESCRIPTION
229              
230             This module provides some Windows-specific generic functions.
231              
232             =head1 FUNCTIONS
233              
234             =head2 getWMIObjects(%params)
235              
236             Returns the list of objects from given WMI class or from a query, with given
237             properties, properly encoded.
238              
239             =over
240              
241             =item moniker a WMI moniker (default: winmgmts:{impersonationLevel=impersonate,(security)}!//./)
242              
243             =item class a WMI class, not used if query parameter is also given
244              
245             =item properties a list of WMI properties
246              
247             =item query a WMI request to execute, if specified, class parameter is not used
248              
249             =item method an object method to call, in that case, you will also need the
250             following parameters:
251              
252             =item params a list ref to the parameters to use fro the method. This list contains
253             string as key to other parameters defining the call. The key names should not
254             match any exiting parameter definition. Each parameter definition must be a list
255             of the type and default value.
256              
257             =item binds a hash ref to the properties to bind to the returned object
258              
259             =back
260              
261             =head2 getRegistryValue(%params)
262              
263             Returns a value from the registry.
264              
265             =over
266              
267             =item path a string in hive/key/value format
268              
269             E.g: HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/ProductName
270              
271             =item logger
272              
273             =back
274              
275             =head2 getRegistryKey(%params)
276              
277             Returns a key from the registry. If key name is '*', all the keys of the path are returned as a hash reference.
278              
279             =over
280              
281             =item path a string in hive/key format
282              
283             E.g: HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion
284              
285             =item logger
286              
287             =back