line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Symantec::PCAnywhere::Profile; |
2
|
|
|
|
|
|
|
|
3
|
4
|
|
|
4
|
|
42752
|
use strict; |
|
4
|
|
|
|
|
11
|
|
|
4
|
|
|
|
|
131
|
|
4
|
4
|
|
|
4
|
|
22
|
use warnings; |
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
207
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
=head1 NAME |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
Symantec::PCAnywhere::Profile - Base class for pcAnywhere utility functions |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
=head1 VERSION |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
Version 0.06 |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
=cut |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
our $VERSION = '0.06'; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
=head1 SYNOPSIS |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
This class should not be instantiated or used by itself. Use one of its |
21
|
|
|
|
|
|
|
subclasses instead. |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=head1 DESCRIPTION |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
Provides methods common to pcAnywhere utility functions. See L. Below |
26
|
|
|
|
|
|
|
is an overview of the general decoding mechaism. |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
=head2 FILE OBSCURING ALGORITHM |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
The general idea of the file obscuring algorithm is that each byte is XOR'd |
31
|
|
|
|
|
|
|
with the previous byte plus an incrementing eight-bit counter. For reasons |
32
|
|
|
|
|
|
|
unknown to us, there seems to be some kind of shift in the algorithm starting |
33
|
|
|
|
|
|
|
at byte 448, so we split up our decoding into a "first part" and a "second |
34
|
|
|
|
|
|
|
part). |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
for each byte |
37
|
|
|
|
|
|
|
do |
38
|
|
|
|
|
|
|
char = thisbyte (XOR) prevbyte (XOR) counter++ |
39
|
|
|
|
|
|
|
done |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
=head2 FIELD BREAKDOWN |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
The interesting fields appear to be in fixed positions: this was very helpful. |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
String fields seem to be terminated with a NUL byte, and we have observed that |
46
|
|
|
|
|
|
|
changing a long value to a short one leaves the tail end of the long field |
47
|
|
|
|
|
|
|
inside the file. In some cases we do not ever care about the "old" value, but |
48
|
|
|
|
|
|
|
since passwords and login names are disabled by NULing out the first byte, the |
49
|
|
|
|
|
|
|
bytes that remain might be interesting. See L for further |
50
|
|
|
|
|
|
|
discussion. |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
We believe that some fields are slightly overloaded - we have seen overlap - |
53
|
|
|
|
|
|
|
and they mainly revolve around the GATEWAY fields. We don't know how |
54
|
|
|
|
|
|
|
pcAnywhere gateways work well enough to really know what to make of it. |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
=head2 FIELD DECODING |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
We define all the fields of interest in a hash to allow us to do a bit more |
59
|
|
|
|
|
|
|
than just decode: perhaps a bit of reporting or double-checking for overlaps |
60
|
|
|
|
|
|
|
and the like. |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
Each entry has a name, which is used as the key to the user-returned hash, plus |
63
|
|
|
|
|
|
|
the zero-based offset into the setring, the length, and a "type". The type is |
64
|
|
|
|
|
|
|
one of: |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
0 = string, strip everything after first NUL byte |
67
|
|
|
|
|
|
|
1 = string, strip trailing NUL bytes |
68
|
|
|
|
|
|
|
2 = binary |
69
|
|
|
|
|
|
|
3 = little-endian 16-bit word |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
The reason we allow for type #1 is to avoid stripping NUL bytes from a few |
72
|
|
|
|
|
|
|
fields, such as passwords. If you enter a login name or password, but then |
73
|
|
|
|
|
|
|
disable the "auto-login", pcAnywhere simply NULs out the first byte: this is |
74
|
|
|
|
|
|
|
still useful information. |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
The original code on which this module is based was used for penetration |
77
|
|
|
|
|
|
|
testing, and so Type 1 was useful for recovering partly-obscured credentials. |
78
|
|
|
|
|
|
|
However, using Type 1 hampers the more likely use of this module, so the |
79
|
|
|
|
|
|
|
Hostname, Domain_Logname, and Password fields have been changed from Type 1 to |
80
|
|
|
|
|
|
|
Type 0. |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
Type 3 currently exists only for decoding port numbers. |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
=cut |
85
|
|
|
|
|
|
|
|
86
|
4
|
|
|
4
|
|
19
|
use Carp; |
|
4
|
|
|
|
|
10
|
|
|
4
|
|
|
|
|
7478
|
|
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
# |
89
|
|
|
|
|
|
|
# These lists hold coderefs for en-/de-coding. |
90
|
|
|
|
|
|
|
# |
91
|
|
|
|
|
|
|
# Pass in (data). Modified on stack and returned. |
92
|
|
|
|
|
|
|
# |
93
|
|
|
|
|
|
|
my @DECODE_SUB = ( |
94
|
|
|
|
|
|
|
# Type 0 -- strip ALL after NUL |
95
|
|
|
|
|
|
|
sub { $_[0] =~ s/\0.*$// }, |
96
|
|
|
|
|
|
|
# Type 1 -- strip trailing NUL only |
97
|
|
|
|
|
|
|
sub { $_[0] =~ s/\0+$// }, |
98
|
|
|
|
|
|
|
# Type 2 -- binary byte |
99
|
|
|
|
|
|
|
sub { $_[0] = ord($_[0]) }, |
100
|
|
|
|
|
|
|
# Type 3 -- little-endian 16-bit word |
101
|
|
|
|
|
|
|
sub { $_[0] = unpack("v", $_[0]) } |
102
|
|
|
|
|
|
|
); |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
# |
105
|
|
|
|
|
|
|
# Pass in (data, len). Modified on stack and returned. |
106
|
|
|
|
|
|
|
# |
107
|
|
|
|
|
|
|
my @ENCODE_SUB = ( |
108
|
|
|
|
|
|
|
# Type 0 -- pad with NUL |
109
|
|
|
|
|
|
|
sub { $_[0] = substr($_[0] . ("\0" x ($_[1] - length $_[0])), 0, $_[1]) }, |
110
|
|
|
|
|
|
|
# Type 1 -- equivalent to Type 0 for encoding |
111
|
|
|
|
|
|
|
sub { $_[0] = substr($_[0] . ("\0" x ($_[1] - length $_[0])), 0, $_[1]) }, |
112
|
|
|
|
|
|
|
# Type 2 -- binary byte |
113
|
|
|
|
|
|
|
sub { $_[0] = chr($_[0]) }, |
114
|
|
|
|
|
|
|
# Type 3 -- little-endian 16-bit word |
115
|
|
|
|
|
|
|
sub { $_[0] = pack("v", $_[0]) } |
116
|
|
|
|
|
|
|
); |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
=head1 METHODS |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
=head2 PUBLIC |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
=over 4 |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
=item new |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
The "new" constructor takes any number of arguments and sets the appropriate |
127
|
|
|
|
|
|
|
flags internally before returning a new object. The object is implemented as a |
128
|
|
|
|
|
|
|
blessed hash; if more than one argument is passed in, the arguments are |
129
|
|
|
|
|
|
|
considered as a list of key-value pairs which are inserted into the object |
130
|
|
|
|
|
|
|
data. Both "regular" and dash-style arguments are supported. |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
=cut |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
sub new { |
135
|
5
|
|
|
5
|
1
|
13
|
my $type = shift; |
136
|
5
|
|
|
|
|
59
|
my %defaults = ( |
137
|
|
|
|
|
|
|
encode_sub => \@ENCODE_SUB, |
138
|
|
|
|
|
|
|
decode_sub => \@DECODE_SUB, |
139
|
|
|
|
|
|
|
); |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
# Support dash- and regular-style arguments, stripping dashes |
142
|
5
|
100
|
|
|
|
14
|
my %args = map { substr($_, /^-/ ? 1 : 0) => {@_}->{$_} } keys %{{@_}}; |
|
12
|
|
|
|
|
108
|
|
|
5
|
|
|
|
|
30
|
|
143
|
5
|
|
|
|
|
50
|
my $self = bless { %defaults, %args }, $type; |
144
|
5
|
|
|
|
|
22
|
return $self; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=item load_from_file |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
$chf->load_from_file($filename); |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
Loads a file for processing, optionally taking a filename. |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
=cut |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
sub load_from_file ($;$) { |
156
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
157
|
0
|
0
|
0
|
|
|
0
|
$self->{filename} ||= shift or croak "No filename to read from"; |
158
|
|
|
|
|
|
|
|
159
|
0
|
|
|
|
|
0
|
local $/ = undef; |
160
|
0
|
0
|
|
|
|
0
|
open F, "<", $self->{filename} |
161
|
|
|
|
|
|
|
or croak "Failed to open '$self->{filename}' for reading"; |
162
|
0
|
|
|
|
|
0
|
binmode F; |
163
|
0
|
|
|
|
|
0
|
$self->{data} = ; |
164
|
0
|
|
|
|
|
0
|
close F; |
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
=item set_attrs |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
$chf->set_attrs( |
170
|
|
|
|
|
|
|
PhoneNumber => 5551234, |
171
|
|
|
|
|
|
|
AreaCode => 800, |
172
|
|
|
|
|
|
|
IPAddress => '172.0.0.11', |
173
|
|
|
|
|
|
|
ControlPort => '4763' |
174
|
|
|
|
|
|
|
); |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
Sets the attributes of the file; pass in any number of key-value pairs. |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
=cut |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
sub set_attrs ($%) { |
181
|
2
|
|
|
2
|
1
|
22
|
my $self = shift; |
182
|
2
|
|
|
|
|
7
|
my %attrs = @_; |
183
|
|
|
|
|
|
|
|
184
|
2
|
|
50
|
|
|
24
|
$self->{attrs} ||= { }; |
185
|
2
|
|
|
|
|
12
|
while (my ($attr, $value) = each %attrs) { |
186
|
6
|
50
|
|
|
|
43
|
$self->{attrs}{$attr} = $value if $self->{fields}{$attr}; |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
=item set_attr |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
$chf->set_attr($attr => $value); |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
This convenience method sets the value for only one attribute. Note that |
195
|
|
|
|
|
|
|
set_attrs() can be called with exactly the same arguments as this method. |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
=cut |
198
|
|
|
|
|
|
|
|
199
|
0
|
|
|
0
|
1
|
0
|
sub set_attr ($$$) { shift->set_attrs(shift, shift) } |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
=item get_attrs |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
my @query = qw(PhoneNumber AreaCode IPAddress ControlPort); |
204
|
|
|
|
|
|
|
my $attr = $chf->get_attrs(@query); |
205
|
|
|
|
|
|
|
my $attrs = $chf->get_attrs(@query); |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
Pass in a list of items whose attributes you wish to retrieve. Returns a |
208
|
|
|
|
|
|
|
reference to a hash whose keys are the values you passed in and whose values |
209
|
|
|
|
|
|
|
are the attributes retrieved. |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
=cut |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
sub get_attrs ($@) { |
214
|
2
|
|
|
2
|
1
|
29
|
my $self = shift; |
215
|
2
|
|
|
|
|
4
|
my %results; |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
# Do the parsing if necessary |
218
|
2
|
|
33
|
|
|
33
|
$self->{attrs} ||= $self->_parse_pca_file; |
219
|
2
|
|
|
|
|
7
|
%results = map { $_ => $self->{attrs}{$_} } @_; |
|
6
|
|
|
|
|
24
|
|
220
|
2
|
|
|
|
|
14
|
return \%results; |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
=item get_attr |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
my $value = $chf->get_attr($attr); |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
This helper method gets the value for only one attribute and returns it as a |
228
|
|
|
|
|
|
|
scalar. |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=cut |
231
|
|
|
|
|
|
|
|
232
|
0
|
|
|
0
|
1
|
0
|
sub get_attr ($$) { (values %{ shift->get_attrs(shift) })[0] } |
|
0
|
|
|
|
|
0
|
|
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
=item get_fields |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
my @fields = $self->get_fields; |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
Returns (in hash order) the names of fields that can be read from or written to |
239
|
|
|
|
|
|
|
the file. |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=cut |
242
|
|
|
|
|
|
|
|
243
|
0
|
|
|
0
|
1
|
0
|
sub get_fields () { keys %{ shift->{fields} } } |
|
0
|
|
|
|
|
0
|
|
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
=item write_to_file |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
Writes data to a file, optionally taking a filename (if none is supplied, the |
248
|
|
|
|
|
|
|
filename object field is used) |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
=cut |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
sub write_to_file ($;$) { |
253
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
254
|
0
|
0
|
0
|
|
|
0
|
$self->{filename} ||= shift or croak "No filename to write to"; |
255
|
0
|
0
|
0
|
|
|
0
|
$self->{data} or do { $self->encode } or croak "No data to write"; |
|
0
|
|
|
|
|
0
|
|
256
|
|
|
|
|
|
|
|
257
|
0
|
0
|
|
|
|
0
|
open F, ">", $self->{filename} |
258
|
|
|
|
|
|
|
or croak "Failed to open '$self->{filename}' for writing"; |
259
|
0
|
|
|
|
|
0
|
binmode F; |
260
|
0
|
|
|
|
|
0
|
print F $self->{data}; |
261
|
0
|
|
|
|
|
0
|
close F; |
262
|
|
|
|
|
|
|
} |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
=item decode |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
$chf->decode; |
267
|
|
|
|
|
|
|
$chf->decode($chfdata); |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
Decodes the currently-loaded data or new data passed in. |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
=cut |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
sub decode ($;$) { |
274
|
2
|
|
|
2
|
1
|
3
|
my $self = shift; |
275
|
2
|
50
|
33
|
|
|
15
|
$self->{data} ||= shift or do { $self->_load }; |
|
0
|
|
|
|
|
0
|
|
276
|
2
|
50
|
|
|
|
8
|
$self->{data} or croak "No data to decode"; |
277
|
2
|
|
|
|
|
15
|
$self->{decoded} = $self->_decode_pca_file; |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
=item encode |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
$chf->encode; |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
Returns an encoded representation of the CHF file, constructed from the |
285
|
|
|
|
|
|
|
attributes previously set by set_attrs or existing from a constructor or |
286
|
|
|
|
|
|
|
load_from_file() call. |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
=cut |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
sub encode ($) { |
291
|
3
|
|
|
3
|
1
|
25
|
my $self = shift; |
292
|
3
|
|
|
|
|
18
|
$self->{decoded} = $self->_edit_pca_file; |
293
|
3
|
50
|
|
|
|
12
|
$self->{decoded} or croak "No data to encode"; |
294
|
3
|
|
|
|
|
24
|
$self->{data} = $self->_encode_pca_file; |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
=item _encode_pca_file |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
=item _decode_pca_file |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
Method declarations ("abstract" methods) to be implmented by subclasses |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
=cut |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
sub _encode_pca_file ($$); |
306
|
|
|
|
|
|
|
sub _decode_pca_file ($$); |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
=back |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
=head2 PRIVATE |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
=over 4 |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
=item _rawencode |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
This is the low-level engine that handles the XOR encoding of the byte stream. |
317
|
|
|
|
|
|
|
It knows nothing of pcAnywhere data, and it can be called on multiple sections |
318
|
|
|
|
|
|
|
of the file independently. |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
$roll - starting value of the rolling counter |
321
|
|
|
|
|
|
|
$prev - the "previous byte" value upon entry to the loop |
322
|
|
|
|
|
|
|
$str - the string we're to encode |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
=cut |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
sub _rawencode { |
327
|
6
|
|
|
6
|
|
9
|
shift; # Get rid of my $self |
328
|
6
|
|
|
|
|
10
|
my ($roll, $prev, $str) = @_; |
329
|
6
|
|
|
|
|
8
|
my $encstr = ""; # encoded string |
330
|
|
|
|
|
|
|
|
331
|
6
|
|
|
|
|
3180
|
foreach ( split( m//, $str) ) { |
332
|
17120
|
|
|
|
|
15834
|
$prev = ord($_) ^ $prev ^ ($roll++ & 0xFF); |
333
|
17120
|
|
|
|
|
16405
|
$encstr .= chr($prev); |
334
|
|
|
|
|
|
|
} |
335
|
|
|
|
|
|
|
|
336
|
6
|
|
|
|
|
1061
|
return $encstr; |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
=item _rawdecode |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
This is the low-level engine that handles the XOR decoding of the byte stream. |
342
|
|
|
|
|
|
|
It knows nothing of pcAnywhere data, and it can be called on multiple sections |
343
|
|
|
|
|
|
|
of the file independently. |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
$roll - starting value of the rolling counter |
346
|
|
|
|
|
|
|
$prev - the "previous byte" value upon entry to the loop |
347
|
|
|
|
|
|
|
$str - the string we're to decode |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
=cut |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
sub _rawdecode { |
352
|
4
|
|
|
4
|
|
6
|
shift; # Get rid of my $self |
353
|
4
|
|
|
|
|
8
|
my ($roll, $prev, $str) = @_; |
354
|
4
|
|
|
|
|
5
|
my $decstr = ""; # decoded string |
355
|
|
|
|
|
|
|
|
356
|
4
|
|
|
|
|
1464
|
foreach ( split( m//, $str) ) { |
357
|
13812
|
|
|
|
|
11760
|
my $c = ord($_); |
358
|
|
|
|
|
|
|
|
359
|
13812
|
|
|
|
|
13872
|
$decstr .= chr( $c ^ $prev ^ ($roll++ & 0xFF) ); |
360
|
13812
|
|
|
|
|
16842
|
$prev = $c; |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
|
363
|
4
|
|
|
|
|
937
|
return $decstr; |
364
|
|
|
|
|
|
|
} |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
=item _edit_pca_file |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
Performs encoding operations (internal) |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
=cut |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
sub _edit_pca_file ($) { |
373
|
3
|
|
|
3
|
|
5
|
my $self = shift; |
374
|
|
|
|
|
|
|
# Make a copy of the template string |
375
|
3
|
|
|
|
|
7
|
my $str = $self->{template}; |
376
|
|
|
|
|
|
|
|
377
|
3
|
|
|
|
|
26
|
foreach my $key ( keys %{ $self->{attrs} } ) { |
|
3
|
|
|
|
|
13
|
|
378
|
6
|
|
|
|
|
11
|
my $f = $self->{fields}{$key}; |
379
|
|
|
|
|
|
|
# This must be a known key to continue |
380
|
6
|
50
|
|
|
|
14
|
unless ($f) { |
381
|
0
|
|
|
|
|
0
|
carp "Tried to set unknown key -- continuing"; |
382
|
0
|
|
|
|
|
0
|
next; |
383
|
|
|
|
|
|
|
} |
384
|
|
|
|
|
|
|
|
385
|
6
|
|
|
|
|
9
|
my ($off, $len, $type) = @$f; |
386
|
6
|
|
|
|
|
13
|
my $val = $self->{attrs}{$key}; |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
# If there is a handler defined for this type, use it |
389
|
6
|
50
|
|
|
|
60
|
$self->{encode_sub}[$type]->($val, $len) |
390
|
|
|
|
|
|
|
if defined $self->{encode_sub}[$type]; |
391
|
|
|
|
|
|
|
|
392
|
6
|
|
|
|
|
47
|
substr($str, $off, $len) = $val; |
393
|
|
|
|
|
|
|
} |
394
|
|
|
|
|
|
|
|
395
|
3
|
|
|
|
|
31
|
return $str; |
396
|
|
|
|
|
|
|
} |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
=item _parse_pca_file |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
Teases the binary format into a hash (internal) |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
=cut |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
sub _parse_pca_file ($) { |
405
|
2
|
|
|
2
|
|
4
|
my $self = shift; |
406
|
2
|
|
33
|
|
|
10
|
my $str = $self->{decoded} || do { $self->decode }; |
407
|
2
|
|
|
|
|
13
|
my $ref = { }; |
408
|
|
|
|
|
|
|
|
409
|
2
|
|
|
|
|
8
|
foreach my $key ( keys %{ $self->{fields} } ) { |
|
2
|
|
|
|
|
22
|
|
410
|
25
|
|
|
|
|
25
|
my ($off, $len, $type) = @{ $self->{fields}{$key} }; |
|
25
|
|
|
|
|
52
|
|
411
|
25
|
|
|
|
|
55
|
my $val = substr($str, $off, $len); |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
# If there is a handler defined for this type, use it |
414
|
25
|
50
|
|
|
|
91
|
$self->{decode_sub}[$type]->($val) |
415
|
|
|
|
|
|
|
if defined $self->{decode_sub}[$type]; |
416
|
|
|
|
|
|
|
|
417
|
25
|
|
|
|
|
64
|
$ref->{$key} = $val; |
418
|
|
|
|
|
|
|
} |
419
|
|
|
|
|
|
|
|
420
|
2
|
|
|
|
|
16
|
return $ref; |
421
|
|
|
|
|
|
|
} |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
=item _load |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
Does loading of filedata if necessary |
426
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
=cut |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
sub _load ($) { |
430
|
0
|
|
|
0
|
|
|
my $self = shift; |
431
|
0
|
0
|
|
|
|
|
unless ($self->{data}) { |
432
|
0
|
0
|
|
|
|
|
if ($self->{filename}) { |
433
|
0
|
|
|
|
|
|
$self->load_from_file; |
434
|
|
|
|
|
|
|
} else { |
435
|
0
|
|
|
|
|
|
croak "No filename specified and no data loaded"; |
436
|
|
|
|
|
|
|
} |
437
|
|
|
|
|
|
|
} |
438
|
|
|
|
|
|
|
} |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
=back |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
=head1 TO DO |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
Our understanding of the decoding process just looks incomplete: it's |
445
|
|
|
|
|
|
|
complicated enough for no good reason that we really just suspect that we have |
446
|
|
|
|
|
|
|
done it wrong. There are a couple of glitches even in the current decoding that |
447
|
|
|
|
|
|
|
it requires a bit more thought. |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
Implement better error handling. |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
Explain the default values for certain special fields. |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
Get rid of the silly prototype definitions on the method definitions. |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
Create (more) tests! |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
=head1 SEE ALSO |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
See L for a useful subclass of this module. |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
=head1 AUTHOR |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
Darren Kulp, C<< >>, based on code from Stephen J. Friedl, |
464
|
|
|
|
|
|
|
(http://unixwiz.net/) |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
This module is based on 'pcainfo' from Stephen J. Friedl. His work, which is in |
469
|
|
|
|
|
|
|
the public domain, has been modified to add encoding capabilities to allow |
470
|
|
|
|
|
|
|
creating CHFs (pcAnywhere connection profiles). Thanks, Stephen! |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
The addition of encoding and an OO interface, as well as the packaging as a |
473
|
|
|
|
|
|
|
CPAN module and the correcting of some typographical errors, semantic |
474
|
|
|
|
|
|
|
redundancies, and spelling mistakes, was done by Darren Kulp. |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
This code is in the public domain. Contains code placed in the public domain |
479
|
|
|
|
|
|
|
2002 by Stephen Friedl. |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
"Symantec" and "pcAnywhere" are trademarks of Symantec Corp. |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
=head1 BUGS |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
Please report any bugs or feature requests to |
486
|
|
|
|
|
|
|
C, or through the web interface at |
487
|
|
|
|
|
|
|
L. |
488
|
|
|
|
|
|
|
I will be notified, and then you'll automatically be notified of progress on |
489
|
|
|
|
|
|
|
your bug as I make changes. |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
=head1 SUPPORT |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command. |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
perldoc Symantec::PCAnywhere::Profile |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
You can also look for information at: |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
=over 4 |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
=item * AnnoCPAN: Annotated CPAN documentation |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
L |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
=item * CPAN Ratings |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
L |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
=item * RT: CPAN's request tracker |
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
L |
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
=item * Search CPAN |
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
L |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
=back |
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
=cut |
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
1; # End of Symantec::PCAnywhere::Profile |