File Coverage

blib/lib/Parse/Win32Registry/WinNT/Security.pm
Criterion Covered Total %
statement 76 85 89.4
branch 17 24 70.8
condition n/a
subroutine 11 14 78.5
pod 0 7 0.0
total 104 130 80.0


line stmt bran cond sub pod time code
1             package Parse::Win32Registry::WinNT::Security;
2              
3 13     13   72 use strict;
  13         30  
  13         439  
4 13     13   67 use warnings;
  13         26  
  13         363  
5              
6 13     13   62 use base qw(Parse::Win32Registry::Entry);
  13         21  
  13         1107  
7              
8 13     13   70 use Carp;
  13         23  
  13         839  
9 13     13   69 use Parse::Win32Registry::Base qw(:all);
  13         24  
  13         3805  
10              
11 13     13   75 use constant SK_HEADER_LENGTH => 0x18;
  13         22  
  13         674  
12 13     13   72 use constant OFFSET_TO_FIRST_HBIN => 0x1000;
  13         25  
  13         9751  
13              
14             sub new {
15 14     14 0 358 my $class = shift;
16 14         26 my $regfile = shift;
17 14         25 my $offset = shift; # offset to sk record relative to start of file
18              
19 14 50       62 croak 'Missing registry file' if !defined $regfile;
20 14 50       44 croak 'Missing offset' if !defined $offset;
21              
22 14 50       60 if (defined(my $cache = $regfile->{_security_cache})) {
23 14 100       51 if (exists $cache->{$offset}) {
24 2         16 return $cache->{$offset};
25             }
26             }
27              
28 12         72 my $fh = $regfile->get_filehandle;
29              
30             # 0x00 dword = security length (negative = allocated)
31             # 0x04 word = 'sk' signature
32             # 0x08 dword = offset to previous sk
33             # 0x0c dword = offset to next sk
34             # 0x10 dword = ref count
35             # 0x14 dword = length of security descriptor
36             # 0x18 = start of security descriptor
37              
38             # Extracted offsets are always relative to first hbin
39              
40 12         69 sysseek($fh, $offset, 0);
41 12         104 my $bytes_read = sysread($fh, my $sk_header, SK_HEADER_LENGTH);
42 12 100       37 if ($bytes_read != SK_HEADER_LENGTH) {
43 1         6 warnf('Could not read security at 0x%x', $offset);
44 1         12 return;
45             }
46              
47 11         505 my ($length,
48             $sig,
49             $offset_to_previous,
50             $offset_to_next,
51             $ref_count,
52             $sd_length,
53             ) = unpack('Va2x2VVVV', $sk_header);
54              
55 11 50       39 $offset_to_previous += OFFSET_TO_FIRST_HBIN
56             if $offset_to_previous != 0xffffffff;
57 11 50       31 $offset_to_next += OFFSET_TO_FIRST_HBIN
58             if $offset_to_next != 0xffffffff;
59              
60 11         145 my $allocated = 0;
61 11 50       32 if ($length > 0x7fffffff) {
62 11         16 $allocated = 1;
63 11         22 $length = (0xffffffff - $length) + 1;
64             }
65             # allocated should be true
66              
67 11 100       44 if ($sig ne 'sk') {
68 1         3 warnf('Invalid signature for security at 0x%x', $offset);
69 1         13 return;
70             }
71              
72 10         69 $bytes_read = sysread($fh, my $sd_data, $sd_length);
73 10 100       43 if ($bytes_read != $sd_length) {
74 1         5 warnf('Could not read security descriptor for security at 0x%x',
75             $offset);
76 1         12 return;
77             }
78              
79 9         47 my $sd = unpack_security_descriptor($sd_data);
80 9 100       37 if (!defined $sd) {
81 1         4 warnf('Invalid security descriptor for security at 0x%x',
82             $offset);
83             # Abandon security object if security descriptor is invalid
84 1         16 return;
85             }
86              
87 8         16 my $self = {};
88 8         23 $self->{_regfile} = $regfile;
89 8         26 $self->{_offset} = $offset;
90 8         18 $self->{_length} = $length;
91 8         67 $self->{_allocated} = $allocated;
92 8         24 $self->{_tag} = $sig;
93 8         23 $self->{_offset_to_previous} = $offset_to_previous;
94 8         17 $self->{_offset_to_next} = $offset_to_next;
95 8         26 $self->{_ref_count} = $ref_count;
96 8         17 $self->{_security_descriptor_length} = $sd_length;
97 8         16 $self->{_security_descriptor} = $sd;
98 8         33 bless $self, $class;
99              
100 8 50       186 if (defined(my $cache = $regfile->{_security_cache})) {
101 8         24 $cache->{$offset} = $self;
102             }
103              
104 8         53 return $self;
105             }
106              
107             sub get_previous {
108 0     0 0 0 my $self = shift;
109 0         0 my $regfile = $self->{_regfile};
110 0         0 my $offset_to_previous = $self->{_offset_to_previous};
111              
112 0         0 return Parse::Win32Registry::WinNT::Security->new($regfile,
113             $offset_to_previous);
114             }
115              
116             sub get_next {
117 7     7 0 15 my $self = shift;
118 7         17 my $regfile = $self->{_regfile};
119 7         21 my $offset_to_next = $self->{_offset_to_next};
120              
121 7         33 return Parse::Win32Registry::WinNT::Security->new($regfile,
122             $offset_to_next);
123             }
124              
125             sub get_reference_count {
126 0     0 0 0 my $self = shift;
127              
128 0         0 return $self->{_ref_count};
129             }
130              
131             sub get_security_descriptor {
132 7     7 0 13 my $self = shift;
133              
134 7         37 return $self->{_security_descriptor};
135             }
136              
137             sub as_string {
138 2     2 0 6 my $self = shift;
139              
140 2         9 return '(security entry)';
141             }
142              
143             sub parse_info {
144 0     0 0   my $self = shift;
145              
146 0           my $info = sprintf '0x%x sk len=0x%x alloc=%d prev=0x%x,next=0x%x refs=%d',
147             $self->{_offset},
148             $self->{_length},
149             $self->{_allocated},
150             $self->{_offset_to_previous},
151             $self->{_offset_to_next},
152             $self->{_ref_count};
153              
154 0           return $info;
155             }
156              
157             1;